From bde8707b659319dc29fe9d748ea6b3d9492d3703 Mon Sep 17 00:00:00 2001 From: Lasse Laukkanen Date: Fri, 20 Feb 2009 12:08:04 +0200 Subject: camerabin: Add aspect ratio capsfilter for view finder If dealing with larger frame sizes than view finder sink element accepts then maintain aspect ratio when scaling frames to fit. --- gst/camerabin/gstcamerabin.c | 129 +++++++++++++++++++++++++++++++++++++++---- gst/camerabin/gstcamerabin.h | 2 + 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/gst/camerabin/gstcamerabin.c b/gst/camerabin/gstcamerabin.c index ffa7575a..e836b4b7 100644 --- a/gst/camerabin/gstcamerabin.c +++ b/gst/camerabin/gstcamerabin.c @@ -274,6 +274,12 @@ static void gst_camerabin_set_allowed_framerate (GstCameraBin * camera, GstCaps * filter_caps); +static const GValue *gst_camerabin_find_better_framerate (GstCameraBin * camera, + GstStructure * st, const GValue * orig_framerate); + +static void +gst_camerabin_update_aspect_filter (GstCameraBin * camera, GstCaps * new_caps); + /* * GObject callback functions declaration */ @@ -295,8 +301,6 @@ static void gst_camerabin_set_property (GObject * object, guint prop_id, static void gst_camerabin_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static const GValue *gst_camerabin_find_better_framerate (GstCameraBin * camera, - GstStructure * st, const GValue * orig_framerate); /* * GstElement function declarations */ @@ -562,6 +566,9 @@ camerabin_create_src_elements (GstCameraBin * camera) gst_camerabin_create_and_add_element (cbin, "output-selector"))) goto done; + camera->srcpad_videosrc = + gst_element_get_static_pad (camera->src_vid_src, "src"); + camera->srcpad_zoom_filter = gst_element_get_static_pad (camera->src_zoom_filter, "src"); @@ -642,6 +649,12 @@ camerabin_create_view_elements (GstCameraBin * camera) "videoscale"))) { goto error; } + + if (!(camera->aspect_filter = + gst_camerabin_create_and_add_element (GST_BIN (camera), + "capsfilter"))) { + goto error; + } #ifdef USE_COLOR_CONVERTER if (!gst_camerabin_create_and_add_element (GST_BIN (camera), "ffmpegcolorspace")) { @@ -785,6 +798,16 @@ camerabin_destroy_elements (GstCameraBin * camera) camera->pad_src_view = NULL; } + if (camera->srcpad_zoom_filter) { + gst_object_unref (camera->srcpad_zoom_filter); + camera->srcpad_zoom_filter = NULL; + } + + if (camera->srcpad_videosrc) { + gst_object_unref (camera->srcpad_videosrc); + camera->srcpad_videosrc = NULL; + } + camera->view_sink = NULL; camera->view_scale = NULL; camera->view_in_sel = NULL; @@ -1264,6 +1287,7 @@ gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps) /* Update capsfilters */ g_object_set (G_OBJECT (camera->src_filter), "caps", new_caps, NULL); g_object_set (G_OBJECT (camera->src_zoom_filter), "caps", new_caps, NULL); + gst_camerabin_update_aspect_filter (camera, new_caps); } static void @@ -1489,7 +1513,7 @@ image_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data) GST_DEBUG_OBJECT (camera, "%s %s:%s", blocked ? "blocking" : "unblocking", GST_DEBUG_PAD_NAME (pad)); - if (blocked && (pad == camera->pad_src_img)) { + if (blocked && (pad == camera->srcpad_videosrc)) { /* Send eos and block until image bin reaches eos */ GST_DEBUG_OBJECT (camera, "sending eos to image bin"); gst_element_send_event (camera->imgbin, gst_event_new_eos ()); @@ -1534,12 +1558,6 @@ gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer, /* Check for first buffer after capture start, we want to pass it forward directly. */ if (!camera->num_img_buffers) { - /* Restore filter caps for view finder mode if necessary. - The v4l2camsrc switches automatically to view finder - resolution after hi-res still image capture. */ - if (camera->image_capture_caps) { - gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps); - } goto done; } @@ -1579,7 +1597,7 @@ done: /* Block when next buffer arrives, we want to push eos event between frames and make sure that eos reaches the filesink before processing the next buffer. */ - gst_pad_set_blocked_async (pad, TRUE, + gst_pad_set_blocked_async (camera->srcpad_videosrc, TRUE, (GstPadBlockCallback) image_pad_blocked, camera); } @@ -1875,6 +1893,87 @@ gst_camerabin_find_better_framerate (GstCameraBin * camera, GstStructure * st, return framerate; } +/* + * gst_camerabin_update_aspect_filter: + * @camera: camerabin object + * @new_caps: new caps of next buffers arriving to view finder sink element + * + * Updates aspect ratio capsfilter to maintain aspect ratio, if we need to + * scale frames for showing them in view finder. + */ +static void +gst_camerabin_update_aspect_filter (GstCameraBin * camera, GstCaps * new_caps) +{ + GstCaps *sink_caps, *ar_caps; + GstStructure *st; + gint in_w = 0, in_h = 0, sink_w = 0, sink_h = 0, target_w = 0, target_h = 0; + gdouble ratio_w, ratio_h; + GstPad *sink_pad; + const GValue *range; + + sink_pad = gst_element_get_static_pad (camera->view_sink, "sink"); + + if (sink_pad) { + sink_caps = gst_pad_get_caps (sink_pad); + gst_object_unref (sink_pad); + if (sink_caps) { + GST_DEBUG_OBJECT (camera, "sink element caps %" GST_PTR_FORMAT, + sink_caps); + /* Get maximum resolution that view finder sink accepts */ + st = gst_caps_get_structure (sink_caps, 0); + if (gst_structure_has_field_typed (st, "width", GST_TYPE_INT_RANGE)) { + range = gst_structure_get_value (st, "width"); + sink_w = gst_value_get_int_range_max (range); + } + if (gst_structure_has_field_typed (st, "height", GST_TYPE_INT_RANGE)) { + range = gst_structure_get_value (st, "height"); + sink_h = gst_value_get_int_range_max (range); + } + gst_caps_unref (sink_caps); + GST_DEBUG_OBJECT (camera, "sink element accepts max %dx%d", sink_w, + sink_h); + + /* Get incoming frames' resolution */ + if (sink_h && sink_w) { + st = gst_caps_get_structure (new_caps, 0); + gst_structure_get_int (st, "width", &in_w); + gst_structure_get_int (st, "height", &in_h); + GST_DEBUG_OBJECT (camera, "new caps with %dx%d", in_w, in_h); + } + } + } + + /* If we get bigger frames than view finder sink accepts, then we scale. + If we scale we need to adjust aspect ratio capsfilter caps in order + to maintain aspect ratio while scaling. */ + if (in_w && in_h && (in_w > sink_w || in_h > sink_h)) { + ratio_w = (gdouble) sink_w / in_w; + ratio_h = (gdouble) sink_h / in_h; + + if (ratio_w < ratio_h) { + target_w = sink_w; + target_h = (gint) (ratio_w * in_h); + } else { + target_w = (gint) (ratio_h * in_w); + target_h = sink_h; + } + + GST_DEBUG_OBJECT (camera, "setting %dx%d filter to maintain aspect ratio", + target_w, target_h); + ar_caps = gst_caps_copy (new_caps); + gst_caps_set_simple (ar_caps, "width", G_TYPE_INT, target_w, "height", + G_TYPE_INT, target_h, NULL); + } else { + GST_DEBUG_OBJECT (camera, "no scaling"); + ar_caps = gst_caps_ref (new_caps); + } + + GST_DEBUG_OBJECT (camera, "aspect ratio filter caps %" GST_PTR_FORMAT, + ar_caps); + g_object_set (G_OBJECT (camera->aspect_filter), "caps", ar_caps, NULL); + gst_caps_unref (ar_caps); +} + /* * GObject callback functions implementation */ @@ -2273,7 +2372,9 @@ gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass) camera->pad_view_img = NULL; camera->pad_src_vid = NULL; camera->pad_view_vid = NULL; + camera->srcpad_zoom_filter = NULL; + camera->srcpad_videosrc = NULL; /* source elements */ camera->src_vid_src = NULL; @@ -2604,8 +2705,14 @@ gst_camerabin_handle_message_func (GstBin * bin, GstMessage * msg) } else if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->imgbin)) { /* Image eos */ GST_DEBUG_OBJECT (camera, "got image eos message"); + + /* Still image capture buffer handled, restore filter caps */ + if (camera->image_capture_caps) { + gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps); + } + /* Unblock pad to process next buffer */ - gst_pad_set_blocked_async (camera->pad_src_img, FALSE, + gst_pad_set_blocked_async (camera->srcpad_videosrc, FALSE, (GstPadBlockCallback) image_pad_blocked, camera); } break; diff --git a/gst/camerabin/gstcamerabin.h b/gst/camerabin/gstcamerabin.h index 809ce722..f4eefe91 100644 --- a/gst/camerabin/gstcamerabin.h +++ b/gst/camerabin/gstcamerabin.h @@ -97,6 +97,7 @@ struct _GstCameraBin GstPad *pad_view_vid; GstPad *srcpad_zoom_filter; + GstPad *srcpad_videosrc; GstElement *imgbin; /* bin that holds image capturing elements */ GstElement *vidbin; /* bin that holds video capturing elements */ @@ -112,6 +113,7 @@ struct _GstCameraBin /* view finder elements */ GstElement *view_in_sel; + GstElement *aspect_filter; GstElement *view_scale; GstElement *view_sink; -- cgit v1.2.1