From aa671439e1709b0aaec2a435c292aa3e2708ec91 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 30 Dec 2010 00:26:07 -0300 Subject: [PATCH] camerabin2: Add methods for preview image message posting Adds a helper struct and functions for implementing a preview message in camerabin2. --- .../gst/basecamerabinsrc/gstbasecamerasrc.h | 2 + gst/camerabin2/Makefile.am | 2 +- gst/camerabin2/camerabingeneral.c | 186 +++++++++++++++++- gst/camerabin2/camerabingeneral.h | 16 ++ 4 files changed, 204 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h index 8ab0008048..70535bccff 100644 --- a/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h +++ b/gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h @@ -52,6 +52,8 @@ typedef struct _GstBaseCameraSrcClass GstBaseCameraSrcClass; #define GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME "imgsrc" #define GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME "vidsrc" +#define GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME "preview-image" + /** * GstBaseCameraSrc: */ diff --git a/gst/camerabin2/Makefile.am b/gst/camerabin2/Makefile.am index a4299be10f..cf32a7082f 100644 --- a/gst/camerabin2/Makefile.am +++ b/gst/camerabin2/Makefile.am @@ -17,7 +17,7 @@ libgstcamerabin2_la_CFLAGS = \ libgstcamerabin2_la_LIBADD = \ $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-$(GST_MAJORMINOR).la \ $(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-$(GST_MAJORMINOR).la \ - $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR) \ + $(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR) -lgstapp-$(GST_MAJORMINOR) \ $(GST_BASE_LIBS) $(GST_LIBS) libgstcamerabin2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/gst/camerabin2/camerabingeneral.c b/gst/camerabin2/camerabingeneral.c index 0219a0fe3b..a354075b5e 100644 --- a/gst/camerabin2/camerabingeneral.c +++ b/gst/camerabin2/camerabingeneral.c @@ -28,8 +28,11 @@ */ #include -#include "camerabingeneral.h" #include +#include +#include +#include +#include "camerabingeneral.h" /** * gst_camerabin_add_element: @@ -272,3 +275,184 @@ gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data) } return ret; } + +static GstFlowReturn +gst_camerabin_preview_pipeline_new_preroll (GstAppSink * appsink, + gpointer user_data) +{ + GstBuffer *buffer; + + buffer = gst_app_sink_pull_preroll (appsink); + gst_buffer_unref (buffer); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_camerabin_preview_pipeline_new_buffer (GstAppSink * appsink, + gpointer user_data) +{ + GstBuffer *buffer; + GstStructure *s; + GstMessage *msg; + GstCameraBinPreviewPipelineData *data; + + data = user_data; + + buffer = gst_app_sink_pull_buffer (appsink); + s = gst_structure_new (GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME, + "buffer", GST_TYPE_BUFFER, buffer, NULL); + gst_buffer_unref (buffer); + msg = gst_message_new_element (GST_OBJECT (data->element), s); + + GST_DEBUG_OBJECT (data->element, "sending message with preview image"); + if (gst_element_post_message (data->element, msg) == FALSE) { + GST_WARNING_OBJECT (data->element, + "This element has no bus, therefore no message sent!"); + } + + return GST_FLOW_OK; +} + +/** + * gst_camerabin_create_preview_pipeline: + * @element: Owner of this pipeline + * + * Creates a new previewing pipeline that can receive buffers + * to be posted as camerabin preview messages for @element + * + * Returns: The newly created #GstCameraBinPreviewPipelineData + */ +GstCameraBinPreviewPipelineData * +gst_camerabin_create_preview_pipeline (GstElement * element) +{ + GstCameraBinPreviewPipelineData *data; + GstElement *csp; + GstElement *csp2; + GstElement *vscale; + gboolean added = FALSE; + GstAppSinkCallbacks callbacks = { 0, }; + + data = g_new (GstCameraBinPreviewPipelineData, 1); + + data->pipeline = gst_pipeline_new ("preview-pipeline"); + data->appsrc = gst_element_factory_make ("appsrc", "preview-appsrc"); + data->capsfilter = gst_element_factory_make ("capsfilter", + "preview-capsfilter"); + data->appsink = gst_element_factory_make ("appsink", "preview-appsink"); + csp = gst_element_factory_make ("ffmpegcolorspace", "preview-csp0"); + csp2 = gst_element_factory_make ("ffmpegcolorspace", "preview-csp1"); + vscale = gst_element_factory_make ("videoscale", "preview-vscale"); + + if (!data->appsrc || !data->capsfilter || !data->appsink || !csp || + !csp2 || !vscale) { + goto error; + } + + gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->capsfilter, + data->appsink, csp, csp2, vscale, NULL); + added = TRUE; + + if (!gst_element_link_many (data->appsrc, csp, vscale, csp2, data->capsfilter, + data->appsink, NULL)) + goto error; + + callbacks.new_preroll = gst_camerabin_preview_pipeline_new_preroll; + callbacks.new_buffer = gst_camerabin_preview_pipeline_new_buffer; + gst_app_sink_set_callbacks ((GstAppSink *) data->appsink, &callbacks, data, + NULL); + + data->element = element; + + return data; +error: + GST_WARNING ("Failed to create camerabin's preview pipeline"); + if (!added) { + if (csp) + gst_object_unref (csp); + if (csp2) + gst_object_unref (csp2); + if (vscale) + gst_object_unref (vscale); + if (data->appsrc) + gst_object_unref (data->appsrc); + if (data->capsfilter) + gst_object_unref (data->capsfilter); + if (data->appsink) + gst_object_unref (data->appsink); + } + gst_camerabin_destroy_preview_pipeline (data); + return NULL; +} + +/** + * gst_camerabin_destroy_preview_pipeline: + * @preview: the #GstCameraBinPreviewPipelineData + * + * Frees a #GstCameraBinPreviewPipelineData + */ +void +gst_camerabin_destroy_preview_pipeline (GstCameraBinPreviewPipelineData * + preview) +{ + if (preview->pipeline) { + gst_element_set_state (preview->pipeline, GST_STATE_NULL); + gst_object_unref (preview->pipeline); + } + g_free (preview); +} + +/** + * gst_camerabin_preview_pipeline_post: + * @preview: the #GstCameraBinPreviewPipelineData + * @buffer: the buffer to be posted as a preview + * + * Converts the @buffer to the desired format and posts the preview + * message to the bus. + * + * Returns: %TRUE on success + */ +gboolean +gst_camerabin_preview_pipeline_post (GstCameraBinPreviewPipelineData * preview, + GstBuffer * buffer) +{ + g_return_val_if_fail (preview != NULL, FALSE); + g_return_val_if_fail (preview->pipeline != NULL, FALSE); + g_return_val_if_fail (buffer, FALSE); + + gst_app_src_push_buffer ((GstAppSrc *) preview->appsrc, + gst_buffer_ref (buffer)); + + return TRUE; +} + +/** + * gst_camerabin_preview_set_caps: + * @preview: the #GstCameraBinPreviewPipelineData + * @caps: the #GstCaps to be set + * + * The caps that preview buffers should have when posted + * on the bus + */ +void +gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * preview, + GstCaps * caps) +{ + GstState state, pending; + GstStateChangeReturn ret; + + g_return_if_fail (preview != NULL); + + ret = gst_element_get_state (preview->pipeline, &state, &pending, 0); + if (ret == GST_STATE_CHANGE_FAILURE) { + /* make it try again */ + state = GST_STATE_PLAYING; + pending = GST_STATE_VOID_PENDING; + } + + gst_element_set_state (preview->pipeline, GST_STATE_NULL); + g_object_set (preview->capsfilter, "caps", caps, NULL); + if (pending != GST_STATE_VOID_PENDING) + state = pending; + gst_element_set_state (preview->pipeline, state); +} diff --git a/gst/camerabin2/camerabingeneral.h b/gst/camerabin2/camerabingeneral.h index 7f453aca2f..096038b9a7 100644 --- a/gst/camerabin2/camerabingeneral.h +++ b/gst/camerabin2/camerabingeneral.h @@ -23,6 +23,22 @@ #include +typedef struct +{ + GstElement *pipeline; + + GstElement *appsrc; + GstElement *capsfilter; + GstElement *appsink; + + GstElement *element; +} GstCameraBinPreviewPipelineData; + +GstCameraBinPreviewPipelineData *gst_camerabin_create_preview_pipeline (GstElement * element); +void gst_camerabin_destroy_preview_pipeline (GstCameraBinPreviewPipelineData * preview); +gboolean gst_camerabin_preview_pipeline_post (GstCameraBinPreviewPipelineData * preview, GstBuffer * buffer); +void gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * preview, GstCaps * caps); + gboolean gst_camerabin_try_add_element (GstBin * bin, const gchar * srcpad, GstElement * new_elem, const gchar * dstpad); gboolean gst_camerabin_add_element (GstBin * bin, GstElement * new_elem); gboolean gst_camerabin_add_element_full (GstBin * bin, const gchar * srcpad, GstElement * new_elem, const gchar * dstpad);