mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
camerabin2: Implement previewing
Implement previewing functionality using 2 properties. A boolean (post-previews) that indicates if previews should be posted, and a GstCaps (preview-caps) to provide the desired preview caps. wrappercamerabinsrc implements previewing by supplying the captured image to a pipeline to adapt it to the required caps before posting.
This commit is contained in:
parent
aa671439e1
commit
9863feb328
4 changed files with 133 additions and 1 deletions
|
@ -66,7 +66,9 @@ enum
|
|||
PROP_IMAGE_CAPTURE_SUPPORTED_CAPS,
|
||||
PROP_VIDEO_CAPTURE_SUPPORTED_CAPS,
|
||||
PROP_IMAGE_CAPTURE_CAPS,
|
||||
PROP_VIDEO_CAPTURE_CAPS
|
||||
PROP_VIDEO_CAPTURE_CAPS,
|
||||
PROP_POST_PREVIEWS,
|
||||
PROP_PREVIEW_CAPS
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -82,6 +84,7 @@ static guint camerabin_signals[LAST_SIGNAL];
|
|||
#define DEFAULT_MODE MODE_IMAGE
|
||||
#define DEFAULT_VID_LOCATION "vid_%d"
|
||||
#define DEFAULT_IMG_LOCATION "img_%d"
|
||||
#define DEFAULT_POST_PREVIEWS TRUE
|
||||
|
||||
/********************************
|
||||
* Standard GObject boilerplate *
|
||||
|
@ -328,6 +331,15 @@ gst_camera_bin_class_init (GstCameraBinClass * klass)
|
|||
"Caps for video capture",
|
||||
GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_POST_PREVIEWS,
|
||||
g_param_spec_boolean ("post-previews", "Post Previews",
|
||||
"If capture preview images should be posted to the bus",
|
||||
DEFAULT_POST_PREVIEWS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PREVIEW_CAPS,
|
||||
g_param_spec_boxed ("preview-caps", "Preview caps",
|
||||
"The caps of the preview image to be posted",
|
||||
GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstCameraBin::capture-start:
|
||||
|
@ -357,6 +369,7 @@ gst_camera_bin_class_init (GstCameraBinClass * klass)
|
|||
static void
|
||||
gst_camera_bin_init (GstCameraBin * camera)
|
||||
{
|
||||
camera->post_previews = DEFAULT_POST_PREVIEWS;
|
||||
camera->mode = DEFAULT_MODE;
|
||||
camera->video_location = g_strdup (DEFAULT_VID_LOCATION);
|
||||
camera->image_location = g_strdup (DEFAULT_IMG_LOCATION);
|
||||
|
@ -465,6 +478,12 @@ gst_camera_bin_create_elements (GstCameraBin * camera)
|
|||
|
||||
g_assert (camera->src != NULL);
|
||||
g_object_set (camera->src, "mode", camera->mode, NULL);
|
||||
if (camera->src
|
||||
&& g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src),
|
||||
"preview-caps")) {
|
||||
g_object_set (camera->src, "post-previews", camera->post_previews,
|
||||
"preview-caps", camera->preview_caps, NULL);
|
||||
}
|
||||
if (new_src) {
|
||||
gst_bin_add (GST_BIN_CAST (camera), gst_object_ref (camera->src));
|
||||
camera->src_capture_notify_id = g_signal_connect (G_OBJECT (camera->src),
|
||||
|
@ -603,6 +622,22 @@ gst_camera_bin_set_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
break;
|
||||
case PROP_POST_PREVIEWS:
|
||||
camera->post_previews = g_value_get_boolean (value);
|
||||
if (camera->src
|
||||
&& g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src),
|
||||
"post-previews"))
|
||||
g_object_set (camera->src, "post-previews", camera->post_previews,
|
||||
NULL);
|
||||
break;
|
||||
case PROP_PREVIEW_CAPS:
|
||||
gst_caps_replace (&camera->preview_caps,
|
||||
(GstCaps *) gst_value_get_caps (value));
|
||||
if (camera->src
|
||||
&& g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src),
|
||||
"preview-caps"))
|
||||
g_object_set (camera->src, "preview-caps", camera->preview_caps, NULL);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -678,6 +713,13 @@ gst_camera_bin_get_property (GObject * object, guint prop_id,
|
|||
gst_caps_unref (caps);
|
||||
}
|
||||
break;
|
||||
case PROP_POST_PREVIEWS:
|
||||
g_value_set_boolean (value, camera->post_previews);
|
||||
break;
|
||||
case PROP_PREVIEW_CAPS:
|
||||
if (camera->preview_caps)
|
||||
gst_value_set_caps (value, camera->preview_caps);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -60,6 +60,8 @@ struct _GstCameraBin
|
|||
gint mode;
|
||||
gchar *video_location;
|
||||
gchar *image_location;
|
||||
gboolean post_previews;
|
||||
GstCaps *preview_caps;
|
||||
|
||||
gboolean elements_created;
|
||||
};
|
||||
|
|
|
@ -38,9 +38,12 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
PROP_VIDEO_SRC,
|
||||
PROP_POST_PREVIEWS,
|
||||
PROP_PREVIEW_CAPS
|
||||
};
|
||||
|
||||
#define CAMERABIN_DEFAULT_VF_CAPS "video/x-raw-yuv,format=(fourcc)I420"
|
||||
#define DEFAULT_POST_PREVIEWS TRUE
|
||||
|
||||
/* Using "bilinear" as default zoom method */
|
||||
#define CAMERABIN_DEFAULT_ZOOM_METHOD 1
|
||||
|
@ -64,6 +67,11 @@ gst_wrapper_camera_bin_src_dispose (GObject * object)
|
|||
self->app_vid_src = NULL;
|
||||
}
|
||||
|
||||
if (self->preview_pipeline) {
|
||||
gst_camerabin_destroy_preview_pipeline (self->preview_pipeline);
|
||||
self->preview_pipeline = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -93,6 +101,16 @@ gst_wrapper_camera_bin_src_set_property (GObject * object,
|
|||
gst_object_ref (self->app_vid_src);
|
||||
}
|
||||
break;
|
||||
case PROP_POST_PREVIEWS:
|
||||
self->post_previews = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_PREVIEW_CAPS:
|
||||
gst_caps_replace (&self->preview_caps,
|
||||
(GstCaps *) gst_value_get_caps (value));
|
||||
if (self->preview_pipeline)
|
||||
gst_camerabin_preview_set_caps (self->preview_pipeline,
|
||||
(GstCaps *) gst_value_get_caps (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
|
||||
break;
|
||||
|
@ -112,6 +130,13 @@ gst_wrapper_camera_bin_src_get_property (GObject * object,
|
|||
else
|
||||
g_value_set_object (value, self->app_vid_src);
|
||||
break;
|
||||
case PROP_POST_PREVIEWS:
|
||||
g_value_set_boolean (value, self->post_previews);
|
||||
break;
|
||||
case PROP_PREVIEW_CAPS:
|
||||
if (self->preview_caps)
|
||||
gst_value_set_caps (value, self->preview_caps);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
|
||||
break;
|
||||
|
@ -151,6 +176,13 @@ gst_wrapper_camera_bin_src_imgsrc_probe (GstPad * pad, GstBuffer * buffer,
|
|||
if (self->image_capture_count > 0) {
|
||||
ret = TRUE;
|
||||
self->image_capture_count--;
|
||||
|
||||
/* post preview */
|
||||
/* TODO This can likely be optimized if the viewfinder caps is the same as
|
||||
* the preview caps, avoiding another scaling of the same buffer. */
|
||||
if (self->post_previews)
|
||||
gst_camerabin_preview_pipeline_post (self->preview_pipeline, buffer);
|
||||
|
||||
if (self->image_capture_count == 0) {
|
||||
gst_base_camera_src_finish_capture (camerasrc);
|
||||
}
|
||||
|
@ -190,6 +222,11 @@ gst_wrapper_camera_bin_src_vidsrc_probe (GstPad * pad, GstBuffer * buffer,
|
|||
gst_pad_push_event (pad, gst_event_new_new_segment (FALSE, 1.0,
|
||||
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer), -1, 0));
|
||||
self->video_rec_status = GST_VIDEO_RECORDING_STATUS_RUNNING;
|
||||
|
||||
/* post preview */
|
||||
if (self->post_previews)
|
||||
gst_camerabin_preview_pipeline_post (self->preview_pipeline, buffer);
|
||||
|
||||
ret = TRUE;
|
||||
} else if (self->video_rec_status == GST_VIDEO_RECORDING_STATUS_FINISHING) {
|
||||
/* send eos */
|
||||
|
@ -357,6 +394,12 @@ gst_wrapper_camera_bin_src_construct_pipeline (GstBaseCameraSrc * bcamsrc)
|
|||
gst_pad_set_active (self->imgsrc, TRUE); /* XXX ??? */
|
||||
gst_pad_set_active (self->vidsrc, TRUE); /* XXX ??? */
|
||||
|
||||
/* create the preview pipeline */
|
||||
self->preview_pipeline =
|
||||
gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self));
|
||||
if (self->preview_caps)
|
||||
gst_camerabin_preview_set_caps (self->preview_pipeline, self->preview_caps);
|
||||
|
||||
ret = TRUE;
|
||||
self->elements_created = TRUE;
|
||||
done:
|
||||
|
@ -890,6 +933,30 @@ gst_wrapper_camera_bin_src_stop_capture (GstBaseCameraSrc * camerasrc)
|
|||
}
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_wrapper_camera_bin_src_change_state (GstElement * element,
|
||||
GstStateChange trans)
|
||||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (element);
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
|
||||
|
||||
switch (trans) {
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL);
|
||||
break;
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
gst_element_set_state (self->preview_pipeline->pipeline,
|
||||
GST_STATE_PLAYING);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_wrapper_camera_bin_src_base_init (gpointer g_class)
|
||||
{
|
||||
|
@ -907,9 +974,11 @@ static void
|
|||
gst_wrapper_camera_bin_src_class_init (GstWrapperCameraBinSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseCameraSrcClass *gstbasecamerasrc_class;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
gstbasecamerasrc_class = GST_BASE_CAMERA_SRC_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = gst_wrapper_camera_bin_src_dispose;
|
||||
|
@ -924,6 +993,18 @@ gst_wrapper_camera_bin_src_class_init (GstWrapperCameraBinSrcClass * klass)
|
|||
"The video source element to be used",
|
||||
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_POST_PREVIEWS,
|
||||
g_param_spec_boolean ("post-previews", "Post Previews",
|
||||
"If capture preview images should be posted to the bus",
|
||||
DEFAULT_POST_PREVIEWS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PREVIEW_CAPS,
|
||||
g_param_spec_boxed ("preview-caps", "Preview caps",
|
||||
"The caps of the preview image to be posted",
|
||||
GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gstelement_class->change_state = gst_wrapper_camera_bin_src_change_state;
|
||||
|
||||
gstbasecamerasrc_class->construct_pipeline =
|
||||
gst_wrapper_camera_bin_src_construct_pipeline;
|
||||
gstbasecamerasrc_class->set_zoom = gst_wrapper_camera_bin_src_set_zoom;
|
||||
|
@ -967,6 +1048,7 @@ gst_wrapper_camera_bin_src_init (GstWrapperCameraBinSrc * self,
|
|||
self->video_renegotiate = FALSE;
|
||||
self->image_renegotiate = FALSE;
|
||||
self->mode = GST_BASE_CAMERA_SRC_CAST (self)->mode;
|
||||
self->post_previews = DEFAULT_POST_PREVIEWS;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
|
||||
#include "camerabingeneral.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_WRAPPER_CAMERA_BIN_SRC \
|
||||
|
@ -107,6 +108,11 @@ struct _GstWrapperCameraBinSrc
|
|||
GstCaps *image_capture_caps;
|
||||
gboolean image_renegotiate;
|
||||
gboolean video_renegotiate;
|
||||
|
||||
/* Preview convert pipeline */
|
||||
GstCameraBinPreviewPipelineData *preview_pipeline;
|
||||
gboolean post_previews;
|
||||
GstCaps *preview_caps;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue