summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gst/camerabin2/Makefile.am17
-rw-r--r--gst/camerabin2/camerabingeneral.c276
-rw-r--r--gst/camerabin2/camerabingeneral.h42
-rw-r--r--gst/camerabin2/gstbasecamerasrc.c509
-rw-r--r--gst/camerabin2/gstbasecamerasrc.h146
-rw-r--r--gst/camerabin2/gstcamerabin-enum.c78
-rw-r--r--gst/camerabin2/gstcamerabin-enum.h140
-rw-r--r--gst/camerabin2/gstplugin.c3
-rw-r--r--gst/camerabin2/gstv4l2camerasrc.c1077
-rw-r--r--gst/camerabin2/gstv4l2camerasrc.h112
10 files changed, 2397 insertions, 3 deletions
diff --git a/gst/camerabin2/Makefile.am b/gst/camerabin2/Makefile.am
index 49d29aa00..25b1e61ed 100644
--- a/gst/camerabin2/Makefile.am
+++ b/gst/camerabin2/Makefile.am
@@ -2,17 +2,28 @@ plugin_LTLIBRARIES = libgstcamerabin2.la
libgstcamerabin2_la_SOURCES = gstviewfinderbin.c \
gstimagecapturebin.c \
+ camerabingeneral.c \
+ gstbasecamerasrc.c \
+ gstcamerabin-enum.c \
+ gstv4l2camerasrc.c \
gstplugin.c
libgstcamerabin2_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
- $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+ $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+ -DGST_USE_UNSTABLE_API
libgstcamerabin2_la_LIBADD = \
- $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
+ $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-$(GST_MAJORMINOR).la \
+ $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \
+ -lgstinterfaces-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR)
libgstcamerabin2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstcamerabin2_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstviewfinderbin.h \
- gstimagecapturebin.h
+ gstimagecapturebin.h \
+ camerabingeneral.h \
+ gstbasecamerasrc.h \
+ gstv4l2camerasrc.h \
+ gstcamerabin-enum.h
diff --git a/gst/camerabin2/camerabingeneral.c b/gst/camerabin2/camerabingeneral.c
new file mode 100644
index 000000000..2a50d9e12
--- /dev/null
+++ b/gst/camerabin2/camerabingeneral.c
@@ -0,0 +1,276 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:camerabingeneral
+ * @short_description: helper functions for #GstCameraBin and it's modules
+ *
+ * Common helper functions for #GstCameraBin, #GstCameraBinImage and
+ * #GstCameraBinVideo.
+ *
+ */
+#include <string.h>
+
+#include "camerabingeneral.h"
+#include <glib.h>
+
+GST_DEBUG_CATEGORY (gst_camerabin_debug);
+
+/**
+ * gst_camerabin_add_element:
+ * @bin: add an element to this bin
+ * @new_elem: new element to be added
+ *
+ * Adds given element to given @bin. Looks for an unconnected src pad
+ * from the @bin and links the element to it. Raises an error if adding
+ * or linking failed. Unrefs the element in the case of an error.
+ *
+ * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise.
+ */
+gboolean
+gst_camerabin_add_element (GstBin * bin, GstElement * new_elem)
+{
+ return gst_camerabin_add_element_full (bin, NULL, new_elem, NULL);
+}
+
+/**
+ * gst_camerabin_add_element_full:
+ * @bin: add an element to this bin
+ * @srcpad: src pad name, or NULL for any
+ * @new_elem: new element to be added
+ * @dstpad: dst pad name, or NULL for any
+ *
+ * Adds given element to given @bin. Looks for an unconnected src pad
+ * (with name @srcpad, if specified) from the @bin and links the element
+ * to it. Raises an error if adding or linking failed. Unrefs the element
+ * in the case of an error.
+ *
+ * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise.
+ */
+gboolean
+gst_camerabin_add_element_full (GstBin * bin, const gchar * srcpad,
+ GstElement * new_elem, const gchar * dstpad)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (bin, FALSE);
+ g_return_val_if_fail (new_elem, FALSE);
+
+ ret = gst_camerabin_try_add_element (bin, srcpad, new_elem, dstpad);
+
+ if (!ret) {
+ gchar *elem_name = gst_element_get_name (new_elem);
+ GST_ELEMENT_ERROR (bin, CORE, NEGOTIATION, (NULL),
+ ("linking %s failed", elem_name));
+ g_free (elem_name);
+ gst_object_unref (new_elem);
+ }
+
+ return ret;
+}
+
+/**
+ * gst_camerabin_try_add_element:
+ * @bin: tries adding an element to this bin
+ * @srcpad: src pad name, or NULL for any
+ * @new_elem: new element to be added
+ * @dstpad: dst pad name, or NULL for any
+ *
+ * Adds given element to given @bin. Looks for an unconnected src pad
+ * (with name @srcpad, if specified) from the @bin and links the element to
+ * it.
+ *
+ * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise.
+ */
+gboolean
+gst_camerabin_try_add_element (GstBin * bin, const gchar * srcpad,
+ GstElement * new_elem, const gchar * dstpad)
+{
+ GstPad *bin_pad;
+ GstElement *bin_elem;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (bin, FALSE);
+ g_return_val_if_fail (new_elem, FALSE);
+
+ /* Get pads for linking */
+ bin_pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC);
+ /* Add to bin */
+ gst_bin_add (GST_BIN (bin), new_elem);
+ /* Link, if unconnected pad was found, otherwise just add it to bin */
+ if (bin_pad) {
+ GST_DEBUG_OBJECT (bin, "linking %s to %s:%s", GST_OBJECT_NAME (new_elem),
+ GST_DEBUG_PAD_NAME (bin_pad));
+ bin_elem = gst_pad_get_parent_element (bin_pad);
+ gst_object_unref (bin_pad);
+ if (!gst_element_link_pads (bin_elem, srcpad, new_elem, dstpad)) {
+ gst_object_ref (new_elem);
+ gst_bin_remove (bin, new_elem);
+ ret = FALSE;
+ }
+ gst_object_unref (bin_elem);
+ } else {
+ GST_INFO_OBJECT (bin, "no unlinked source pad in bin");
+ }
+
+ return ret;
+}
+
+/**
+ * gst_camerabin_create_and_add_element:
+ * @bin: tries adding an element to this bin
+ * @elem_name: name of the element to be created
+ *
+ * Creates an element according to given name and
+ * adds it to given @bin. Looks for an unconnected src pad
+ * from the @bin and links the element to it.
+ *
+ * Returns: pointer to the new element if successful, NULL otherwise.
+ */
+GstElement *
+gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name)
+{
+ GstElement *new_elem;
+
+ g_return_val_if_fail (bin, FALSE);
+ g_return_val_if_fail (elem_name, FALSE);
+
+ new_elem = gst_element_factory_make (elem_name, NULL);
+ if (!new_elem) {
+ GST_ELEMENT_ERROR (bin, CORE, MISSING_PLUGIN, (NULL),
+ ("could not create \"%s\" element.", elem_name));
+ } else if (!gst_camerabin_add_element (bin, new_elem)) {
+ new_elem = NULL;
+ }
+
+ return new_elem;
+}
+
+/* try to change the state of an element. This function returns the element when
+ * the state change could be performed. When this function returns NULL an error
+ * occured and the element is unreffed if @unref is TRUE. */
+static GstElement *
+try_element (GstElement * bin, GstElement * element, gboolean unref)
+{
+ GstStateChangeReturn ret;
+
+ if (element) {
+ ret = gst_element_set_state (element, GST_STATE_READY);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ GST_DEBUG_OBJECT (bin, "failed state change..");
+ gst_element_set_state (element, GST_STATE_NULL);
+ if (unref)
+ gst_object_unref (element);
+ element = NULL;
+ }
+ }
+ return element;
+}
+
+GstElement *
+gst_camerabin_setup_default_element (GstBin * bin, GstElement * user_elem,
+ const gchar * auto_elem_name, const gchar * default_elem_name)
+{
+ GstElement *elem;
+
+ if (user_elem) {
+ GST_DEBUG_OBJECT (bin, "trying configured element");
+ elem = try_element (GST_ELEMENT_CAST (bin), user_elem, FALSE);
+ } else {
+ /* only try fallback if no specific sink was chosen */
+ GST_DEBUG_OBJECT (bin, "trying %s", auto_elem_name);
+ elem = gst_element_factory_make (auto_elem_name, NULL);
+ elem = try_element (GST_ELEMENT_CAST (bin), elem, TRUE);
+ if (elem == NULL) {
+ /* if default sink from config.h is different then try it too */
+ if (strcmp (default_elem_name, auto_elem_name)) {
+ GST_DEBUG_OBJECT (bin, "trying %s", default_elem_name);
+ elem = gst_element_factory_make (default_elem_name, NULL);
+ elem = try_element (GST_ELEMENT_CAST (bin), elem, TRUE);
+ }
+ }
+ }
+ return elem;
+}
+
+/**
+ * gst_camerabin_remove_elements_from_bin:
+ * @bin: removes all elements from this bin
+ *
+ * Removes all elements from this @bin.
+ */
+void
+gst_camerabin_remove_elements_from_bin (GstBin * bin)
+{
+ GstIterator *iter = NULL;
+ gpointer data = NULL;
+ GstElement *elem = NULL;
+ gboolean done = FALSE;
+
+ iter = gst_bin_iterate_elements (bin);
+ while (!done) {
+ switch (gst_iterator_next (iter, &data)) {
+ case GST_ITERATOR_OK:
+ elem = GST_ELEMENT (data);
+ gst_bin_remove (bin, elem);
+ gst_element_set_state (GST_ELEMENT (elem), GST_STATE_NULL);
+ /* Iterator increased the element refcount, so unref */
+ gst_object_unref (elem);
+ break;
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (iter);
+ break;
+ case GST_ITERATOR_ERROR:
+ GST_WARNING_OBJECT (bin, "error in iterating elements");
+ done = TRUE;
+ break;
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
+ }
+ }
+ gst_iterator_free (iter);
+}
+
+/**
+ * gst_camerabin_drop_eos_probe:
+ * @pad: pad receiving the event
+ * @event: received event
+ * @u_data: not used
+ *
+ * Event probe that drop all eos events.
+ *
+ * Returns: FALSE to drop the event, TRUE otherwise
+ */
+gboolean
+gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data)
+{
+ gboolean ret = TRUE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ GST_DEBUG ("dropping eos in %s:%s", GST_DEBUG_PAD_NAME (pad));
+ ret = FALSE;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
diff --git a/gst/camerabin2/camerabingeneral.h b/gst/camerabin2/camerabingeneral.h
new file mode 100644
index 000000000..93520c5a6
--- /dev/null
+++ b/gst/camerabin2/camerabingeneral.h
@@ -0,0 +1,42 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CAMERABIN_GENERAL_H_
+#define __CAMERABIN_GENERAL_H_
+
+#include <gst/gst.h>
+
+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);
+
+GstElement *gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name);
+
+GstElement * gst_camerabin_setup_default_element (GstBin * bin, GstElement *user_elem, const gchar *auto_elem_name, const gchar *default_elem_name);
+
+void gst_camerabin_remove_elements_from_bin (GstBin * bin);
+
+gboolean gst_camerabin_drop_eos_probe (GstPad * pad, GstEvent * event, gpointer u_data);
+
+/* debug logging category */
+GST_DEBUG_CATEGORY_EXTERN (gst_camerabin_debug);
+#define GST_CAT_DEFAULT gst_camerabin_debug
+
+#endif /* #ifndef __CAMERABIN_GENERAL_H_ */
diff --git a/gst/camerabin2/gstbasecamerasrc.c b/gst/camerabin2/gstbasecamerasrc.c
new file mode 100644
index 000000000..aba756e82
--- /dev/null
+++ b/gst/camerabin2/gstbasecamerasrc.c
@@ -0,0 +1,509 @@
+/*
+ * GStreamer
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+
+/**
+ * SECTION:element-basecamerasrc
+ *
+ * Base class for the camera src bin used by camerabin. Indented to be
+ * subclassed when plugging in more sophisticated cameras.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gstbasecamerasrc.h"
+
+GST_DEBUG_CATEGORY (base_camera_src_debug);
+#define GST_CAT_DEFAULT base_camera_src_debug
+
+GST_BOILERPLATE (GstBaseCameraSrc, gst_base_camera_src, GstBin, GST_TYPE_BIN);
+
+static GstStaticPadTemplate vfsrc_template = GST_STATIC_PAD_TEMPLATE ("vfsrc",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate imgsrc_template = GST_STATIC_PAD_TEMPLATE ("imgsrc",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate vidsrc_template = GST_STATIC_PAD_TEMPLATE ("vidsrc",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+/* note: we could provide a vmethod for derived class to overload to provide
+ * it's own implementation of interface.. but in all cases I can think of at
+ * moment, either the camerasrc itself, or some element within the bin, will
+ * be implementing the interface..
+ */
+
+/**
+ * gst_base_camera_src_get_photography:
+ * @self: the camerasrc bin
+ *
+ * Get object implementing photography interface, if there is one. Otherwise
+ * returns NULL.
+ */
+GstPhotography *
+gst_base_camera_src_get_photography (GstBaseCameraSrc * self)
+{
+ GstElement *elem;
+
+ if (GST_IS_PHOTOGRAPHY (self)) {
+ elem = GST_ELEMENT (self);
+ } else {
+ elem = gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_PHOTOGRAPHY);
+ }
+
+ if (elem) {
+ return GST_PHOTOGRAPHY (self);
+ }
+
+ return NULL;
+}
+
+
+/**
+ * gst_base_camera_src_get_colorbalance:
+ * @self: the camerasrc bin
+ *
+ * Get object implementing colorbalance interface, if there is one. Otherwise
+ * returns NULL.
+ */
+GstColorBalance *
+gst_base_camera_src_get_color_balance (GstBaseCameraSrc * self)
+{
+ GstElement *elem;
+
+ if (GST_IS_COLOR_BALANCE (self)) {
+ elem = GST_ELEMENT (self);
+ } else {
+ elem = gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_COLOR_BALANCE);
+ }
+
+ if (elem) {
+ return GST_COLOR_BALANCE (self);
+ }
+
+ return NULL;
+}
+
+/**
+ * gst_base_camera_src_set_mode:
+ * @self: the camerasrc bin
+ * @mode: the mode
+ *
+ * XXX
+ */
+gboolean
+gst_base_camera_src_set_mode (GstBaseCameraSrc * self, GstCameraBinMode mode)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+
+ g_return_val_if_fail (bclass->set_mode, FALSE);
+
+ return bclass->set_mode (self, mode);
+}
+
+/**
+ * gst_base_camera_src_setup_zoom:
+ * @self: camerasrc object
+ *
+ * Apply zoom configured to camerabin to capture.
+ */
+void
+gst_base_camera_src_setup_zoom (GstBaseCameraSrc * self)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+ gint zoom;
+
+ zoom = g_atomic_int_get (&self->zoom);
+
+ g_return_if_fail (zoom);
+ g_return_if_fail (bclass->set_zoom);
+
+ bclass->set_zoom (self, zoom);
+}
+
+
+/**
+ * gst_base_camera_src_get_allowed_input_caps:
+ * @self: the camerasrc bin
+ *
+ * Retrieve caps from videosrc describing formats it supports
+ *
+ * Returns: caps object from videosrc
+ */
+GstCaps *
+gst_base_camera_src_get_allowed_input_caps (GstBaseCameraSrc * self)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+
+ g_return_val_if_fail (bclass->get_allowed_input_caps, NULL);
+
+ return bclass->get_allowed_input_caps (self);
+}
+
+/**
+ * gst_base_camera_src_finish_image_capture:
+ * @self: camerasrc object
+ *
+ * Perform finishing operations after image capture is done and
+ * returning back to view finder mode.
+ */
+void
+gst_base_camera_src_finish_image_capture (GstBaseCameraSrc * self)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+
+ if (bclass->finish_image_capture) {
+ bclass->finish_image_capture (self);
+ }
+}
+
+/**
+ * gst_base_camera_src_find_better_framerate:
+ * @self: camerasrc object
+ * @st: structure that contains framerate candidates
+ * @orig_framerate: best framerate so far
+ *
+ * Looks for framerate better than @orig_framerate from @st structure.
+ * In night mode lowest framerate is considered best, otherwise highest is
+ * best.
+ *
+ * Returns: @orig_framerate or better if found
+ */
+const GValue *
+gst_base_camera_src_find_better_framerate (GstBaseCameraSrc * self,
+ GstStructure * st, const GValue * orig_framerate)
+{
+ const GValue *framerate = NULL;
+ guint i, i_best, list_size;
+ gint res, comparison;
+
+ if (self->night_mode) {
+ GST_LOG_OBJECT (self, "finding min framerate in %" GST_PTR_FORMAT, st);
+ comparison = GST_VALUE_LESS_THAN;
+ } else {
+ GST_LOG_OBJECT (self, "finding max framerate in %" GST_PTR_FORMAT, st);
+ comparison = GST_VALUE_GREATER_THAN;
+ }
+
+ if (gst_structure_has_field (st, "framerate")) {
+ framerate = gst_structure_get_value (st, "framerate");
+ /* Handle framerate lists */
+ if (GST_VALUE_HOLDS_LIST (framerate)) {
+ list_size = gst_value_list_get_size (framerate);
+ GST_LOG_OBJECT (self, "finding framerate from list");
+ for (i = 0, i_best = 0; i < list_size; i++) {
+ res = gst_value_compare (gst_value_list_get_value (framerate, i),
+ gst_value_list_get_value (framerate, i_best));
+ if (comparison == res) {
+ i_best = i;
+ }
+ }
+ GST_LOG_OBJECT (self, "found best framerate from index %d", i_best);
+ framerate = gst_value_list_get_value (framerate, i_best);
+ }
+ /* Handle framerate ranges */
+ if (GST_VALUE_HOLDS_FRACTION_RANGE (framerate)) {
+ if (self->night_mode) {
+ GST_LOG_OBJECT (self, "getting min framerate from range");
+ framerate = gst_value_get_fraction_range_min (framerate);
+ } else {
+ GST_LOG_OBJECT (self, "getting max framerate from range");
+ framerate = gst_value_get_fraction_range_max (framerate);
+ }
+ }
+ }
+
+ /* Check if we found better framerate */
+ if (orig_framerate && framerate) {
+ res = gst_value_compare (orig_framerate, framerate);
+ if (comparison == res) {
+ GST_LOG_OBJECT (self, "original framerate was the best");
+ framerate = orig_framerate;
+ }
+ }
+
+ return framerate;
+}
+
+/**
+ *
+ */
+static void
+gst_base_camera_src_dispose (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_base_camera_src_finalize (GstBaseCameraSrc * self)
+{
+ G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (self));
+}
+
+static void
+gst_base_camera_src_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object);
+
+ switch (prop_id) {
+ case ARG_ZOOM:{
+ g_atomic_int_set (&self->zoom, g_value_get_int (value));
+ /* does not set it if in NULL, the src is not created yet */
+ if (GST_STATE (self) != GST_STATE_NULL)
+ gst_base_camera_src_setup_zoom (self);
+ break;
+ }
+ case ARG_IMAGE_CAPTURE_WIDTH:{
+ gint width = g_value_get_int (value);
+
+ if (width != self->image_capture_width) {
+ self->image_capture_width = width;
+//XXX self->image_capture_caps_update = TRUE;
+ }
+ break;
+ }
+ case ARG_IMAGE_CAPTURE_HEIGHT:{
+ gint height = g_value_get_int (value);
+
+ if (height != self->image_capture_height) {
+ self->image_capture_height = height;
+//XXX self->image_capture_caps_update = TRUE;
+ }
+ break;
+ }
+ case ARG_VIDEO_CAPTURE_WIDTH:{
+ gint width = g_value_get_int (value);
+
+ if (width != self->width) {
+ self->width = width;
+//XXX self->video_capture_caps_update = TRUE;
+ }
+ break;
+ }
+ case ARG_VIDEO_CAPTURE_HEIGHT:{
+ gint height = g_value_get_int (value);
+
+ if (height != self->height) {
+ self->height = height;
+//XXX self->video_capture_caps_update = TRUE;
+ }
+ break;
+ }
+ case ARG_VIDEO_CAPTURE_FRAMERATE:{
+ gint fps_n, fps_d;
+
+ fps_n = gst_value_get_fraction_numerator (value);
+ fps_d = gst_value_get_fraction_denominator (value);
+
+ if (fps_n != self->fps_n || fps_d != self->fps_d) {
+ self->fps_n = fps_n;
+ self->fps_d = fps_d;
+//XXX self->video_capture_caps_update = TRUE;
+ }
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_base_camera_src_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object);
+
+ switch (prop_id) {
+ case ARG_ZOOM:
+ g_value_set_int (value, g_atomic_int_get (&self->zoom));
+ break;
+ case ARG_IMAGE_CAPTURE_WIDTH:
+ g_value_set_int (value, self->image_capture_width);
+ break;
+ case ARG_IMAGE_CAPTURE_HEIGHT:
+ g_value_set_int (value, self->image_capture_height);
+ break;
+ case ARG_VIDEO_CAPTURE_WIDTH:
+ g_value_set_int (value, self->width);
+ break;
+ case ARG_VIDEO_CAPTURE_HEIGHT:
+ g_value_set_int (value, self->height);
+ break;
+ case ARG_VIDEO_CAPTURE_FRAMERATE:
+ gst_value_set_fraction (value, self->fps_n, self->fps_d);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+construct_pipeline (GstBaseCameraSrc * self)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+ GstPad *vfsrc = NULL;
+ GstPad *imgsrc = NULL;
+ GstPad *vidsrc = NULL;
+
+ g_return_val_if_fail (bclass->construct_pipeline, FALSE);
+
+ if (!bclass->construct_pipeline (self, &vfsrc, &imgsrc, &vidsrc)) {
+ GST_ERROR_OBJECT (self, "pipeline construction failed");
+ return FALSE;
+ }
+
+ if (!vfsrc || !imgsrc || !vidsrc) {
+ GST_ERROR_OBJECT (self, "derived class must return src pads");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (self, "vfsrc: %" GST_PTR_FORMAT, vfsrc);
+ GST_DEBUG_OBJECT (self, "imgsrc: %" GST_PTR_FORMAT, imgsrc);
+ GST_DEBUG_OBJECT (self, "vidsrc: %" GST_PTR_FORMAT, vidsrc);
+
+ /* hook-up the ghostpads */
+ gst_ghost_pad_set_target (GST_GHOST_PAD (self->vfsrc), vfsrc);
+ gst_ghost_pad_set_target (GST_GHOST_PAD (self->imgsrc), imgsrc);
+ gst_ghost_pad_set_target (GST_GHOST_PAD (self->vidsrc), vidsrc);
+
+ gst_pad_set_active (self->vfsrc, TRUE);
+ gst_pad_set_active (self->imgsrc, TRUE); /* XXX ??? */
+ gst_pad_set_active (self->vidsrc, TRUE); /* XXX ??? */
+
+ return TRUE;
+}
+
+static gboolean
+setup_pipeline (GstBaseCameraSrc * self)
+{
+ GstBaseCameraSrcClass *bclass = GST_BASE_CAMERA_SRC_GET_CLASS (self);
+ if (bclass->setup_pipeline)
+ return bclass->setup_pipeline (self);
+ return TRUE;
+}
+
+static GstStateChangeReturn
+gst_base_camera_src_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (element);
+
+ GST_DEBUG_OBJECT (self, "%d -> %d",
+ GST_STATE_TRANSITION_CURRENT (transition),
+ GST_STATE_TRANSITION_NEXT (transition));
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!construct_pipeline (self))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ if (!setup_pipeline (self))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ return ret;
+}
+
+static void
+gst_base_camera_src_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+ GST_DEBUG_CATEGORY_INIT (base_camera_src_debug, "base_camera_src", 0,
+ "Base camera src");
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "Base class for camerabin src bin", "Source/Video",
+ "Abstracts capture device for camerabin", "Rob Clark <rob@ti.com>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vfsrc_template));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&imgsrc_template));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vidsrc_template));
+}
+
+static void
+gst_base_camera_src_class_init (GstBaseCameraSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->dispose = gst_base_camera_src_dispose;
+ gobject_class->finalize = (GObjectFinalizeFunc) gst_base_camera_src_finalize;
+ gobject_class->set_property = gst_base_camera_src_set_property;
+ gobject_class->get_property = gst_base_camera_src_get_property;
+
+ // g_object_class_install_property ....
+
+ gstelement_class->change_state = gst_base_camera_src_change_state;
+
+}
+
+static void
+gst_base_camera_src_init (GstBaseCameraSrc * self,
+ GstBaseCameraSrcClass * klass)
+{
+ self->vfsrc = gst_ghost_pad_new_no_target ("vfsrc", GST_PAD_SRC);
+ gst_element_add_pad (GST_ELEMENT (self), self->vfsrc);
+
+ self->imgsrc = gst_ghost_pad_new_no_target ("imgsrc", GST_PAD_SRC);
+ gst_element_add_pad (GST_ELEMENT (self), self->imgsrc);
+
+ self->vidsrc = gst_ghost_pad_new_no_target ("vidsrc", GST_PAD_SRC);
+ gst_element_add_pad (GST_ELEMENT (self), self->vidsrc);
+
+ self->width = DEFAULT_WIDTH;
+ self->height = DEFAULT_HEIGHT;
+ self->zoom = DEFAULT_ZOOM;
+ self->image_capture_width = 0;
+ self->image_capture_height = 0;
+
+ self->night_mode = FALSE;
+
+ self->fps_n = DEFAULT_FPS_N;
+ self->fps_d = DEFAULT_FPS_D;
+}
diff --git a/gst/camerabin2/gstbasecamerasrc.h b/gst/camerabin2/gstbasecamerasrc.h
new file mode 100644
index 000000000..75ef0222a
--- /dev/null
+++ b/gst/camerabin2/gstbasecamerasrc.h
@@ -0,0 +1,146 @@
+/*
+ * GStreamer
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_BASE_CAMERA_SRC_H__
+#define __GST_BASE_CAMERA_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/gstbin.h>
+#include <gst/interfaces/photography.h>
+#include <gst/interfaces/colorbalance.h>
+#include "gstcamerabin-enum.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_BASE_CAMERA_SRC \
+ (gst_base_camera_src_get_type())
+#define GST_BASE_CAMERA_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_CAMERA_SRC,GstBaseCameraSrc))
+#define GST_BASE_CAMERA_SRC_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASE_CAMERA_SRC, GstBaseCameraSrcClass))
+#define GST_BASE_CAMERA_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_CAMERA_SRC,GstBaseCameraSrcClass))
+#define GST_IS_BASE_CAMERA_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_CAMERA_SRC))
+#define GST_IS_BASE_CAMERA_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_CAMERA_SRC))
+ GType gst_base_camera_src_get_type (void);
+
+typedef struct _GstBaseCameraSrc GstBaseCameraSrc;
+typedef struct _GstBaseCameraSrcClass GstBaseCameraSrcClass;
+
+
+/**
+ * GstBaseCameraSrc:
+ */
+struct _GstBaseCameraSrc
+{
+ GstBin parent;
+
+ GstPad *vfsrc;
+ GstPad *imgsrc;
+ GstPad *vidsrc;
+
+ /* XXX preview pads? */
+
+ /* Resolution of the buffers configured to camerabin */
+ gint width;
+ gint height;
+
+ /* The digital zoom (from 100% to 1000%) */
+ gint zoom;
+
+ /* Image capture resolution */
+ gint image_capture_width;
+ gint image_capture_height;
+
+ /* Frames per second configured to camerabin */
+ gint fps_n;
+ gint fps_d;
+
+ /* Night mode handling */
+ gboolean night_mode;
+ gint pre_night_fps_n;
+ gint pre_night_fps_d;
+
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+
+/**
+ * GstBaseCameraSrcClass:
+ * @construct_pipeline: construct pipeline must be implemented by derived
+ * class, and return by reference vfsrc, imgsrc, and vidsrc pads of the
+ * contained pipeline, which will be ghosted to the src pads of the
+ * camerasrc bin (and optionally the preview src pads?)
+ * @setup_pipeline:
+ * @set_zoom: set the zoom
+ * @set_mode: set the mode
+ */
+struct _GstBaseCameraSrcClass
+{
+ GstBinClass parent;
+
+ /* construct pipeline must be implemented by derived class, and return by
+ * reference vfsrc, imgsrc, and vidsrc pads of the contained pipeline, which
+ * will be ghosted to the src pads of the camerasrc bin (and optionally the
+ * preview src pads?) */
+ gboolean (*construct_pipeline) (GstBaseCameraSrc *self,
+ GstPad **vfsrc, GstPad **imgsrc,
+ GstPad **vidsrc);
+
+ /* optional */
+ gboolean (*setup_pipeline) (GstBaseCameraSrc *self);
+
+ /* set the zoom */
+ void (*set_zoom) (GstBaseCameraSrc *self, gint zoom);
+
+ /* set the mode */
+ gboolean (*set_mode) (GstBaseCameraSrc *self,
+ GstCameraBinMode mode);
+
+ /* */
+ GstCaps * (*get_allowed_input_caps) (GstBaseCameraSrc * self);
+
+ /* optional */
+ void (*finish_image_capture) (GstBaseCameraSrc * self);
+
+
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+
+#define MIN_ZOOM 100
+#define MAX_ZOOM 1000
+#define ZOOM_1X MIN_ZOOM
+
+GstPhotography * gst_base_camera_src_get_photography (GstBaseCameraSrc *self);
+GstColorBalance * gst_base_camera_src_get_color_balance (GstBaseCameraSrc *self);
+
+gboolean gst_base_camera_src_set_mode (GstBaseCameraSrc *self, GstCameraBinMode mode);
+void gst_base_camera_src_setup_zoom (GstBaseCameraSrc * self);
+GstCaps * gst_base_camera_src_get_allowed_input_caps (GstBaseCameraSrc * self);
+void gst_base_camera_src_finish_image_capture (GstBaseCameraSrc * self);
+const GValue * gst_base_camera_src_find_better_framerate (
+ GstBaseCameraSrc * self, GstStructure * st, const GValue * orig_framerate);
+
+// XXX add methods to get/set img capture and vid capture caps..
+
+#endif /* __GST_BASE_CAMERA_SRC_H__ */
diff --git a/gst/camerabin2/gstcamerabin-enum.c b/gst/camerabin2/gstcamerabin-enum.c
new file mode 100644
index 000000000..8d1d0c92d
--- /dev/null
+++ b/gst/camerabin2/gstcamerabin-enum.c
@@ -0,0 +1,78 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Nokia Corporation <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstcamerabin-enum.h"
+
+#define C_FLAGS(v) ((guint) v)
+
+static void
+register_gst_camerabin_flags (GType * id)
+{
+ static const GFlagsValue values[] = {
+ {C_FLAGS (GST_CAMERABIN_FLAG_SOURCE_RESIZE),
+ "Enable source crop and scale", "source-resize"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION),
+ "Enable colorspace conversion for video source",
+ "source-colorspace-conversion"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION),
+ "Enable colorspace conversion for viewfinder",
+ "viewfinder-colorspace-conversion"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_VIEWFINDER_SCALE),
+ "Enable scale for viewfinder", "viewfinder-scale"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_AUDIO_CONVERSION),
+ "Enable audio conversion for video capture", "audio-conversion"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_DISABLE_AUDIO),
+ "Disable audio elements for video capture", "disable-audio"},
+ {C_FLAGS (GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION),
+ "Enable colorspace conversion for still image",
+ "image-colorspace-conversion"},
+ {0, NULL, NULL}
+ };
+ *id = g_flags_register_static ("GstCameraBinFlags", values);
+}
+
+GType
+gst_camerabin_flags_get_type (void)
+{
+ static GType id;
+ static GOnce once = G_ONCE_INIT;
+
+ g_once (&once, (GThreadFunc) register_gst_camerabin_flags, &id);
+ return id;
+}
+
+
+GType
+gst_camerabin_mode_get_type (void)
+{
+ static GType gtype = 0;
+
+ if (gtype == 0) {
+ static const GEnumValue values[] = {
+ {MODE_PREVIEW, "Preview mode (should be default?)", "mode-preview"},
+ {MODE_IMAGE, "Still image capture (default)", "mode-image"},
+ {MODE_VIDEO, "Video recording", "mode-video"},
+ {0, NULL, NULL}
+ };
+
+ gtype = g_enum_register_static ("GstCameraBinMode", values);
+ }
+ return gtype;
+}
diff --git a/gst/camerabin2/gstcamerabin-enum.h b/gst/camerabin2/gstcamerabin-enum.h
new file mode 100644
index 000000000..cd1707dd2
--- /dev/null
+++ b/gst/camerabin2/gstcamerabin-enum.h
@@ -0,0 +1,140 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Nokia Corporation <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAMERABIN_ENUM_H__
+#define __GST_CAMERABIN_ENUM_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/* XXX find better place for property related enum/defaults */
+enum
+{
+ ARG_0,
+ ARG_FILENAME,
+ ARG_MODE,
+ ARG_FLAGS,
+ ARG_MUTE,
+ ARG_ZOOM,
+ ARG_IMAGE_POST,
+ ARG_IMAGE_ENC,
+ ARG_VIDEO_POST,
+ ARG_VIDEO_ENC,
+ ARG_AUDIO_ENC,
+ ARG_VIDEO_MUX,
+ ARG_VF_SINK,
+ ARG_VIDEO_SRC,
+ ARG_AUDIO_SRC,
+ ARG_INPUT_CAPS,
+ ARG_FILTER_CAPS,
+ ARG_PREVIEW_CAPS,
+ ARG_WB_MODE,
+ ARG_COLOUR_TONE,
+ ARG_SCENE_MODE,
+ ARG_FLASH_MODE,
+ ARG_FOCUS_STATUS,
+ ARG_CAPABILITIES,
+ ARG_SHAKE_RISK,
+ ARG_EV_COMP,
+ ARG_ISO_SPEED,
+ ARG_APERTURE,
+ ARG_EXPOSURE,
+ ARG_VIDEO_SOURCE_FILTER,
+ ARG_IMAGE_CAPTURE_SUPPORTED_CAPS,
+ ARG_VIEWFINDER_FILTER,
+ ARG_FLICKER_MODE,
+ ARG_FOCUS_MODE,
+ ARG_BLOCK_VIEWFINDER,
+ ARG_IMAGE_CAPTURE_WIDTH,
+ ARG_IMAGE_CAPTURE_HEIGHT,
+ ARG_VIDEO_CAPTURE_WIDTH,
+ ARG_VIDEO_CAPTURE_HEIGHT,
+ ARG_VIDEO_CAPTURE_FRAMERATE
+};
+
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+#define DEFAULT_CAPTURE_WIDTH 800
+#define DEFAULT_CAPTURE_HEIGHT 600
+#define DEFAULT_FPS_N 0 /* makes it use the default */
+#define DEFAULT_FPS_D 1
+#define DEFAULT_ZOOM MIN_ZOOM
+
+
+/**
+ * GstCameraBinFlags:
+ * @GST_CAMERABIN_FLAG_SOURCE_RESIZE: enable video crop and scale
+ * after capture
+ * @GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION: enable conversion
+ * of native video format by enabling ffmpegcolorspace
+ * @GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION: enable color
+ * conversion for viewfinder element
+ * @GST_CAMERABIN_FLAG_VIEWFINDER_SCALE: enable scaling in
+ * viewfinder element retaining aspect ratio
+ * @GST_CAMERABIN_FLAG_AUDIO_CONVERSION: enable audioconvert and
+ * audioresample elements
+ * @GST_CAMERABIN_FLAG_DISABLE_AUDIO: disable audio elements
+ * @GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION: enable color
+ * conversion for image output element
+ *
+ * Extra flags to configure the behaviour of the sinks.
+ */
+typedef enum {
+ GST_CAMERABIN_FLAG_SOURCE_RESIZE = (1 << 0),
+ GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION = (1 << 1),
+ GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION = (1 << 2),
+ GST_CAMERABIN_FLAG_VIEWFINDER_SCALE = (1 << 3),
+ GST_CAMERABIN_FLAG_AUDIO_CONVERSION = (1 << 4),
+ GST_CAMERABIN_FLAG_DISABLE_AUDIO = (1 << 5),
+ GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION = (1 << 6)
+} GstCameraBinFlags;
+
+#define GST_TYPE_CAMERABIN_FLAGS (gst_camerabin_flags_get_type())
+GType gst_camerabin_flags_get_type (void);
+
+
+/**
+ * GstCameraBinMode:
+ * @MODE_PREVIEW: preview only (no capture) mode
+ * @MODE_IMAGE: image capture
+ * @MODE_VIDEO: video capture
+ *
+ * Capture mode to use.
+ */
+typedef enum
+{
+ /* note: changed to align with 'capture-mode' property (even though
+ * I have no idea where this property comes from..) But it somehow
+ * seems more logical for preview to be mode==0 even if it is an ABI
+ * break..
+ */
+ MODE_PREVIEW = 0,
+ MODE_IMAGE = 1,
+ MODE_VIDEO = 2,
+} GstCameraBinMode;
+
+
+#define GST_TYPE_CAMERABIN_MODE (gst_camerabin_mode_get_type ())
+GType gst_camerabin_mode_get_type (void);
+
+G_END_DECLS
+
+#endif /* #ifndef __GST_CAMERABIN_ENUM_H__ */
diff --git a/gst/camerabin2/gstplugin.c b/gst/camerabin2/gstplugin.c
index 1f1dd0ea7..c88ad8d03 100644
--- a/gst/camerabin2/gstplugin.c
+++ b/gst/camerabin2/gstplugin.c
@@ -25,6 +25,7 @@
#include "gstviewfinderbin.h"
#include "gstimagecapturebin.h"
+#include "gstv4l2camerasrc.h"
static gboolean
plugin_init (GstPlugin * plugin)
@@ -33,6 +34,8 @@ plugin_init (GstPlugin * plugin)
return FALSE;
if (!gst_image_capture_bin_plugin_init (plugin))
return FALSE;
+ if (!gst_v4l2_camera_src_plugin_init (plugin))
+ return FALSE;
return TRUE;
}
diff --git a/gst/camerabin2/gstv4l2camerasrc.c b/gst/camerabin2/gstv4l2camerasrc.c
new file mode 100644
index 000000000..1cc4ca81d
--- /dev/null
+++ b/gst/camerabin2/gstv4l2camerasrc.c
@@ -0,0 +1,1077 @@
+/*
+ * GStreamer
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+/**
+ * SECTION:element-v4l2camerasrc
+ *
+ * A camera src element for camerabin.. currently uses v4l2 directly.
+ * It could be worthwhile to make this subclassable, so that other
+ * camera elements with a single src pad could re-use this..
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "gstv4l2camerasrc.h"
+#include "camerabingeneral.h"
+#include "gstcamerabin-enum.h"
+
+
+#define CAMERABIN_DEFAULT_VF_CAPS "video/x-raw-yuv,format=(fourcc)I420"
+//#define CAMERABIN_MAX_VF_WIDTH 848
+//#define CAMERABIN_MAX_VF_HEIGHT 848
+
+/* Using "bilinear" as default zoom method */
+#define CAMERABIN_DEFAULT_ZOOM_METHOD 1
+
+/* FIXME: this is v4l2camsrc specific */
+#define DEFAULT_V4L2CAMSRC_DRIVER_NAME "omap3cam"
+
+//GST_DEBUG_CATEGORY (v4l2_camera_src_debug);
+//#define GST_CAT_DEFAULT v4l2_camera_src_debug
+
+GST_BOILERPLATE (GstV4l2CameraSrc, gst_v4l2_camera_src, GstBaseCameraSrc,
+ GST_TYPE_BASE_CAMERA_SRC);
+
+static void configure_format (GstV4l2CameraSrc * self, GstCaps * caps);
+static void set_capsfilter_caps (GstV4l2CameraSrc * self, GstCaps * new_caps);
+
+static void
+gst_v4l2_camera_src_dispose (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_v4l2_camera_src_finalize (GstV4l2CameraSrc * self)
+{
+ G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (self));
+}
+
+static void
+gst_v4l2_camera_src_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (object);
+
+ switch (prop_id) {
+ case ARG_FILTER_CAPS:
+ GST_OBJECT_LOCK (self);
+ gst_caps_replace (&self->view_finder_caps,
+ (GstCaps *) gst_value_get_caps (value));
+ GST_OBJECT_UNLOCK (self);
+ configure_format (self, self->view_finder_caps);
+ break;
+ case ARG_VIDEO_SOURCE_FILTER:
+ if (GST_STATE (self) != GST_STATE_NULL) {
+ GST_ELEMENT_ERROR (self, CORE, FAILED,
+ ("camerasrc must be in NULL state when setting the video filter element"),
+ (NULL));
+ } else {
+ if (self->app_video_filter)
+ gst_object_unref (self->app_video_filter);
+ self->app_video_filter = g_value_dup_object (value);
+ }
+ break;
+ case ARG_VIDEO_SRC:
+ if (GST_STATE (self) != GST_STATE_NULL) {
+ GST_ELEMENT_ERROR (self, CORE, FAILED,
+ ("camerasrc must be in NULL state when setting the video source element"),
+ (NULL));
+ } else {
+ if (self->app_vid_src)
+ gst_object_unref (self->app_vid_src);
+ self->app_vid_src = g_value_get_object (value);
+ gst_object_ref (self->app_vid_src);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_v4l2_camera_src_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (object);
+
+ switch (prop_id) {
+ case ARG_FILTER_CAPS:
+ gst_value_set_caps (value, self->view_finder_caps);
+ break;
+ case ARG_VIDEO_SOURCE_FILTER:
+ g_value_set_object (value, self->app_video_filter);
+ break;
+ case ARG_VIDEO_SRC:
+ if (self->src_vid_src)
+ g_value_set_object (value, self->src_vid_src);
+ else
+ g_value_set_object (value, self->app_vid_src);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gst_v4l2_camera_src_imgsrc_probe:
+ *
+ * Buffer probe called before sending each buffer to image queue.
+ */
+static gboolean
+gst_v4l2_camera_src_imgsrc_probe (GstPad * pad, GstBuffer * buffer,
+ gpointer data)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (data);
+ GST_DEBUG_OBJECT (self, "pass buffer: %d", self->mode == MODE_IMAGE);
+ return self->mode == MODE_IMAGE;
+}
+
+/**
+ * gst_v4l2_camera_src_vidsrc_probe:
+ *
+ * Buffer probe called before sending each buffer to image queue.
+ */
+static gboolean
+gst_v4l2_camera_src_vidsrc_probe (GstPad * pad, GstBuffer * buffer,
+ gpointer data)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (data);
+ GST_DEBUG_OBJECT (self, "pass buffer: %d", self->mode == MODE_VIDEO);
+ return self->mode == MODE_VIDEO;
+}
+
+/**
+ * gst_v4l2_camera_src_construct_pipeline:
+ * @bcamsrc: camerasrc object
+ * @vfsrc: viewfinder src element (returned by reference)
+ * @imgsrc: image src element (returned by reference)
+ * @vidsrc: video src element (returned by reference)
+ *
+ * This function creates and links the elements of the camerasrc bin
+ * videosrc ! cspconv ! capsfilter ! crop ! scale ! capsfilter ! tee ! ..
+ *
+ * Returns: TRUE, if elements were successfully created, FALSE otherwise
+ */
+static gboolean
+gst_v4l2_camera_src_construct_pipeline (GstBaseCameraSrc * bcamsrc,
+ GstPad ** vfsrc, GstPad ** imgsrc, GstPad ** vidsrc)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+ GstBin *cbin = GST_BIN (bcamsrc);
+ GstElement *tee;
+ gboolean ret = FALSE;
+
+ 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))) {
+ self->src_vid_src = NULL;
+ goto done;
+ } else {
+ if (!gst_camerabin_add_element (cbin, self->src_vid_src)) {
+ goto done;
+ }
+ }
+
+#if 0
+ /* XXX srcbin needs to know of some flags, perhaps?? */
+ if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION) {
+#else
+ if (1) {
+#endif
+ if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace"))
+ goto done;
+ }
+
+ if (!(self->src_filter =
+ gst_camerabin_create_and_add_element (cbin, "capsfilter")))
+ goto done;
+
+#if 0
+ /* XXX srcbin needs to know of some flags, perhaps?? */
+ if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_RESIZE) {
+#else
+ if (1) {
+#endif
+ if (!(self->src_zoom_crop =
+ gst_camerabin_create_and_add_element (cbin, "videocrop")))
+ goto done;
+ if (!(self->src_zoom_scale =
+ gst_camerabin_create_and_add_element (cbin, "videoscale")))
+ goto done;
+ if (!(self->src_zoom_filter =
+ gst_camerabin_create_and_add_element (cbin, "capsfilter")))
+ goto done;
+ }
+
+ if (self->app_video_filter) {
+ if (!gst_camerabin_add_element (cbin, self->app_video_filter)) {
+ goto done;
+ }
+ }
+
+ if (!(tee = gst_camerabin_create_and_add_element (cbin, "tee")))
+ goto done;
+
+ self->tee_vf_srcpad = gst_element_get_request_pad (tee, "src%d");
+ self->tee_image_srcpad = gst_element_get_request_pad (tee, "src%d");
+ self->tee_video_srcpad = gst_element_get_request_pad (tee, "src%d");
+
+ gst_pad_add_buffer_probe (self->tee_image_srcpad,
+ G_CALLBACK (gst_v4l2_camera_src_imgsrc_probe), self);
+ gst_pad_add_buffer_probe (self->tee_video_srcpad,
+ G_CALLBACK (gst_v4l2_camera_src_vidsrc_probe), self);
+
+ *vfsrc = self->tee_vf_srcpad;
+ *imgsrc = self->tee_image_srcpad;
+ *vidsrc = self->tee_video_srcpad;
+
+#if 0
+ /* XXX another idea... put common parts in GstBaseCameraSrc.. perhaps
+ * derived class could use some flags, or something like this, to
+ * indicate which pads in needs vscale and queue on.. (but I think it
+ * doesn't hurt ot have on all..)
+ */
+ /* XXX perhaps we should keep queues and vscale's in camerabin itself,
+ * because GstOmxCameraSrc would also probably need the queues.. and
+ * maybe some OMX camera implementations would want the vscale's (and
+ * at least the vscale's should become pass-through if OMX camera can
+ * negotiate the requested sizes..
+ */
+ queue = gst_element_factory_make ("queue", "viewfinder-queue");
+ if (!gst_camerabin_add_element (cbin, queue)) {
+ goto error;
+ }
+ /* Set queue leaky, we don't want to block video encoder feed, but
+ * prefer leaking view finder buffers instead. */
+ g_object_set (G_OBJECT (queue), "leaky", 2, "max-size-buffers", 1, NULL);
+#endif
+
+ /* Set default "driver-name" for v4l2camsrc if not set */
+ /* FIXME: v4l2camsrc specific */
+ {
+ gchar *driver_name = NULL;
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (self->src_vid_src),
+ "driver-name")) {
+ g_object_get (G_OBJECT (self->src_vid_src), "driver-name",
+ &driver_name, NULL);
+ if (!driver_name) {
+ g_object_set (G_OBJECT (self->src_vid_src), "driver-name",
+ DEFAULT_V4L2CAMSRC_DRIVER_NAME, NULL);
+ }
+ }
+ }
+
+ ret = TRUE;
+done:
+ return ret;
+}
+
+/**
+ * get_srcpad_current_format:
+ * @element: element to get the format from
+ *
+ * Helper function to get the negotiated fourcc
+ * format from @element src pad.
+ *
+ * Returns: negotiated format (fourcc), 0 if not found
+ */
+static guint32
+get_srcpad_current_format (GstElement * element)
+{
+ GstPad *srcpad = NULL;
+ GstCaps *srccaps = NULL;
+ GstStructure *structure;
+ guint32 format = 0;
+
+ g_return_val_if_fail (element != NULL, 0);
+
+ if ((srcpad = gst_element_get_static_pad (element, "src")) == NULL) {
+ goto no_pad;
+ }
+
+ if ((srccaps = gst_pad_get_negotiated_caps (srcpad)) == NULL) {
+ goto no_caps;
+ }
+
+ GST_LOG ("negotiated caps %" GST_PTR_FORMAT, srccaps);
+
+ structure = gst_caps_get_structure (srccaps, 0);
+ if (gst_structure_has_field (structure, "format")) {
+ gst_structure_get_fourcc (structure, "format", &format);
+ }
+
+ gst_caps_unref (srccaps);
+no_caps:
+ gst_object_unref (srcpad);
+no_pad:
+ GST_DEBUG ("current format for %" GST_PTR_FORMAT ": %" GST_FOURCC_FORMAT,
+ element, GST_FOURCC_ARGS (format));
+ return format;
+}
+
+/**
+ * set_allowed_framerate:
+ * @self: camerasrc object
+ * @filter_caps: update allowed framerate to these caps
+ *
+ * Find allowed frame rate from video source that matches with
+ * resolution in @filter_caps. Set found frame rate to @filter_caps.
+ */
+static void
+set_allowed_framerate (GstV4l2CameraSrc * self, GstCaps * filter_caps)
+{
+ GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
+ GstStructure *structure;
+ GstCaps *allowed_caps = NULL, *intersect = NULL, *tmp_caps = NULL;
+ const GValue *framerate = NULL;
+ guint caps_size, i;
+ guint32 format = 0;
+
+ GST_INFO_OBJECT (self, "filter caps:%" GST_PTR_FORMAT, filter_caps);
+
+ structure = gst_structure_copy (gst_caps_get_structure (filter_caps, 0));
+
+ /* Set fourcc format according to current videosrc format */
+ format = get_srcpad_current_format (self->src_vid_src);
+ if (format) {
+ GST_DEBUG_OBJECT (self,
+ "using format %" GST_FOURCC_FORMAT " for matching",
+ GST_FOURCC_ARGS (format));
+ gst_structure_set (structure, "format", GST_TYPE_FOURCC, format, NULL);
+ } else {
+ GST_DEBUG_OBJECT (self, "not matching against fourcc format");
+ gst_structure_remove_field (structure, "format");
+ }
+
+ tmp_caps = gst_caps_new_full (structure, NULL);
+
+ /* Get supported caps from video src that matches with new filter caps */
+ allowed_caps = gst_base_camera_src_get_allowed_input_caps (bcamsrc);
+ intersect = gst_caps_intersect (allowed_caps, tmp_caps);
+ GST_INFO_OBJECT (self, "intersect caps:%" GST_PTR_FORMAT, intersect);
+
+ /* Find the best framerate from the caps */
+ caps_size = gst_caps_get_size (intersect);
+ for (i = 0; i < caps_size; i++) {
+ structure = gst_caps_get_structure (intersect, i);
+ framerate = gst_base_camera_src_find_better_framerate (bcamsrc,
+ structure, framerate);
+ }
+
+ /* Set found frame rate to original caps */
+ if (GST_VALUE_HOLDS_FRACTION (framerate)) {
+ gst_caps_set_simple (filter_caps,
+ "framerate", GST_TYPE_FRACTION,
+ gst_value_get_fraction_numerator (framerate),
+ gst_value_get_fraction_denominator (framerate), NULL);
+ }
+
+ /* Unref helper caps */
+ if (allowed_caps) {
+ gst_caps_unref (allowed_caps);
+ }
+ if (intersect) {
+ gst_caps_unref (intersect);
+ }
+ if (tmp_caps) {
+ gst_caps_unref (tmp_caps);
+ }
+}
+
+/**
+ * gst_v4l2_camera_src_setup_pipeline:
+ * @bcamsrc: camerasrc object
+ *
+ * This function updates camerabin capsfilters according
+ * to fps, resolution and zoom that have been configured
+ * to camerabin.
+ */
+static gboolean
+gst_v4l2_camera_src_setup_pipeline (GstBaseCameraSrc * bcamsrc)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+ GstStructure *st;
+ GstCaps *new_caps;
+ gboolean detect_framerate = FALSE;
+
+ /* clear video update status */
+//XXX self->video_capture_caps_update = FALSE;
+
+ if (!self->view_finder_caps) {
+ st = gst_structure_from_string (CAMERABIN_DEFAULT_VF_CAPS, NULL);
+ } else {
+ st = gst_structure_copy (gst_caps_get_structure (self->view_finder_caps,
+ 0));
+ }
+
+ if (bcamsrc->width > 0 && bcamsrc->height > 0) {
+ gst_structure_set (st,
+ "width", G_TYPE_INT, bcamsrc->width,
+ "height", G_TYPE_INT, bcamsrc->height, NULL);
+ }
+
+ if (bcamsrc->fps_n > 0 && bcamsrc->fps_d > 0) {
+ if (bcamsrc->night_mode) {
+ GST_INFO_OBJECT (self, "night mode, lowest allowed fps will be forced");
+ bcamsrc->pre_night_fps_n = bcamsrc->fps_n;
+ bcamsrc->pre_night_fps_d = bcamsrc->fps_d;
+ detect_framerate = TRUE;
+ } else {
+ gst_structure_set (st,
+ "framerate", GST_TYPE_FRACTION, bcamsrc->fps_n, bcamsrc->fps_d, NULL);
+ new_caps = gst_caps_new_full (st, NULL);
+ }
+ } else {
+ GST_DEBUG_OBJECT (self, "no framerate specified");
+ detect_framerate = TRUE;
+ }
+
+ if (detect_framerate) {
+ GST_DEBUG_OBJECT (self, "detecting allowed framerate");
+ /* Remove old framerate if any */
+ if (gst_structure_has_field (st, "framerate")) {
+ gst_structure_remove_field (st, "framerate");
+ }
+ new_caps = gst_caps_new_full (st, NULL);
+
+ /* Set allowed framerate for the resolution */
+ set_allowed_framerate (self, new_caps);
+ }
+
+ /* Set default zoom method */
+ if (self->src_zoom_scale) {
+ g_object_set (self->src_zoom_scale, "method",
+ CAMERABIN_DEFAULT_ZOOM_METHOD, NULL);
+ }
+
+ /* we create new caps in any way and they take ownership of the structure st */
+ gst_caps_replace (&self->view_finder_caps, new_caps);
+ gst_caps_unref (new_caps);
+
+ /* Set caps for view finder mode */
+ /* This also sets zoom */
+ set_capsfilter_caps (self, self->view_finder_caps);
+
+ return TRUE;
+}
+
+static gboolean
+copy_missing_fields (GQuark field_id, const GValue * value, gpointer user_data)
+{
+ GstStructure *st = (GstStructure *) user_data;
+ const GValue *val = gst_structure_id_get_value (st, field_id);
+
+ if (G_UNLIKELY (val == NULL)) {
+ gst_structure_id_set_value (st, field_id, value);
+ }
+
+ return TRUE;
+}
+
+/**
+ * adapt_image_capture:
+ * @self: camerasrc object
+ * @in_caps: caps object that describes incoming image format
+ *
+ * Adjust capsfilters and crop according image capture caps if necessary.
+ * The captured image format from video source might be different from
+ * what application requested, so we can try to fix that in camerabin.
+ *
+ */
+static void
+adapt_image_capture (GstV4l2CameraSrc * self, GstCaps * in_caps)
+{
+ GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
+ GstStructure *in_st, *new_st, *req_st;
+ gint in_width = 0, in_height = 0, req_width = 0, req_height = 0, crop = 0;
+ gdouble ratio_w, ratio_h;
+ GstCaps *filter_caps = NULL;
+
+ GST_LOG_OBJECT (self, "in caps: %" GST_PTR_FORMAT, in_caps);
+ GST_LOG_OBJECT (self, "requested caps: %" GST_PTR_FORMAT,
+ self->image_capture_caps);
+
+ in_st = gst_caps_get_structure (in_caps, 0);
+ gst_structure_get_int (in_st, "width", &in_width);
+ gst_structure_get_int (in_st, "height", &in_height);
+
+ req_st = gst_caps_get_structure (self->image_capture_caps, 0);
+ gst_structure_get_int (req_st, "width", &req_width);
+ gst_structure_get_int (req_st, "height", &req_height);
+
+ GST_INFO_OBJECT (self, "we requested %dx%d, and got %dx%d", req_width,
+ req_height, in_width, in_height);
+
+ new_st = gst_structure_copy (req_st);
+ /* If new fields have been added, we need to copy them */
+ gst_structure_foreach (in_st, copy_missing_fields, new_st);
+
+#if 0
+ /* XXX srcbin needs to know of some flags, perhaps?? */
+ if (!(camera->flags & GST_CAMERABIN_FLAG_SOURCE_RESIZE)) {
+#else
+ if (1) {
+#endif
+ GST_DEBUG_OBJECT (self,
+ "source-resize flag disabled, unable to adapt resolution");
+ gst_structure_set (new_st, "width", G_TYPE_INT, in_width, "height",
+ G_TYPE_INT, in_height, NULL);
+ }
+
+ GST_LOG_OBJECT (self, "new image capture caps: %" GST_PTR_FORMAT, new_st);
+
+ /* Crop if requested aspect ratio differs from incoming frame aspect ratio */
+ if (self->src_zoom_crop) {
+
+ ratio_w = (gdouble) in_width / req_width;
+ ratio_h = (gdouble) in_height / req_height;
+
+ if (ratio_w < ratio_h) {
+ crop = in_height - (req_height * ratio_w);
+ self->base_crop_top = crop / 2;
+ self->base_crop_bottom = crop / 2;
+ } else {
+ crop = in_width - (req_width * ratio_h);
+ self->base_crop_left = crop / 2;
+ self->base_crop_right += crop / 2;
+ }
+
+ GST_INFO_OBJECT (self,
+ "setting base crop: left:%d, right:%d, top:%d, bottom:%d",
+ self->base_crop_left, self->base_crop_right, self->base_crop_top,
+ self->base_crop_bottom);
+ g_object_set (G_OBJECT (self->src_zoom_crop),
+ "top", self->base_crop_top,
+ "bottom", self->base_crop_bottom,
+ "left", self->base_crop_left, "right", self->base_crop_right, NULL);
+ }
+
+ /* Update capsfilters */
+ gst_caps_replace (&self->image_capture_caps,
+ gst_caps_new_full (new_st, NULL));
+ set_capsfilter_caps (self, self->image_capture_caps);
+
+ /* Adjust the capsfilter before crop and videoscale elements if necessary */
+ if (in_width == bcamsrc->width && in_height == bcamsrc->height) {
+ GST_DEBUG_OBJECT (self, "no adaptation with resolution needed");
+ } else {
+ GST_DEBUG_OBJECT (self,
+ "changing %" GST_PTR_FORMAT " from %dx%d to %dx%d", self->src_filter,
+ bcamsrc->width, bcamsrc->height, in_width, in_height);
+ /* Apply the width and height to filter caps */
+ g_object_get (G_OBJECT (self->src_filter), "caps", &filter_caps, NULL);
+ filter_caps = gst_caps_make_writable (filter_caps);
+ gst_caps_set_simple (filter_caps, "width", G_TYPE_INT, in_width, "height",
+ G_TYPE_INT, in_height, NULL);
+ g_object_set (G_OBJECT (self->src_filter), "caps", filter_caps, NULL);
+ gst_caps_unref (filter_caps);
+ }
+}
+
+/**
+ * img_capture_prepared:
+ * @data: camerasrc object
+ * @caps: caps describing the prepared image format
+ *
+ * Callback which is called after image capture has been prepared.
+ */
+static void
+img_capture_prepared (gpointer data, GstCaps * caps)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (data);
+
+ GST_INFO_OBJECT (self, "image capture prepared");
+
+ /* It is possible we are about to get something else that we requested */
+ if (!gst_caps_is_equal (self->image_capture_caps, caps)) {
+ adapt_image_capture (self, caps);
+ } else {
+ set_capsfilter_caps (self, self->image_capture_caps);
+ }
+
+//XXX g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
+//XXX "active-pad", camera->pad_src_img, NULL);
+}
+
+static void
+set_image_capture_caps (GstV4l2CameraSrc * self, gint width, gint height)
+{
+ GstStructure *structure;
+ GstCaps *new_caps = NULL;
+
+ if (width && height && self->view_finder_caps) {
+ /* Use view finder mode caps as a basis */
+ structure = gst_caps_get_structure (self->view_finder_caps, 0);
+
+ /* Set new resolution for image capture */
+ new_caps = gst_caps_new_simple (gst_structure_get_name (structure),
+ "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
+
+ /* Set allowed framerate for the resolution. */
+ set_allowed_framerate (self, new_caps);
+ }
+
+ GST_INFO_OBJECT (self,
+ "init filter caps for image capture %" GST_PTR_FORMAT, new_caps);
+ gst_caps_replace (&self->image_capture_caps, new_caps);
+ self->image_capture_caps_update = FALSE;
+}
+
+/**
+ *
+ */
+static gboolean
+start_image_capture (GstV4l2CameraSrc * self)
+{
+ GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
+ GstPhotography *photography = gst_base_camera_src_get_photography (bcamsrc);
+ gboolean wait_for_prepare = FALSE, ret = FALSE;
+
+ if (photography) {
+ wait_for_prepare = TRUE;
+
+ if (!self->image_capture_caps || self->image_capture_caps_update) {
+ if (bcamsrc->image_capture_width && bcamsrc->image_capture_height) {
+ /* Resolution is set, but it isn't in use yet */
+ set_image_capture_caps (self, bcamsrc->image_capture_width,
+ bcamsrc->image_capture_height);
+ } else {
+ /* Capture resolution not set. Use viewfinder resolution */
+ self->image_capture_caps = gst_caps_copy (self->view_finder_caps);
+ self->image_capture_caps_update = FALSE;
+ }
+ }
+
+ /* Start preparations for image capture */
+ GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT,
+ self->image_capture_caps);
+
+ ret = gst_photography_prepare_for_capture (photography,
+ (GstPhotoCapturePrepared) img_capture_prepared,
+ self->image_capture_caps, self);
+
+ } else {
+//XXX g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE,
+//XXX "active-pad", camera->pad_src_img, NULL);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_v4l2_camera_src_set_mode (GstBaseCameraSrc * bcamsrc, GstCameraBinMode mode)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+ GstPhotography *photography = gst_base_camera_src_get_photography (bcamsrc);
+
+ if (photography) {
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (photography),
+ "capture-mode")) {
+ g_object_set (G_OBJECT (photography), "capture-mode", mode, NULL);
+ }
+ }
+
+ self->mode = mode;
+
+ switch (mode) {
+ case MODE_PREVIEW:
+ return TRUE; // XXX
+ case MODE_IMAGE:
+ return start_image_capture (GST_V4L2_CAMERA_SRC (bcamsrc));
+ case MODE_VIDEO:
+ return TRUE; // XXX
+ }
+
+ g_assert_not_reached ();
+
+ return FALSE;
+}
+
+static gboolean
+set_videosrc_zoom (GstV4l2CameraSrc * self, gint zoom)
+{
+ gboolean ret = FALSE;
+
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (self->src_vid_src),
+ "zoom")) {
+ g_object_set (G_OBJECT (self->src_vid_src), "zoom",
+ (gfloat) zoom / 100, NULL);
+ ret = TRUE;
+ }
+ return ret;
+}
+
+static gboolean
+set_element_zoom (GstV4l2CameraSrc * self, gint zoom)
+{
+ gboolean ret = FALSE;
+ GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
+ gint w2_crop = 0, h2_crop = 0;
+ GstPad *pad_zoom_sink = NULL;
+ gint left = self->base_crop_left;
+ gint right = self->base_crop_right;
+ gint top = self->base_crop_top;
+ gint bottom = self->base_crop_bottom;
+
+ if (self->src_zoom_crop) {
+ /* Update capsfilters to apply the zoom */
+ GST_INFO_OBJECT (self, "zoom: %d, orig size: %dx%d", zoom,
+ bcamsrc->width, bcamsrc->height);
+
+ if (zoom != ZOOM_1X) {
+ w2_crop = (bcamsrc->width - (bcamsrc->width * ZOOM_1X / zoom)) / 2;
+ h2_crop = (bcamsrc->height - (bcamsrc->height * ZOOM_1X / zoom)) / 2;
+
+ left += w2_crop;
+ right += w2_crop;
+ top += h2_crop;
+ bottom += h2_crop;
+
+ /* force number of pixels cropped from left to be even, to avoid slow code
+ * path on videoscale */
+ left &= 0xFFFE;
+ }
+
+ pad_zoom_sink = gst_element_get_static_pad (self->src_zoom_crop, "sink");
+
+ GST_INFO_OBJECT (self,
+ "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top,
+ bottom);
+
+ GST_PAD_STREAM_LOCK (pad_zoom_sink);
+ g_object_set (self->src_zoom_crop, "left", left, "right", right, "top",
+ top, "bottom", bottom, NULL);
+ GST_PAD_STREAM_UNLOCK (pad_zoom_sink);
+ gst_object_unref (pad_zoom_sink);
+ ret = TRUE;
+ }
+ return ret;
+}
+
+static void
+gst_v4l2_camera_src_set_zoom (GstBaseCameraSrc * bcamsrc, gint zoom)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+
+ GST_INFO_OBJECT (self, "setting zoom %d", zoom);
+
+ if (set_videosrc_zoom (self, zoom)) {
+ set_element_zoom (self, ZOOM_1X);
+ GST_INFO_OBJECT (self, "zoom set using videosrc");
+ } else if (set_element_zoom (self, zoom)) {
+ GST_INFO_OBJECT (self, "zoom set using gst elements");
+ } else {
+ GST_INFO_OBJECT (self, "setting zoom failed");
+ }
+}
+
+static GstCaps *
+gst_v4l2_camera_src_get_allowed_input_caps (GstBaseCameraSrc * bcamsrc)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+ GstCaps *caps = NULL;
+ GstPad *pad = NULL, *peer_pad = NULL;
+ GstState state;
+ GstElement *videosrc;
+
+ videosrc = self->src_vid_src ? self->src_vid_src : self->app_vid_src;
+
+ if (!videosrc) {
+ GST_WARNING_OBJECT (self, "no videosrc, can't get allowed caps");
+ goto failed;
+ }
+
+ if (self->allowed_caps) {
+ GST_DEBUG_OBJECT (self, "returning cached caps");
+ goto done;
+ }
+
+ pad = gst_element_get_static_pad (videosrc, "src");
+
+ if (!pad) {
+ GST_WARNING_OBJECT (self, "no srcpad in videosrc");
+ goto failed;
+ }
+
+ state = GST_STATE (videosrc);
+
+ /* Make this function work also in NULL state */
+ if (state == GST_STATE_NULL) {
+ GST_DEBUG_OBJECT (self, "setting videosrc to ready temporarily");
+ peer_pad = gst_pad_get_peer (pad);
+ if (peer_pad) {
+ gst_pad_unlink (pad, peer_pad);
+ }
+ /* Set videosrc to READY to open video device */
+ gst_element_set_locked_state (videosrc, TRUE);
+ gst_element_set_state (videosrc, GST_STATE_READY);
+ }
+
+ self->allowed_caps = gst_pad_get_caps (pad);
+
+ /* Restore state and re-link if necessary */
+ if (state == GST_STATE_NULL) {
+ GST_DEBUG_OBJECT (self, "restoring videosrc state %d", state);
+ /* Reset videosrc to NULL state, some drivers seem to need this */
+ gst_element_set_state (videosrc, GST_STATE_NULL);
+ if (peer_pad) {
+ gst_pad_link (pad, peer_pad);
+ gst_object_unref (peer_pad);
+ }
+ gst_element_set_locked_state (videosrc, FALSE);
+ }
+
+ gst_object_unref (pad);
+
+done:
+ if (self->allowed_caps) {
+ caps = gst_caps_copy (self->allowed_caps);
+ }
+ GST_DEBUG_OBJECT (self, "allowed caps:%" GST_PTR_FORMAT, caps);
+failed:
+ return caps;
+}
+
+/**
+ * configure_format:
+ * @self: camerasrc object
+ * @caps: caps describing new format
+ *
+ * Configure internal video format for camerabin.
+ */
+static void
+configure_format (GstV4l2CameraSrc * self, GstCaps * caps)
+{
+ GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
+ GstStructure *st;
+ gint width, height;
+
+ st = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_int (st, "width", &width);
+ gst_structure_get_int (st, "height", &height);
+
+ g_object_set (self, "width", width, "height", height, NULL);
+
+ if (gst_structure_has_field_typed (st, "framerate", GST_TYPE_FRACTION)) {
+ gst_structure_get_fraction (st, "framerate", &bcamsrc->fps_n,
+ &bcamsrc->fps_d);
+ }
+}
+
+
+/**
+ * update_aspect_filter:
+ * @self: camerasrc 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
+update_aspect_filter (GstV4l2CameraSrc * self, GstCaps * new_caps)
+{
+ // XXX why not instead add a preserve-aspect-ratio property to videoscale?
+#if 0
+ if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_SCALE) {
+ 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) {
+ if (!gst_caps_is_any (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_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);
+ }
+ }
+ gst_caps_unref (sink_caps);
+ }
+ }
+
+ /* 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 = 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);
+ if (ar_caps != new_caps)
+ gst_caps_unref (ar_caps);
+ }
+#endif
+}
+
+
+/**
+ * set_capsfilter_caps:
+ * @self: camerasrc object
+ * @new_caps: pointer to caps object to set
+ *
+ * Set given caps to camerabin capsfilters.
+ */
+static void
+set_capsfilter_caps (GstV4l2CameraSrc * self, GstCaps * new_caps)
+{
+ GST_INFO_OBJECT (self, "new_caps:%" GST_PTR_FORMAT, new_caps);
+
+ configure_format (self, new_caps);
+
+ /* Update zoom */
+ gst_base_camera_src_setup_zoom (GST_BASE_CAMERA_SRC (self));
+
+ /* Update capsfilters */
+ g_object_set (G_OBJECT (self->src_filter), "caps", new_caps, NULL);
+ if (self->src_zoom_filter)
+ g_object_set (G_OBJECT (self->src_zoom_filter), "caps", new_caps, NULL);
+ update_aspect_filter (self, new_caps);
+ GST_INFO_OBJECT (self, "udpated");
+}
+
+static void
+gst_v4l2_camera_src_finish_image_capture (GstBaseCameraSrc * bcamsrc)
+{
+ GstV4l2CameraSrc *self = GST_V4L2_CAMERA_SRC (bcamsrc);
+
+ if (self->image_capture_caps) {
+ /* If we used specific caps for image capture we need to
+ restore the caps and zoom/crop for view finder mode */
+ if (self->src_zoom_crop) {
+ GST_DEBUG_OBJECT (self, "resetting crop in camerabin");
+ g_object_set (self->src_zoom_crop, "left", 0, "right", 0,
+ "top", 0, "bottom", 0, NULL);
+ }
+ self->base_crop_left = 0;
+ self->base_crop_right = 0;
+ self->base_crop_top = 0;
+ self->base_crop_bottom = 0;
+ set_capsfilter_caps (self, self->view_finder_caps);
+ }
+}
+
+static void
+gst_v4l2_camera_src_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+// GST_DEBUG_CATEGORY_INIT (v4l2_camera_src_debug, "v4l2_camera_src", 0,
+// "V4l2 camera src");
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "V4l2 camera src element for camerabin", "Source/Video",
+ "V4l2 camera src element for camerabin", "Rob Clark <rob@ti.com>");
+}
+
+static void
+gst_v4l2_camera_src_class_init (GstV4l2CameraSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstBaseCameraSrcClass *gstbasecamerasrc_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstbasecamerasrc_class = GST_BASE_CAMERA_SRC_CLASS (klass);
+
+ gobject_class->dispose = gst_v4l2_camera_src_dispose;
+ gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2_camera_src_finalize;
+ gobject_class->set_property = gst_v4l2_camera_src_set_property;
+ gobject_class->get_property = gst_v4l2_camera_src_get_property;
+
+ // g_object_class_install_property ....
+
+ gstbasecamerasrc_class->construct_pipeline =
+ gst_v4l2_camera_src_construct_pipeline;
+ gstbasecamerasrc_class->setup_pipeline = gst_v4l2_camera_src_setup_pipeline;
+ gstbasecamerasrc_class->set_zoom = gst_v4l2_camera_src_set_zoom;
+ gstbasecamerasrc_class->set_mode = gst_v4l2_camera_src_set_mode;
+ gstbasecamerasrc_class->get_allowed_input_caps =
+ gst_v4l2_camera_src_get_allowed_input_caps;
+ gstbasecamerasrc_class->finish_image_capture =
+ gst_v4l2_camera_src_finish_image_capture;
+}
+
+static void
+gst_v4l2_camera_src_init (GstV4l2CameraSrc * self,
+ GstV4l2CameraSrcClass * klass)
+{
+ self->mode = MODE_PREVIEW;
+}
+
+gboolean
+gst_v4l2_camera_src_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "v4l2camerasrc", GST_RANK_NONE,
+ gst_v4l2_camera_src_get_type ());
+}
diff --git a/gst/camerabin2/gstv4l2camerasrc.h b/gst/camerabin2/gstv4l2camerasrc.h
new file mode 100644
index 000000000..dd3ea4ea4
--- /dev/null
+++ b/gst/camerabin2/gstv4l2camerasrc.h
@@ -0,0 +1,112 @@
+/*
+ * GStreamer
+ * Copyright (C) 2010 Texas Instruments, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_V4L2_CAMERA_SRC_H__
+#define __GST_V4L2_CAMERA_SRC_H__
+
+#include <gst/gst.h>
+#include "gstbasecamerasrc.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_V4L2_CAMERA_SRC \
+ (gst_v4l2_camera_src_get_type())
+#define GST_V4L2_CAMERA_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2_CAMERA_SRC,GstV4l2CameraSrc))
+#define GST_V4L2_CAMERA_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2_CAMERA_SRC,GstV4l2CameraSrcClass))
+#define GST_IS_V4L2_CAMERA_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2_CAMERA_SRC))
+#define GST_IS_V4L2_CAMERA_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2_CAMERA_SRC))
+ GType gst_v4l2_camera_src_get_type (void);
+
+typedef struct _GstV4l2CameraSrc GstV4l2CameraSrc;
+typedef struct _GstV4l2CameraSrcClass GstV4l2CameraSrcClass;
+
+
+/**
+ * GstV4l2CameraSrc:
+ *
+ */
+struct _GstV4l2CameraSrc
+{
+ GstBaseCameraSrc parent;
+
+ GstCameraBinMode mode;
+
+ /* source elements */
+ GstElement *src_vid_src;
+ GstElement *src_filter;
+ GstElement *src_zoom_crop;
+ GstElement *src_zoom_scale;
+ GstElement *src_zoom_filter;
+ GstElement *src_out_sel;
+
+ /* srcpads of tee */
+ GstPad *tee_vf_srcpad;
+ GstPad *tee_image_srcpad;
+ GstPad *tee_video_srcpad;
+
+ /* Application configurable elements */
+ GstElement *app_vid_src;
+ GstElement *app_video_filter;
+
+ /* Caps that videosrc supports */
+ GstCaps *allowed_caps;
+
+ /* Optional base crop for frames. Used to crop frames e.g.
+ due to wrong aspect ratio, before the crop related to zooming. */
+ gint base_crop_top;
+ gint base_crop_bottom;
+ gint base_crop_left;
+ gint base_crop_right;
+
+ /* Caps applied to capsfilters when in view finder mode */
+ GstCaps *view_finder_caps;
+
+ /* Caps applied to capsfilters when taking still image */
+ GstCaps *image_capture_caps;
+ gboolean image_capture_caps_update; // XXX where does this get set..
+
+ /* if GstV4l2CameraSrc is moved into camerabin plugin, then this isn't
+ * needed:
+ */
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+
+/**
+ * GstV4l2CameraSrcClass:
+ *
+ */
+struct _GstV4l2CameraSrcClass
+{
+ GstBaseCameraSrcClass parent;
+
+ /* if GstV4l2CameraSrc is moved into camerabin plugin, then this isn't
+ * needed:
+ */
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+gboolean gst_v4l2_camera_src_plugin_init (GstPlugin * plugin);
+
+#endif /* __GST_V4L2_CAMERA_SRC_H__ */