From 55d98ef488a252ae0944c973c1a0adb6c07a5832 Mon Sep 17 00:00:00 2001 From: Lasse Laukkanen Date: Tue, 2 Mar 2010 14:04:44 +0200 Subject: [PATCH] camerabin: add block-after-capture property for viewfinder blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds block-after-capture property to block running viewfinder after capturing. This property is useful if application wants to display capture preview and avoid running viewfinder on background. Based on a patch by Tommi Myöhänen --- gst/camerabin/gstcamerabin-enum.h | 3 +- gst/camerabin/gstcamerabin.c | 83 +++++++++++++++++++++++++++++-- gst/camerabin/gstcamerabin.h | 1 + tests/check/elements/camerabin.c | 6 +++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/gst/camerabin/gstcamerabin-enum.h b/gst/camerabin/gstcamerabin-enum.h index 43e87ba46e..bd5b987185 100644 --- a/gst/camerabin/gstcamerabin-enum.h +++ b/gst/camerabin/gstcamerabin-enum.h @@ -60,7 +60,8 @@ enum ARG_IMAGE_CAPTURE_SUPPORTED_CAPS, ARG_VIEWFINDER_FILTER, ARG_FLICKER_MODE, - ARG_FOCUS_MODE + ARG_FOCUS_MODE, + ARG_BLOCK_VIEWFINDER }; /** diff --git a/gst/camerabin/gstcamerabin.c b/gst/camerabin/gstcamerabin.c index b7ed540472..9db7cae6f2 100644 --- a/gst/camerabin/gstcamerabin.c +++ b/gst/camerabin/gstcamerabin.c @@ -223,6 +223,8 @@ static guint camerabin_signals[LAST_SIGNAL]; /* FIXME: this is v4l2camsrc specific */ #define DEFAULT_V4L2CAMSRC_DRIVER_NAME "omap3cam" +#define DEFAULT_BLOCK_VIEWFINDER FALSE + /* message names */ #define PREVIEW_MESSAGE_NAME "preview-image" #define IMG_CAPTURED_MESSAGE_NAME "image-captured" @@ -266,6 +268,9 @@ static void gst_camerabin_start_image_capture (GstCameraBin * camera); static void gst_camerabin_start_video_recording (GstCameraBin * camera); +static void +camerabin_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data); + static gboolean gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer, gpointer u_data); @@ -1592,6 +1597,11 @@ gst_camerabin_send_video_eos (GstCameraBin * camera) videopad = gst_element_get_static_pad (camera->vidbin, "sink"); gst_pad_send_event (videopad, gst_event_new_eos ()); gst_object_unref (videopad); + /* Block viewfinder after capturing if requested by application */ + if (camera->block_viewfinder) { + gst_pad_set_blocked_async (camera->pad_src_view, TRUE, + (GstPadBlockCallback) camerabin_pad_blocked, camera); + } camera->eos_handled = TRUE; } else { GST_INFO_OBJECT (camera, "dropping duplicate EOS"); @@ -1599,15 +1609,15 @@ gst_camerabin_send_video_eos (GstCameraBin * camera) } /* - * image_pad_blocked: + * camerabin_pad_blocked: * @pad: pad to block/unblock * @blocked: TRUE to block, FALSE to unblock * @u_data: camera bin object * - * The pad will be unblocked when image bin posts eos message. + * Callback function for blocking a pad. */ static void -image_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data) +camerabin_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data) { GstCameraBin *camera; @@ -1802,6 +1812,12 @@ gst_camerabin_have_src_buffer (GstPad * pad, GstBuffer * buffer, gst_camerabin_send_img_queue_custom_event (camera, gst_structure_new ("img-eos", NULL)); + /* Prevent video source from pushing frames until we want them */ + if (camera->block_viewfinder) { + gst_pad_set_blocked_async (camera->pad_src_view, TRUE, + (GstPadBlockCallback) camerabin_pad_blocked, camera); + } + /* our work is done, disconnect */ gst_pad_remove_buffer_probe (pad, camera->image_captured_id); @@ -1865,7 +1881,7 @@ gst_camerabin_have_queue_data (GstPad * pad, GstMiniObject * mini_obj, } else if (evs && gst_structure_has_name (evs, "img-eos")) { GST_DEBUG_OBJECT (camera, "queue sending EOS to image pipeline"); gst_pad_set_blocked_async (camera->pad_src_queue, TRUE, - (GstPadBlockCallback) image_pad_blocked, camera); + (GstPadBlockCallback) camerabin_pad_blocked, camera); gst_element_send_event (camera->imgbin, gst_event_new_eos ()); ret = FALSE; } @@ -2452,6 +2468,39 @@ copy_missing_fields (GQuark field_id, const GValue * value, gpointer user_data) return TRUE; } +/* +* gst_camerabin_change_viewfinder_blocking: +* @camera: camerabin object +* @blocked: new viewfinder blocking state +* +* Handle viewfinder blocking parameter change. +*/ +static void +gst_camerabin_change_viewfinder_blocking (GstCameraBin * camera, + gboolean blocked) +{ + gboolean old_value; + + GST_OBJECT_LOCK (camera); + old_value = camera->block_viewfinder; + camera->block_viewfinder = blocked; + GST_OBJECT_UNLOCK (camera); + + /* "block_viewfinder" is now set and will be checked after capture */ + GST_DEBUG_OBJECT (camera, "viewfinder blocking set to %d, was %d", + camera->block_viewfinder, old_value); + + if (old_value == blocked) + return; + + if (!blocked && camera->pad_src_view + && gst_pad_is_blocked (camera->pad_src_view)) { + /* Unblock viewfinder: the pad is blocked and we need to unblock it */ + gst_pad_set_blocked_async (camera->pad_src_view, FALSE, + (GstPadBlockCallback) camerabin_pad_blocked, camera); + } +} + /* * GObject callback functions implementation */ @@ -2739,6 +2788,23 @@ gst_camerabin_class_init (GstCameraBinClass * klass) "viewfinder filter GStreamer element", GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + /** + * GstCameraBin:block-after-capture: + * + * Block viewfinder after capture. + * When set to TRUE, camerabin will freeze the viewfinder after capturing. + * This is useful if application wants to display the preview image + * and running the viewfinder at the same time would be just a waste of + * CPU cycles. Viewfinder can be enabled again by setting this property to + * FALSE. + */ + + g_object_class_install_property (gobject_class, ARG_BLOCK_VIEWFINDER, + g_param_spec_boolean ("block-after-capture", + "Block viewfinder after capture", + "Block viewfinder after capturing an image or video", + DEFAULT_BLOCK_VIEWFINDER, G_PARAM_READWRITE)); + /** * GstCameraBin::capture-start: * @camera: the camera bin element @@ -3198,6 +3264,10 @@ gst_camerabin_set_property (GObject * object, guint prop_id, camera->app_viewfinder_filter = g_value_dup_object (value); } break; + case ARG_BLOCK_VIEWFINDER: + gst_camerabin_change_viewfinder_blocking (camera, + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3293,6 +3363,9 @@ gst_camerabin_get_property (GObject * object, guint prop_id, case ARG_VIEWFINDER_FILTER: g_value_set_object (value, camera->app_viewfinder_filter); break; + case ARG_BLOCK_VIEWFINDER: + g_value_set_boolean (value, camera->block_viewfinder); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3408,7 +3481,7 @@ gst_camerabin_imgbin_finished (gpointer u_data) /* Unblock image queue pad to process next buffer */ gst_pad_set_blocked_async (camera->pad_src_queue, FALSE, - (GstPadBlockCallback) image_pad_blocked, camera); + (GstPadBlockCallback) camerabin_pad_blocked, camera); GST_DEBUG_OBJECT (camera, "Queue srcpad unblocked"); /* disconnect automatically */ diff --git a/gst/camerabin/gstcamerabin.h b/gst/camerabin/gstcamerabin.h index 474c3ebe5a..b91c232af0 100644 --- a/gst/camerabin/gstcamerabin.h +++ b/gst/camerabin/gstcamerabin.h @@ -63,6 +63,7 @@ struct _GstCameraBin GstCameraBinFlags flags; gboolean stop_requested; /* TRUE if capturing stop needed */ gboolean paused; /* TRUE if capturing paused */ + gboolean block_viewfinder; /* TRUE if viewfinder blocks after capture */ /* Resolution of the buffers configured to camerabin */ gint width; diff --git a/tests/check/elements/camerabin.c b/tests/check/elements/camerabin.c index be6a96a11c..306e4fb667 100644 --- a/tests/check/elements/camerabin.c +++ b/tests/check/elements/camerabin.c @@ -81,6 +81,9 @@ handle_image_captured_cb (gpointer data) { GMainLoop *loop = (GMainLoop *) data; + /* unblock viewfinder */ + g_object_set (camera, "block-after-capture", FALSE, NULL); + GST_DEBUG ("handle_image_captured_cb, cycle: %d", cycle_count); if (cycle_count == 0) { GST_DEBUG ("all cycles done"); @@ -661,6 +664,9 @@ GST_START_TEST (test_single_image_capture) g_object_set (camera, "mode", 0, "filename", make_test_file_name (SINGLE_IMAGE_FILENAME), NULL); + /* don't run viewfinder after capture */ + g_object_set (camera, "block-after-capture", TRUE, NULL); + GST_INFO ("starting capture"); g_signal_emit_by_name (camera, "capture-start", NULL);