camerabin2: Add preview-filter property
authorThiago Santos <thiago.sousa.santos@collabora.co.uk>
Thu, 27 Jan 2011 17:39:19 +0000 (14:39 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.co.uk>
Thu, 3 Feb 2011 22:09:20 +0000 (19:09 -0300)
Adds a property to select a custom element for preview pipeline
buffers processing

gst/camerabin2/camerabingeneral.c
gst/camerabin2/camerabingeneral.h
gst/camerabin2/gstcamerabin2.c
gst/camerabin2/gstcamerabin2.h
gst/camerabin2/gstwrappercamerabinsrc.c
gst/camerabin2/gstwrappercamerabinsrc.h

index d6c1c86..26edc12 100644 (file)
@@ -320,6 +320,7 @@ gst_camerabin_preview_pipeline_new_buffer (GstAppSink * appsink,
 /**
  * gst_camerabin_create_preview_pipeline:
  * @element: Owner of this pipeline
+ * @filter: Custom filter to process preview data (an extra ref is taken)
  *
  * Creates a new previewing pipeline that can receive buffers
  * to be posted as camerabin preview messages for @element
@@ -327,7 +328,8 @@ gst_camerabin_preview_pipeline_new_buffer (GstAppSink * appsink,
  * Returns: The newly created #GstCameraBinPreviewPipelineData
  */
 GstCameraBinPreviewPipelineData *
-gst_camerabin_create_preview_pipeline (GstElement * element)
+gst_camerabin_create_preview_pipeline (GstElement * element,
+    GstElement * filter)
 {
   GstCameraBinPreviewPipelineData *data;
   GstElement *csp;
@@ -354,11 +356,19 @@ gst_camerabin_create_preview_pipeline (GstElement * element)
 
   gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->capsfilter,
       data->appsink, csp, csp2, vscale, NULL);
+  if (filter)
+    gst_bin_add (GST_BIN (data->pipeline), gst_object_ref (filter));
   added = TRUE;
 
-  if (!gst_element_link_many (data->appsrc, csp, vscale, csp2, data->capsfilter,
-          data->appsink, NULL))
-    goto error;
+  if (filter) {
+    if (!gst_element_link_many (data->appsrc, filter, csp, vscale, csp2,
+            data->capsfilter, data->appsink, NULL))
+      goto error;
+  } else {
+    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;
@@ -366,6 +376,7 @@ gst_camerabin_create_preview_pipeline (GstElement * element)
       NULL);
 
   data->element = element;
+  data->filter = filter;
 
   return data;
 error:
index 4e0812a..f39cbd7 100644 (file)
@@ -28,13 +28,14 @@ typedef struct
   GstElement *pipeline;
 
   GstElement *appsrc;
+  GstElement *filter;
   GstElement *capsfilter;
   GstElement *appsink;
 
   GstElement *element;
 } GstCameraBinPreviewPipelineData;
 
-GstCameraBinPreviewPipelineData *gst_camerabin_create_preview_pipeline (GstElement * element);
+GstCameraBinPreviewPipelineData *gst_camerabin_create_preview_pipeline (GstElement * element, GstElement * filter);
 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);
index 85a5696..d7139a4 100644 (file)
@@ -75,7 +75,8 @@ enum
   PROP_VIDEO_ENCODING_PROFILE,
   PROP_IMAGE_FILTER,
   PROP_VIDEO_FILTER,
-  PROP_VIEWFINDER_FILTER
+  PROP_VIEWFINDER_FILTER,
+  PROP_PREVIEW_FILTER
 };
 
 enum
@@ -303,6 +304,10 @@ gst_camera_bin_dispose (GObject * object)
 
   if (camerabin->preview_caps)
     gst_caps_replace (&camerabin->preview_caps, NULL);
+  if (camerabin->preview_filter) {
+    gst_object_unref (camerabin->preview_filter);
+    camerabin->preview_filter = NULL;
+  }
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -432,6 +437,12 @@ gst_camera_bin_class_init (GstCameraBinClass * klass)
           " (Should be set on NULL state)",
           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (object_class, PROP_PREVIEW_FILTER,
+      g_param_spec_object ("preview-filter", "Preview filter",
+          "The element that will process preview buffers."
+          " (Should be set on NULL state)",
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
 
   /**
    * GstCameraBin::capture-start:
@@ -678,7 +689,8 @@ gst_camera_bin_create_elements (GstCameraBin * camera)
       && 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);
+        "preview-caps", camera->preview_caps, "preview-filter",
+        camera->preview_filter, NULL);
   }
   if (new_src) {
     gst_bin_add (GST_BIN_CAST (camera), gst_object_ref (camera->src));
@@ -872,6 +884,17 @@ gst_camera_bin_set_property (GObject * object, guint prop_id,
 
       camera->user_viewfinder_filter = g_value_dup_object (value);
       break;
+    case PROP_PREVIEW_FILTER:
+      if (camera->preview_filter)
+        g_object_unref (camera->preview_filter);
+
+      camera->preview_filter = g_value_dup_object (value);
+      if (camera->src
+          && g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src),
+              "preview-filter"))
+        g_object_set (camera->src, "preview-filter", camera->preview_filter,
+            NULL);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -972,6 +995,10 @@ gst_camera_bin_get_property (GObject * object, guint prop_id,
       if (camera->viewfinder_filter)
         g_value_set_object (value, camera->viewfinder_filter);
       break;
+    case PROP_PREVIEW_FILTER:
+      if (camera->preview_filter)
+        g_value_set_object (value, camera->preview_filter);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index f24417f..64828b4 100644 (file)
@@ -71,6 +71,7 @@ struct _GstCameraBin
   gchar *image_location;
   gboolean post_previews;
   GstCaps *preview_caps;
+  GstElement *preview_filter;
   GstEncodingProfile *video_profile;
 
   gboolean elements_created;
index 864373b..c35fe8d 100644 (file)
@@ -39,7 +39,8 @@ enum
   PROP_0,
   PROP_VIDEO_SRC,
   PROP_POST_PREVIEWS,
-  PROP_PREVIEW_CAPS
+  PROP_PREVIEW_CAPS,
+  PROP_PREVIEW_FILTER
 };
 
 #define DEFAULT_POST_PREVIEWS TRUE
@@ -74,6 +75,11 @@ gst_wrapper_camera_bin_src_dispose (GObject * object)
   if (self->preview_caps)
     gst_caps_replace (&self->preview_caps, NULL);
 
+  if (self->preview_filter) {
+    gst_object_unref (self->preview_filter);
+    self->preview_filter = NULL;
+  }
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
@@ -113,6 +119,12 @@ gst_wrapper_camera_bin_src_set_property (GObject * object,
         gst_camerabin_preview_set_caps (self->preview_pipeline,
             (GstCaps *) gst_value_get_caps (value));
       break;
+    case PROP_PREVIEW_FILTER:
+      if (self->preview_filter)
+        gst_object_unref (self->preview_filter);
+      self->preview_filter = g_value_dup_object (value);
+      self->preview_filter_changed = TRUE;
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
       break;
@@ -139,6 +151,10 @@ gst_wrapper_camera_bin_src_get_property (GObject * object,
       if (self->preview_caps)
         gst_value_set_caps (value, self->preview_caps);
       break;
+    case PROP_PREVIEW_FILTER:
+      if (self->preview_filter)
+        g_value_set_object (value, self->preview_filter);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
       break;
@@ -294,127 +310,138 @@ gst_wrapper_camera_bin_src_construct_pipeline (GstBaseCameraSrc * bcamsrc)
   GstPad *vf_pad;
   GstPad *tee_capture_pad;
 
-  if (self->elements_created)
-    return TRUE;
+  if (!self->elements_created) {
 
-  GST_DEBUG_OBJECT (self, "constructing pipeline");
+    GST_DEBUG_OBJECT (self, "constructing pipeline");
 
-  /* Add application set or default video src element */
-  if (!(self->src_vid_src = gst_camerabin_setup_default_element (cbin,
-              self->app_vid_src, "autovideosrc", DEFAULT_VIDEOSRC,
-              "camerasrc-real-src"))) {
-    self->src_vid_src = NULL;
-    goto done;
-  } else {
-    if (!gst_camerabin_add_element (cbin, self->src_vid_src)) {
+    /* Add application set or default video src element */
+    if (!(self->src_vid_src = gst_camerabin_setup_default_element (cbin,
+                self->app_vid_src, "autovideosrc", DEFAULT_VIDEOSRC,
+                "camerasrc-real-src"))) {
+      self->src_vid_src = NULL;
       goto done;
+    } else {
+      if (!gst_camerabin_add_element (cbin, self->src_vid_src)) {
+        goto done;
+      }
     }
-  }
-  /* we lost the reference */
-  self->app_vid_src = NULL;
+    /* we lost the reference */
+    self->app_vid_src = NULL;
 
-  /* add a buffer probe to the src elemento to drop EOS from READY->NULL */
-  {
-    GstPad *pad;
-    pad = gst_element_get_static_pad (self->src_vid_src, "src");
+    /* add a buffer probe to the src elemento to drop EOS from READY->NULL */
+    {
+      GstPad *pad;
+      pad = gst_element_get_static_pad (self->src_vid_src, "src");
 
-    self->src_event_probe_id = gst_pad_add_event_probe (pad,
-        (GCallback) gst_camerabin_drop_eos_probe, NULL);
-    gst_object_unref (pad);
-  }
+      self->src_event_probe_id = gst_pad_add_event_probe (pad,
+          (GCallback) gst_camerabin_drop_eos_probe, NULL);
+      gst_object_unref (pad);
+    }
 
-  if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
-          "src-colorspace"))
-    goto done;
+    if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
+            "src-colorspace"))
+      goto done;
 
-  if (!(self->src_filter =
-          gst_camerabin_create_and_add_element (cbin, "capsfilter",
-              "src-capsfilter")))
-    goto done;
+    if (!(self->src_filter =
+            gst_camerabin_create_and_add_element (cbin, "capsfilter",
+                "src-capsfilter")))
+      goto done;
 
-  if (!(self->src_zoom_crop =
-          gst_camerabin_create_and_add_element (cbin, "videocrop",
-              "zoom-crop")))
-    goto done;
-  if (!(self->src_zoom_scale =
-          gst_camerabin_create_and_add_element (cbin, "videoscale",
-              "zoom-scale")))
-    goto done;
-  if (!(self->src_zoom_filter =
-          gst_camerabin_create_and_add_element (cbin, "capsfilter",
-              "zoom-capsfilter")))
-    goto done;
+    if (!(self->src_zoom_crop =
+            gst_camerabin_create_and_add_element (cbin, "videocrop",
+                "zoom-crop")))
+      goto done;
+    if (!(self->src_zoom_scale =
+            gst_camerabin_create_and_add_element (cbin, "videoscale",
+                "zoom-scale")))
+      goto done;
+    if (!(self->src_zoom_filter =
+            gst_camerabin_create_and_add_element (cbin, "capsfilter",
+                "zoom-capsfilter")))
+      goto done;
 
-  if (!(tee =
-          gst_camerabin_create_and_add_element (cbin, "tee", "camerasrc-tee")))
-    goto done;
+    if (!(tee =
+            gst_camerabin_create_and_add_element (cbin, "tee",
+                "camerasrc-tee")))
+      goto done;
 
-  /* viewfinder pad */
-  vf_pad = gst_element_get_request_pad (tee, "src%d");
-  g_object_set (tee, "alloc-pad", vf_pad, NULL);
-  gst_object_unref (vf_pad);
+    /* viewfinder pad */
+    vf_pad = gst_element_get_request_pad (tee, "src%d");
+    g_object_set (tee, "alloc-pad", vf_pad, NULL);
+    gst_object_unref (vf_pad);
 
-  /* the viewfinder should always work, so we add some converters to it */
-  if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
-          "viewfinder-colorspace"))
-    goto done;
-  if (!(videoscale =
-          gst_camerabin_create_and_add_element (cbin, "videoscale",
-              "viewfinder-scale")))
-    goto done;
+    /* the viewfinder should always work, so we add some converters to it */
+    if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
+            "viewfinder-colorspace"))
+      goto done;
+    if (!(videoscale =
+            gst_camerabin_create_and_add_element (cbin, "videoscale",
+                "viewfinder-scale")))
+      goto done;
 
-  /* image/video pad from tee */
-  tee_capture_pad = gst_element_get_request_pad (tee, "src%d");
+    /* image/video pad from tee */
+    tee_capture_pad = gst_element_get_request_pad (tee, "src%d");
 
-  self->output_selector =
-      gst_element_factory_make ("output-selector", "outsel");
-  g_object_set (self->output_selector, "pad-negotiation-mode", 0, NULL);
-  gst_bin_add (GST_BIN (self), self->output_selector);
-  {
-    GstPad *pad = gst_element_get_static_pad (self->output_selector, "sink");
+    self->output_selector =
+        gst_element_factory_make ("output-selector", "outsel");
+    g_object_set (self->output_selector, "pad-negotiation-mode", 0, NULL);
+    gst_bin_add (GST_BIN (self), self->output_selector);
+    {
+      GstPad *pad = gst_element_get_static_pad (self->output_selector, "sink");
 
-    /* check return TODO */
-    gst_pad_link (tee_capture_pad, pad);
-    gst_object_unref (pad);
+      /* check return TODO */
+      gst_pad_link (tee_capture_pad, pad);
+      gst_object_unref (pad);
+    }
+    gst_object_unref (tee_capture_pad);
+
+    /* Create the 2 output pads for video and image */
+    self->outsel_vidpad =
+        gst_element_get_request_pad (self->output_selector, "src%d");
+    self->outsel_imgpad =
+        gst_element_get_request_pad (self->output_selector, "src%d");
+
+    g_assert (self->outsel_vidpad != NULL);
+    g_assert (self->outsel_imgpad != NULL);
+
+    gst_pad_add_buffer_probe (self->outsel_imgpad,
+        G_CALLBACK (gst_wrapper_camera_bin_src_imgsrc_probe), self);
+    gst_pad_add_buffer_probe (self->outsel_vidpad,
+        G_CALLBACK (gst_wrapper_camera_bin_src_vidsrc_probe), self);
+    gst_ghost_pad_set_target (GST_GHOST_PAD (self->imgsrc),
+        self->outsel_imgpad);
+    gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc),
+        self->outsel_vidpad);
+
+    if (bcamsrc->mode == MODE_IMAGE) {
+      g_object_set (self->output_selector, "active-pad", self->outsel_imgpad,
+          NULL);
+    } else {
+      g_object_set (self->output_selector, "active-pad", self->outsel_vidpad,
+          NULL);
+    }
+
+    /* hook-up the vf ghostpad */
+    vf_pad = gst_element_get_static_pad (videoscale, "src");
+    gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), vf_pad);
+    gst_object_unref (vf_pad);
+
+    gst_pad_set_active (self->vfsrc, TRUE);
+    gst_pad_set_active (self->imgsrc, TRUE);    /* XXX ??? */
+    gst_pad_set_active (self->vidsrc, TRUE);    /* XXX ??? */
   }
-  gst_object_unref (tee_capture_pad);
-
-  /* Create the 2 output pads for video and image */
-  self->outsel_vidpad =
-      gst_element_get_request_pad (self->output_selector, "src%d");
-  self->outsel_imgpad =
-      gst_element_get_request_pad (self->output_selector, "src%d");
-
-  g_assert (self->outsel_vidpad != NULL);
-  g_assert (self->outsel_imgpad != NULL);
-
-  gst_pad_add_buffer_probe (self->outsel_imgpad,
-      G_CALLBACK (gst_wrapper_camera_bin_src_imgsrc_probe), self);
-  gst_pad_add_buffer_probe (self->outsel_vidpad,
-      G_CALLBACK (gst_wrapper_camera_bin_src_vidsrc_probe), self);
-  gst_ghost_pad_set_target (GST_GHOST_PAD (self->imgsrc), self->outsel_imgpad);
-  gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc), self->outsel_vidpad);
-
-  if (bcamsrc->mode == MODE_IMAGE) {
-    g_object_set (self->output_selector, "active-pad", self->outsel_imgpad,
-        NULL);
-  } else {
-    g_object_set (self->output_selector, "active-pad", self->outsel_vidpad,
-        NULL);
+  /* recreate the preview pipeline */
+  if (self->preview_pipeline && self->preview_filter_changed) {
+    gst_camerabin_destroy_preview_pipeline (self->preview_pipeline);
   }
 
-  /* hook-up the vf ghostpad */
-  vf_pad = gst_element_get_static_pad (videoscale, "src");
-  gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), vf_pad);
-  gst_object_unref (vf_pad);
-
-  gst_pad_set_active (self->vfsrc, TRUE);
-  gst_pad_set_active (self->imgsrc, TRUE);      /* XXX ??? */
-  gst_pad_set_active (self->vidsrc, TRUE);      /* XXX ??? */
+  if (self->preview_pipeline == NULL)
+    self->preview_pipeline =
+        gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self),
+        self->preview_filter);
 
-  /* create the preview pipeline */
-  self->preview_pipeline =
-      gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self));
+  g_assert (self->preview_pipeline != NULL);
+  self->preview_filter_changed = FALSE;
   if (self->preview_caps)
     gst_camerabin_preview_set_caps (self->preview_pipeline, self->preview_caps);
 
@@ -1025,6 +1052,11 @@ gst_wrapper_camera_bin_src_class_init (GstWrapperCameraBinSrcClass * klass)
           "The caps of the preview image to be posted",
           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_PREVIEW_FILTER,
+      g_param_spec_object ("preview-filter", "Preview filter",
+          "A custom preview filter to process preview image data",
+          GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gstelement_class->change_state = gst_wrapper_camera_bin_src_change_state;
 
   gstbasecamerasrc_class->construct_pipeline =
index c74be27..b2f4c7a 100644 (file)
@@ -113,6 +113,8 @@ struct _GstWrapperCameraBinSrc
   GstCameraBinPreviewPipelineData *preview_pipeline;
   gboolean post_previews;
   GstCaps *preview_caps;
+  GstElement *preview_filter;
+  gboolean preview_filter_changed;
 };