GST_PLUGINS_SELECTED=`echo $GST_PLUGINS_SELECTED | $SED -e s/festival//`
fi
-dnl used by camerabin
AC_CHECK_HEADERS([sys/time.h])
dnl used by ext/dts
dnl Non ported plugins (non-dependant, then dependant)
dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" aiff \
- camerabin cdxaparse \
+ cdxaparse \
dccp faceoverlay festival \
fieldanalysis freeverb freeze frei0r gaudieffects \
hdvparse id3tag inter interlace ivfparse jpegformat jp2kdecimator \
AG_GST_CHECK_PLUGIN(audiovisualizers)
AG_GST_CHECK_PLUGIN(autoconvert)
AG_GST_CHECK_PLUGIN(bayer)
-AG_GST_CHECK_PLUGIN(camerabin)
AG_GST_CHECK_PLUGIN(camerabin2)
AG_GST_CHECK_PLUGIN(cdxaparse)
AG_GST_CHECK_PLUGIN(coloreffects)
gst/audiovisualizers/Makefile
gst/autoconvert/Makefile
gst/bayer/Makefile
-gst/camerabin/Makefile
gst/camerabin2/Makefile
gst/cdxaparse/Makefile
gst/coloreffects/Makefile
tests/check/Makefile
tests/files/Makefile
tests/examples/Makefile
-tests/examples/camerabin/Makefile
tests/examples/camerabin2/Makefile
tests/examples/directfb/Makefile
tests/examples/mxf/Makefile
$(top_srcdir)/gst/audiovisualizers/gstspectrascope.h \
$(top_srcdir)/gst/audiovisualizers/gstsynaescope.h \
$(top_srcdir)/gst/audiovisualizers/gstwavescope.h \
- $(top_srcdir)/gst/camerabin/gstcamerabin.h \
$(top_srcdir)/gst/camerabin2/gstcamerabin2.h \
$(top_srcdir)/gst/coloreffects/gstcoloreffects.h \
$(top_srcdir)/gst/dataurisrc/gstdataurisrc.h \
<xi:include href="xml/element-bulge.xml" />
<xi:include href="xml/element-burn.xml" />
<xi:include href="xml/element-camerabin.xml" />
- <xi:include href="xml/element-camerabin2.xml" />
<xi:include href="xml/element-celtdec.xml" />
<xi:include href="xml/element-celtenc.xml" />
<xi:include href="xml/element-chromium.xml" />
<xi:include href="xml/plugin-bayer.xml" />
<xi:include href="xml/plugin-bz2.xml" />
<xi:include href="xml/plugin-camerabin.xml" />
- <xi:include href="xml/plugin-camerabin2.xml" />
<xi:include href="xml/plugin-cdaudio.xml" />
<xi:include href="xml/plugin-cdxaparse.xml" />
<xi:include href="xml/plugin-celt.xml" />
<FILE>element-camerabin</FILE>
<TITLE>camerabin</TITLE>
GstCameraBin
-GstCameraBinMode
<SUBSECTION Standard>
GstCameraBinClass
-GST_CAMERABIN
-GST_IS_CAMERABIN
-GST_TYPE_CAMERABIN
-GST_CAMERABIN_CLASS
-GST_IS_CAMERABIN_CLASS
-gst_camerabin_get_type
-</SECTION>
-
-<SECTION>
-<FILE>element-camerabin2</FILE>
-<TITLE>camerabin2</TITLE>
-GstCameraBin2
-<SUBSECTION Standard>
-GstCameraBin2Class
-GST_CAMERA_BIN2
-GST_IS_CAMERA_BIN2
-GST_TYPE_CAMERA_BIN2
-GST_CAMERA_BIN2_CLASS
-GST_IS_CAMERA_BIN2_CLASS
-gst_camera_bin2_get_type
+GST_CAMERA_BIN
+GST_IS_CAMERA_BIN
+GST_TYPE_CAMERA_BIN
+GST_CAMERA_BIN_CLASS
+GST_IS_CAMERA_BIN_CLASS
+gst_camera_bin_get_type
</SECTION>
<SECTION>
+++ /dev/null
-<plugin>
- <name>camerabin</name>
- <description>High level api for DC (Digital Camera) application</description>
- <filename>../../gst/camerabin/.libs/libgstcamerabin.so</filename>
- <basename>libgstcamerabin.so</basename>
- <version>0.10.23.1</version>
- <license>LGPL</license>
- <source>gst-plugins-bad</source>
- <package>GStreamer Bad Plug-ins git</package>
- <origin>Unknown package origin</origin>
- <elements>
- <element>
- <name>camerabin</name>
- <longname>Camera Bin</longname>
- <class>Generic/Bin/Camera</class>
- <description>Handle lot of features present in DSC</description>
- <author>Nokia Corporation <multimedia@maemo.org>, Edgard Lima <edgard.lima@indt.org.br></author>
- <pads>
- </pads>
- </element>
- </elements>
-</plugin>
\ No newline at end of file
+++ /dev/null
-<plugin>
- <name>camerabin2</name>
- <description>camerabin2</description>
- <filename>../../gst/camerabin2/.libs/libgstcamerabin2.so</filename>
- <basename>libgstcamerabin2.so</basename>
- <version>0.11.90</version>
- <license>LGPL</license>
- <source>gst-plugins-bad</source>
- <package>GStreamer Bad Plug-ins source release</package>
- <origin>Unknown package origin</origin>
- <elements>
- <element>
- <name>camerabin2</name>
- <longname>CameraBin2</longname>
- <class>Generic/Bin/Camera</class>
- <description>CameraBin2</description>
- <author>Thiago Santos <thiago.sousa.santos@collabora.co.uk></author>
- <pads>
- </pads>
- </element>
- <element>
- <name>viewfinderbin</name>
- <longname>Viewfinder Bin</longname>
- <class>Sink/Video</class>
- <description>Viewfinder Bin used in camerabin2</description>
- <author>Thiago Santos <thiago.sousa.santos@collabora.com></author>
- <pads>
- <caps>
- <name>sink</name>
- <direction>sink</direction>
- <presence>always</presence>
- <details>video/x-raw</details>
- </caps>
- </pads>
- </element>
- <element>
- <name>wrappercamerabinsrc</name>
- <longname>Wrapper camera src element for camerabin2</longname>
- <class>Source/Video</class>
- <description>Wrapper camera src element for camerabin2</description>
- <author>Thiago Santos <thiago.sousa.santos@collabora.com></author>
- <pads>
- <caps>
- <name>imgsrc</name>
- <direction>source</direction>
- <presence>always</presence>
- <details>ANY</details>
- </caps>
- <caps>
- <name>vfsrc</name>
- <direction>source</direction>
- <presence>always</presence>
- <details>ANY</details>
- </caps>
- <caps>
- <name>vidsrc</name>
- <direction>source</direction>
- <presence>always</presence>
- <details>ANY</details>
- </caps>
- </pads>
- </element>
- </elements>
-</plugin>
\ No newline at end of file
+++ /dev/null
-gstcamerabin-marshal.c
-gstcamerabin-marshal.h
+++ /dev/null
-glib_gen_prefix = __gst_camerabin
-glib_gen_basename = gstcamerabin
-
-include $(top_srcdir)/common/gst-glib-gen.mak
-
-built_sources = gstcamerabin-marshal.c
-built_headers = gstcamerabin-marshal.h
-
-BUILT_SOURCES = $(built_sources) $(built_headers)
-
-CLEANFILES = $(BUILT_SOURCES)
-
-EXTRA_DIST = gstcamerabin-marshal.list
-
-plugin_LTLIBRARIES = libgstcamerabin.la
-
-libgstcamerabin_la_SOURCES = gstcamerabin.c \
- gstcamerabincolorbalance.c \
- gstinputselector.c \
- camerabinimage.c \
- camerabinvideo.c \
- camerabingeneral.c \
- camerabinpreview.c \
- gstcamerabin-enum.c
-
-nodist_libgstcamerabin_la_SOURCES = $(built_sources)
-libgstcamerabin_la_CFLAGS = \
- $(GST_PLUGINS_BAD_CFLAGS) \
- $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
- -DGST_USE_UNSTABLE_API
-libgstcamerabin_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-$(GST_API_VERSION).la \
- $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \
- -lgstinterfaces-$(GST_API_VERSION) -lgsttag-$(GST_API_VERSION)
-
-libgstcamerabin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstcamerabin_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = gstcamerabin.h \
- gstcamerabincolorbalance.h \
- gstinputselector.h \
- camerabinimage.h \
- camerabinvideo.h \
- camerabindebug.h \
- camerabingeneral.h \
- camerabinpreview.h \
- gstcamerabin-enum.h
-
-Android.mk: Makefile.am $(BUILT_SOURCES)
- androgenizer \
- -:PROJECT libgstcamerabin -:SHARED libgstcamerabin \
- -:TAGS eng debug \
- -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
- -:SOURCES $(libgstcamerabin_la_SOURCES) \
- -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstcamerabin_la_CFLAGS) \
- -:LDFLAGS $(libgstcamerabin_la_LDFLAGS) \
- $(libgstcamerabin_la_LIBADD) \
- -ldl \
- -:LIBFILTER_STATIC gstphotography-@GST_API_VERSION@ \
- gstbasecamerabinsrc-@GST_API_VERSION@ \
- -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
- LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
- > $@
+++ /dev/null
-= Cleanups =
-* often two g_object_set for same object one after the other
-* use GST_*_OBJECT () more often
-* there are two gst_element_set_state() one after each other
-
-= Renaming =
-* internal use of img->image, vid->video
-
-= Refactorisation =
-* gstcamerabin:gst_camerabin_rewrite_tags
- - sounds fishy, should use normal tagsetter method
- - gst_camerabin_rewrite_tags_to_bin(9 why don't we just send a tag-event?
-
-* file-name property
- - supplying an already opened filedeskriptor would be more safe
- - need to check what filesink does if the file exists and cannot be overwritten
-
-* imagbin
- - we want async operation here (especialy for burst mode capture)
- - right now, its a bit fragile as we muck with locked_state
- - main problem is that the location for filesink can only be set in NULL/READY
- and we need to do that sync'ed with the dataflow. we can't use multifilesink
- as it does a file per pad_push
- - one problem of the current approach is that we can't have an image in e.g,
- postprocessing while anotherone is beeing saved
- - we could use a pool of imagebins:
- - configure one (set filename)
- - push_buffer
- - on eos, put it back to the pool
- - for this we need to check that we can have multiple instances of e.g.
- dsp jpeg encoders
+++ /dev/null
-/*
- * GStreamer
- * Copyright (C) 2010 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_DEBUG_H_
-#define __CAMERABIN_DEBUG_H_
-
-#include <gst/gst.h>
-
-/* debug logging category */
-GST_DEBUG_CATEGORY_EXTERN (gst_camerabin_debug);
-#define GST_CAT_DEFAULT gst_camerabin_debug
-
-#endif /* #ifndef __CAMERABIN_DEBUG_H_ */
+++ /dev/null
-/*
- * 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 <glib.h>
-
-#include "camerabingeneral.h"
-#include "gstinputselector.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)
-{
- gboolean ret;
-
- g_return_val_if_fail (bin, FALSE);
- g_return_val_if_fail (new_elem, FALSE);
-
- ret = gst_camerabin_try_add_element (bin, new_elem);
-
- 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
- * @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.
- *
- * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise.
- */
-gboolean
-gst_camerabin_try_add_element (GstBin * bin, GstElement * new_elem)
-{
- 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_full (bin_elem, NULL, new_elem, NULL,
- GST_PAD_LINK_CHECK_CAPS)) {
- 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
- * @instance_name: name of the instance 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,
- const gchar * instance_name)
-{
- GstElement *new_elem;
-
- g_return_val_if_fail (bin, FALSE);
- g_return_val_if_fail (elem_name, FALSE);
-
- if (strcmp (elem_name, "input-selector") == 0) {
- /* we ship our own copy of input-selector because we still use the
- * "select-all" property which was removed when input-selector was
- * moved to core */
- new_elem = g_object_new (GST_TYPE_INPUT_SELECTOR, NULL);
- } else {
- 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;
-}
+++ /dev/null
-/*
- * 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, GstElement * new_elem);
-gboolean gst_camerabin_add_element (GstBin * bin, GstElement * new_elem);
-GstElement *gst_camerabin_create_and_add_element (GstBin * bin, const gchar * elem_name, const gchar * instance_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);
-
-#endif /* #ifndef __CAMERABIN_GENERAL_H_ */
+++ /dev/null
-/*
- * 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:camerabinimage
- * @short_description: image capturing module of #GstCameraBin
- *
- * <refsect2>
- * <para>
- *
- * The pipeline for this module is:
- *
- * <informalexample>
- * <programlisting>
- *-----------------------------------------------------------------------------
- *
- * -> [post proc] -> csp -> imageenc -> metadatamuxer -> filesink
- *
- *-----------------------------------------------------------------------------
- * </programlisting>
- * </informalexample>
- *
- * The image bin opens file for image writing in READY to PAUSED state change.
- * The image bin closes the file in PAUSED to READY state change.
- *
- * </para>
- * </refsect2>
- */
-
-/*
- * includes
- */
-
-#include <gst/gst.h>
-
-#include "camerabinimage.h"
-#include "camerabindebug.h"
-#include "camerabingeneral.h"
-#include "gstcamerabin-enum.h"
-
-#include "string.h"
-
-/* default internal element names */
-
-#define DEFAULT_SINK "filesink"
-#define DEFAULT_ENC "jpegenc"
-#define DEFAULT_FORMATTER "jifmux"
-#define DEFAULT_FLAGS GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION
-
-enum
-{
- PROP_0,
- PROP_FILENAME
-};
-
-static gboolean gst_camerabin_image_create_elements (GstCameraBinImage * img);
-static void gst_camerabin_image_destroy_elements (GstCameraBinImage * img);
-
-static void gst_camerabin_image_dispose (GstCameraBinImage * sink);
-static GstStateChangeReturn
-gst_camerabin_image_change_state (GstElement * element,
- GstStateChange transition);
-static gboolean gst_camerabin_image_send_event (GstElement * element,
- GstEvent * event);
-static void gst_camerabin_image_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_camerabin_image_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static gboolean metadata_write_probe (GstPad * pad, GstBuffer * buffer,
- gpointer u_data);
-static gboolean prepare_element (GList ** result,
- const gchar * default_element_name, GstElement * app_elem,
- GstElement ** res_elem);
-
-
-GST_BOILERPLATE (GstCameraBinImage, gst_camerabin_image, GstBin, GST_TYPE_BIN);
-
-static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-static void
-gst_camerabin_image_base_init (gpointer klass)
-{
- GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (eklass,
- gst_static_pad_template_get (&sink_template));
- gst_element_class_set_details_simple (eklass,
- "Image capture bin for camerabin", "Bin/Image",
- "Process and store image data",
- "Edgard Lima <edgard.lima@indt.org.br>, "
- "Nokia Corporation <multimedia@maemo.org>");
-}
-
-static void
-gst_camerabin_image_class_init (GstCameraBinImageClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
-
- gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->dispose =
- (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_camerabin_image_dispose);
- eklass->change_state = GST_DEBUG_FUNCPTR (gst_camerabin_image_change_state);
- eklass->send_event = GST_DEBUG_FUNCPTR (gst_camerabin_image_send_event);
-
- gobject_class->set_property =
- GST_DEBUG_FUNCPTR (gst_camerabin_image_set_property);
- gobject_class->get_property =
- GST_DEBUG_FUNCPTR (gst_camerabin_image_get_property);
-
- /**
- * GstCameraBinImage:filename
- *
- * This property can be used to specify the filename of the image.
- *
- **/
- g_object_class_install_property (gobject_class, PROP_FILENAME,
- g_param_spec_string ("filename", "Filename",
- "Filename of the image to save", NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_camerabin_image_init (GstCameraBinImage * img,
- GstCameraBinImageClass * g_class)
-{
- img->filename = g_string_new ("");
-
- img->post = NULL;
- img->csp = NULL;
- img->enc = NULL;
- img->app_enc = NULL;
- img->formatter = NULL;
- img->app_formatter = NULL;
- img->sink = NULL;
-
- /* Create src and sink ghost pads */
- img->sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
- gst_element_add_pad (GST_ELEMENT (img), img->sinkpad);
-
- img->flags = DEFAULT_FLAGS;
-}
-
-static void
-gst_camerabin_image_dispose (GstCameraBinImage * img)
-{
- GST_DEBUG_OBJECT (img, "disposing");
-
- g_string_free (img->filename, TRUE);
- img->filename = NULL;
-
- if (img->elements) {
- g_list_free (img->elements);
- img->elements = NULL;
- }
-
- if (img->sink) {
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->sink), GST_OBJECT_REFCOUNT_VALUE (img->sink));
- gst_object_unref (img->sink);
- img->sink = NULL;
- }
-
- if (img->formatter) {
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->formatter),
- GST_OBJECT_REFCOUNT_VALUE (img->formatter));
- gst_object_unref (img->formatter);
- img->formatter = NULL;
- }
-
- if (img->app_formatter) {
- gst_object_sink (img->app_formatter);
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->app_formatter),
- GST_OBJECT_REFCOUNT_VALUE (img->app_formatter));
- gst_object_unref (img->app_formatter);
- img->app_formatter = NULL;
- }
-
- if (img->enc) {
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->enc), GST_OBJECT_REFCOUNT_VALUE (img->enc));
- gst_object_unref (img->enc);
- img->enc = NULL;
- }
-
- if (img->csp) {
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->csp), GST_OBJECT_REFCOUNT_VALUE (img->csp));
- gst_object_unref (img->csp);
- img->csp = NULL;
- }
-
- /* Note: if imagebin was never set to READY state the
- ownership of elements created by application were never
- taken by bin and therefore gst_object_sink is called for
- these elements (they may still be in floating state
- and not unreffed properly without sinking first)
- FIXME, something else is wrong if you have to sink here
- */
- if (img->app_enc) {
- //gst_object_ref_sink (img->app_enc);
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->app_enc),
- GST_OBJECT_REFCOUNT_VALUE (img->app_enc));
- gst_object_unref (img->app_enc);
- img->app_enc = NULL;
- }
-
- if (img->post) {
- //gst_object_ref_sink (img->post);
- GST_LOG_OBJECT (img, "disposing %s with refcount %d",
- GST_ELEMENT_NAME (img->post), GST_OBJECT_REFCOUNT_VALUE (img->post));
- gst_object_unref (img->post);
- img->post = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose ((GObject *) img);
-}
-
-static GstStateChangeReturn
-gst_camerabin_image_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstCameraBinImage *img = GST_CAMERABIN_IMAGE (element);
-
- GST_DEBUG_OBJECT (element, "changing state: %s -> %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (!gst_camerabin_image_create_elements (img)) {
- return GST_STATE_CHANGE_FAILURE;
- }
- /* Allow setting filename when image bin in READY state */
- gst_element_set_locked_state (img->sink, TRUE);
- GST_INFO_OBJECT (img, "locking imagebin->sink state to %s",
- gst_element_state_get_name (GST_STATE (img->sink)));
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- if (!g_str_equal (img->filename->str, "")) {
- GST_INFO_OBJECT (img, "preparing image with filename: %s",
- img->filename->str);
- gst_element_set_locked_state (img->sink, FALSE);
- } else {
- GST_INFO_OBJECT (img, "keep sink locked, we have no filename yet");
- }
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* Set sink to NULL in order to write the file _now_ */
- GST_INFO_OBJECT (img, "write image with filename: %s",
- img->filename->str);
- gst_element_set_locked_state (img->sink, TRUE);
- gst_element_set_state (img->sink, GST_STATE_NULL);
- g_string_assign (img->filename, "");
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (GST_ELEMENT_PARENT (img)),
- GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE |
- GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS, "imagebin.playing");
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_camerabin_image_destroy_elements (img);
- break;
- default:
- break;
- }
-
- GST_DEBUG_OBJECT (element, "changed state: %s -> %s = %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)),
- gst_element_state_change_return_get_name (ret));
-
- return ret;
-}
-
-gboolean
-gst_camerabin_image_send_event (GstElement * element, GstEvent * event)
-{
- GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (element);
- gboolean ret = FALSE;
-
- GST_INFO ("got %s event", GST_EVENT_TYPE_NAME (event));
-
- if (GST_EVENT_IS_DOWNSTREAM (event)) {
- ret = gst_pad_send_event (bin->sinkpad, event);
- } else {
- if (bin->sink) {
- ret = gst_element_send_event (bin->sink, event);
- } else {
- GST_WARNING ("upstream event handling failed");
- }
- }
-
- return ret;
-}
-
-static void
-gst_camerabin_image_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (object);
-
- switch (prop_id) {
- case PROP_FILENAME:
- g_string_assign (bin->filename, g_value_get_string (value));
- GST_INFO_OBJECT (bin, "received filename: '%s'", bin->filename->str);
- if (bin->sink) {
- if (!g_str_equal (bin->filename->str, "")) {
- g_object_set (G_OBJECT (bin->sink), "location", bin->filename->str,
- NULL);
- gst_element_set_locked_state (bin->sink, FALSE);
- gst_element_sync_state_with_parent (bin->sink);
- } else {
- GST_INFO_OBJECT (bin, "empty filename");
- }
- } else {
- GST_INFO_OBJECT (bin, "no sink, not setting name yet");
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_camerabin_image_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstCameraBinImage *bin = GST_CAMERABIN_IMAGE (object);
-
- switch (prop_id) {
- case PROP_FILENAME:
- g_value_set_string (value, bin->filename->str);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/*
- * gst_camerabin_image_prepare_elements:
- * @imagebin: a pointer to #GstCameraBinImage object
- *
- * This function creates an ordered list of elements configured for imagebin
- * pipeline and creates the elements if necessary. It also stores pointers
- * to created elements for re-using them.
- *
- * Image bin:
- * img->sinkpad ! [ post process !] [ csp !] encoder ! metadata ! filesink
- *
- * Returns: %FALSE if there was error creating element, %TRUE otherwise
- */
-gboolean
-gst_camerabin_image_prepare_elements (GstCameraBinImage * imagebin)
-{
- gboolean ret = FALSE;
- GstPad *sinkpad = NULL;
-
- g_return_val_if_fail (imagebin != NULL, FALSE);
-
- GST_DEBUG_OBJECT (imagebin, "preparing image capture elements");
-
- if (imagebin->elements != NULL) {
- g_list_free (imagebin->elements);
- imagebin->elements = NULL;
- }
-
- /* Create file sink element */
- if (!prepare_element (&imagebin->elements, DEFAULT_SINK, NULL,
- &imagebin->sink)) {
- goto done;
- } else {
- g_object_set (G_OBJECT (imagebin->sink), "location",
- imagebin->filename->str, "async", FALSE, "buffer-mode", 2,
- /* non buffered io */ NULL);
- }
-
- /* Create metadata muxer element */
- if (!prepare_element (&imagebin->elements, DEFAULT_FORMATTER,
- imagebin->app_formatter, &imagebin->formatter)) {
- goto done;
- } else if (!imagebin->metadata_probe_id) {
- /* Add probe for default XMP metadata writing */
- sinkpad = gst_element_get_static_pad (imagebin->formatter, "sink");
- imagebin->metadata_probe_id =
- gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (metadata_write_probe),
- imagebin);
- gst_object_unref (sinkpad);
- }
-
- /* Create image encoder element */
- if (!prepare_element (&imagebin->elements, DEFAULT_ENC, imagebin->app_enc,
- &imagebin->enc)) {
- goto done;
- }
-
- /* Create optional colorspace conversion element */
- if (imagebin->flags & GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION) {
- if (!prepare_element (&imagebin->elements, "ffmpegcolorspace", NULL,
- &imagebin->csp)) {
- goto done;
- }
- }
-
- /* Add optional image post processing element */
- if (!prepare_element (&imagebin->elements, NULL, imagebin->post,
- &imagebin->post)) {
- goto done;
- }
-
- ret = TRUE;
-
-done:
- GST_DEBUG_OBJECT (imagebin, "preparing finished %s", ret ? "OK" : "NOK");
- return ret;
-}
-
-
-/*
- * static helper functions implementation
- */
-
-/*
- * metadata_write_probe:
- * @pad: sink pad of metadata muxer
- * @buffer: received buffer
- * @u_data: image bin object
- *
- * Buffer probe that sets Xmp.dc.type and Xmp.dc.format tags
- * to metadata muxer based on preceding element src pad caps.
- *
- * Returns: TRUE always
- */
-static gboolean
-metadata_write_probe (GstPad * pad, GstBuffer * buffer, gpointer u_data)
-{
- /* Add XMP tags */
- GstCameraBinImage *img = NULL;
- GstTagSetter *setter = NULL;
- GstPad *srcpad = NULL;
- GstCaps *caps = NULL;
- GstStructure *st = NULL;
-
- img = GST_CAMERABIN_IMAGE (u_data);
-
- g_return_val_if_fail (img != NULL, TRUE);
-
- if (GST_IS_TAG_SETTER (img->formatter)) {
- setter = GST_TAG_SETTER (img->formatter);
- }
-
- if (!setter) {
- GST_WARNING_OBJECT (img, "setting tags failed");
- goto done;
- }
-
- /* Xmp.dc.type tag */
- gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
- GST_TAG_CODEC, "Image", NULL);
- /* Xmp.dc.format tag */
- if (img->enc) {
- srcpad = gst_element_get_static_pad (img->enc, "src");
- }
- GST_LOG_OBJECT (img, "srcpad:%" GST_PTR_FORMAT, srcpad);
- if (srcpad) {
- caps = gst_pad_get_negotiated_caps (srcpad);
- GST_LOG_OBJECT (img, "caps:%" GST_PTR_FORMAT, caps);
- if (caps) {
- /* If there are many structures, we can't know which one to use */
- if (gst_caps_get_size (caps) != 1) {
- GST_WARNING_OBJECT (img, "can't decide structure for format tag");
- goto done;
- }
- st = gst_caps_get_structure (caps, 0);
- if (st) {
- GST_DEBUG_OBJECT (img, "Xmp.dc.format:%s", gst_structure_get_name (st));
- gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
- GST_TAG_VIDEO_CODEC, gst_structure_get_name (st), NULL);
- }
- }
- }
-done:
- if (caps)
- gst_caps_unref (caps);
- if (srcpad)
- gst_object_unref (srcpad);
-
- return TRUE;
-}
-
-/*
- * prepare_element:
- * @result: result list address
- * @default_element_name: name of default element to be created
- * @app_elem: pointer to application set element
- * @res_elem: pointer to current element to be replaced if needed
- *
- * This function chooses given image capture element or creates a new one and
- * and prepends it to @result list.
- *
- * Returns: %FALSE if there was error creating new element, %TRUE otherwise
- */
-static gboolean
-prepare_element (GList ** result, const gchar * default_element_name,
- GstElement * app_elem, GstElement ** res_elem)
-{
- GstElement *elem = NULL;
- gboolean ret = TRUE;
-
- if (app_elem) {
- /* Prefer application set element */
- elem = app_elem;
- } else if (*res_elem) {
- /* Use existing element if any */
- elem = *res_elem;
- } else if (default_element_name) {
- /* Create new element */
- if (!(elem = gst_element_factory_make (default_element_name, NULL))) {
- GST_WARNING ("creating %s failed", default_element_name);
- ret = FALSE;
- }
- }
-
- if (*res_elem != elem) {
- /* Keep reference and store pointer to chosen element, which can be re-used
- until imagebin is disposed or new image capture element is chosen. */
- gst_object_replace ((GstObject **) res_elem, (GstObject *) elem);
- }
- if (elem) {
- *result = g_list_prepend (*result, elem);
- }
-
- return ret;
-}
-
-/*
- * gst_camerabin_image_link_first_element:
- * @img: a pointer to #GstCameraBinImage object
- * @elem: first element to be linked on imagebin
- *
- * Adds given element to imagebin and links it to imagebin's ghost sink pad.
- *
- * Returns: %TRUE if adding and linking succeeded, %FALSE otherwise
- */
-static gboolean
-gst_camerabin_image_link_first_element (GstCameraBinImage * imagebin,
- GstElement * elem)
-{
- GstPad *first_sinkpad = NULL;
- gboolean ret = FALSE;
-
- g_return_val_if_fail (imagebin != NULL, FALSE);
- /* Link given element to imagebin ghost sink pad */
- if (gst_bin_add (GST_BIN (imagebin), elem)) {
- first_sinkpad = gst_element_get_static_pad (elem, "sink");
- if (first_sinkpad) {
- if (gst_ghost_pad_set_target (GST_GHOST_PAD (imagebin->sinkpad),
- first_sinkpad)) {
- ret = TRUE;
- } else {
- GST_WARNING ("linking first element failed");
- }
- gst_object_unref (first_sinkpad);
- } else {
- GST_WARNING ("no sink pad in first element");
- }
- } else {
- GST_WARNING ("adding element failed");
- }
- return ret;
-}
-
-/*
- * gst_camerabin_image_link_elements:
- * @imagebin: a pointer to #GstCameraBinImage object
- *
- * Link elements configured to imagebin elements list.
- *
- * Returns %TRUE if linking succeeded, %FALSE otherwise.
- */
-static gboolean
-gst_camerabin_image_link_elements (GstCameraBinImage * imagebin)
-{
- GList *prev = NULL;
- GList *next = NULL;
- gboolean ret = FALSE;
-
- GST_DEBUG_OBJECT (imagebin, "linking image elements");
-
- if (!imagebin->elements) {
- GST_WARNING ("no elements to link");
- goto done;
- }
-
- /* Link the elements in list */
- prev = imagebin->elements;
- next = g_list_next (imagebin->elements);
- for (; next != NULL; next = g_list_next (next)) {
- /* Link first element in list to imagebin ghost sink pad */
- if (prev == imagebin->elements
- && !gst_camerabin_image_link_first_element (imagebin,
- GST_ELEMENT (prev->data))) {
- goto done;
- }
- if (!gst_bin_add (GST_BIN (imagebin), GST_ELEMENT (next->data))) {
- GST_WARNING_OBJECT (imagebin, "adding element failed");
- goto done;
- }
- GST_LOG_OBJECT (imagebin, "linking %s - %s",
- GST_ELEMENT_NAME (GST_ELEMENT (prev->data)),
- GST_ELEMENT_NAME (GST_ELEMENT (next->data)));
- if (!gst_element_link (GST_ELEMENT (prev->data), GST_ELEMENT (next->data))) {
- GST_WARNING_OBJECT (imagebin, "linking element failed");
- goto done;
- }
-
- prev = next;
- }
-
- ret = TRUE;
-
-done:
-
- if (!ret) {
- gst_camerabin_remove_elements_from_bin (GST_BIN (imagebin));
- }
-
- GST_DEBUG_OBJECT (imagebin, "linking finished %s", ret ? "OK" : "NOK");
-
- return ret;
-}
-
-/*
- * gst_camerabin_image_create_elements:
- * @img: a pointer to #GstCameraBinImage object
- *
- * This function creates needed elements, adds them to
- * imagebin and links them.
- *
- * Returns %TRUE if success, %FALSE otherwise.
- */
-static gboolean
-gst_camerabin_image_create_elements (GstCameraBinImage * img)
-{
- gboolean ret = FALSE;
- g_return_val_if_fail (img != NULL, FALSE);
-
- if (gst_camerabin_image_prepare_elements (img)) {
- ret = gst_camerabin_image_link_elements (img);
- }
-
- return ret;
-}
-
-/*
- * gst_camerabin_image_destroy_elements:
- * @img: a pointer to #GstCameraBinImage object
- *
- * This function releases resources allocated in
- * gst_camerabin_image_create_elements.
- *
- */
-static void
-gst_camerabin_image_destroy_elements (GstCameraBinImage * img)
-{
- GST_LOG ("destroying image elements");
-
- gst_ghost_pad_set_target (GST_GHOST_PAD (img->sinkpad), NULL);
-
- gst_camerabin_remove_elements_from_bin (GST_BIN (img));
-}
-
-void
-gst_camerabin_image_set_encoder (GstCameraBinImage * img, GstElement * encoder)
-{
- GST_DEBUG ("setting image encoder %" GST_PTR_FORMAT, encoder);
- if (img->app_enc)
- gst_object_unref (img->app_enc);
- if (encoder)
- gst_object_ref (encoder);
-
- img->app_enc = encoder;
-}
-
-void
-gst_camerabin_image_set_postproc (GstCameraBinImage * img,
- GstElement * postproc)
-{
- GST_DEBUG ("setting image postprocessing element %" GST_PTR_FORMAT, postproc);
- if (img->post)
- gst_object_unref (img->post);
- if (postproc)
- gst_object_ref (postproc);
-
- img->post = postproc;
-}
-
-void
-gst_camerabin_image_set_formatter (GstCameraBinImage * img,
- GstElement * formatter)
-{
- GstElement **app_formatter;
- GST_DEBUG ("setting image formatter %" GST_PTR_FORMAT, formatter);
-
- app_formatter = &img->app_formatter;
- GST_OBJECT_LOCK (img);
- gst_object_replace ((GstObject **) app_formatter, GST_OBJECT (formatter));
- GST_OBJECT_UNLOCK (img);
-}
-
-void
-gst_camerabin_image_set_flags (GstCameraBinImage * img, GstCameraBinFlags flags)
-{
- GST_DEBUG_OBJECT (img, "setting image flags: %d", flags);
- img->flags = flags;
-}
-
-GstElement *
-gst_camerabin_image_get_encoder (GstCameraBinImage * img)
-{
- GstElement *enc;
-
- if (img->app_enc) {
- enc = img->app_enc;
- } else {
- enc = img->enc;
- }
-
- return enc;
-}
-
-GstElement *
-gst_camerabin_image_get_formatter (GstCameraBinImage * img)
-{
- /* Prefer formatter that is currently in use */
- return img->formatter ? img->formatter : img->app_formatter;
-}
-
-GstElement *
-gst_camerabin_image_get_postproc (GstCameraBinImage * img)
-{
- return img->post;
-}
+++ /dev/null
-/*
- * 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_IMAGE_H__
-#define __CAMERABIN_IMAGE_H__
-
-#include <gst/gstbin.h>
-
-#include "gstcamerabin-enum.h"
-
-G_BEGIN_DECLS
-#define GST_TYPE_CAMERABIN_IMAGE (gst_camerabin_image_get_type())
-#define GST_CAMERABIN_IMAGE_CAST(obj) ((GstCameraBinImage*)(obj))
-#define GST_CAMERABIN_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN_IMAGE,GstCameraBinImage))
-#define GST_CAMERABIN_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN_IMAGE,GstCameraBinImageClass))
-#define GST_IS_CAMERABIN_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN_IMAGE))
-#define GST_IS_CAMERABIN_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN_IMAGE))
-/**
- * GstCameraBinImage:
- *
- * The opaque #GstCameraBinImage structure.
- */
-typedef struct _GstCameraBinImage GstCameraBinImage;
-typedef struct _GstCameraBinImageClass GstCameraBinImageClass;
-
-struct _GstCameraBinImage
-{
- GstBin parent;
- GString *filename;
-
- /* Ghost pads of image bin */
- GstPad *sinkpad;
-
- /* Ordered list of elements configured to imagebin */
- GList *elements;
- /* Imagebin elements */
- GstElement *post;
- GstElement *csp;
- GstElement *enc;
- GstElement *app_enc;
- GstElement *formatter;
- GstElement *app_formatter;
- GstElement *sink;
-
- GstCameraBinFlags flags;
- gulong metadata_probe_id;
-};
-
-struct _GstCameraBinImageClass
-{
- GstBinClass parent_class;
-};
-
-GType gst_camerabin_image_get_type (void);
-
-void
-gst_camerabin_image_set_encoder (GstCameraBinImage * img, GstElement * encoder);
-
-void
-gst_camerabin_image_set_postproc (GstCameraBinImage * img,
- GstElement * postproc);
-
-void
-gst_camerabin_image_set_formatter (GstCameraBinImage * img, GstElement * formatter);
-
-void
-gst_camerabin_image_set_flags (GstCameraBinImage * img,
- GstCameraBinFlags flags);
-
-GstElement *gst_camerabin_image_get_encoder (GstCameraBinImage * img);
-
-GstElement *gst_camerabin_image_get_postproc (GstCameraBinImage * img);
-
-GstElement *gst_camerabin_image_get_formatter (GstCameraBinImage * img);
-
-gboolean gst_camerabin_image_prepare_elements (GstCameraBinImage * imagebin);
-
-G_END_DECLS
-#endif /* #ifndef __CAMERABIN_IMAGE_H__ */
+++ /dev/null
-/*
-* 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.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <string.h>
-
-#include "camerabindebug.h"
-#include "camerabingeneral.h"
-#include "camerabinpreview.h"
-
-static void
-save_result (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer data)
-{
- GstBuffer **p_buf = (GstBuffer **) data;
-
- *p_buf = gst_buffer_ref (buf);
-
- GST_DEBUG ("received converted buffer %p with caps %" GST_PTR_FORMAT,
- *p_buf, GST_BUFFER_CAPS (*p_buf));
-}
-
-static gboolean
-create_element (const gchar * factory_name, const gchar * elem_name,
- GstElement ** element, GError ** err)
-{
- *element = gst_element_factory_make (factory_name, elem_name);
- if (*element)
- return TRUE;
-
- if (err && *err == NULL) {
- *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN,
- "cannot create element '%s' - please check your GStreamer installation",
- factory_name);
- }
-
- return FALSE;
-}
-
-
-/**
- * gst_camerabin_preview_create_pipeline:
- * @element: #GstCameraBin element
- * @caps: pointer to the caps used in pipeline
- * @src_filter: source filter element
- *
- * Create a preview converter pipeline that outputs the format defined in
- * @caps parameter.
- *
- * Returns: New pipeline data structure, or NULL if error occured.
- */
-GstCameraBinPreviewPipelineData *
-gst_camerabin_preview_create_pipeline (GstElement * element, GstCaps * caps,
- GstElement * src_filter)
-{
- GstElement *csp = NULL, *vscale = NULL;
- GError *error = NULL;
- GstCameraBinPreviewPipelineData *data;
-
- g_return_val_if_fail (caps != NULL, NULL);
-
- GST_DEBUG ("creating elements");
-
- data = g_new (GstCameraBinPreviewPipelineData, 1);
-
- /* We have multiple pipelines created by using this function, so we can't
- * give a name to them. Another way would to ensure the uniqueness of the
- * name here*/
- data->pipeline = gst_pipeline_new (NULL);
- if (!data->pipeline)
- goto create_error;
-
- if (!create_element ("appsrc", "prev_src", &data->appsrc, &error) ||
- !create_element ("videoscale", NULL, &vscale, &error) ||
- !create_element ("ffmpegcolorspace", NULL, &csp, &error) ||
- !create_element ("capsfilter", NULL, &data->capsfilter, &error) ||
- !create_element ("fakesink", "prev_sink", &data->appsink, &error))
- goto create_error;
-
- GST_DEBUG ("adding elements");
- gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, csp,
- data->capsfilter, vscale, data->appsink, NULL);
- if (src_filter) {
- gst_bin_add (GST_BIN (data->pipeline), src_filter);
- }
-
- data->element = element;
-
- GST_DEBUG ("preview format is: %" GST_PTR_FORMAT, caps);
-
- g_object_set (data->capsfilter, "caps", caps, NULL);
- g_object_set (data->appsink, "preroll-queue-len", 1, "signal-handoffs", TRUE,
- NULL);
- g_object_set (vscale, "method", 0, NULL);
-
- GST_DEBUG ("linking src->vscale");
- if (!gst_element_link_pads (data->appsrc, "src", vscale, "sink"))
- goto link_error;
-
- if (src_filter) {
- GST_DEBUG ("linking vscale->src_filter");
- if (!gst_element_link_pads (vscale, "src", src_filter, "sink")) {
- goto link_error;
- }
- GST_DEBUG ("linking filter->csp");
- if (!gst_element_link_pads (src_filter, "src", csp, "sink")) {
- goto link_error;
- }
- } else {
- GST_DEBUG ("linking vscale->csp");
- if (!gst_element_link_pads (vscale, "src", csp, "sink"))
- goto link_error;
- }
-
- GST_DEBUG ("linking csp->capsfilter");
- if (!gst_element_link_pads (csp, "src", data->capsfilter, "sink"))
- goto link_error;
-
- GST_DEBUG ("linking capsfilter->sink");
- if (!gst_element_link_pads (data->capsfilter, "src", data->appsink, "sink"))
- goto link_error;
-
- return data;
-
-create_error:
- if (error) {
- GST_WARNING ("Preview pipeline element creation failed: %s",
- error->message);
- g_error_free (error);
- }
- if (csp)
- gst_object_unref (csp);
- if (vscale)
- gst_object_unref (vscale);
- if (data->appsrc)
- gst_object_unref (data->appsrc);
- if (data->capsfilter)
- gst_object_unref (data->capsfilter);
- if (data->appsink)
- gst_object_unref (data->appsink);
-
-link_error:
- GST_WARNING ("Could not create preview pipeline");
- gst_camerabin_preview_destroy_pipeline (data);
-
- return NULL;
-}
-
-
-/**
- * gst_camerabin_preview_destroy_pipeline:
- * @data: the pipeline data to be destroyed
- *
- * Destroy preview converter pipeline.
- */
-void
-gst_camerabin_preview_destroy_pipeline (GstCameraBinPreviewPipelineData * data)
-{
- if (data->pipeline) {
- gst_element_set_state (data->pipeline, GST_STATE_NULL);
- gst_object_unref (data->pipeline);
- }
- g_free (data);
-}
-
-
-/**
- * gst_camerabin_preview_convert:
- * @data: preview pipeline data to use
- * @buf: #GstBuffer that contains the frame to be converted
- *
- * Create a preview image of the given frame.
- *
- * Returns: converted preview image, or NULL if operation failed.
- */
-GstBuffer *
-gst_camerabin_preview_convert (GstCameraBinPreviewPipelineData * data,
- GstBuffer * buf)
-{
- GstMessage *msg;
- GstBuffer *result = NULL;
- GError *error = NULL;
- GstBus *bus;
- GstElement *src, *sink;
- GstBufferFlag bflags;
- GstFlowReturn fret;
-
- g_return_val_if_fail (GST_BUFFER_CAPS (buf) != NULL, NULL);
- g_return_val_if_fail (data != NULL, NULL);
-
- if (data->pipeline == NULL) {
- GST_WARNING ("pipeline is NULL");
- goto no_pipeline;
- }
-
- src = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_src");
- sink = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_sink");
-
- if (!src || !sink) {
- GST_WARNING ("pipeline doesn't have src / sink elements");
- goto missing_elements;
- }
-
- g_object_set (src, "size", (gint64) GST_BUFFER_SIZE (buf),
- "blocksize", (guint32) GST_BUFFER_SIZE (buf),
- "caps", GST_BUFFER_CAPS (buf), "num-buffers", 1, NULL);
-
- g_signal_connect (sink, "handoff", G_CALLBACK (save_result), &result);
-
- bflags = GST_BUFFER_FLAGS (buf);
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
-
- GST_DEBUG ("running conversion pipeline, source is: %" GST_PTR_FORMAT,
- GST_BUFFER_CAPS (buf));
- gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
-
- g_signal_emit_by_name (src, "push-buffer", buf, &fret);
-
- bus = gst_element_get_bus (data->pipeline);
- msg = gst_bus_timed_pop_filtered (bus, (25 * GST_SECOND),
- GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
- gst_object_unref (bus);
-
- if (msg) {
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:{
- if (result) {
- GST_DEBUG ("preview image successful: result = %p", result);
- } else {
- GST_WARNING ("EOS but no result frame?!");
- }
- break;
- }
- case GST_MESSAGE_ERROR:{
- gchar *dbg = NULL;
-
- gst_message_parse_error (msg, &error, &dbg);
- if (error) {
- g_warning ("Could not make preview image: %s", error->message);
- GST_DEBUG ("%s [debug: %s]", error->message, GST_STR_NULL (dbg));
- g_error_free (error);
- } else {
- g_warning ("Could not make preview image (and NULL error!)");
- }
- g_free (dbg);
- result = NULL;
- break;
- }
- default:{
- g_return_val_if_reached (NULL);
- }
- }
- gst_message_unref (msg);
- } else {
- g_warning ("Could not make preview image: %s", "timeout during conversion");
- result = NULL;
- }
-
- g_signal_handlers_disconnect_by_func (sink, G_CALLBACK (save_result),
- &result);
- gst_element_set_state (data->pipeline, GST_STATE_READY);
-
- GST_BUFFER_FLAGS (buf) = bflags;
-
-done:
- if (src)
- gst_object_unref (src);
- if (sink)
- gst_object_unref (sink);
-
- return result;
-
- /* ERRORS */
-missing_elements:
- {
- g_warning ("Could not make preview image: %s",
- "missing elements in pipeline (unknown error)");
- goto done;
- }
-no_pipeline:
- {
- g_warning ("Could not make preview image: %s",
- "no pipeline (unknown error)");
- return NULL;
- }
-}
-
-/**
- * gst_camerabin_preview_send_event:
- * @data: preview pipeline data to use
- * @evt: The #GstEvent to be pushed, takes ownership
- *
- * Pushes an event to the preview pipeline.
- *
- * Returns: True if the event was handled
- */
-gboolean
-gst_camerabin_preview_send_event (GstCameraBinPreviewPipelineData * data,
- GstEvent * evt)
-{
- GstElement *src;
-
- src = gst_bin_get_by_name (GST_BIN (data->pipeline), "prev_src");
- if (!src) {
- GST_WARNING ("Preview pipeline doesn't have src element, can't push event");
- gst_event_unref (evt);
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (data->element, "Pushing event %p to preview pipeline", evt);
-
- return gst_element_send_event (src, evt);
-}
-
-/**
- * gst_camerabin_preview_set_caps:
- * @data: preview pipeline data to use
- * @caps: New #GstCaps to be set for the pipeline
- *
- * Sets new caps for the preview pipeline
- */
-void
-gst_camerabin_preview_set_caps (GstCameraBinPreviewPipelineData * data,
- GstCaps * caps)
-{
- GstState state, pending;
- GstStateChangeReturn ret;
-
- g_return_if_fail (data->pipeline != NULL);
- g_return_if_fail (caps != NULL);
-
- ret = gst_element_get_state (data->pipeline, &state, &pending, 0);
- if (ret == GST_STATE_CHANGE_FAILURE) {
- /* make it try again */
- state = GST_STATE_PLAYING;
- pending = GST_STATE_VOID_PENDING;
- }
-
- gst_element_set_state (data->pipeline, GST_STATE_NULL);
- g_object_set (data->capsfilter, "caps", caps, NULL);
- if (pending != GST_STATE_VOID_PENDING)
- state = pending;
- gst_element_set_state (data->pipeline, state);
-}
+++ /dev/null
-/*
-* 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 __CAMERABINPREVIEW_H__
-#define __CAMERABINPREVIEW_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-typedef struct
-{
- GstElement *pipeline;
-
- GstElement *appsrc;
- GstElement *capsfilter;
- GstElement *appsink;
-
- GstElement *element;
-} GstCameraBinPreviewPipelineData;
-
-
-GstCameraBinPreviewPipelineData * gst_camerabin_preview_create_pipeline (
- GstElement *element, GstCaps *caps, GstElement *src_filter);
-
-void gst_camerabin_preview_destroy_pipeline (
- GstCameraBinPreviewPipelineData *data);
-
-GstBuffer *gst_camerabin_preview_convert (
- GstCameraBinPreviewPipelineData *data, GstBuffer *buf);
-
-gboolean gst_camerabin_preview_send_event (
- GstCameraBinPreviewPipelineData *pipeline, GstEvent *event);
-
-void gst_camerabin_preview_set_caps (
- GstCameraBinPreviewPipelineData *pipeline, GstCaps *caps);
-
-G_END_DECLS
-
-#endif /* __CAMERABINPREVIEW_H__ */
+++ /dev/null
-/*
- * 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:camerabinvideo
- * @short_description: video recording module of #GstCameraBin
- *
- * <refsect2>
- * <para>
- *
- * The pipeline for this module is:
- *
- * <informalexample>
- * <programlisting>
- *-----------------------------------------------------------------------------
- * audiosrc -> audio_queue -> audioconvert -> volume -> audioenc
- * > videomux -> filesink
- * video_queue -> [timeoverlay] -> [csp] -> videoenc -> queue
- * -> [post proc] -> tee <
- * queue ->
- *-----------------------------------------------------------------------------
- * </programlisting>
- * </informalexample>
- *
- * The properties of elements are:
- *
- * queue - "leaky", 2 (Leaky on downstream (old buffers))
- *
- * </para>
- * </refsect2>
- */
-
-/*
- * includes
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include "camerabindebug.h"
-#include "camerabingeneral.h"
-
-#include "camerabinvideo.h"
-
-/*
- * defines and static global vars
- */
-
-/* internal element names */
-
-#define DEFAULT_AUD_ENC "vorbisenc"
-#define DEFAULT_VID_ENC "theoraenc"
-#define DEFAULT_MUX "oggmux"
-#define DEFAULT_SINK "filesink"
-
-#define DEFAULT_FLAGS 0
-
-enum
-{
- PROP_0,
- PROP_FILENAME
-};
-
-static void gst_camerabin_video_dispose (GstCameraBinVideo * sink);
-static void gst_camerabin_video_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_camerabin_video_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GstStateChangeReturn
-gst_camerabin_video_change_state (GstElement * element,
- GstStateChange transition);
-
-static
- gboolean camerabin_video_pad_tee_src0_have_buffer (GstPad * pad,
- GstBuffer * buffer, gpointer u_data);
-static gboolean camerabin_video_sink_have_event (GstPad * pad, GstEvent * event,
- gpointer u_data);
-static gboolean gst_camerabin_video_create_elements (GstCameraBinVideo * vid);
-static void gst_camerabin_video_destroy_elements (GstCameraBinVideo * vid);
-
-GST_BOILERPLATE (GstCameraBinVideo, gst_camerabin_video, GstBin, GST_TYPE_BIN);
-
-static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-
-/* GObject methods implementation */
-
-static void
-gst_camerabin_video_base_init (gpointer klass)
-{
- GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (eklass,
- gst_static_pad_template_get (&sink_template));
- gst_element_class_add_pad_template (eklass,
- gst_static_pad_template_get (&src_template));
- gst_element_class_set_details_simple (eklass,
- "Video capture bin for camerabin", "Bin/Video",
- "Process and store video data",
- "Edgard Lima <edgard.lima@indt.org.br>, "
- "Nokia Corporation <multimedia@maemo.org>");
-}
-
-static void
-gst_camerabin_video_class_init (GstCameraBinVideoClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
-
- gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->dispose =
- (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_camerabin_video_dispose);
- eklass->change_state = GST_DEBUG_FUNCPTR (gst_camerabin_video_change_state);
-
- gobject_class->set_property =
- GST_DEBUG_FUNCPTR (gst_camerabin_video_set_property);
- gobject_class->get_property =
- GST_DEBUG_FUNCPTR (gst_camerabin_video_get_property);
-
- /**
- * GstCameraBinVideo:filename:
- *
- * This property can be used to specify the filename of the video.
- *
- **/
- g_object_class_install_property (gobject_class, PROP_FILENAME,
- g_param_spec_string ("filename", "Filename",
- "Filename of the video to save", NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_camerabin_video_init (GstCameraBinVideo * vid,
- GstCameraBinVideoClass * g_class)
-{
- vid->filename = g_string_new ("");
-
- vid->app_post = NULL;
- vid->app_vid_enc = NULL;
- vid->app_aud_enc = NULL;
- vid->app_aud_src = NULL;
- vid->app_mux = NULL;
-
- vid->aud_src = NULL;
- vid->sink = NULL;
- vid->tee = NULL;
- vid->volume = NULL;
- vid->video_queue = NULL;
-
- vid->tee_video_srcpad = NULL;
- vid->tee_vf_srcpad = NULL;
-
- vid->pending_eos = NULL;
-
- vid->mute = ARG_DEFAULT_MUTE;
- vid->flags = DEFAULT_FLAGS;
-
- vid->vid_src_probe_id = 0;
- vid->vid_tee_probe_id = 0;
- vid->vid_sink_probe_id = 0;
-
- /* Create src and sink ghost pads */
- vid->sinkpad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
- gst_element_add_pad (GST_ELEMENT (vid), vid->sinkpad);
-
- vid->srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC);
- gst_element_add_pad (GST_ELEMENT (vid), vid->srcpad);
-
- /* Add probe for handling eos when stopping recording */
- vid->vid_sink_probe_id = gst_pad_add_event_probe (vid->sinkpad,
- G_CALLBACK (camerabin_video_sink_have_event), vid);
-}
-
-static void
-gst_camerabin_video_dispose (GstCameraBinVideo * vid)
-{
- GST_DEBUG_OBJECT (vid, "disposing");
-
- g_string_free (vid->filename, TRUE);
- vid->filename = NULL;
-
- if (vid->vid_sink_probe_id) {
- gst_pad_remove_event_probe (vid->sinkpad, vid->vid_sink_probe_id);
- vid->vid_sink_probe_id = 0;
- }
-
- /* Note: if videobin was never set to READY state the
- ownership of elements created by application were never
- taken by bin and therefore gst_object_sink is called for
- these elements (they may still be in floating state
- and not unreffed properly without sinking first)
- FIXME, something else is wrong when you have to sink here
- */
- if (vid->app_post) {
- //gst_object_sink (vid->app_post);
- gst_object_unref (vid->app_post);
- vid->app_post = NULL;
- }
-
- if (vid->app_vid_enc) {
- //gst_object_sink (vid->app_vid_enc);
- gst_object_unref (vid->app_vid_enc);
- vid->app_vid_enc = NULL;
- }
-
- if (vid->app_aud_enc) {
- //gst_object_sink (vid->app_aud_enc);
- gst_object_unref (vid->app_aud_enc);
- vid->app_aud_enc = NULL;
- }
-
- if (vid->app_aud_src) {
- //gst_object_sink (vid->app_aud_src);
- gst_object_unref (vid->app_aud_src);
- vid->app_aud_src = NULL;
- }
-
- if (vid->app_mux) {
- //gst_object_sink (vid->app_mux);
- gst_object_unref (vid->app_mux);
- vid->app_mux = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose ((GObject *) vid);
-}
-
-
-static void
-gst_camerabin_video_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstCameraBinVideo *bin = GST_CAMERABIN_VIDEO (object);
-
- switch (prop_id) {
- case PROP_FILENAME:
- g_string_assign (bin->filename, g_value_get_string (value));
- GST_INFO_OBJECT (bin, "received filename: '%s'", bin->filename->str);
- if (bin->sink) {
- g_object_set (G_OBJECT (bin->sink), "location", bin->filename->str,
- NULL);
- } else {
- GST_INFO_OBJECT (bin, "no sink, not setting name yet");
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_camerabin_video_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstCameraBinVideo *bin = GST_CAMERABIN_VIDEO (object);
-
- switch (prop_id) {
- case PROP_FILENAME:
- g_value_set_string (value, bin->filename->str);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstStateChangeReturn
-gst_camerabin_video_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstCameraBinVideo *vid = GST_CAMERABIN_VIDEO (element);
-
- GST_DEBUG_OBJECT (element, "changing state: %s -> %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (!gst_camerabin_video_create_elements (vid)) {
- return GST_STATE_CHANGE_FAILURE;
- }
- /* Don't change sink to READY yet to allow changing the
- filename in READY state. */
- gst_element_set_locked_state (vid->sink, TRUE);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- vid->calculate_adjust_ts_video = TRUE;
- g_object_set (G_OBJECT (vid->sink), "async", FALSE, NULL);
- gst_element_set_locked_state (vid->sink, FALSE);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- vid->calculate_adjust_ts_video = TRUE;
- break;
-
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* Set sink to NULL in order to write the file _now_ */
- GST_INFO ("write video file: %s", vid->filename->str);
- gst_element_set_locked_state (vid->sink, TRUE);
- gst_element_set_state (vid->sink, GST_STATE_NULL);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (GST_ELEMENT_PARENT (vid)),
- GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE |
- GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS, "videobin.playing");
-
- if (vid->pending_eos) {
- /* Video bin is still paused, so push eos directly to video queue */
- GST_DEBUG_OBJECT (vid, "pushing pending eos");
- gst_pad_push_event (vid->tee_video_srcpad, vid->pending_eos);
- vid->pending_eos = NULL;
- }
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* Reset counters related to timestamp rewriting */
- vid->adjust_ts_video = 0;
- vid->last_ts_video = 0;
-
- if (vid->pending_eos) {
- gst_event_unref (vid->pending_eos);
- vid->pending_eos = NULL;
- }
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_camerabin_video_destroy_elements (vid);
- break;
- default:
- break;
- }
-
- GST_DEBUG_OBJECT (element, "changed state: %s -> %s = %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)),
- gst_element_state_change_return_get_name (ret));
-
- return ret;
-}
-
-/*
- * static helper functions implementation
- */
-
-/*
- * camerabin_video_pad_tee_src0_have_buffer:
- * @pad: tee src pad leading to video encoding
- * @event: received buffer
- * @u_data: video bin object
- *
- * Buffer probe for rewriting video buffer timestamps.
- *
- * Returns: TRUE always
- */
-static gboolean
-camerabin_video_pad_tee_src0_have_buffer (GstPad * pad, GstBuffer * buffer,
- gpointer u_data)
-{
- GstCameraBinVideo *vid = (GstCameraBinVideo *) u_data;
-
- GST_LOG ("buffer in with size %d ts %" GST_TIME_FORMAT,
- GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
-
- if (G_UNLIKELY (vid->calculate_adjust_ts_video)) {
- GstEvent *event;
- GstObject *tee;
- GstPad *sinkpad;
-
- vid->adjust_ts_video = GST_BUFFER_TIMESTAMP (buffer) - vid->last_ts_video;
- vid->calculate_adjust_ts_video = FALSE;
- event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
- 0, GST_CLOCK_TIME_NONE, vid->last_ts_video);
- /* Send the newsegment to both view finder and video bin */
- tee = gst_pad_get_parent (pad);
- sinkpad = gst_element_get_static_pad (GST_ELEMENT (tee), "sink");
- gst_pad_send_event (sinkpad, event);
- gst_object_unref (tee);
- gst_object_unref (sinkpad);
- GST_LOG_OBJECT (vid, "vid ts adjustment: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vid->adjust_ts_video));
- GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
- }
- GST_BUFFER_TIMESTAMP (buffer) -= vid->adjust_ts_video;
- vid->last_ts_video = GST_BUFFER_TIMESTAMP (buffer);
- if (GST_BUFFER_DURATION_IS_VALID (buffer))
- vid->last_ts_video += GST_BUFFER_DURATION (buffer);
-
- GST_LOG ("buffer out with size %d ts %" GST_TIME_FORMAT,
- GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
- return TRUE;
-}
-
-/*
- * camerabin_video_sink_have_event:
- * @pad: video bin sink pad
- * @event: received event
- * @u_data: video bin object
- *
- * Event probe for video bin eos handling.
- * Copies the eos event to audio branch of video bin.
- *
- * Returns: FALSE to drop the event, TRUE otherwise
- */
-static gboolean
-camerabin_video_sink_have_event (GstPad * pad, GstEvent * event,
- gpointer u_data)
-{
- GstCameraBinVideo *vid = (GstCameraBinVideo *) u_data;
- gboolean ret = TRUE;
-
- GST_DEBUG_OBJECT (vid, "got videobin sink event: %s",
- GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- if (vid->aud_src) {
- GST_DEBUG_OBJECT (vid, "copying %s to audio branch",
- GST_EVENT_TYPE_NAME (event));
- gst_element_send_event (vid->aud_src, gst_event_copy (event));
- }
-
- /* If we're paused, we can't pass eos to video now to avoid blocking.
- Instead send eos when changing to playing next time. */
- if (GST_STATE (GST_ELEMENT (vid)) == GST_STATE_PAUSED) {
- GST_DEBUG_OBJECT (vid, "paused, delay eos sending");
- vid->pending_eos = gst_event_ref (event);
- ret = FALSE; /* Drop the event */
- }
- break;
- default:
- break;
- }
- return ret;
-}
-
-/*
- * gst_camerabin_video_create_elements:
- * @vid: a pointer to #GstCameraBinVideo
- *
- * This function creates the needed #GstElements and resources to record videos.
- * Use gst_camerabin_video_destroy_elements() to free these resources.
- *
- * Returns: %TRUE if succeeded or FALSE if failed
- */
-static gboolean
-gst_camerabin_video_create_elements (GstCameraBinVideo * vid)
-{
- GstPad *vid_sinkpad = NULL, *vid_srcpad = NULL;
- GstBin *vidbin = GST_BIN (vid);
- GstElement *queue = NULL;
-
- vid->adjust_ts_video = 0;
- vid->last_ts_video = 0;
- vid->calculate_adjust_ts_video = FALSE;
-
- /* Add video post processing element if any */
- if (vid->app_post) {
- if (!gst_camerabin_add_element (vidbin, vid->app_post)) {
- goto error;
- }
- vid_sinkpad = gst_element_get_static_pad (vid->app_post, "sink");
- }
-
- /* Add tee element */
- if (!(vid->tee =
- gst_camerabin_create_and_add_element (vidbin, "tee", "video-tee"))) {
- goto error;
- }
-
- /* Set up sink ghost pad for video bin */
- if (!vid_sinkpad) {
- vid_sinkpad = gst_element_get_static_pad (vid->tee, "sink");
- }
- gst_ghost_pad_set_target (GST_GHOST_PAD (vid->sinkpad), vid_sinkpad);
- gst_object_unref (vid_sinkpad);
-
- /* Add queue element for video */
- vid->tee_video_srcpad = gst_element_get_request_pad (vid->tee, "src_%u");
-
- vid->video_queue = gst_element_factory_make ("queue", "video-queue");
- if (!gst_camerabin_add_element (vidbin, vid->video_queue)) {
- goto error;
- }
- g_object_set (vid->video_queue, "silent", TRUE, NULL);
-
- /* Add probe for rewriting video timestamps */
- vid->vid_tee_probe_id = gst_pad_add_buffer_probe (vid->tee_video_srcpad,
- G_CALLBACK (camerabin_video_pad_tee_src0_have_buffer), vid);
-
- if (vid->flags & GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION) {
- /* Add colorspace converter */
- if (gst_camerabin_create_and_add_element (vidbin,
- "ffmpegcolorspace", "video-ffmpegcolorspace") == NULL) {
- goto error;
- }
- }
-
- /* Add user set or default video encoder element */
- if (vid->app_vid_enc) {
- vid->vid_enc = vid->app_vid_enc;
- if (!gst_camerabin_add_element (vidbin, vid->vid_enc)) {
- goto error;
- }
- } else if (!(vid->vid_enc =
- gst_camerabin_create_and_add_element (vidbin, DEFAULT_VID_ENC,
- "video-encoder"))) {
- goto error;
- }
-
- /* Add application set or default muxer element */
- if (vid->app_mux) {
- vid->muxer = vid->app_mux;
- if (!gst_camerabin_add_element (vidbin, vid->muxer)) {
- goto error;
- }
- } else if (!(vid->muxer =
- gst_camerabin_create_and_add_element (vidbin, DEFAULT_MUX,
- "video-muxer"))) {
- goto error;
- }
-
- /* Add sink element for storing the video */
- if (!(vid->sink =
- gst_camerabin_create_and_add_element (vidbin, DEFAULT_SINK,
- "video-sink"))) {
- goto error;
- }
- g_object_set (G_OBJECT (vid->sink), "location", vid->filename->str, "buffer-mode", 2, /* non buffered io */
- NULL);
-
- if (!(vid->flags & GST_CAMERABIN_FLAG_DISABLE_AUDIO)) {
- /* Add application set or default audio source element */
- if (!(vid->aud_src = gst_camerabin_setup_default_element (vidbin,
- vid->app_aud_src, "autoaudiosrc", DEFAULT_AUDIOSRC))) {
- vid->aud_src = NULL;
- goto error;
- } else {
- if (!gst_camerabin_add_element (vidbin, vid->aud_src))
- goto error;
- }
-
- /* Add queue element for audio */
- queue = gst_element_factory_make ("queue", "audio-queue");
- if (!gst_camerabin_add_element (vidbin, queue)) {
- goto error;
- }
- g_object_set (queue, "silent", TRUE, NULL);
-
- /* Add optional audio conversion and volume elements and
- raise no errors if adding them fails */
- if (vid->flags & GST_CAMERABIN_FLAG_AUDIO_CONVERSION) {
- if (!gst_camerabin_try_add_element (vidbin,
- gst_element_factory_make ("audioconvert", NULL))) {
- GST_WARNING_OBJECT (vid, "unable to add audio conversion element");
- /* gst_camerabin_try_add_element() destroyed the element */
- }
- }
-
- vid->volume = gst_element_factory_make ("volume", NULL);
- if (!gst_camerabin_try_add_element (vidbin, vid->volume)) {
- GST_WARNING_OBJECT (vid, "unable to add volume element");
- /* gst_camerabin_try_add_element() destroyed the element */
- vid->volume = NULL;
- } else {
- g_object_set (vid->volume, "mute", vid->mute, NULL);
- }
-
- /* Add application set or default audio encoder element */
- if (vid->app_aud_enc) {
- vid->aud_enc = vid->app_aud_enc;
- if (!gst_camerabin_add_element (vidbin, vid->aud_enc)) {
- goto error;
- }
- } else if (!(vid->aud_enc =
- gst_camerabin_create_and_add_element (vidbin, DEFAULT_AUD_ENC,
- "audio-encoder"))) {
- goto error;
- }
-
- /* Link audio part to the muxer */
- if (!gst_element_link_pads_full (vid->aud_enc, NULL, vid->muxer, NULL,
- GST_PAD_LINK_CHECK_CAPS)) {
- GST_ELEMENT_ERROR (vid, CORE, NEGOTIATION, (NULL),
- ("linking audio encoder and muxer failed"));
- goto error;
- }
- }
- /* Add queue leading out of the video bin and to view finder */
- vid->tee_vf_srcpad = gst_element_get_request_pad (vid->tee, "src_%u");
- queue = gst_element_factory_make ("queue", "viewfinder-queue");
- if (!gst_camerabin_add_element (vidbin, 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, "silent",
- TRUE, NULL);
-
- /* Set up src ghost pad for video bin */
- vid_srcpad = gst_element_get_static_pad (queue, "src");
- gst_ghost_pad_set_target (GST_GHOST_PAD (vid->srcpad), vid_srcpad);
- /* Never let video bin eos events reach view finder */
- vid->vid_src_probe_id = gst_pad_add_event_probe (vid_srcpad,
- G_CALLBACK (gst_camerabin_drop_eos_probe), vid);
- gst_object_unref (vid_srcpad);
-
- /* audio source is not always present and might be set to NULL during operation */
- if (vid->aud_src
- && g_object_class_find_property (G_OBJECT_GET_CLASS (vid->aud_src),
- "provide-clock")) {
- g_object_set (vid->aud_src, "provide-clock", FALSE, NULL);
- }
-
- GST_DEBUG ("created video elements");
-
- return TRUE;
-
-error:
-
- gst_camerabin_video_destroy_elements (vid);
-
- return FALSE;
-
-}
-
-/*
- * gst_camerabin_video_destroy_elements:
- * @vid: a pointer to #GstCameraBinVideo
- *
- * This function destroys all the elements created by
- * gst_camerabin_video_create_elements().
- *
- */
-static void
-gst_camerabin_video_destroy_elements (GstCameraBinVideo * vid)
-{
- GST_DEBUG ("destroying video elements");
-
- /* Remove EOS event probe from videobin srcpad (queue's srcpad) */
- if (vid->vid_src_probe_id) {
- GstPad *pad = gst_ghost_pad_get_target (GST_GHOST_PAD (vid->srcpad));
- if (pad) {
- gst_pad_remove_event_probe (pad, vid->vid_src_probe_id);
- gst_object_unref (pad);
- }
- vid->vid_src_probe_id = 0;
- }
-
- /* Remove buffer probe from video tee srcpad */
- if (vid->vid_tee_probe_id) {
- gst_pad_remove_buffer_probe (vid->tee_video_srcpad, vid->vid_tee_probe_id);
- vid->vid_tee_probe_id = 0;
- }
-
- /* Release tee request pads */
- if (vid->tee_video_srcpad) {
- gst_element_release_request_pad (vid->tee, vid->tee_video_srcpad);
- gst_object_unref (vid->tee_video_srcpad);
- vid->tee_video_srcpad = NULL;
- }
- if (vid->tee_vf_srcpad) {
- gst_element_release_request_pad (vid->tee, vid->tee_vf_srcpad);
- gst_object_unref (vid->tee_vf_srcpad);
- vid->tee_vf_srcpad = NULL;
- }
-
- gst_ghost_pad_set_target (GST_GHOST_PAD (vid->sinkpad), NULL);
- gst_ghost_pad_set_target (GST_GHOST_PAD (vid->srcpad), NULL);
-
- gst_camerabin_remove_elements_from_bin (GST_BIN (vid));
-
- vid->aud_src = NULL;
- vid->sink = NULL;
- vid->tee = NULL;
- vid->volume = NULL;
- vid->video_queue = NULL;
- vid->vid_enc = NULL;
- vid->aud_enc = NULL;
- vid->muxer = NULL;
-
- if (vid->pending_eos) {
- gst_event_unref (vid->pending_eos);
- vid->pending_eos = NULL;
- }
-}
-
-/*
- * Set & get mute and video capture elements
- */
-
-void
-gst_camerabin_video_set_mute (GstCameraBinVideo * vid, gboolean mute)
-{
- g_return_if_fail (vid != NULL);
-
- GST_DEBUG_OBJECT (vid, "setting mute %s", mute ? "on" : "off");
- vid->mute = mute;
- if (vid->volume) {
- g_object_set (vid->volume, "mute", mute, NULL);
- }
-}
-
-void
-gst_camerabin_video_set_post (GstCameraBinVideo * vid, GstElement * post)
-{
- GstElement **app_post;
- GST_DEBUG_OBJECT (vid, "setting video post processing: %" GST_PTR_FORMAT,
- post);
- GST_OBJECT_LOCK (vid);
- app_post = &vid->app_post;
- gst_object_replace ((GstObject **) app_post, GST_OBJECT (post));
- GST_OBJECT_UNLOCK (vid);
-}
-
-void
-gst_camerabin_video_set_video_enc (GstCameraBinVideo * vid,
- GstElement * video_enc)
-{
- GstElement **app_vid_enc;
- GST_DEBUG_OBJECT (vid, "setting video encoder: %" GST_PTR_FORMAT, video_enc);
- GST_OBJECT_LOCK (vid);
- app_vid_enc = &vid->app_vid_enc;
- gst_object_replace ((GstObject **) app_vid_enc, GST_OBJECT (video_enc));
- GST_OBJECT_UNLOCK (vid);
-}
-
-void
-gst_camerabin_video_set_audio_enc (GstCameraBinVideo * vid,
- GstElement * audio_enc)
-{
- GstElement **app_aud_enc;
- GST_DEBUG_OBJECT (vid, "setting audio encoder: %" GST_PTR_FORMAT, audio_enc);
- GST_OBJECT_LOCK (vid);
- app_aud_enc = &vid->app_aud_enc;
- gst_object_replace ((GstObject **) app_aud_enc, GST_OBJECT (audio_enc));
- GST_OBJECT_UNLOCK (vid);
-}
-
-void
-gst_camerabin_video_set_muxer (GstCameraBinVideo * vid, GstElement * muxer)
-{
- GstElement **app_mux;
- GST_DEBUG_OBJECT (vid, "setting muxer: %" GST_PTR_FORMAT, muxer);
- GST_OBJECT_LOCK (vid);
- app_mux = &vid->app_mux;
- gst_object_replace ((GstObject **) app_mux, GST_OBJECT (muxer));
- GST_OBJECT_UNLOCK (vid);
-}
-
-void
-gst_camerabin_video_set_audio_src (GstCameraBinVideo * vid,
- GstElement * audio_src)
-{
- GstElement **app_aud_src;
- GST_DEBUG_OBJECT (vid, "setting audio source: %" GST_PTR_FORMAT, audio_src);
- GST_OBJECT_LOCK (vid);
- app_aud_src = &vid->app_aud_src;
- gst_object_replace ((GstObject **) app_aud_src, GST_OBJECT (audio_src));
- GST_OBJECT_UNLOCK (vid);
-}
-
-void
-gst_camerabin_video_set_flags (GstCameraBinVideo * vid, GstCameraBinFlags flags)
-{
- GST_DEBUG_OBJECT (vid, "setting video flags: %d", flags);
- GST_OBJECT_LOCK (vid);
- vid->flags = flags;
- GST_OBJECT_UNLOCK (vid);
-}
-
-
-gboolean
-gst_camerabin_video_get_mute (GstCameraBinVideo * vid)
-{
- g_return_val_if_fail (vid != NULL, FALSE);
-
- if (vid->volume) {
- g_object_get (vid->volume, "mute", &vid->mute, NULL);
- }
-
- return vid->mute;
-}
-
-GstElement *
-gst_camerabin_video_get_post (GstCameraBinVideo * vid)
-{
- return vid->app_post;
-}
-
-GstElement *
-gst_camerabin_video_get_video_enc (GstCameraBinVideo * vid)
-{
- return vid->vid_enc ? vid->vid_enc : vid->app_vid_enc;
-}
-
-GstElement *
-gst_camerabin_video_get_audio_enc (GstCameraBinVideo * vid)
-{
- return vid->aud_enc ? vid->aud_enc : vid->app_aud_enc;
-}
-
-GstElement *
-gst_camerabin_video_get_muxer (GstCameraBinVideo * vid)
-{
- return vid->muxer ? vid->muxer : vid->app_mux;
-}
-
-GstElement *
-gst_camerabin_video_get_audio_src (GstCameraBinVideo * vid)
-{
- return vid->aud_src ? vid->aud_src : vid->app_aud_src;
-}
+++ /dev/null
-/*
- * 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_VIDEO_H__
-#define __CAMERABIN_VIDEO_H__
-
-#include <gst/gstbin.h>
-
-#include "gstcamerabin-enum.h"
-
-G_BEGIN_DECLS
-#define ARG_DEFAULT_MUTE FALSE
-#define GST_TYPE_CAMERABIN_VIDEO (gst_camerabin_video_get_type())
-#define GST_CAMERABIN_VIDEO_CAST(obj) ((GstCameraBinVideo*)(obj))
-#define GST_CAMERABIN_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN_VIDEO,GstCameraBinVideo))
-#define GST_CAMERABIN_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN_VIDEO,GstCameraBinVideoClass))
-#define GST_IS_CAMERABIN_VIDEO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN_VIDEO))
-#define GST_IS_CAMERABIN_VIDEO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN_VIDEO))
-/**
- * GstCameraBinVideo:
- *
- * The opaque #GstCameraBinVideo structure.
- */
-typedef struct _GstCameraBinVideo GstCameraBinVideo;
-typedef struct _GstCameraBinVideoClass GstCameraBinVideoClass;
-
-struct _GstCameraBinVideo
-{
- GstBin parent;
-
- GString *filename;
-
- /* A/V timestamp rewriting */
- guint64 adjust_ts_video;
- guint64 last_ts_video;
- gboolean calculate_adjust_ts_video;
-
- /* Sink and src pads of video bin */
- GstPad *sinkpad;
- GstPad *srcpad;
-
- /* Tee src pads leading to video encoder and view finder */
- GstPad *tee_video_srcpad;
- GstPad *tee_vf_srcpad;
-
- /* Application set elements */
- GstElement *app_post; /* Video post processing */
- GstElement *app_vid_enc;
- GstElement *app_aud_enc;
- GstElement *app_aud_src;
- GstElement *app_mux;
-
- /* Other elements */
- GstElement *aud_src; /* Audio source */
- GstElement *sink; /* Sink for recorded video */
- GstElement *tee; /* Split output to view finder and recording sink */
- GstElement *volume; /* Volume for muting */
- GstElement *video_queue; /* Buffer for raw video frames */
- GstElement *vid_enc; /* Video encoder */
- GstElement *aud_enc; /* Audio encoder */
- GstElement *muxer; /* Muxer */
-
- GstEvent *pending_eos;
-
- /* Probe IDs */
- gulong vid_src_probe_id;
- gulong vid_tee_probe_id;
- gulong vid_sink_probe_id;
-
- gboolean mute;
- GstCameraBinFlags flags;
-};
-
-struct _GstCameraBinVideoClass
-{
- GstBinClass parent_class;
-};
-
-GType gst_camerabin_video_get_type (void);
-
-/*
- * external function prototypes
- */
-
-void gst_camerabin_video_set_mute (GstCameraBinVideo * vid, gboolean mute);
-
-void gst_camerabin_video_set_post (GstCameraBinVideo * vid, GstElement * post);
-
-void
-gst_camerabin_video_set_video_enc (GstCameraBinVideo * vid,
- GstElement * video_enc);
-
-void
-gst_camerabin_video_set_audio_enc (GstCameraBinVideo * vid,
- GstElement * audio_enc);
-
-void
-gst_camerabin_video_set_muxer (GstCameraBinVideo * vid, GstElement * muxer);
-
-void
-gst_camerabin_video_set_audio_src (GstCameraBinVideo * vid,
- GstElement * audio_src);
-
-void
-gst_camerabin_video_set_flags (GstCameraBinVideo * vid,
- GstCameraBinFlags flags);
-
-
-gboolean gst_camerabin_video_get_mute (GstCameraBinVideo * vid);
-
-GstElement *gst_camerabin_video_get_post (GstCameraBinVideo * vid);
-
-GstElement *gst_camerabin_video_get_video_enc (GstCameraBinVideo * vid);
-
-GstElement *gst_camerabin_video_get_audio_enc (GstCameraBinVideo * vid);
-
-GstElement *gst_camerabin_video_get_muxer (GstCameraBinVideo * vid);
-
-GstElement *gst_camerabin_video_get_audio_src (GstCameraBinVideo * vid);
-
-G_END_DECLS
-#endif /* #ifndef __CAMERABIN_VIDEO_H__ */
+++ /dev/null
-/*
- * 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"},
- {C_FLAGS (GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION),
- "Enable colorspace conversion for video capture",
- "video-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;
-}
+++ /dev/null
-/*
- * 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
-
-enum
-{
- ARG_0,
- ARG_FILENAME,
- ARG_MODE,
- ARG_FLAGS,
- ARG_MUTE,
- ARG_ZOOM,
- ARG_IMAGE_POST,
- ARG_IMAGE_ENC,
- ARG_IMAGE_FORMATTER,
- 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,
- ARG_PREVIEW_SOURCE_FILTER,
- ARG_READY_FOR_CAPTURE,
- ARG_IDLE
-};
-
-/**
- * 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
- * @GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION: enable color
- * conversion for video encoder 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),
- GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION = (1 << 7)
-} GstCameraBinFlags;
-
-#define GST_TYPE_CAMERABIN_FLAGS (gst_camerabin_flags_get_type())
-GType gst_camerabin_flags_get_type (void);
-
-G_END_DECLS
-
-#endif /* #ifndef __GST_CAMERABIN_ENUM_H__ */
+++ /dev/null
-# glib-genmarshal --header --prefix=gst_camerabin camerabin_marshal.marshal > camerabin_marshal.h
-# glib-genmarshal --body --prefix=gst_camerabin camerabin_marshal.marshal > camerabin_marshal.c
-
-VOID:INT,INT,INT,INT
-VOID:INT,INT
-BOOLEAN:STRING
-INT64:VOID
-VOID:OBJECT,INT64,INT64
+++ /dev/null
-/*
- * 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:element-camerabin
- *
- * GstCameraBin is a high-level camera object that encapsulates the gstreamer
- * internals and provides a task based API for the application. It consists of
- * three main data paths: view-finder, image capture and video capture.
- *
- * <informalfigure>
- * <mediaobject>
- * <imageobject><imagedata fileref="camerabin.png"/></imageobject>
- * <textobject><phrase>CameraBin structure</phrase></textobject>
- * <caption><para>Structural decomposition of CameraBin object.</para></caption>
- * </mediaobject>
- * </informalfigure>
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v -m camerabin
- * ]|
- * </refsect2>
- * <refsect2>
- * <title>Image capture</title>
- * <para>
- * Image capture is selected by switching #GstCameraBin:mode to %MODE_IMAGE.
- * Taking still images is initiated with the #GstCameraBin::capture-start action
- * signal. Once the image has been captured, "image-captured" gst message is
- * posted to the bus and capturing another image is possible. If application
- * has set #GstCameraBin:preview-caps property, then a "preview-image" gst
- * message is posted to bus containing preview image formatted according to
- * specified caps. Eventually when image has been saved
- * #GstCameraBin::image-done signal is emitted.
- *
- * Available resolutions can be taken from the #GstCameraBin:video-source-caps
- * property. Image capture resolution can be set with
- * #GstCameraBin::set-image-resolution action signal.
- *
- * Some video source elements implement the #GstPhotography interface, which contains
- * functions and properties for setting photography parameters. One can use
- * gst_bin_iterate_all_by_interface() to get a reference to it.
- *
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Video capture</title>
- * <para>
- * Video capture is selected by switching #GstCameraBin:mode to %MODE_VIDEO.
- * The capture is started with the #GstCameraBin::capture-start action signal
- * too. In addition to image capture one can use #GstCameraBin::capture-pause to
- * pause recording and #GstCameraBin::capture-stop to end recording.
- *
- * Available resolutions and fps can be taken from the
- * #GstCameraBin:video-source-caps property.
- * #GstCameraBin::set-video-resolution-fps action signal can be used to set
- * frame rate and resolution for the video recording and view finder as well.
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>States</title>
- * <para>
- * Elements within GstCameraBin are created and destroyed when switching
- * between NULL and READY states. Therefore element properties should be set
- * in NULL state. User set elements are not unreffed until GstCameraBin is
- * unreffed or replaced by a new user set element. Initially only elements
- * needed for view finder mode are created to speed up startup. Image bin and
- * video bin elements are created when setting the mode or starting capture.
- * GstCameraBin must be in the PLAYING state before #GstCameraBin::capture-start
- * is called.
- * </para>
- * </refsect2>
- * <refsect2>
- * <title>Video and image previews</title>
- * <para>
- * GstCameraBin contains #GstCameraBin:preview-caps property, which is used to
- * determine whether the application wants a preview image of the captured
- * picture or video. When set, a GstMessage named "preview-image" will be sent.
- * This message will contain a GstBuffer holding the preview image, converted
- * to a format defined by those preview caps. The ownership of the preview
- * image is kept in GstCameraBin, so application should ref the preview buffer
- * object if it needs to use it elsewhere than in message handler.
- *
- * Defining preview caps is done by selecting the capturing #GstCameraBin:mode
- * first and then setting the property. Camerabin remembers caps separately for
- * both modes, so it is not necessary to set the caps again after changing the
- * mode.
- * </para>
- * </refsect2>
- * <refsect2>
- * <note>
- * <para>
- * Since the muxers tested so far have problems with discontinous buffers, QoS
- * has been disabled, and then in order to record video, you MUST ensure that
- * there is enough CPU to encode the video. Thus choose smart resolution and
- * frames per second values. It is also highly recommended to avoid color
- * conversions; make sure all the elements involved work with the same
- * colorspace (i.e. rgb or yuv i420 or whatelse).
- * </para>
- * </note>
- * </refsect2>
- */
-
-/*
- * The pipeline in the camerabin is
- *
- * videosrc [ ! ffmpegcsp ] ! capsfilter ! crop ! scale ! capsfilter ! \
- * [ video_filter ! ] out-sel name=osel ! queue name=img_q
- *
- * View finder:
- * osel. ! in-sel name=isel ! scale ! capsfilter [ ! ffmpegcsp ] ! vfsink
- *
- * Image bin:
- * img_q. [ ! ipp ] ! ffmpegcsp ! imageenc ! metadatamux ! filesink
- *
- * Video bin:
- * osel. ! tee name=t ! queue ! videoenc ! videomux name=mux ! filesink
- * t. ! queue ! isel.
- * audiosrc ! queue ! audioconvert ! volume ! audioenc ! mux.
- *
- * The properties of elements are:
- *
- * vfsink - "sync", FALSE, "qos", FALSE, "async", FALSE
- * output-selector - "resend-latest", FALSE
- * input-selector - "select-all", TRUE
- */
-
-/*
- * includes
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <gst/gst.h>
-#include <gst/tag/tag.h>
-#include <gst/glib-compat-private.h>
-/* FIXME: include #include <gst/gst-i18n-plugin.h> and use _(" ") */
-
-#include "gstcamerabin.h"
-#include "gstcamerabincolorbalance.h"
-
-#include "camerabindebug.h"
-#include "camerabingeneral.h"
-#include "camerabinpreview.h"
-
-#include "gstcamerabin-marshal.h"
-
-/*
- * enum and types
- */
-
-enum
-{
- /* action signals */
- CAPTURE_START_SIGNAL,
- CAPTURE_STOP_SIGNAL,
- CAPTURE_PAUSE_SIGNAL,
- SET_VIDEO_RESOLUTION_FPS_SIGNAL,
- SET_IMAGE_RESOLUTION_SIGNAL,
- /* emit signals */
- IMG_DONE_SIGNAL,
- LAST_SIGNAL
-};
-
-
-/*
- * defines and static global vars
- */
-
-static guint camerabin_signals[LAST_SIGNAL];
-
-#define GST_TYPE_CAMERABIN_MODE (gst_camerabin_mode_get_type ())
-
-/* default and range values for args */
-
-#define DEFAULT_MODE MODE_IMAGE
-#define DEFAULT_ZOOM 1.0
-#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 CAMERABIN_DEFAULT_VF_CAPS "video/x-raw-yuv,format=(fourcc)I420"
-#define CAMERABIN_MAX_VF_WIDTH 848
-#define CAMERABIN_MAX_VF_HEIGHT 848
-
-#define DEFAULT_FLAGS GST_CAMERABIN_FLAG_SOURCE_RESIZE | \
- GST_CAMERABIN_FLAG_VIEWFINDER_SCALE | \
- GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION | \
- GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION | \
- GST_CAMERABIN_FLAG_VIDEO_COLOR_CONVERSION | \
- GST_CAMERABIN_FLAG_AUDIO_CONVERSION
-
-/* Using "bilinear" as default zoom method */
-#define CAMERABIN_DEFAULT_ZOOM_METHOD 1
-
-#define MIN_ZOOM 1.0
-#define MAX_ZOOM 10.0
-#define ZOOM_1X MIN_ZOOM
-
-/* FIXME: this is v4l2camsrc specific */
-#define DEFAULT_V4L2CAMSRC_DRIVER_NAME "omap3cam"
-
-#define DEFAULT_BLOCK_VIEWFINDER FALSE
-#define DEFAULT_READY_FOR_CAPTURE TRUE
-
-/* message names */
-#define PREVIEW_MESSAGE_NAME "preview-image"
-#define IMG_CAPTURED_MESSAGE_NAME "image-captured"
-
-#define CAMERABIN_PROCESSING_INC_UNLOCKED(c) \
- (c)->processing_counter += 1; \
- GST_DEBUG_OBJECT ((c), "Processing counter incremented to: %d", \
- (c)->processing_counter); \
- if ((c)->processing_counter == 1) \
- g_object_notify (G_OBJECT (c), "idle");
-
-#define CAMERABIN_PROCESSING_DEC_UNLOCKED(c) \
- (c)->processing_counter -= 1; \
- GST_DEBUG_OBJECT ((c), "Processing counter decremented to: %d", \
- (c)->processing_counter); \
- g_assert ((c)->processing_counter >= 0); \
- if ((c)->processing_counter == 0) { \
- g_cond_signal ((c)->idle_cond); \
- g_object_notify (G_OBJECT (c), "idle"); \
- }
-
-#define CAMERABIN_PROCESSING_INC(c) \
- g_mutex_lock ((c)->capture_mutex); \
- CAMERABIN_PROCESSING_INC_UNLOCKED ((c)); \
- g_mutex_unlock ((c)->capture_mutex);
-
-#define CAMERABIN_PROCESSING_DEC(c) \
- g_mutex_lock ((c)->capture_mutex); \
- CAMERABIN_PROCESSING_DEC_UNLOCKED ((c)); \
- g_mutex_unlock ((c)->capture_mutex);
-
-#define CAMERABIN_PROCESSING_WAIT_IDLE(c) \
- g_mutex_lock ((c)->capture_mutex); \
- if ((c)->processing_counter > 0) { \
- GST_DEBUG_OBJECT ((c), "Waiting for processing operations to finish %d", \
- (c)->processing_counter); \
- g_cond_wait ((c)->idle_cond, (c)->capture_mutex); \
- GST_DEBUG_OBJECT ((c), "Processing operations finished"); \
- } \
- g_mutex_unlock ((c)->capture_mutex);
-
-/*
- * static helper functions declaration
- */
-
-static void camerabin_setup_src_elements (GstCameraBin * camera);
-
-static gboolean camerabin_create_src_elements (GstCameraBin * camera);
-
-static void camerabin_setup_view_elements (GstCameraBin * camera);
-
-static gboolean camerabin_create_view_elements (GstCameraBin * camera);
-
-static gboolean camerabin_create_elements (GstCameraBin * camera);
-
-static void camerabin_destroy_elements (GstCameraBin * camera);
-
-static void camerabin_dispose_elements (GstCameraBin * camera);
-
-static void gst_camerabin_change_mode (GstCameraBin * camera, gint mode);
-
-static void
-gst_camerabin_set_flags (GstCameraBin * camera, GstCameraBinFlags flags);
-
-static void
-gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name);
-
-static void gst_camerabin_setup_zoom (GstCameraBin * camera);
-
-static GstCaps *gst_camerabin_get_allowed_input_caps (GstCameraBin * camera);
-
-static void gst_camerabin_rewrite_tags (GstCameraBin * camera);
-
-static void
-gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps);
-
-static void gst_camerabin_start_image_capture (GstCameraBin * camera);
-
-static void gst_camerabin_start_video_recording (GstCameraBin * camera);
-
-static void
-camerabin_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data);
-
-static gboolean
-gst_camerabin_have_img_buffer (GstPad * pad, GstMiniObject * obj,
- gpointer u_data);
-static gboolean
-gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer,
- gpointer u_data);
-static gboolean
-gst_camerabin_have_queue_data (GstPad * pad, GstMiniObject * mini_obj,
- gpointer u_data);
-static gboolean
-gst_camerabin_have_src_buffer (GstPad * pad, GstBuffer * buffer,
- gpointer u_data);
-
-static void gst_camerabin_reset_to_view_finder (GstCameraBin * camera);
-
-static void gst_camerabin_do_stop (GstCameraBin * camera);
-
-static void
-gst_camerabin_set_allowed_framerate (GstCameraBin * camera,
- GstCaps * filter_caps);
-
-static guint32 get_srcpad_current_format (GstElement * element);
-
-static const GValue *gst_camerabin_find_better_framerate (GstCameraBin * camera,
- GstStructure * st, const GValue * orig_framerate);
-
-static void
-gst_camerabin_update_aspect_filter (GstCameraBin * camera, GstCaps * new_caps);
-
-static void gst_camerabin_finish_image_capture (GstCameraBin * camera);
-static void gst_camerabin_adapt_image_capture (GstCameraBin * camera,
- GstCaps * new_caps);
-static void gst_camerabin_scene_mode_notify_cb (GObject * video_source,
- GParamSpec * pspec, gpointer user_data);
-static void gst_camerabin_zoom_notify_cb (GObject * video_source,
- GParamSpec * pspec, gpointer user_data);
-static void gst_camerabin_monitor_video_source_properties (GstCameraBin *
- camera);
-static void gst_camerabin_configure_format (GstCameraBin * camera,
- GstCaps * caps);
-static gboolean
-copy_missing_fields (GQuark field_id, const GValue * value, gpointer user_data);
-
-/*
- * GObject callback functions declaration
- */
-
-static void gst_camerabin_dispose (GObject * object);
-
-static void gst_camerabin_finalize (GObject * object);
-
-static void gst_camerabin_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-
-static void gst_camerabin_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-/*
- * GstElement function declarations
- */
-
-static GstStateChangeReturn
-gst_camerabin_change_state (GstElement * element, GstStateChange transition);
-
-static GstClock *gst_camerabin_provide_clock (GstElement * element);
-
-/*
- * GstBin function declarations
- */
-static void
-gst_camerabin_handle_message_func (GstBin * bin, GstMessage * message);
-
-
-/*
- * Action signal function declarations
- */
-
-static void gst_camerabin_capture_start (GstCameraBin * camera);
-
-static void gst_camerabin_capture_stop (GstCameraBin * camera);
-
-static void gst_camerabin_capture_pause (GstCameraBin * camera);
-
-static void
-gst_camerabin_set_image_capture_caps (GstCameraBin * camera, gint width,
- gint height);
-
-static void
-gst_camerabin_set_video_resolution_fps (GstCameraBin * camera, gint width,
- gint height, gint fps_n, gint fps_d);
-static void
-do_set_video_resolution_fps (GstCameraBin * camera, gint width,
- gint height, gint fps_n, gint fps_d);
-
-static void
-gst_camerabin_set_image_resolution (GstCameraBin * camera, gint width,
- gint height);
-
-
-/*
- * GST BOILERPLATE and GObject types
- */
-
-static GType
-gst_camerabin_mode_get_type (void)
-{
- static GType gtype = 0;
-
- if (gtype == 0) {
- static const GEnumValue values[] = {
- {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;
-}
-
-
-static gboolean
-gst_camerabin_iface_supported (GstImplementsInterface * iface, GType iface_type)
-{
- GstCameraBin *camera = GST_CAMERABIN (iface);
-
- if (iface_type == GST_TYPE_COLOR_BALANCE) {
- if (camera->src_vid_src) {
- return GST_IS_COLOR_BALANCE (camera->src_vid_src);
- }
- } else if (iface_type == GST_TYPE_TAG_SETTER) {
- /* Note: Tag setter elements aren't
- present when image and video bin in NULL */
- GstElement *setter;
- setter = gst_bin_get_by_interface (GST_BIN (camera), iface_type);
- if (setter) {
- gst_object_unref (setter);
- return TRUE;
- } else {
- return FALSE;
- }
- }
- return FALSE;
-}
-
-static void
-gst_camerabin_interface_init (GstImplementsInterfaceClass * klass)
-{
- /*
- * default virtual functions
- */
- klass->supported = gst_camerabin_iface_supported;
-}
-
-static void
-camerabin_init_interfaces (GType type)
-{
-
- static const GInterfaceInfo camerabin_info = {
- (GInterfaceInitFunc) gst_camerabin_interface_init,
- NULL,
- NULL,
- };
-
- static const GInterfaceInfo camerabin_color_balance_info = {
- (GInterfaceInitFunc) gst_camerabin_color_balance_init,
- NULL,
- NULL,
- };
-
- static const GInterfaceInfo camerabin_tagsetter_info = {
- NULL,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &camerabin_info);
-
- g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
- &camerabin_color_balance_info);
-
- g_type_add_interface_static (type, GST_TYPE_TAG_SETTER,
- &camerabin_tagsetter_info);
-}
-
-GST_BOILERPLATE_FULL (GstCameraBin, gst_camerabin, GstPipeline,
- GST_TYPE_PIPELINE, camerabin_init_interfaces);
-
-/*
- * static helper functions implementation
- */
-
-/*
- * camerabin_setup_src_elements:
- * @camera: camerabin object
- *
- * This function updates camerabin capsfilters according
- * to fps, resolution and zoom that have been configured
- * to camerabin.
- */
-static void
-camerabin_setup_src_elements (GstCameraBin * camera)
-{
- GstStructure *st;
- GstCaps *new_caps;
- gboolean detect_framerate = FALSE;
-
- /* clear video update status */
- camera->video_capture_caps_update = FALSE;
-
- if (!camera->view_finder_caps) {
- st = gst_structure_from_string (CAMERABIN_DEFAULT_VF_CAPS, NULL);
- } else {
- st = gst_structure_copy (gst_caps_get_structure (camera->view_finder_caps,
- 0));
- }
-
- gst_camerabin_monitor_video_source_properties (camera);
-
- if (camera->app_width > 0 && camera->app_height > 0) {
- gst_structure_set (st,
- "width", G_TYPE_INT, camera->app_width,
- "height", G_TYPE_INT, camera->app_height, NULL);
- }
-
- if (camera->app_fps_n > 0 && camera->app_fps_d > 0) {
- if (camera->night_mode) {
- GST_INFO_OBJECT (camera, "night mode, lowest allowed fps will be forced");
- camera->pre_night_fps_n = camera->app_fps_n;
- camera->pre_night_fps_d = camera->app_fps_d;
- detect_framerate = TRUE;
- } else {
- gst_structure_set (st,
- "framerate", GST_TYPE_FRACTION, camera->app_fps_n,
- camera->app_fps_d, NULL);
- new_caps = gst_caps_new_full (st, NULL);
- }
- } else {
- GST_DEBUG_OBJECT (camera, "no framerate specified");
- detect_framerate = TRUE;
- }
-
- if (detect_framerate) {
- GST_DEBUG_OBJECT (camera, "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 */
- gst_camerabin_set_allowed_framerate (camera, new_caps);
- }
-
- /* Set default zoom method */
- if (camera->src_zoom_scale) {
- g_object_set (camera->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 (&camera->view_finder_caps, new_caps);
- gst_caps_unref (new_caps);
-
- /* Set caps for view finder mode */
- /* This also sets zoom */
- gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps);
-}
-
-/*
- * camerabin_create_src_elements:
- * @camera: camerabin object
- *
- * This function creates and links upstream side elements for camerabin.
- * videosrc ! cspconv ! capsfilter ! crop ! scale ! capsfilter ! out-sel !
- *
- * Returns: TRUE, if elements were successfully created, FALSE otherwise
- */
-static gboolean
-camerabin_create_src_elements (GstCameraBin * camera)
-{
- gboolean ret = FALSE;
- GstBin *cbin = GST_BIN (camera);
- gchar *driver_name = NULL;
-
- /* Add application set or default video src element */
- if (!(camera->src_vid_src = gst_camerabin_setup_default_element (cbin,
- camera->app_vid_src, "autovideosrc", DEFAULT_VIDEOSRC))) {
- camera->src_vid_src = NULL;
- goto done;
- } else {
- if (!gst_camerabin_add_element (cbin, camera->src_vid_src))
- goto done;
- }
- if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION) {
- if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
- "src-ffmpegcolorspace"))
- goto done;
- }
- if (!(camera->src_filter =
- gst_camerabin_create_and_add_element (cbin, "capsfilter",
- "src-capsfilter")))
- goto done;
- if (camera->flags & GST_CAMERABIN_FLAG_SOURCE_RESIZE) {
- if (!(camera->src_zoom_crop =
- gst_camerabin_create_and_add_element (cbin, "videocrop",
- "src-videocrop")))
- goto done;
- if (!(camera->src_zoom_scale =
- gst_camerabin_create_and_add_element (cbin, "videoscale",
- "src-videoscale")))
- goto done;
- if (!(camera->src_zoom_filter =
- gst_camerabin_create_and_add_element (cbin, "capsfilter",
- "src-resize-capsfilter")))
- goto done;
- }
- if (camera->app_video_filter) {
- if (!gst_camerabin_add_element (cbin, camera->app_video_filter)) {
- goto done;
- }
- }
- if (!(camera->src_out_sel =
- gst_camerabin_create_and_add_element (cbin, "output-selector", NULL)))
- goto done;
-
- /* Set pad-negotiation-mode to active */
- g_object_set (camera->src_out_sel, "pad-negotiation-mode", 2, NULL);
-
- /* Set default "driver-name" for v4l2camsrc if not set */
- /* FIXME: v4l2camsrc specific */
- if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
- "driver-name")) {
- g_object_get (G_OBJECT (camera->src_vid_src), "driver-name",
- &driver_name, NULL);
- if (!driver_name) {
- g_object_set (G_OBJECT (camera->src_vid_src), "driver-name",
- DEFAULT_V4L2CAMSRC_DRIVER_NAME, NULL);
- }
- }
-
- ret = TRUE;
-done:
- return ret;
-}
-
-/*
- * camerabin_setup_view_elements:
- * @camera: camerabin object
- *
- * This function configures properties for view finder sink element.
- */
-static void
-camerabin_setup_view_elements (GstCameraBin * camera)
-{
- GST_DEBUG_OBJECT (camera, "setting view finder properties");
- g_object_set (G_OBJECT (camera->view_in_sel), "select-all", TRUE, NULL);
- /* Set properties for view finder sink */
- /* Find the actual sink if using bin like autovideosink */
- if (GST_IS_BIN (camera->view_sink)) {
- GList *child = NULL, *children = GST_BIN_CHILDREN (camera->view_sink);
- for (child = children; child != NULL; child = g_list_next (child)) {
- GObject *ch = G_OBJECT (child->data);
- if (g_object_class_find_property (G_OBJECT_GET_CLASS (ch), "sync")) {
- g_object_set (G_OBJECT (ch), "sync", FALSE, "qos", FALSE, "async",
- FALSE, NULL);
- }
- }
- } else {
- g_object_set (G_OBJECT (camera->view_sink), "sync", FALSE, "qos", FALSE,
- "async", FALSE, NULL);
- }
-}
-
-/*
- * camerabin_create_view_elements:
- * @camera: camerabin object
- *
- * This function creates and links downstream side elements for camerabin.
- * ! scale ! cspconv ! view finder sink
- *
- * Returns: TRUE, if elements were successfully created, FALSE otherwise
- */
-static gboolean
-camerabin_create_view_elements (GstCameraBin * camera)
-{
- const GList *pads;
- GstBin *cbin = GST_BIN (camera);
-
- if (!(camera->view_in_sel =
- gst_camerabin_create_and_add_element (cbin, "input-selector",
- NULL))) {
- goto error;
- }
-
- /* Look for recently added input selector sink pad, we need to release it later */
- pads = GST_ELEMENT_PADS (camera->view_in_sel);
- while (pads != NULL
- && (GST_PAD_DIRECTION (GST_PAD (pads->data)) != GST_PAD_SINK)) {
- pads = g_list_next (pads);
- }
- camera->pad_view_src = GST_PAD (pads->data);
-
- /* Add videoscale in case we need to downscale frame for view finder */
- if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_SCALE) {
- if (!(camera->view_scale =
- gst_camerabin_create_and_add_element (cbin, "videoscale",
- "vf-videoscale"))) {
- goto error;
- }
-
- /* Add capsfilter to maintain aspect ratio while scaling */
- if (!(camera->aspect_filter =
- gst_camerabin_create_and_add_element (cbin, "capsfilter",
- "vf-scale-capsfilter"))) {
- goto error;
- }
- }
- if (camera->flags & GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION) {
- if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace",
- "vf-ffmpegcolorspace")) {
- goto error;
- }
- }
-
- if (camera->app_viewfinder_filter) {
- if (!gst_camerabin_add_element (GST_BIN (camera),
- camera->app_viewfinder_filter)) {
- goto error;
- }
- }
-
- /* Add application set or default video sink element */
- if (!(camera->view_sink = gst_camerabin_setup_default_element (cbin,
- camera->app_vf_sink, "autovideosink", DEFAULT_VIDEOSINK))) {
- camera->view_sink = NULL;
- goto error;
- } else {
- if (!gst_camerabin_add_element (cbin, camera->view_sink))
- goto error;
- }
-
- return TRUE;
-error:
- return FALSE;
-}
-
-/*
- * camerabin_create_elements:
- * @camera: camerabin object
- *
- * This function creates and links all elements for camerabin,
- *
- * Returns: TRUE, if elements were successfully created, FALSE otherwise
- */
-static gboolean
-camerabin_create_elements (GstCameraBin * camera)
-{
- gboolean ret = FALSE;
- GstPadLinkReturn link_ret = GST_PAD_LINK_REFUSED;
- GstPad *unconnected_pad;
-
- GST_LOG_OBJECT (camera, "creating elements");
-
- /* Create "src" elements */
- if (!camerabin_create_src_elements (camera)) {
- goto done;
- }
-
- camera->pad_src_img =
- gst_element_get_request_pad (camera->src_out_sel, "src_%u");
-
- gst_pad_add_data_probe (camera->pad_src_img,
- G_CALLBACK (gst_camerabin_have_img_buffer), camera);
-
- /* Add queue leading to image bin */
- camera->img_queue = gst_element_factory_make ("queue", "image-queue");
- if (!gst_camerabin_add_element (GST_BIN (camera), camera->img_queue)) {
- goto done;
- }
-
- /* To avoid deadlock, we won't restrict the image queue size */
- /* FIXME: actually we would like to have some kind of restriction here (size),
- but deadlocks must be handled somehow... */
- g_object_set (G_OBJECT (camera->img_queue), "max-size-buffers", 0,
- "max-size-bytes", 0, "max-size-time", G_GUINT64_CONSTANT (0), NULL);
- g_object_set (camera->img_queue, "silent", TRUE, NULL);
-
- camera->pad_src_queue = gst_element_get_static_pad (camera->img_queue, "src");
-
- gst_pad_add_data_probe (camera->pad_src_queue,
- G_CALLBACK (gst_camerabin_have_queue_data), camera);
-
- /* Add image bin */
- if (!gst_camerabin_add_element (GST_BIN (camera), camera->imgbin)) {
- goto done;
- }
-
- camera->pad_src_view =
- gst_element_get_request_pad (camera->src_out_sel, "src_%u");
-
- /* Create view finder elements */
- if (!camerabin_create_view_elements (camera)) {
- GST_WARNING_OBJECT (camera, "creating view finder elements failed");
- goto done;
- }
-
- /* Set view finder active as default */
- g_object_set (G_OBJECT (camera->src_out_sel), "active-pad",
- camera->pad_src_view, NULL);
-
- /* Add video bin */
- camera->pad_src_vid =
- gst_element_get_request_pad (camera->src_out_sel, "src_%u");
- if (!gst_camerabin_add_element (GST_BIN (camera), camera->vidbin)) {
- goto done;
- }
- gst_pad_add_buffer_probe (camera->pad_src_vid,
- G_CALLBACK (gst_camerabin_have_vid_buffer), camera);
-
- /* Link video bin ! view finder */
- unconnected_pad = gst_bin_find_unlinked_pad (GST_BIN (camera), GST_PAD_SRC);
- camera->pad_view_vid =
- gst_element_get_request_pad (camera->view_in_sel, "sink_%u");
- link_ret =
- gst_pad_link_full (unconnected_pad, camera->pad_view_vid,
- GST_PAD_LINK_CHECK_CAPS);
- gst_object_unref (unconnected_pad);
- if (GST_PAD_LINK_FAILED (link_ret)) {
- GST_ELEMENT_ERROR (camera, CORE, NEGOTIATION, (NULL),
- ("linking video bin and view finder failed"));
- goto done;
- }
-
- ret = TRUE;
-
-done:
-
- if (FALSE == ret)
- camerabin_destroy_elements (camera);
-
- return ret;
-}
-
-/*
- * camerabin_destroy_elements:
- * @camera: camerabin object
- *
- * This function removes all elements from camerabin.
- */
-static void
-camerabin_destroy_elements (GstCameraBin * camera)
-{
- GST_DEBUG_OBJECT (camera, "destroying elements");
-
- /* Release request pads */
- if (camera->pad_view_vid) {
- gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_vid);
- gst_object_unref (camera->pad_view_vid);
- camera->pad_view_vid = NULL;
- }
- if (camera->pad_src_vid) {
- gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_vid);
- gst_object_unref (camera->pad_src_vid);
- camera->pad_src_vid = NULL;
- }
- if (camera->pad_src_img) {
- gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_img);
- gst_object_unref (camera->pad_src_img);
- camera->pad_src_img = NULL;
- }
- if (camera->pad_view_src) {
- gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_src);
- /* don't unref, we have not requested it */
- camera->pad_view_src = NULL;
- }
- if (camera->pad_src_view) {
- gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_view);
- gst_object_unref (camera->pad_src_view);
- camera->pad_src_view = NULL;
- }
-
- if (camera->pad_src_queue) {
- gst_object_unref (camera->pad_src_queue);
- camera->pad_src_queue = NULL;
- }
-
- /* view finder elements */
- camera->view_in_sel = NULL;
- camera->view_scale = NULL;
- camera->aspect_filter = NULL;
- camera->view_sink = NULL;
-
- /* source elements */
- camera->src_vid_src = NULL;
- camera->src_filter = NULL;
- camera->src_zoom_crop = NULL;
- camera->src_zoom_scale = NULL;
- camera->src_zoom_filter = NULL;
- camera->src_out_sel = NULL;
-
- camera->active_bin = NULL;
-
- /* Reset caps data as the elements might be completely different next
- * time we 'start' */
- if (camera->view_finder_caps) {
- gst_caps_replace (&camera->view_finder_caps, NULL);
- }
- gst_caps_replace (&camera->allowed_caps, NULL);
- camera->fps_n = camera->fps_d = 0;
- camera->width = camera->height = 0;
-
- /* Remove elements */
- gst_camerabin_remove_elements_from_bin (GST_BIN (camera));
-}
-
-/*
- * camerabin_dispose_elements:
- * @camera: camerabin object
- *
- * This function releases all allocated camerabin resources.
- */
-static void
-camerabin_dispose_elements (GstCameraBin * camera)
-{
- GST_INFO ("cleaning");
-
- if (camera->capture_mutex) {
- g_mutex_free (camera->capture_mutex);
- camera->capture_mutex = NULL;
- }
- if (camera->cond) {
- g_cond_free (camera->cond);
- camera->cond = NULL;
- }
- if (camera->idle_cond) {
- g_cond_free (camera->idle_cond);
- camera->idle_cond = NULL;
- }
- if (camera->filename) {
- g_string_free (camera->filename, TRUE);
- camera->filename = NULL;
- }
- /* Unref application set elements */
- if (camera->app_vf_sink) {
- gst_object_unref (camera->app_vf_sink);
- camera->app_vf_sink = NULL;
- }
- if (camera->app_vid_src) {
- gst_object_unref (camera->app_vid_src);
- camera->app_vid_src = NULL;
- }
-
- if (camera->app_video_filter) {
- gst_object_unref (camera->app_video_filter);
- camera->app_video_filter = NULL;
- }
-
- if (camera->app_viewfinder_filter) {
- gst_object_unref (camera->app_viewfinder_filter);
- camera->app_viewfinder_filter = NULL;
- }
-
- if (camera->app_preview_source_filter) {
- gst_object_unref (camera->app_preview_source_filter);
- camera->app_preview_source_filter = NULL;
- }
-
- if (camera->app_video_preview_source_filter) {
- gst_object_unref (camera->app_video_preview_source_filter);
- camera->app_video_preview_source_filter = NULL;
- }
-
- /* Free caps */
- gst_caps_replace (&camera->image_capture_caps, NULL);
- gst_caps_replace (&camera->view_finder_caps, NULL);
- gst_caps_replace (&camera->allowed_caps, NULL);
- gst_caps_replace (&camera->preview_caps, NULL);
- gst_caps_replace (&camera->video_preview_caps, NULL);
- gst_buffer_replace (&camera->video_preview_buffer, NULL);
-
- if (camera->event_tags) {
- gst_tag_list_free (camera->event_tags);
- camera->event_tags = NULL;
- }
-}
-
-/*
- * gst_camerabin_image_capture_continue:
- * @camera: camerabin object
- * @filename: filename of the finished image
- *
- * Notify application that image has been saved with a signal.
- *
- * Returns TRUE if another image should be captured, FALSE otherwise.
- */
-static gboolean
-gst_camerabin_image_capture_continue (GstCameraBin * camera,
- const gchar * filename)
-{
- gboolean cont = FALSE;
-
- GST_DEBUG_OBJECT (camera, "emitting img_done signal, filename: %s", filename);
- g_signal_emit (G_OBJECT (camera), camerabin_signals[IMG_DONE_SIGNAL], 0,
- filename, &cont);
-
- /* If the app wants to continue make sure new filename has been set */
- if (cont && g_str_equal (camera->filename->str, "")) {
- GST_ELEMENT_ERROR (camera, RESOURCE, NOT_FOUND,
- ("cannot continue capture, no filename has been set"), (NULL));
- cont = FALSE;
- }
-
- return cont;
-}
-
-/*
- * gst_camerabin_change_mode:
- * @camera: camerabin object
- * @mode: image or video mode
- *
- * Change camerabin mode between image and video capture.
- * Changing mode will stop ongoing capture.
- */
-static void
-gst_camerabin_change_mode (GstCameraBin * camera, gint mode)
-{
- if (camera->mode != mode || !camera->active_bin) {
- GstState state, pending_state;
-
- GST_DEBUG_OBJECT (camera, "setting mode: %d (old_mode=%d)",
- mode, camera->mode);
- /* Interrupt ongoing capture */
- gst_camerabin_do_stop (camera);
-
- /* reset night-mode stored values */
- camera->pre_night_fps_n = 0;
- camera->pre_night_fps_d = 1;
-
- camera->mode = mode;
- gst_element_get_state (GST_ELEMENT (camera), &state, &pending_state, 0);
- if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING ||
- pending_state == GST_STATE_PAUSED
- || pending_state == GST_STATE_PLAYING) {
- if (camera->active_bin) {
- GST_DEBUG_OBJECT (camera, "stopping active bin");
- gst_element_set_state (camera->active_bin, GST_STATE_READY);
- }
- if (camera->mode == MODE_IMAGE) {
- GstStateChangeReturn state_ret;
-
- camera->active_bin = camera->imgbin;
- state_ret =
- gst_element_set_state (camera->active_bin, GST_STATE_PAUSED);
-
- if (state_ret == GST_STATE_CHANGE_FAILURE) {
- GST_WARNING_OBJECT (camera, "state change failed");
- gst_element_set_state (camera->active_bin, GST_STATE_NULL);
- camera->active_bin = NULL;
- }
- } else if (camera->mode == MODE_VIDEO) {
- camera->active_bin = camera->vidbin;
- }
- gst_camerabin_reset_to_view_finder (camera);
- } else if (camera->mode == MODE_IMAGE) {
- /* Prepare needed elements for image processing */
- gst_camerabin_image_prepare_elements (GST_CAMERABIN_IMAGE
- (camera->imgbin));
- }
- }
-}
-
-/*
- * gst_camerabin_set_flags:
- * @camera: camerabin object
- * @flags: flags for camerabin, videobin and imagebin
- *
- * Change camerabin capture flags.
- */
-static void
-gst_camerabin_set_flags (GstCameraBin * camera, GstCameraBinFlags flags)
-{
- g_return_if_fail (camera != NULL);
-
- GST_DEBUG_OBJECT (camera, "setting flags: %d", flags);
-
- GST_OBJECT_LOCK (camera);
- camera->flags = flags;
- GST_OBJECT_UNLOCK (camera);
-
- gst_camerabin_video_set_flags (GST_CAMERABIN_VIDEO (camera->vidbin), flags);
- gst_camerabin_image_set_flags (GST_CAMERABIN_IMAGE (camera->imgbin), flags);
-}
-
-/*
- * gst_camerabin_change_filename:
- * @camera: camerabin object
- * @name: new filename for capture
- *
- * Change filename for image or video capture.
- */
-static void
-gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name)
-{
- if (name == NULL)
- name = "";
-
- if (0 != strcmp (camera->filename->str, name)) {
- GST_DEBUG_OBJECT (camera, "changing filename from '%s' to '%s'",
- camera->filename->str, name);
- g_string_assign (camera->filename, name);
- }
-}
-
-static gboolean
-gst_camerabin_set_videosrc_zoom (GstCameraBin * camera, gfloat zoom)
-{
- gboolean ret = FALSE;
-
- /* Try with photography interface zooming */
- if (GST_IS_ELEMENT (camera->src_vid_src) &&
- gst_element_implements_interface (camera->src_vid_src,
- GST_TYPE_PHOTOGRAPHY)) {
- gst_photography_set_zoom (GST_PHOTOGRAPHY (camera->src_vid_src), zoom);
- ret = TRUE;
- }
- return ret;
-}
-
-
-static gboolean
-gst_camerabin_set_element_zoom (GstCameraBin * camera, gfloat zoom)
-{
- gint w2_crop = 0, h2_crop = 0;
- GstPad *pad_zoom_sink = NULL;
- gboolean ret = FALSE;
- gint left = camera->base_crop_left;
- gint right = camera->base_crop_right;
- gint top = camera->base_crop_top;
- gint bottom = camera->base_crop_bottom;
-
- if (camera->src_zoom_crop) {
- /* Update capsfilters to apply the zoom */
- GST_INFO_OBJECT (camera, "zoom: %f, orig size: %dx%d", zoom,
- camera->width, camera->height);
-
- if (zoom != ZOOM_1X) {
- w2_crop = (camera->width - (camera->width * ZOOM_1X / zoom)) / 2;
- h2_crop = (camera->height - (camera->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 (camera->src_zoom_crop, "sink");
-
- GST_INFO_OBJECT (camera,
- "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top,
- bottom);
-
- GST_PAD_STREAM_LOCK (pad_zoom_sink);
- g_object_set (camera->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;
-}
-
-/*
- * gst_camerabin_setup_zoom:
- * @camera: camerabin object
- *
- * Apply zoom configured to camerabin to capture.
- */
-static void
-gst_camerabin_setup_zoom (GstCameraBin * camera)
-{
- gfloat zoom;
-
- g_return_if_fail (camera != NULL);
-
- zoom = camera->zoom;
-
- g_return_if_fail (zoom);
-
- GST_INFO_OBJECT (camera, "setting zoom %f", zoom);
-
- if (gst_camerabin_set_videosrc_zoom (camera, zoom)) {
- gst_camerabin_set_element_zoom (camera, ZOOM_1X);
- GST_INFO_OBJECT (camera, "zoom set using videosrc");
- } else if (gst_camerabin_set_element_zoom (camera, zoom)) {
- GST_INFO_OBJECT (camera, "zoom set using gst elements");
- } else {
- GST_INFO_OBJECT (camera, "setting zoom failed");
- }
-}
-
-/*
- * gst_camerabin_get_allowed_input_caps:
- * @camera: camerabin object
- *
- * Retrieve caps from videosrc describing formats it supports
- *
- * Returns: caps object from videosrc
- */
-static GstCaps *
-gst_camerabin_get_allowed_input_caps (GstCameraBin * camera)
-{
- GstCaps *caps = NULL;
- GstPad *pad = NULL, *peer_pad = NULL;
- GstState state;
- GstElement *videosrc;
-
- g_return_val_if_fail (camera != NULL, NULL);
-
- videosrc = camera->src_vid_src ? camera->src_vid_src : camera->app_vid_src;
-
- if (!videosrc) {
- GST_WARNING_OBJECT (camera, "no videosrc, can't get allowed caps");
- goto failed;
- }
-
- if (camera->allowed_caps) {
- GST_DEBUG_OBJECT (camera, "returning cached caps");
- goto done;
- }
-
- pad = gst_element_get_static_pad (videosrc, "src");
-
- if (!pad) {
- GST_WARNING_OBJECT (camera, "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 (camera, "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);
- }
-
- camera->allowed_caps = gst_pad_get_caps (pad);
-
- /* Restore state and re-link if necessary */
- if (state == GST_STATE_NULL) {
- GST_DEBUG_OBJECT (camera, "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_full (pad, peer_pad, GST_PAD_LINK_CHECK_CAPS);
- gst_object_unref (peer_pad);
- }
- gst_element_set_locked_state (videosrc, FALSE);
- }
-
- gst_object_unref (pad);
-
-done:
- if (camera->allowed_caps) {
- caps = gst_caps_copy (camera->allowed_caps);
- }
- GST_DEBUG_OBJECT (camera, "allowed caps:%" GST_PTR_FORMAT, caps);
-failed:
- return caps;
-}
-
-/*
- * gst_camerabin_send_img_queue_event:
- * @camera: camerabin object
- * @event: event to be sent
- *
- * Send the given event to image queue.
- */
-static void
-gst_camerabin_send_img_queue_event (GstCameraBin * camera, GstEvent * event)
-{
- GstPad *queue_sink;
-
- g_return_if_fail (camera != NULL);
- g_return_if_fail (event != NULL);
-
- queue_sink = gst_element_get_static_pad (camera->img_queue, "sink");
- gst_pad_send_event (queue_sink, event);
- gst_object_unref (queue_sink);
-}
-
-/*
- * gst_camerabin_send_img_queue_custom_event:
- * @camera: camerabin object
- * @ev_struct: event structure to be sent
- *
- * Generate and send a custom event to image queue.
- */
-static void
-gst_camerabin_send_img_queue_custom_event (GstCameraBin * camera,
- GstStructure * ev_struct)
-{
- GstEvent *event;
-
- g_return_if_fail (camera != NULL);
- g_return_if_fail (ev_struct != NULL);
-
- event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, ev_struct);
- gst_camerabin_send_img_queue_event (camera, event);
-}
-
-/*
- * gst_camerabin_rewrite_tags_to_bin:
- * @bin: bin holding tag setter elements
- * @list: tag list to be written
- *
- * This function looks for certain tag setters from given bin
- * and REPLACES ALL setter tags with given tag list
- *
- */
-static void
-gst_camerabin_rewrite_tags_to_bin (GstBin * bin, const GstTagList * list)
-{
- GstElement *setter;
- GstIterator *iter;
- GstIteratorResult res = GST_ITERATOR_OK;
- gpointer data;
-
- iter = gst_bin_iterate_all_by_interface (bin, GST_TYPE_TAG_SETTER);
-
- while (res == GST_ITERATOR_OK || res == GST_ITERATOR_RESYNC) {
- res = gst_iterator_next (iter, &data);
- switch (res) {
- case GST_ITERATOR_DONE:
- break;
- case GST_ITERATOR_RESYNC:
- gst_iterator_resync (iter);
- break;
- case GST_ITERATOR_ERROR:
- GST_WARNING ("error iterating tag setters");
- break;
- case GST_ITERATOR_OK:
- setter = GST_ELEMENT (data);
- GST_LOG ("iterating tag setters: %" GST_PTR_FORMAT, setter);
- GST_DEBUG ("replacement tags %" GST_PTR_FORMAT, list);
- gst_tag_setter_merge_tags (GST_TAG_SETTER (setter), list,
- GST_TAG_MERGE_REPLACE_ALL);
- gst_object_unref (setter);
- break;
- default:
- break;
- }
- }
-
- gst_iterator_free (iter);
-}
-
-/*
- * gst_camerabin_get_internal_tags:
- * @camera: the camera bin element
- *
- * Returns tag list containing metadata from camerabin
- * and it's elements
- */
-static GstTagList *
-gst_camerabin_get_internal_tags (GstCameraBin * camera)
-{
- GstTagList *list = gst_tag_list_new ();
- GstColorBalance *balance = NULL;
- const GList *controls = NULL, *item;
- GstColorBalanceChannel *channel;
- gint min_value, max_value, mid_value, cur_value;
-
- if (camera->active_bin == camera->vidbin) {
- /* FIXME: check if internal video tag setting is needed */
- goto done;
- }
-
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, (gdouble) camera->zoom, NULL);
-
- if (gst_element_implements_interface (GST_ELEMENT (camera),
- GST_TYPE_COLOR_BALANCE)) {
- balance = GST_COLOR_BALANCE (camera);
- }
-
- if (balance) {
- controls = gst_color_balance_list_channels (balance);
- }
- for (item = controls; item; item = g_list_next (item)) {
- channel = item->data;
- min_value = channel->min_value;
- max_value = channel->max_value;
- /* the default value would probably better */
- mid_value = min_value + ((max_value - min_value) / 2);
- cur_value = gst_color_balance_get_value (balance, channel);
-
- if (!g_ascii_strcasecmp (channel->label, "brightness")) {
- /* The value of brightness. The unit is the APEX value (Additive System of Photographic Exposure).
- * Ordinarily it is given in the range of -99.99 to 99.99. Note that
- * if the numerator of the recorded value is 0xFFFFFFFF, Unknown shall be indicated.
- *
- * BrightnessValue (Bv) = log2 ( B/NK )
- * Note that: B:cd/cm² (candela per square centimeter), N,K: constant
- *
- * http://johnlind.tripod.com/science/scienceexposure.html
- *
- */
-/*
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- "capture-brightness", cur_value, 1, NULL);
-*/
- } else if (!g_ascii_strcasecmp (channel->label, "contrast")) {
- /* 0 = Normal, 1 = Soft, 2 = Hard */
-
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_CAPTURING_CONTRAST,
- (cur_value == mid_value) ? "normal" : ((cur_value < mid_value)
- ? "soft" : "hard"), NULL);
- } else if (!g_ascii_strcasecmp (channel->label, "gain")) {
- /* 0 = Normal, 1 = Low Up, 2 = High Up, 3 = Low Down, 4 = Hight Down */
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_CAPTURING_GAIN_ADJUSTMENT,
- (cur_value == mid_value) ? "normal" : ((cur_value <
- mid_value) ? "low-gain-up" : "low-gain-down"), NULL);
- } else if (!g_ascii_strcasecmp (channel->label, "saturation")) {
- /* 0 = Normal, 1 = Low, 2 = High */
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_CAPTURING_SATURATION,
- (cur_value == mid_value) ? "normal" : ((cur_value < mid_value)
- ? "low-saturation" : "high-saturation"), NULL);
- }
- }
-
-done:
-
- return list;
-}
-
-/*
- * gst_camerabin_rewrite_tags:
- * @camera: the camera bin element
- *
- * Merges application set tags to camerabin internal tags,
- * and writes them using image or video bin tag setters.
- */
-static void
-gst_camerabin_rewrite_tags (GstCameraBin * camera)
-{
- const GstTagList *app_tag_list = NULL;
- GstTagList *list = NULL;
-
- /* Get application set tags */
- app_tag_list = gst_tag_setter_get_tag_list (GST_TAG_SETTER (camera));
-
- /* Get tags from camerabin and it's elements */
- list = gst_camerabin_get_internal_tags (camera);
-
- if (app_tag_list) {
- gst_tag_list_insert (list, app_tag_list, GST_TAG_MERGE_REPLACE);
- }
-
- /* Write tags */
- if (camera->active_bin == camera->vidbin) {
- gst_camerabin_rewrite_tags_to_bin (GST_BIN (camera->active_bin), list);
- } else {
- /* Image tags need to be sent as a serialized event into image queue */
- GstEvent *tagevent = gst_event_new_tag (gst_tag_list_copy (list));
- gst_camerabin_send_img_queue_event (camera, tagevent);
- }
-
- gst_tag_list_free (list);
-}
-
-/*
- * gst_camerabin_set_capsfilter_caps:
- * @camera: camerabin object
- * @new_caps: pointer to caps object to set
- *
- * Set given caps to camerabin capsfilters.
- */
-static void
-gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps)
-{
- GST_INFO_OBJECT (camera, "new_caps:%" GST_PTR_FORMAT, new_caps);
-
- gst_camerabin_configure_format (camera, new_caps);
-
- /* Update zoom */
- gst_camerabin_setup_zoom (camera);
-
- /* Update capsfilters */
- g_object_set (G_OBJECT (camera->src_filter), "caps", new_caps, NULL);
- if (camera->src_zoom_filter)
- g_object_set (G_OBJECT (camera->src_zoom_filter), "caps", new_caps, NULL);
- gst_camerabin_update_aspect_filter (camera, new_caps);
- GST_INFO_OBJECT (camera, "udpated");
-}
-
-/*
- * img_capture_prepared:
- * @data: camerabin 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)
-{
- GstCameraBin *camera = GST_CAMERABIN (data);
-
- GST_INFO_OBJECT (camera, "image capture prepared");
-
- /* It is possible we are about to get something else that we requested */
- if (!gst_caps_is_equal (camera->image_capture_caps, caps)) {
- gst_camerabin_adapt_image_capture (camera, caps);
- } else {
- gst_camerabin_set_capsfilter_caps (camera, camera->image_capture_caps);
- }
-
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
- "active-pad", camera->pad_src_img, NULL);
-}
-
-/*
- * gst_camerabin_start_image_capture:
- * @camera: camerabin object
- *
- * Initiates image capture.
- */
-static void
-gst_camerabin_start_image_capture (GstCameraBin * camera)
-{
- gboolean wait_for_prepare = FALSE, ret = FALSE;
-
- GST_INFO_OBJECT (camera, "starting image capture");
-
- if (GST_IS_ELEMENT (camera->src_vid_src) &&
- gst_element_implements_interface (camera->src_vid_src,
- GST_TYPE_PHOTOGRAPHY)) {
- /* Start image capture preparations using photography iface */
- wait_for_prepare = TRUE;
- g_mutex_lock (camera->capture_mutex);
-
- /* Enable still image capture mode in v4l2camsrc */
- if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
- "capture-mode")) {
- g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 1, NULL);
- }
-
- if (!camera->image_capture_caps || camera->image_capture_caps_update) {
- if (camera->image_capture_width && camera->image_capture_height) {
- /* Resolution is set, but it isn't in use yet */
- gst_camerabin_set_image_capture_caps (camera,
- camera->image_capture_width, camera->image_capture_height);
- } else {
- /* Capture resolution not set. Use viewfinder resolution */
- camera->image_capture_caps = gst_caps_copy (camera->view_finder_caps);
- camera->image_capture_caps_update = FALSE;
- }
- }
-
- /* Start preparations for image capture */
- GST_DEBUG_OBJECT (camera, "prepare image capture caps %" GST_PTR_FORMAT,
- camera->image_capture_caps);
- ret =
- gst_photography_prepare_for_capture (GST_PHOTOGRAPHY
- (camera->src_vid_src), (GstPhotoCapturePrepared) img_capture_prepared,
- camera->image_capture_caps, camera);
- camera->capturing = TRUE;
- g_mutex_unlock (camera->capture_mutex);
- }
-
- if (!wait_for_prepare) {
- g_mutex_lock (camera->capture_mutex);
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE,
- "active-pad", camera->pad_src_img, NULL);
- camera->capturing = TRUE;
- ret = TRUE;
- g_mutex_unlock (camera->capture_mutex);
- }
-
- if (!ret) {
- CAMERABIN_PROCESSING_DEC_UNLOCKED (camera);
- GST_WARNING_OBJECT (camera, "starting image capture failed");
- }
-}
-
- /*
- * FIXME ideally a caps renegotiation is better here
- */
-static void
-reset_video_capture_caps (GstCameraBin * camera)
-{
- GstState state, pending;
- GstPad *activepad = NULL;
-
- GST_INFO_OBJECT (camera, "switching resolution to %dx%d and fps to %d/%d",
- camera->width, camera->height, camera->fps_n, camera->fps_d);
-
- /* Interrupt ongoing capture */
- gst_camerabin_do_stop (camera);
-
- /* prevent image captures from being lost */
- CAMERABIN_PROCESSING_WAIT_IDLE (camera);
-
- gst_element_get_state (GST_ELEMENT (camera), &state, &pending, 0);
- if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING) {
- GST_INFO_OBJECT (camera,
- "changing to READY to initialize videosrc with new format");
- g_object_get (G_OBJECT (camera->src_out_sel), "active-pad", &activepad,
- NULL);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_READY);
- }
- if (pending != GST_STATE_VOID_PENDING) {
- GST_LOG_OBJECT (camera, "restoring pending state: %s",
- gst_element_state_get_name (pending));
- state = pending;
- }
-
- /* Re-set the active pad since switching camerabin to READY state clears this
- * setting in output-selector */
- if (activepad) {
- GST_INFO_OBJECT (camera, "re-setting active pad in output-selector");
-
- g_object_set (G_OBJECT (camera->src_out_sel), "active-pad", activepad,
- NULL);
- }
-
- gst_element_set_state (GST_ELEMENT (camera), state);
-}
-
-/*
- * gst_camerabin_start_video_recording:
- * @camera: camerabin object
- *
- * Initiates video recording.
- */
-static void
-gst_camerabin_start_video_recording (GstCameraBin * camera)
-{
- GstStateChangeReturn state_ret;
- GstCameraBinVideo *vidbin = (GstCameraBinVideo *) camera->vidbin;
- /* FIXME: how to ensure resolution and fps is supported by CPU?
- * use a queue overrun signal?
- */
- GST_INFO_OBJECT (camera, "starting video capture");
-
- /* check if need to update video capture caps */
- if (camera->video_capture_caps_update) {
- reset_video_capture_caps (camera);
- }
-
- gst_camerabin_rewrite_tags (camera);
-
- /* Pause the pipeline in order to distribute new clock in paused_to_playing */
- /* Audio source needs to go to null to reset the ringbuffer */
- if (vidbin->aud_src)
- gst_element_set_state (vidbin->aud_src, GST_STATE_NULL);
- state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
-
- if (state_ret != GST_STATE_CHANGE_FAILURE) {
- GstClock *clock = gst_element_get_clock (GST_ELEMENT (camera));
-
- g_mutex_lock (camera->capture_mutex);
- camera->capturing = TRUE;
- g_mutex_unlock (camera->capture_mutex);
- gst_element_set_locked_state (camera->vidbin, FALSE);
- /* ensure elements activated before feeding data into it */
- state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
- "active-pad", camera->pad_src_vid, NULL);
-
- /* Enable video mode in v4l2camsrc */
- if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
- "capture-mode")) {
- g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL);
- }
-
- /* Clock might be distributed as NULL to audiosrc, messing timestamping */
- if (vidbin->aud_src)
- gst_element_set_clock (vidbin->aud_src, clock);
- gst_object_unref (clock);
-
- /* videobin will not go to playing if file is not writable */
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_ELEMENT_ERROR (camera, CORE, STATE_CHANGE,
- ("Setting videobin to PLAYING failed"), (NULL));
- gst_element_set_state (camera->vidbin, GST_STATE_NULL);
- gst_element_set_locked_state (camera->vidbin, TRUE);
- g_mutex_lock (camera->capture_mutex);
- camera->capturing = FALSE;
- g_mutex_unlock (camera->capture_mutex);
- gst_camerabin_reset_to_view_finder (camera);
- } else {
- gst_element_set_locked_state (camera->vidbin, TRUE);
- }
- } else {
- GST_WARNING_OBJECT (camera, "videobin state change failed");
- gst_element_set_state (camera->vidbin, GST_STATE_NULL);
- gst_camerabin_reset_to_view_finder (camera);
-
- CAMERABIN_PROCESSING_DEC (camera);
- }
-}
-
-/*
- * gst_camerabin_send_video_eos:
- * @camera: camerabin object
- *
- * Generate and send eos event to video bin in order to
- * finish recording properly.
- */
-static void
-gst_camerabin_send_video_eos (GstCameraBin * camera)
-{
- GstPad *videopad;
-
- g_return_if_fail (camera != NULL);
-
- if (!camera->eos_handled) {
- /* Send eos event to video bin */
- GST_INFO_OBJECT (camera, "sending eos to videobin");
- videopad = gst_element_get_static_pad (camera->vidbin, "sink");
- gst_pad_send_event (videopad, gst_event_new_eos ());
- gst_object_unref (videopad);
- /* Block viewfinder after capturing if requested by application */
- GST_OBJECT_LOCK (camera);
- if (camera->block_viewfinder_trigger) {
- gst_pad_set_blocked_async (camera->pad_src_view, TRUE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
- }
- GST_OBJECT_UNLOCK (camera);
- camera->eos_handled = TRUE;
- } else {
- GST_INFO_OBJECT (camera, "dropping duplicate EOS");
- }
-}
-
-/*
- * camerabin_pad_blocked:
- * @pad: pad to block/unblock
- * @blocked: TRUE to block, FALSE to unblock
- * @u_data: camera bin object
- *
- * Callback function for blocking a pad.
- */
-static void
-camerabin_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
-{
- GstCameraBin *camera;
-
- camera = (GstCameraBin *) user_data;
-
- GST_DEBUG_OBJECT (camera, "%s %s:%s",
- blocked ? "blocking" : "unblocking", GST_DEBUG_PAD_NAME (pad));
-}
-
-/*
- * gst_camerabin_send_preview:
- * @camera: camerabin object
- * @buffer: received buffer
- *
- * Convert given buffer to desired preview format and send is as a #GstMessage
- * to application.
- *
- * Returns: TRUE always
- */
-static gboolean
-gst_camerabin_send_preview (GstCameraBin * camera, GstBuffer * buffer)
-{
- GstCameraBinPreviewPipelineData *data;
- GstBuffer *prev = NULL;
- GstStructure *s;
- GstMessage *msg;
- gboolean ret = FALSE;
-
- GST_DEBUG_OBJECT (camera, "creating preview");
-
- data = (camera->mode == MODE_IMAGE) ?
- camera->preview_pipeline : camera->video_preview_pipeline;
- prev = gst_camerabin_preview_convert (data, buffer);
-
- GST_DEBUG_OBJECT (camera, "preview created: %p", prev);
-
- if (prev) {
- s = gst_structure_new (PREVIEW_MESSAGE_NAME,
- "buffer", GST_TYPE_BUFFER, prev, NULL);
- gst_buffer_unref (prev);
-
- msg = gst_message_new_element (GST_OBJECT (camera), s);
-
- GST_DEBUG_OBJECT (camera, "sending message with preview image");
-
- if (gst_element_post_message (GST_ELEMENT (camera), msg) == FALSE) {
- GST_WARNING_OBJECT (camera,
- "This element has no bus, therefore no message sent!");
- }
- ret = TRUE;
- }
-
- return ret;
-}
-
-/*
- * gst_camerabin_have_img_buffer:
- * @pad: output-selector src pad leading to image bin
- * @buffer: still image frame
- * @u_data: camera bin object
- *
- * Buffer probe called before sending each buffer to image queue.
- * Generates and sends preview image as gst message if requested.
- */
-static gboolean
-gst_camerabin_have_img_buffer (GstPad * pad, GstMiniObject * obj,
- gpointer u_data)
-{
- GstCameraBin *camera = (GstCameraBin *) u_data;
-
- if (GST_IS_BUFFER (obj)) {
- GstBuffer *buffer = GST_BUFFER_CAST (obj);
- GstStructure *fn_ev_struct = NULL;
- GstPad *os_sink = NULL;
-
- GST_LOG ("got buffer %p with size %d", buffer, GST_BUFFER_SIZE (buffer));
-
- if (camera->preview_caps) {
- gst_camerabin_send_preview (camera, buffer);
- }
-
- /* Image filename should be set by now */
- if (g_str_equal (camera->filename->str, "")) {
- GST_DEBUG_OBJECT (camera, "filename not set, dropping buffer");
- CAMERABIN_PROCESSING_DEC_UNLOCKED (camera);
- goto done;
- }
-
- gst_camerabin_rewrite_tags (camera);
-
- /* Send a custom event which tells the filename to image queue */
- /* NOTE: This needs to be THE FIRST event to be sent to queue for
- every image. It triggers imgbin state change to PLAYING. */
- fn_ev_struct = gst_structure_new ("img-filename",
- "filename", G_TYPE_STRING, camera->filename->str, NULL);
- GST_DEBUG_OBJECT (camera, "sending filename event to image queue");
- gst_camerabin_send_img_queue_custom_event (camera, fn_ev_struct);
-
- /* Add buffer probe to outputselector's sink pad. It sends
- EOS event to image queue. */
- os_sink = gst_element_get_static_pad (camera->src_out_sel, "sink");
- camera->image_captured_id = gst_pad_add_buffer_probe (os_sink,
- G_CALLBACK (gst_camerabin_have_src_buffer), camera);
- gst_object_unref (os_sink);
-
- done:
-
- /* HACK: v4l2camsrc changes to view finder resolution automatically
- after one captured still image */
- gst_camerabin_finish_image_capture (camera);
-
- GST_DEBUG_OBJECT (camera, "image captured, switching to viewfinder");
-
- gst_camerabin_reset_to_view_finder (camera);
-
- GST_DEBUG_OBJECT (camera, "switched back to viewfinder");
-
- return TRUE;
- } else if (GST_IS_EVENT (obj)) {
- GstEvent *event = GST_EVENT_CAST (obj);
-
- GST_DEBUG_OBJECT (camera, "Received event in image pipeline");
-
- /* forward tag events to preview pipeline */
- if (camera->preview_caps && GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
- GstCameraBinPreviewPipelineData *data;
-
- data = (camera->mode == MODE_IMAGE) ?
- camera->preview_pipeline : camera->video_preview_pipeline;
- gst_camerabin_preview_send_event (data, gst_event_ref (event));
- }
- }
-
- return TRUE;
-}
-
-/*
- * gst_camerabin_have_vid_buffer:
- * @pad: output-selector src pad leading to video bin
- * @buffer: buffer pushed to the pad
- * @u_data: camerabin object
- *
- * Buffer probe for src pad leading to video bin.
- * Sends eos event to video bin if stop requested and drops
- * all buffers after this.
- */
-static gboolean
-gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer,
- gpointer u_data)
-{
- GstCameraBin *camera = (GstCameraBin *) u_data;
- gboolean ret = TRUE;
- GST_LOG ("got video buffer %p with size %d",
- buffer, GST_BUFFER_SIZE (buffer));
-
- if (!camera->video_preview_buffer && camera->video_preview_caps) {
- GST_DEBUG ("storing video preview %p", buffer);
- camera->video_preview_buffer = gst_buffer_copy (buffer);
- }
-
- if (G_UNLIKELY (camera->stop_requested)) {
- gst_camerabin_send_video_eos (camera);
- ret = FALSE; /* Drop buffer */
- }
-
- return ret;
-}
-
-/*
- * gst_camerabin_have_src_buffer:
- * @pad: output-selector sink pad which receives frames from video source
- * @buffer: buffer pushed to the pad
- * @u_data: camerabin object
- *
- * Buffer probe for sink pad. It sends custom eos event to image queue and
- * notifies application by sending a "image-captured" message to GstBus.
- * This probe is installed after image has been captured and it disconnects
- * itself after EOS has been sent.
- */
-static gboolean
-gst_camerabin_have_src_buffer (GstPad * pad, GstBuffer * buffer,
- gpointer u_data)
-{
- GstCameraBin *camera = (GstCameraBin *) u_data;
- GstMessage *msg;
-
- GST_LOG_OBJECT (camera, "got image buffer %p with size %d",
- buffer, GST_BUFFER_SIZE (buffer));
-
- g_mutex_lock (camera->capture_mutex);
- camera->capturing = FALSE;
- g_cond_signal (camera->cond);
- g_mutex_unlock (camera->capture_mutex);
-
- msg = gst_message_new_element (GST_OBJECT (camera),
- gst_structure_new (IMG_CAPTURED_MESSAGE_NAME, NULL));
-
- GST_DEBUG_OBJECT (camera, "sending 'image captured' message");
-
- if (gst_element_post_message (GST_ELEMENT (camera), msg) == FALSE) {
- GST_WARNING_OBJECT (camera,
- "This element has no bus, therefore no message sent!");
- }
-
- /* We can't send real EOS event, since it would switch the image queue
- into "draining mode". Therefore we send our own custom eos and
- catch & drop it later in queue's srcpad data probe */
- GST_DEBUG_OBJECT (camera, "sending img-eos to image queue");
- gst_camerabin_send_img_queue_custom_event (camera,
- gst_structure_new ("img-eos", NULL));
-
- /* Prevent video source from pushing frames until we want them */
- GST_OBJECT_LOCK (camera);
- if (camera->block_viewfinder_trigger) {
- gst_pad_set_blocked_async (camera->pad_src_view, TRUE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
- }
- GST_OBJECT_UNLOCK (camera);
-
- /* our work is done, disconnect */
- gst_pad_remove_buffer_probe (pad, camera->image_captured_id);
-
- /* Image captured, notify that preparing a new capture is possible */
- g_object_notify (G_OBJECT (camera), "ready-for-capture");
-
- return TRUE;
-}
-
-/*
- * gst_camerabin_have_queue_data:
- * @pad: image queue src pad leading to image bin
- * @mini_obj: buffer or event pushed to the pad
- * @u_data: camerabin object
- *
- * Buffer probe for image queue src pad leading to image bin. It sets imgbin
- * into PLAYING mode when image buffer is passed to it. This probe also
- * monitors our internal custom events and handles them accordingly.
- */
-static gboolean
-gst_camerabin_have_queue_data (GstPad * pad, GstMiniObject * mini_obj,
- gpointer u_data)
-{
- GstCameraBin *camera = (GstCameraBin *) u_data;
- gboolean ret = TRUE;
-
- if (GST_IS_BUFFER (mini_obj)) {
- GstEvent *tagevent;
-
- GST_LOG_OBJECT (camera, "queue sending image buffer to imagebin");
-
- tagevent = gst_event_new_tag (gst_tag_list_copy (camera->event_tags));
- gst_element_send_event (camera->imgbin, tagevent);
- gst_tag_list_free (camera->event_tags);
- camera->event_tags = gst_tag_list_new ();
- } else if (GST_IS_EVENT (mini_obj)) {
- const GstStructure *evs;
- GstEvent *event;
-
- event = GST_EVENT_CAST (mini_obj);
- evs = gst_event_get_structure (event);
-
- GST_LOG_OBJECT (camera, "got event %s", GST_EVENT_TYPE_NAME (event));
-
- if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
- GstTagList *tlist;
-
- GST_DEBUG_OBJECT (camera, "queue sending taglist to image pipeline");
- gst_event_parse_tag (event, &tlist);
- gst_tag_list_insert (camera->event_tags, tlist, GST_TAG_MERGE_REPLACE);
- ret = FALSE;
- } else if (evs && gst_structure_has_name (evs, "img-filename")) {
- const gchar *fname;
-
- GST_DEBUG_OBJECT (camera, "queue setting image filename to imagebin");
- fname = gst_structure_get_string (evs, "filename");
- g_object_set (G_OBJECT (camera->imgbin), "filename", fname, NULL);
-
- /* imgbin fails to start unless the filename is set or file
- cannot be written */
- if (gst_element_set_state (camera->imgbin, GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_ELEMENT_ERROR (camera, CORE, STATE_CHANGE,
- ("Setting imagebin to PLAYING failed"), (NULL));
- gst_element_set_state (camera->imgbin, GST_STATE_NULL);
- } else {
- GST_LOG_OBJECT (camera, "Set imagebin to PLAYING");
- }
-
- ret = FALSE;
- } else if (evs && gst_structure_has_name (evs, "img-eos")) {
- GST_DEBUG_OBJECT (camera, "queue sending EOS to image pipeline");
- gst_pad_set_blocked_async (camera->pad_src_queue, TRUE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
- gst_element_send_event (camera->imgbin, gst_event_new_eos ());
- ret = FALSE;
- }
- }
-
- return ret;
-}
-
-/*
- * gst_camerabin_reset_to_view_finder:
- * @camera: camerabin object
- *
- * Stop capturing and set camerabin to view finder mode.
- * Reset capture counters and flags.
- */
-static void
-gst_camerabin_reset_to_view_finder (GstCameraBin * camera)
-{
- GstStateChangeReturn state_ret;
- GST_DEBUG_OBJECT (camera, "resetting");
-
- if (camera->src_out_sel) {
- /* Set selector to forward data to view finder */
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
- "active-pad", camera->pad_src_view, NULL);
- }
-
- /* Set video bin to READY state */
- if (camera->active_bin == camera->vidbin) {
- state_ret = gst_element_set_state (camera->active_bin, GST_STATE_READY);
- if (state_ret == GST_STATE_CHANGE_FAILURE) {
- GST_WARNING_OBJECT (camera, "state change failed");
- gst_element_set_state (camera->active_bin, GST_STATE_NULL);
- camera->active_bin = NULL;
- }
- }
-
- /* Reset counters and flags */
- camera->stop_requested = FALSE;
- camera->paused = FALSE;
- camera->eos_handled = FALSE;
- if (camera->video_preview_buffer) {
- gst_buffer_unref (camera->video_preview_buffer);
- camera->video_preview_buffer = NULL;
- }
-
- /* Enable view finder mode in v4l2camsrc */
- if (camera->src_vid_src &&
- g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
- "capture-mode")) {
- g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 0, NULL);
- }
-
- GST_DEBUG_OBJECT (camera, "reset done");
-}
-
-/*
- * gst_camerabin_do_stop:
- * @camera: camerabin object
- *
- * Raise flag to indicate to image and video bin capture stop.
- * Stopping paused video recording handled as a special case.
- * Wait for ongoing capturing to finish.
- */
-static void
-gst_camerabin_do_stop (GstCameraBin * camera)
-{
- gboolean video_preview_sent = FALSE;
- g_mutex_lock (camera->capture_mutex);
- if (camera->capturing) {
- GST_DEBUG_OBJECT (camera, "mark stop");
- camera->stop_requested = TRUE;
-
- /* Post preview image ASAP and don't wait that video recording
- finishes as it may take time. */
- if (camera->video_preview_buffer) {
- gst_camerabin_send_preview (camera, camera->video_preview_buffer);
- video_preview_sent = TRUE;
- }
-
- /* Take special care when stopping paused video capture */
- if ((camera->active_bin == camera->vidbin) && camera->paused) {
- /* Send eos event to video bin before setting it to playing */
- gst_camerabin_send_video_eos (camera);
- /* We must change to playing now in order to get video bin eos events
- and buffered data through and finish recording properly */
- gst_element_set_state (GST_ELEMENT (camera->vidbin), GST_STATE_PLAYING);
- camera->paused = FALSE;
- }
-
- GST_DEBUG_OBJECT (camera, "waiting for capturing to finish");
- g_cond_wait (camera->cond, camera->capture_mutex);
- GST_DEBUG_OBJECT (camera, "capturing finished");
-
- if (camera->video_preview_buffer) {
- /* Double check that preview image has been sent. This is useful
- in a corner case where capture-stop is issued immediately after
- start before a single video buffer is actually recorded */
- if (video_preview_sent == FALSE) {
- gst_camerabin_send_preview (camera, camera->video_preview_buffer);
- }
- }
- }
- g_mutex_unlock (camera->capture_mutex);
-}
-
-/*
- * gst_camerabin_default_signal_img_done:
- * @camera: camerabin object
- * @fname: filename of the recently saved image
- *
- * Default handler for #GstCameraBin::image-done signal,
- * stops always capture.
- *
- * Returns: FALSE always
- */
-static gboolean
-gst_camerabin_default_signal_img_done (GstCameraBin * camera,
- const gchar * fname)
-{
- return FALSE;
-}
-
-/*
- * gst_camerabin_set_allowed_framerate:
- * @camera: camerabin 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
-gst_camerabin_set_allowed_framerate (GstCameraBin * camera,
- GstCaps * filter_caps)
-{
- 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 (camera, "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 (camera->src_vid_src);
- if (format) {
- GST_DEBUG_OBJECT (camera,
- "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 (camera, "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_camerabin_get_allowed_input_caps (camera);
- intersect = gst_caps_intersect (allowed_caps, tmp_caps);
- GST_INFO_OBJECT (camera, "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_camerabin_find_better_framerate (camera, 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);
- }
-}
-
-
-/**
- * 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;
-}
-
-/*
- * gst_camerabin_find_better_framerate:
- * @camera: camerabin 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
- */
-static const GValue *
-gst_camerabin_find_better_framerate (GstCameraBin * camera, GstStructure * st,
- const GValue * orig_framerate)
-{
- const GValue *framerate = NULL;
- guint i, i_best, list_size;
- gint res, comparison;
-
- if (camera->night_mode) {
- GST_LOG_OBJECT (camera, "finding min framerate in %" GST_PTR_FORMAT, st);
- comparison = GST_VALUE_LESS_THAN;
- } else {
- GST_LOG_OBJECT (camera, "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 (camera, "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 (camera, "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 (camera->night_mode) {
- GST_LOG_OBJECT (camera, "getting min framerate from range");
- framerate = gst_value_get_fraction_range_min (framerate);
- } else {
- GST_LOG_OBJECT (camera, "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 (camera, "original framerate was the best");
- framerate = orig_framerate;
- }
- }
-
- return framerate;
-}
-
-/*
- * gst_camerabin_update_aspect_filter:
- * @camera: camerabin 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
-gst_camerabin_update_aspect_filter (GstCameraBin * camera, GstCaps * new_caps)
-{
- 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);
- }
-}
-
-/*
- * gst_camerabin_finish_image_capture:
- * @camera: camerabin object
- *
- * Perform finishing operations after image capture is done and
- * returning back to view finder mode.
- */
-static void
-gst_camerabin_finish_image_capture (GstCameraBin * camera)
-{
- if (camera->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 (camera->src_zoom_crop) {
- GST_DEBUG_OBJECT (camera, "resetting crop in camerabin");
- g_object_set (camera->src_zoom_crop, "left", 0, "right", 0,
- "top", 0, "bottom", 0, NULL);
- }
- camera->base_crop_left = 0;
- camera->base_crop_right = 0;
- camera->base_crop_top = 0;
- camera->base_crop_bottom = 0;
- gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps);
- }
-}
-
-/*
- * gst_camerabin_adapt_image_capture:
- * @camera: camerabin 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
-gst_camerabin_adapt_image_capture (GstCameraBin * camera, GstCaps * in_caps)
-{
- 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 (camera, "in caps: %" GST_PTR_FORMAT, in_caps);
- GST_LOG_OBJECT (camera, "requested caps: %" GST_PTR_FORMAT,
- camera->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 (camera->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 (camera, "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 (!(camera->flags & GST_CAMERABIN_FLAG_SOURCE_RESIZE)) {
- GST_DEBUG_OBJECT (camera,
- "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 (camera, "new image capture caps: %" GST_PTR_FORMAT, new_st);
-
- /* Crop if requested aspect ratio differs from incoming frame aspect ratio */
- if (camera->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);
- camera->base_crop_top = crop / 2;
- camera->base_crop_bottom = crop / 2;
- } else {
- crop = in_width - (req_width * ratio_h);
- camera->base_crop_left = crop / 2;
- camera->base_crop_right += crop / 2;
- }
-
- GST_INFO_OBJECT (camera,
- "setting base crop: left:%d, right:%d, top:%d, bottom:%d",
- camera->base_crop_left, camera->base_crop_right, camera->base_crop_top,
- camera->base_crop_bottom);
- g_object_set (G_OBJECT (camera->src_zoom_crop), "top",
- camera->base_crop_top, "bottom", camera->base_crop_bottom, "left",
- camera->base_crop_left, "right", camera->base_crop_right, NULL);
- }
-
- /* Update capsfilters */
- gst_caps_replace (&camera->image_capture_caps,
- gst_caps_new_full (new_st, NULL));
- gst_camerabin_set_capsfilter_caps (camera, camera->image_capture_caps);
-
- /* Adjust the capsfilter before crop and videoscale elements if necessary */
- if (in_width == camera->width && in_height == camera->height) {
- GST_DEBUG_OBJECT (camera, "no adaptation with resolution needed");
- } else {
- GST_DEBUG_OBJECT (camera,
- "changing %" GST_PTR_FORMAT " from %dx%d to %dx%d", camera->src_filter,
- camera->width, camera->height, in_width, in_height);
- /* Apply the width and height to filter caps */
- g_object_get (G_OBJECT (camera->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 (camera->src_filter), "caps", filter_caps, NULL);
- gst_caps_unref (filter_caps);
- }
-}
-
-/*
- * gst_camerabin_handle_scene_mode:
- * @camera: camerabin object
- * scene_mode: scene mode
- *
- * Handle scene mode if night mode was selected/deselected in video-source
- *
- */
-static void
-gst_camerabin_handle_scene_mode (GstCameraBin * camera, GstSceneMode scene_mode)
-{
- if (scene_mode == GST_PHOTOGRAPHY_SCENE_MODE_NIGHT) {
- if (!camera->night_mode) {
- GST_DEBUG ("enabling night mode, lowering fps");
- /* Make camerabin select the lowest allowed frame rate */
- camera->night_mode = TRUE;
- /* Remember frame rate before setting night mode */
- camera->pre_night_fps_n = camera->fps_n;
- camera->pre_night_fps_d = camera->fps_d;
- do_set_video_resolution_fps (camera, camera->width, camera->height, 0, 1);
- } else {
- GST_DEBUG ("night mode already enabled");
- }
- } else {
- if (camera->night_mode) {
- GST_DEBUG ("disabling night mode, restoring fps to %d/%d",
- camera->pre_night_fps_n, camera->pre_night_fps_d);
- camera->night_mode = FALSE;
- do_set_video_resolution_fps (camera, camera->width, camera->height,
- camera->pre_night_fps_n, camera->pre_night_fps_d);
- }
- }
-}
-
-/*
- * gst_camerabin_scene_mode_notify_cb:
- * @video_source: videosrc object
- * @pspec: GParamSpec for property
- * @user_data: camerabin object
- *
- * Update framerate if scene mode was updated in video-source
- *
- */
-static void
-gst_camerabin_scene_mode_notify_cb (GObject * video_source, GParamSpec * pspec,
- gpointer user_data)
-{
- GstSceneMode scene_mode;
- const gchar *name = g_param_spec_get_name (pspec);
- GstCameraBin *camera = GST_CAMERABIN (user_data);
-
- g_object_get (video_source, name, &scene_mode, NULL);
- gst_camerabin_handle_scene_mode (camera, scene_mode);
-}
-
- /*
- * gst_camerabin_zoom_notify_cb:
- * @video_source: videosrc object
- * @pspec: GParamSpec for property
- * @user_data: camerabin object
- *
- * Update zoom value if video-source updated its zoom
- *
- */
-static void
-gst_camerabin_zoom_notify_cb (GObject * video_source, GParamSpec * pspec,
- gpointer user_data)
-{
- gfloat zoom;
- const gchar *name = g_param_spec_get_name (pspec);
- GstCameraBin *camera = GST_CAMERABIN (user_data);
-
- g_object_get (video_source, name, &zoom, NULL);
-
- camera->zoom = zoom;
- g_object_notify (G_OBJECT (camera), "zoom");
-}
-
-/*
- * gst_camerabin_monitor_video_source_properties:
- * @camera: camerabin object
- *
- * Monitor notify signals from video source photography interface
- * property scene mode.
- *
- */
-static void
-gst_camerabin_monitor_video_source_properties (GstCameraBin * camera)
-{
- GST_DEBUG_OBJECT (camera, "checking for photography interface support");
- if (GST_IS_ELEMENT (camera->src_vid_src) &&
- gst_element_implements_interface (camera->src_vid_src,
- GST_TYPE_PHOTOGRAPHY)) {
- gint scene_mode;
- GST_DEBUG_OBJECT (camera,
- "connecting to %" GST_PTR_FORMAT " - notify::scene-mode",
- camera->src_vid_src);
- g_signal_connect (G_OBJECT (camera->src_vid_src), "notify::scene-mode",
- (GCallback) gst_camerabin_scene_mode_notify_cb, camera);
- g_object_get (G_OBJECT (camera->src_vid_src), "scene-mode", &scene_mode,
- NULL);
- camera->night_mode = scene_mode == GST_PHOTOGRAPHY_SCENE_MODE_NIGHT;
-
- GST_DEBUG_OBJECT (camera,
- "connecting to %" GST_PTR_FORMAT " - notify::zoom",
- camera->src_vid_src);
- g_signal_connect (G_OBJECT (camera->src_vid_src), "notify::zoom",
- (GCallback) gst_camerabin_zoom_notify_cb, camera);
- }
-}
-
-/*
- * gst_camerabin_configure_format:
- * @camera: camerabin object
- * @caps: caps describing new format
- *
- * Configure internal video format for camerabin.
- *
- */
-static void
-gst_camerabin_configure_format (GstCameraBin * camera, GstCaps * caps)
-{
- GstStructure *st;
-
- st = gst_caps_get_structure (caps, 0);
-
- gst_structure_get_int (st, "width", &camera->width);
- gst_structure_get_int (st, "height", &camera->height);
-
- if (gst_structure_has_field_typed (st, "framerate", GST_TYPE_FRACTION)) {
- gst_structure_get_fraction (st, "framerate", &camera->fps_n,
- &camera->fps_d);
- }
-}
-
-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;
-}
-
-/*
-* gst_camerabin_change_viewfinder_blocking:
-* @camera: camerabin object
-* @blocked: new viewfinder blocking state
-*
-* Handle viewfinder blocking parameter change.
-*/
-static void
-gst_camerabin_change_viewfinder_blocking (GstCameraBin * camera,
- gboolean blocked)
-{
- gboolean old_value;
-
- GST_OBJECT_LOCK (camera);
- old_value = camera->block_viewfinder_prop;
- camera->block_viewfinder_prop = blocked;
- if (blocked == FALSE) {
- camera->block_viewfinder_trigger = FALSE;
- }
- GST_OBJECT_UNLOCK (camera);
-
- /* "block_viewfinder_prop" is now set and will be checked after capture */
- GST_DEBUG_OBJECT (camera, "viewfinder blocking set to %d, was %d",
- camera->block_viewfinder_prop, old_value);
-
- if (old_value == blocked)
- return;
-
- if (!blocked && camera->pad_src_view
- && gst_pad_is_blocked (camera->pad_src_view)) {
- /* Unblock viewfinder: the pad is blocked and we need to unblock it */
- gst_pad_set_blocked_async (camera->pad_src_view, FALSE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
- }
-}
-
-/*
- * GObject callback functions implementation
- */
-
-static void
-gst_camerabin_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- gst_tag_register_musicbrainz_tags ();
-
- gst_element_class_set_details_simple (element_class, "Camera Bin",
- "Generic/Bin/Camera",
- "Handle lot of features present in DSC",
- "Nokia Corporation <multimedia@maemo.org>, "
- "Edgard Lima <edgard.lima@indt.org.br>");
-}
-
-static void
-gst_camerabin_class_init (GstCameraBinClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
- GstBinClass *gstbin_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gstelement_class = GST_ELEMENT_CLASS (klass);
- gstbin_class = GST_BIN_CLASS (klass);
-
- /* gobject */
-
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_camerabin_dispose);
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_camerabin_finalize);
-
- gobject_class->set_property = gst_camerabin_set_property;
- gobject_class->get_property = gst_camerabin_get_property;
-
- /**
- * GstCameraBin:filename:
- *
- * Set filename for the still image capturing or video capturing.
- */
-
- g_object_class_install_property (gobject_class, ARG_FILENAME,
- g_param_spec_string ("filename", "Filename",
- "Filename of the image or video to save", "",
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:mode:
- *
- * Set the mode of operation: still image capturing or video recording.
- * Setting the mode will create and destroy image bin or video bin elements
- * according to the mode. You can set this property at any time, changing
- * the mode will stop ongoing capture.
- */
-
- g_object_class_install_property (gobject_class, ARG_MODE,
- g_param_spec_enum ("mode", "Mode",
- "The capture mode (still image capture or video recording)",
- GST_TYPE_CAMERABIN_MODE, DEFAULT_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:flags
- *
- * Control the behaviour of camerabin.
- */
- g_object_class_install_property (gobject_class, ARG_FLAGS,
- g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
- GST_TYPE_CAMERABIN_FLAGS, DEFAULT_FLAGS,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:mute:
- *
- * Mute audio in video recording mode.
- * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING.
- */
-
- g_object_class_install_property (gobject_class, ARG_MUTE,
- g_param_spec_boolean ("mute", "Mute",
- "True to mute the recording. False to record with audio",
- ARG_DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:zoom:
- *
- * Set up the zoom applied to the frames.
- * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING.
- */
-
- g_object_class_install_property (gobject_class, ARG_ZOOM,
- g_param_spec_float ("zoom", "Zoom",
- "The zoom. 1.0 for 1x, 2.0 for 2x and so on",
- MIN_ZOOM, MAX_ZOOM, DEFAULT_ZOOM,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:image-post-processing:
- *
- * Set up an element to do image post processing.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
- g_object_class_install_property (gobject_class, ARG_IMAGE_POST,
- g_param_spec_object ("image-post-processing",
- "Image post processing element",
- "Image Post-Processing GStreamer element (default is NULL)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:image-encoder:
- *
- * Set up an image encoder (for example, jpegenc or pngenc) element.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_IMAGE_ENC,
- g_param_spec_object ("image-encoder", "Image encoder",
- "Image encoder GStreamer element (default is jpegenc)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:image-formatter:
- *
- * Set up an image formatter (for example, jifmux) element.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_IMAGE_FORMATTER,
- g_param_spec_object ("image-formatter", "Image formatter",
- "Image formatter GStreamer element (default is jifmux)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-post-processing:
- *
- * Set up an element to do video post processing.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIDEO_POST,
- g_param_spec_object ("video-post-processing",
- "Video post processing element",
- "Video post processing GStreamer element (default is NULL)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-encoder:
- *
- * Set up a video encoder element.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIDEO_ENC,
- g_param_spec_object ("video-encoder", "Video encoder",
- "Video encoder GStreamer element (default is theoraenc)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:audio-encoder:
- *
- * Set up an audio encoder element.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_AUDIO_ENC,
- g_param_spec_object ("audio-encoder", "Audio encoder",
- "Audio encoder GStreamer element (default is vorbisenc)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-muxer:
- *
- * Set up a video muxer element.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIDEO_MUX,
- g_param_spec_object ("video-muxer", "Video muxer",
- "Video muxer GStreamer element (default is oggmux)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:viewfinder-sink:
- *
- * Set up a sink element to render frames in view finder.
- * By default "autovideosink" or DEFAULT_VIDEOSINK will be used.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VF_SINK,
- g_param_spec_object ("viewfinder-sink", "Viewfinder sink",
- "Viewfinder sink GStreamer element (NULL = default video sink)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-source:
- *
- * Set up a video source element.
- * By default "autovideosrc" or DEFAULT_VIDEOSRC will be used.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIDEO_SRC,
- g_param_spec_object ("video-source", "Video source element",
- "Video source GStreamer element (NULL = default video src)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstCameraBin:audio-source:
- *
- * Set up an audio source element.
- * By default "autoaudiosrc" or DEFAULT_AUDIOSRC will be used.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_AUDIO_SRC,
- g_param_spec_object ("audio-source", "Audio source element",
- "Audio source GStreamer element (NULL = default audio src)",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-source-filter:
- *
- * Set up optional video filter element, all frames from video source
- * will be processed by this element. e.g. An application might add
- * image enhancers/parameter adjustment filters here to improve captured
- * image/video results, or add analyzers to give feedback on capture
- * the application.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIDEO_SOURCE_FILTER,
- g_param_spec_object ("video-source-filter", "video source filter element",
- "Optional video filter GStreamer element, filters all frames from"
- "the video source", GST_TYPE_ELEMENT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-source-caps:
- *
- * The allowed modes of operation of the video source. Have in mind that it
- * doesn't mean #GstCameraBin can operate in all those modes,
- * it depends also on the other elements in the pipeline. Remember to
- * gst_caps_unref after using it.
- */
-
- g_object_class_install_property (gobject_class, ARG_INPUT_CAPS,
- g_param_spec_boxed ("video-source-caps", "Video source caps",
- "The allowed modes of the video source operation",
- GST_TYPE_CAPS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:filter-caps:
- *
- * Caps applied to capsfilter element after videosrc [ ! ffmpegcsp ].
- * You can use this e.g. to make sure video color format matches with
- * encoders and other elements configured to camerabin and/or change
- * resolution and frame rate.
- */
-
- g_object_class_install_property (gobject_class, ARG_FILTER_CAPS,
- g_param_spec_boxed ("filter-caps", "Filter caps",
- "Filter video data coming from videosrc element",
- GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:preview-caps:
- *
- * If application wants to receive a preview image, it needs to
- * set this property to depict the desired image format caps. When
- * this property is not set (NULL), message containing the preview
- * image is not sent.
- */
-
- g_object_class_install_property (gobject_class, ARG_PREVIEW_CAPS,
- g_param_spec_boxed ("preview-caps", "Preview caps",
- "Caps defining the preview image format",
- GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:preview-source-filter:
- * Set up preview filter element, all frames coming from appsrc
- * element will be processed by this element.
- * Applications can use this to overlay text/images for preview frame,
- * for example.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_PREVIEW_SOURCE_FILTER,
- g_param_spec_object ("preview-source-filter",
- "preview source filter element",
- "Optional preview source filter GStreamer element",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:viewfinder-filter:
- * Set up viewfinder filter element, all frames going to viewfinder sink
- * element will be processed by this element.
- * Applications can use this to overlay text/images in the screen, or
- * plug facetracking algorithms, for example.
- * This property can only be set while #GstCameraBin is in NULL state.
- * The ownership of the element will be taken by #GstCameraBin.
- */
-
- g_object_class_install_property (gobject_class, ARG_VIEWFINDER_FILTER,
- g_param_spec_object ("viewfinder-filter", "viewfinder filter element",
- "viewfinder filter GStreamer element",
- GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:block-after-capture:
- *
- * Block viewfinder after capture.
- * If it is TRUE when 'capture-start' is issued, camerabin will prepare to
- * block and freeze the viewfinder after capturing. Setting it to FALSE will
- * abort the blocking if it hasn't happened yet, or will enable again the
- * viewfinder if it is already blocked. Note that setting this property
- * to TRUE after 'capture-start' will only work for the next capture. This
- * makes possible for applications to set the property to FALSE to abort
- * the current blocking and already set it back to TRUE again to block at
- * the next capture.
- *
- * This is useful if application wants to display the preview image
- * and running the viewfinder at the same time would be just a waste of
- * CPU cycles.
- */
-
- g_object_class_install_property (gobject_class, ARG_BLOCK_VIEWFINDER,
- g_param_spec_boolean ("block-after-capture",
- "Block viewfinder after capture",
- "Block viewfinder after capturing an image or video",
- DEFAULT_BLOCK_VIEWFINDER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:image-capture-width:
- *
- * The width to be used when capturing still images. If 0, the
- * viewfinder's width will be used.
- */
- g_object_class_install_property (gobject_class, ARG_IMAGE_CAPTURE_WIDTH,
- g_param_spec_int ("image-capture-width",
- "The width used for image capture",
- "The width used for image capture", 0, G_MAXINT16,
- DEFAULT_CAPTURE_WIDTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:image-capture-height:
- *
- * The height to be used when capturing still images. If 0, the
- * viewfinder's height will be used.
- */
- g_object_class_install_property (gobject_class, ARG_IMAGE_CAPTURE_HEIGHT,
- g_param_spec_int ("image-capture-height",
- "The height used for image capture",
- "The height used for image capture", 0, G_MAXINT16,
- DEFAULT_CAPTURE_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-capture-width:
- *
- * The width to be used when capturing video.
- */
- g_object_class_install_property (gobject_class, ARG_VIDEO_CAPTURE_WIDTH,
- g_param_spec_int ("video-capture-width",
- "The width used for video capture",
- "The width used for video capture", 0, G_MAXINT16,
- DEFAULT_CAPTURE_WIDTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-capture-height:
- *
- * The height to be used when capturing video.
- */
- g_object_class_install_property (gobject_class, ARG_VIDEO_CAPTURE_HEIGHT,
- g_param_spec_int ("video-capture-height",
- "The height used for video capture",
- "The height used for video capture", 0, G_MAXINT16,
- DEFAULT_CAPTURE_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:video-capture-framerate:
- *
- * The framerate to be used when capturing video.
- */
- g_object_class_install_property (gobject_class, ARG_VIDEO_CAPTURE_FRAMERATE,
- gst_param_spec_fraction ("video-capture-framerate",
- "The framerate used for video capture",
- "The framerate used for video capture", 0, 1, G_MAXINT32, 1,
- DEFAULT_FPS_N, DEFAULT_FPS_D,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:ready-for-capture:
- *
- * When TRUE new capture can be prepared. If FALSE capturing is ongoing
- * and starting a new capture immediately is not possible.
- */
-
- g_object_class_install_property (gobject_class, ARG_READY_FOR_CAPTURE,
- g_param_spec_boolean ("ready-for-capture",
- "Indicates if preparing a new capture is possible",
- "Indicates if preparing a new capture is possible",
- DEFAULT_READY_FOR_CAPTURE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin:idle:
- *
- * When TRUE no capturing/encoding/saving is running and it is safe to set
- * camerabin to NULL to release resources without losing data.
- *
- * In case of errors, this property is made unreliable. Set the pipeline
- * back to READY or NULL to make it reliable again.
- */
- g_object_class_install_property (gobject_class, ARG_IDLE,
- g_param_spec_boolean ("idle",
- "Indicates if data is being processed (recording/capturing/saving)",
- "Indicates if data is being processed (recording/capturing/saving)",
- TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstCameraBin::capture-start:
- * @camera: the camera bin element
- *
- * Starts image capture or video recording depending on the Mode.
- * If there is a capture already going on, does nothing.
- * Resumes video recording if it has been paused.
- */
-
- camerabin_signals[CAPTURE_START_SIGNAL] =
- g_signal_new ("capture-start",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstCameraBinClass, capture_start),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- /**
- * GstCameraBin::capture-stop:
- * @camera: the camera bin element
- *
- * Stops still image preview, continuous image capture and video
- * recording and returns to the view finder mode.
- */
-
- camerabin_signals[CAPTURE_STOP_SIGNAL] =
- g_signal_new ("capture-stop",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstCameraBinClass, capture_stop),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- /**
- * GstCameraBin::capture-pause:
- * @camera: the camera bin element
- *
- * Pauses video recording or resumes paused video recording.
- * If in image mode or not recording, does nothing.
- */
-
- camerabin_signals[CAPTURE_PAUSE_SIGNAL] =
- g_signal_new ("capture-pause",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstCameraBinClass, capture_pause),
- NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
- /**
- * GstCameraBin::set-video-resolution-fps:
- * @camera: the camera bin element
- * @width: number of horizontal pixels
- * @height: number of vertical pixels
- * @fps_n: frames per second numerator
- * @fps_d: frames per second denominator
- *
- * Changes the frame resolution and frames per second of the video source.
- * The application must be aware of the resolutions supported by the camera.
- * Supported resolutions and frame rates can be get using input-caps property.
- *
- * Setting @fps_n or @fps_d to 0 configures maximum framerate for the
- * given resolution, unless in night mode when minimum is configured.
- *
- * This is the same as setting the 'video-capture-width',
- * 'video-capture-height' and 'video-capture-framerate' properties, but it
- * already updates the caps to force use this resolution and framerate.
- */
-
- camerabin_signals[SET_VIDEO_RESOLUTION_FPS_SIGNAL] =
- g_signal_new ("set-video-resolution-fps",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstCameraBinClass, set_video_resolution_fps),
- NULL, NULL, __gst_camerabin_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4,
- G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
-
- /**
- * GstCameraBin::set-image-resolution:
- * @camera: the camera bin element
- * @width: number of horizontal pixels
- * @height: number of vertical pixels
- *
- * Changes the resolution used for still image capture.
- * Does not affect view finder mode and video recording.
- *
- * This actually sets the 'image-capture-width' and 'image-capture-height'
- * properties.
- */
-
- camerabin_signals[SET_IMAGE_RESOLUTION_SIGNAL] =
- g_signal_new ("set-image-resolution",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstCameraBinClass, set_image_resolution),
- NULL, NULL, __gst_camerabin_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
- G_TYPE_INT, G_TYPE_INT);
-
- /**
- * GstCameraBin::image-done:
- * @camera: the camera bin element
- * @filename: the name of the file just saved
- *
- * Signal emitted when the file has just been saved.
- *
- * Don't call any #GstCameraBin method from this signal, if you do so there
- * will be a deadlock.
- */
-
- camerabin_signals[IMG_DONE_SIGNAL] =
- g_signal_new ("image-done", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstCameraBinClass, img_done),
- g_signal_accumulator_true_handled, NULL,
- __gst_camerabin_marshal_BOOLEAN__STRING, G_TYPE_BOOLEAN, 1,
- G_TYPE_STRING);
-
- klass->capture_start = gst_camerabin_capture_start;
- klass->capture_stop = gst_camerabin_capture_stop;
- klass->capture_pause = gst_camerabin_capture_pause;
- klass->set_video_resolution_fps = gst_camerabin_set_video_resolution_fps;
- klass->set_image_resolution = gst_camerabin_set_image_resolution;
-
- klass->img_done = gst_camerabin_default_signal_img_done;
-
- /* gstelement */
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_camerabin_change_state);
-
- gstelement_class->provide_clock =
- GST_DEBUG_FUNCPTR (gst_camerabin_provide_clock);
-
- /* gstbin */
- /* override handle_message to peek when video or image bin reaches eos */
- gstbin_class->handle_message =
- GST_DEBUG_FUNCPTR (gst_camerabin_handle_message_func);
-
-}
-
-/* initialize the new element
- * instantiate pads and add them to element
- * set functions
- * initialize structure
- */
-static void
-gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass)
-{
- /* GstElementClass *klass = GST_ELEMENT_GET_CLASS (camera); */
-
- camera->filename = g_string_new ("");
- camera->mode = DEFAULT_MODE;
- camera->flags = DEFAULT_FLAGS;
- camera->stop_requested = FALSE;
- camera->paused = FALSE;
- camera->capturing = FALSE;
- camera->night_mode = FALSE;
- camera->eos_handled = FALSE;
-
- camera->app_width = camera->width = DEFAULT_WIDTH;
- camera->app_height = camera->height = DEFAULT_HEIGHT;
- camera->app_fps_n = camera->fps_n = DEFAULT_FPS_N;
- camera->app_fps_d = camera->fps_d = DEFAULT_FPS_D;
- camera->image_capture_width = 0;
- camera->image_capture_height = 0;
- camera->base_crop_left = 0;
- camera->base_crop_right = 0;
- camera->base_crop_top = 0;
- camera->base_crop_bottom = 0;
-
- camera->event_tags = gst_tag_list_new ();
-
- camera->image_capture_caps = NULL;
- camera->view_finder_caps = NULL;
- camera->allowed_caps = NULL;
-
- camera->zoom = DEFAULT_ZOOM;
-
- /* concurrency control */
- camera->capture_mutex = g_mutex_new ();
- camera->cond = g_cond_new ();
- camera->idle_cond = g_cond_new ();
- camera->processing_counter = 0;
-
- /* pad names for output and input selectors */
- camera->pad_src_view = NULL;
- camera->pad_view_src = NULL;
- camera->pad_src_img = NULL;
- camera->pad_src_vid = NULL;
- camera->pad_view_vid = NULL;
-
- camera->video_preview_buffer = NULL;
- camera->preview_caps = NULL;
- camera->video_preview_caps = NULL;
-
- /* image capture bin */
- camera->imgbin = g_object_new (GST_TYPE_CAMERABIN_IMAGE, NULL);
- gst_object_ref (camera->imgbin);
-
- /* video capture bin */
- camera->vidbin = g_object_new (GST_TYPE_CAMERABIN_VIDEO, NULL);
- gst_object_ref (camera->vidbin);
-
- /* view finder elements */
- camera->view_in_sel = NULL;
- camera->view_scale = NULL;
- camera->aspect_filter = NULL;
- camera->view_sink = NULL;
-
- camera->app_vf_sink = NULL;
- camera->app_viewfinder_filter = NULL;
-
- /* preview elements */
- camera->app_preview_source_filter = NULL;
- camera->app_video_preview_source_filter = NULL;
-
- /* source elements */
- camera->src_vid_src = NULL;
- camera->src_filter = NULL;
- camera->src_zoom_crop = NULL;
- camera->src_zoom_scale = NULL;
- camera->src_zoom_filter = NULL;
- camera->src_out_sel = NULL;
-
- camera->app_video_filter = NULL;
- camera->app_vid_src = NULL;
-
- camera->active_bin = NULL;
-}
-
-static void
-gst_camerabin_dispose (GObject * object)
-{
- GstCameraBin *camera;
-
- camera = GST_CAMERABIN (object);
-
- GST_DEBUG_OBJECT (camera, "disposing");
-
- gst_element_set_state (camera->imgbin, GST_STATE_NULL);
- gst_object_unref (camera->imgbin);
-
- gst_element_set_state (camera->vidbin, GST_STATE_NULL);
- gst_object_unref (camera->vidbin);
-
- if (camera->preview_pipeline) {
- gst_camerabin_preview_destroy_pipeline (camera->preview_pipeline);
- camera->preview_pipeline = NULL;
- }
- if (camera->video_preview_pipeline) {
- gst_camerabin_preview_destroy_pipeline (camera->video_preview_pipeline);
- camera->video_preview_pipeline = NULL;
- }
-
- camerabin_destroy_elements (camera);
- camerabin_dispose_elements (camera);
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-gst_camerabin_finalize (GObject * object)
-{
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_camerabin_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstCameraBin *camera = GST_CAMERABIN (object);
-
- switch (prop_id) {
- case ARG_MUTE:
- gst_camerabin_video_set_mute (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_boolean (value));
- break;
- case ARG_ZOOM:
- camera->zoom = g_value_get_float (value);
- /* does not set it if in NULL, the src is not created yet */
- if (GST_STATE (camera) != GST_STATE_NULL)
- gst_camerabin_setup_zoom (camera);
- break;
- case ARG_MODE:
- gst_camerabin_change_mode (camera, g_value_get_enum (value));
- break;
- case ARG_FLAGS:
- gst_camerabin_set_flags (camera, g_value_get_flags (value));
- break;
- case ARG_FILENAME:
- gst_camerabin_change_filename (camera, g_value_get_string (value));
- break;
- case ARG_VIDEO_POST:
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next video bin NULL to READY state change");
- }
- gst_camerabin_video_set_post (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_object (value));
- break;
- case ARG_VIDEO_ENC:
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next video bin NULL to READY state change");
- }
- gst_camerabin_video_set_video_enc (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_object (value));
- break;
- case ARG_AUDIO_ENC:
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next video bin NULL to READY state change");
- }
- gst_camerabin_video_set_audio_enc (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_object (value));
- break;
- case ARG_VIDEO_MUX:
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next video bin NULL to READY state change");
- }
- gst_camerabin_video_set_muxer (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_object (value));
- break;
- case ARG_IMAGE_POST:
- if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next image bin NULL to READY state change");
- }
- gst_camerabin_image_set_postproc (GST_CAMERABIN_IMAGE (camera->imgbin),
- g_value_get_object (value));
- break;
- case ARG_IMAGE_ENC:
- if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next image bin NULL to READY state change");
- }
- gst_camerabin_image_set_encoder (GST_CAMERABIN_IMAGE (camera->imgbin),
- g_value_get_object (value));
- break;
- case ARG_IMAGE_FORMATTER:
- if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next image bin NULL to READY state change");
- }
- gst_camerabin_image_set_formatter (GST_CAMERABIN_IMAGE (camera->imgbin),
- g_value_get_object (value));
- break;
- case ARG_VF_SINK:
- if (GST_STATE (camera) != GST_STATE_NULL) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("camerabin must be in NULL state when setting the view finder element"),
- (NULL));
- } else {
- if (camera->app_vf_sink)
- gst_object_unref (camera->app_vf_sink);
- camera->app_vf_sink = g_value_get_object (value);
- if (camera->app_vf_sink)
- gst_object_ref (camera->app_vf_sink);
- }
- break;
- case ARG_VIDEO_SRC:
- if (GST_STATE (camera) != GST_STATE_NULL) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("camerabin must be in NULL state when setting the video source element"),
- (NULL));
- } else {
- if (camera->app_vid_src)
- gst_object_unref (camera->app_vid_src);
- camera->app_vid_src = g_value_get_object (value);
- if (camera->app_vid_src)
- gst_object_ref (camera->app_vid_src);
- }
- break;
- case ARG_AUDIO_SRC:
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- GST_WARNING_OBJECT (camera,
- "can't use set element until next video bin NULL to READY state change");
- }
- gst_camerabin_video_set_audio_src (GST_CAMERABIN_VIDEO (camera->vidbin),
- g_value_get_object (value));
- break;
- case ARG_VIDEO_SOURCE_FILTER:
- if (GST_STATE (camera) != GST_STATE_NULL) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("camerabin must be in NULL state when setting the video filter element"),
- (NULL));
- } else {
- if (camera->app_video_filter)
- gst_object_unref (camera->app_video_filter);
- camera->app_video_filter = g_value_dup_object (value);
- }
- break;
- case ARG_FILTER_CAPS:
- GST_OBJECT_LOCK (camera);
- gst_caps_replace (&camera->view_finder_caps,
- (GstCaps *) gst_value_get_caps (value));
- GST_OBJECT_UNLOCK (camera);
- if (!camera->view_finder_caps)
- camera->view_finder_caps =
- gst_caps_from_string (CAMERABIN_DEFAULT_VF_CAPS);
- gst_camerabin_configure_format (camera, camera->view_finder_caps);
- break;
- case ARG_PREVIEW_CAPS:
- {
- GstCameraBinPreviewPipelineData **prev_pipe = NULL;
- GstElement **preview_source_filter = NULL;
- GstCaps **prev_caps = NULL;
- GstCaps *new_caps = NULL;
-
- if (camera->mode == MODE_IMAGE) {
- prev_pipe = &camera->preview_pipeline;
- preview_source_filter = &camera->app_preview_source_filter;
- prev_caps = &camera->preview_caps;
- } else { /* MODE VIDEO */
- prev_pipe = &camera->video_preview_pipeline;
- preview_source_filter = &camera->app_video_preview_source_filter;
- prev_caps = &camera->video_preview_caps;
- }
-
- new_caps = (GstCaps *) gst_value_get_caps (value);
-
- if (prev_caps && !gst_caps_is_equal (*prev_caps, new_caps)) {
- GST_DEBUG_OBJECT (camera,
- "setting preview caps: %" GST_PTR_FORMAT, new_caps);
-
- GST_OBJECT_LOCK (camera);
- gst_caps_replace (prev_caps, new_caps);
- GST_OBJECT_UNLOCK (camera);
-
- if (new_caps && !gst_caps_is_any (new_caps) &&
- !gst_caps_is_empty (new_caps)) {
- if (!*prev_pipe) {
- *prev_pipe =
- gst_camerabin_preview_create_pipeline (GST_ELEMENT (camera),
- new_caps, *preview_source_filter);
- } else {
- gst_camerabin_preview_set_caps (*prev_pipe, new_caps);
- }
- }
- }
- break;
- }
- case ARG_PREVIEW_SOURCE_FILTER:
- if (GST_STATE (camera) != GST_STATE_NULL) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("camerabin must be in NULL state when setting the preview source filter element"),
- (NULL));
- } else {
- GstCameraBinPreviewPipelineData **preview_pipe = NULL;
- GstElement **preview_source_filter = NULL;
- GstCaps *preview_caps = NULL;
-
- if (camera->mode == MODE_IMAGE) {
- preview_pipe = &camera->preview_pipeline;
- preview_source_filter = &camera->app_preview_source_filter;
- preview_caps = camera->preview_caps;
- } else { /* MODE VIDEO */
- preview_pipe = &camera->video_preview_pipeline;
- preview_source_filter = &camera->app_video_preview_source_filter;
- preview_caps = camera->video_preview_caps;
- }
-
- if (*preview_source_filter)
- gst_object_unref (*preview_source_filter);
- *preview_source_filter = g_value_dup_object (value);
-
- if (*preview_pipe) {
- gst_camerabin_preview_destroy_pipeline (*preview_pipe);
- *preview_pipe =
- gst_camerabin_preview_create_pipeline (GST_ELEMENT (camera),
- preview_caps, *preview_source_filter);
- }
- }
- break;
- case ARG_VIEWFINDER_FILTER:
- if (GST_STATE (camera) != GST_STATE_NULL) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("camerabin must be in NULL state when setting the viewfinder filter element"),
- (NULL));
- } else {
- if (camera->app_viewfinder_filter)
- gst_object_unref (camera->app_viewfinder_filter);
- camera->app_viewfinder_filter = g_value_dup_object (value);
- }
- break;
- case ARG_BLOCK_VIEWFINDER:
- gst_camerabin_change_viewfinder_blocking (camera,
- g_value_get_boolean (value));
- break;
- case ARG_IMAGE_CAPTURE_WIDTH:
- {
- gint width = g_value_get_int (value);
-
- if (width != camera->image_capture_width) {
- camera->image_capture_width = width;
- camera->image_capture_caps_update = TRUE;
- }
- }
- break;
- case ARG_IMAGE_CAPTURE_HEIGHT:
- {
- gint height = g_value_get_int (value);
-
- if (height != camera->image_capture_height) {
- camera->image_capture_height = height;
- camera->image_capture_caps_update = TRUE;
- }
- }
- break;
- case ARG_VIDEO_CAPTURE_WIDTH:
- {
- gint width = g_value_get_int (value);
-
- camera->app_width = width;
-
- if (width != camera->width) {
- camera->width = width;
- camera->video_capture_caps_update = TRUE;
- }
- }
- break;
- case ARG_VIDEO_CAPTURE_HEIGHT:
- {
- gint height = g_value_get_int (value);
-
- camera->app_height = height;
-
- if (height != camera->height) {
- camera->height = height;
- camera->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);
-
- camera->app_fps_n = fps_n;
- camera->app_fps_d = fps_d;
-
- if (fps_n != camera->fps_n || fps_d != camera->fps_d) {
- camera->fps_n = fps_n;
- camera->fps_d = fps_d;
- camera->video_capture_caps_update = TRUE;
- }
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_camerabin_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstCameraBin *camera = GST_CAMERABIN (object);
-
- switch (prop_id) {
- case ARG_FILENAME:
- g_value_set_string (value, camera->filename->str);
- break;
- case ARG_MODE:
- g_value_set_enum (value, camera->mode);
- break;
- case ARG_FLAGS:
- g_value_set_flags (value, camera->flags);
- break;
- case ARG_MUTE:
- g_value_set_boolean (value,
- gst_camerabin_video_get_mute (GST_CAMERABIN_VIDEO (camera->vidbin)));
- break;
- case ARG_ZOOM:
- g_value_set_float (value, camera->zoom);
- break;
- case ARG_IMAGE_POST:
- g_value_set_object (value,
- gst_camerabin_image_get_postproc (GST_CAMERABIN_IMAGE
- (camera->imgbin)));
- break;
- case ARG_IMAGE_ENC:
- g_value_set_object (value,
- gst_camerabin_image_get_encoder (GST_CAMERABIN_IMAGE
- (camera->imgbin)));
- break;
- case ARG_IMAGE_FORMATTER:
- g_value_set_object (value,
- gst_camerabin_image_get_formatter (GST_CAMERABIN_IMAGE
- (camera->imgbin)));
- break;
- case ARG_VIDEO_POST:
- g_value_set_object (value,
- gst_camerabin_video_get_post (GST_CAMERABIN_VIDEO (camera->vidbin)));
- break;
- case ARG_VIDEO_ENC:
- g_value_set_object (value,
- gst_camerabin_video_get_video_enc (GST_CAMERABIN_VIDEO
- (camera->vidbin)));
- break;
- case ARG_AUDIO_ENC:
- g_value_set_object (value,
- gst_camerabin_video_get_audio_enc (GST_CAMERABIN_VIDEO
- (camera->vidbin)));
- break;
- case ARG_VIDEO_MUX:
- g_value_set_object (value,
- gst_camerabin_video_get_muxer (GST_CAMERABIN_VIDEO (camera->vidbin)));
- break;
- case ARG_VF_SINK:
- if (camera->view_sink)
- g_value_set_object (value, camera->view_sink);
- else
- g_value_set_object (value, camera->app_vf_sink);
- break;
- case ARG_VIDEO_SRC:
- if (camera->src_vid_src)
- g_value_set_object (value, camera->src_vid_src);
- else
- g_value_set_object (value, camera->app_vid_src);
- break;
- case ARG_AUDIO_SRC:
- g_value_set_object (value,
- gst_camerabin_video_get_audio_src (GST_CAMERABIN_VIDEO
- (camera->vidbin)));
- break;
- case ARG_VIDEO_SOURCE_FILTER:
- g_value_set_object (value, camera->app_video_filter);
- break;
- case ARG_INPUT_CAPS:
- gst_value_set_caps (value, gst_camerabin_get_allowed_input_caps (camera));
- break;
- case ARG_FILTER_CAPS:
- gst_value_set_caps (value, camera->view_finder_caps);
- break;
- case ARG_PREVIEW_CAPS:
- if (camera->mode == MODE_IMAGE)
- gst_value_set_caps (value, camera->preview_caps);
- else if (camera->mode == MODE_VIDEO)
- gst_value_set_caps (value, camera->video_preview_caps);
- break;
- case ARG_PREVIEW_SOURCE_FILTER:
- if (camera->mode == MODE_IMAGE)
- g_value_set_object (value, camera->app_preview_source_filter);
- else if (camera->mode == MODE_VIDEO)
- g_value_set_object (value, camera->app_video_preview_source_filter);
- break;
- case ARG_VIEWFINDER_FILTER:
- g_value_set_object (value, camera->app_viewfinder_filter);
- break;
- case ARG_BLOCK_VIEWFINDER:
- g_value_set_boolean (value, camera->block_viewfinder_prop);
- break;
- case ARG_READY_FOR_CAPTURE:
- g_mutex_lock (camera->capture_mutex);
- g_value_set_boolean (value, !camera->capturing);
- g_mutex_unlock (camera->capture_mutex);
- break;
- case ARG_IMAGE_CAPTURE_WIDTH:
- g_value_set_int (value, camera->image_capture_width);
- break;
- case ARG_IMAGE_CAPTURE_HEIGHT:
- g_value_set_int (value, camera->image_capture_height);
- break;
- case ARG_VIDEO_CAPTURE_WIDTH:
- g_value_set_int (value, camera->app_width);
- break;
- case ARG_VIDEO_CAPTURE_HEIGHT:
- g_value_set_int (value, camera->app_height);
- break;
- case ARG_VIDEO_CAPTURE_FRAMERATE:
- gst_value_set_fraction (value, camera->app_fps_n, camera->app_fps_d);
- break;
- case ARG_IDLE:
- g_value_set_boolean (value, camera->processing_counter == 0);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/*
- * GstElement functions implementation
- */
-
-static GstStateChangeReturn
-gst_camerabin_change_state (GstElement * element, GstStateChange transition)
-{
- GstCameraBin *camera = GST_CAMERABIN (element);
- GstStateChangeReturn ret;
-
- GST_DEBUG_OBJECT (element, "changing state: %s -> %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (!camerabin_create_elements (camera)) {
- ret = GST_STATE_CHANGE_FAILURE;
- goto done;
- }
- /* Lock to control image and video bin state separately
- from view finder */
- gst_element_set_locked_state (camera->imgbin, TRUE);
- gst_element_set_locked_state (camera->vidbin, TRUE);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- camerabin_setup_src_elements (camera);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- /* If using autovideosink, set view finder sink properties
- now that actual sink has been created. */
- camerabin_setup_view_elements (camera);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* all processing should stop and those elements could have their state
- * locked, so set them explicitly here */
- if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
- gst_element_set_state (camera->imgbin, GST_STATE_READY);
- }
- if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
- gst_element_set_state (camera->vidbin, GST_STATE_READY);
- }
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_element_set_locked_state (camera->imgbin, FALSE);
- gst_element_set_locked_state (camera->vidbin, FALSE);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- GST_DEBUG_OBJECT (element, "after chaining up: %s -> %s = %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)),
- gst_element_state_change_return_get_name (ret));
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- g_mutex_lock (camera->capture_mutex);
- if (camera->capturing) {
- GST_WARNING_OBJECT (camera, "was capturing when changing to READY");
- camera->capturing = FALSE;
- /* Reset capture and don't wait for capturing to finish properly.
- Proper capturing should have been finished before going to READY. */
- gst_camerabin_reset_to_view_finder (camera);
- g_cond_signal (camera->cond);
- }
-
- /* reset processing counter */
- GST_DEBUG_OBJECT (camera, "Reset processing counter from %d to 0",
- camera->processing_counter);
- camera->processing_counter = 0;
- g_cond_signal (camera->idle_cond);
- g_object_notify (G_OBJECT (camera), "idle");
- g_mutex_unlock (camera->capture_mutex);
-
- /* unblock the viewfinder, but keep the property as is */
- gst_pad_set_blocked_async (camera->pad_src_view, FALSE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
-
- g_signal_handlers_disconnect_by_func (camera->src_vid_src,
- gst_camerabin_scene_mode_notify_cb, camera);
- g_signal_handlers_disconnect_by_func (camera->src_vid_src,
- gst_camerabin_zoom_notify_cb, camera);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- camerabin_destroy_elements (camera);
- break;
- /* In some error situation camerabin may end up being still in NULL
- state so we must take care of destroying elements. */
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (ret == GST_STATE_CHANGE_FAILURE)
- camerabin_destroy_elements (camera);
- break;
- default:
- break;
- }
-
-done:
- GST_DEBUG_OBJECT (element, "changed state: %s -> %s = %s",
- gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
- gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)),
- gst_element_state_change_return_get_name (ret));
-
- return ret;
-}
-
-static GstClock *
-gst_camerabin_provide_clock (GstElement * element)
-{
- GstClock *clock = NULL;
- GstClock *vidbin_clock = NULL;
- GstCameraBin *camera = GST_CAMERABIN (element);
- GstElement *aud_src = GST_CAMERABIN_VIDEO (camera->vidbin)->aud_src;
-
- if (aud_src)
- vidbin_clock = gst_element_provide_clock (aud_src);
-
- if (camera->capturing && camera->mode == MODE_VIDEO && vidbin_clock)
- clock = vidbin_clock;
- else {
- clock = GST_ELEMENT_CLASS (parent_class)->provide_clock (element);
- if (clock == vidbin_clock) {
- /* Do not reuse vidbin_clock if it was current clock */
- clock = gst_system_clock_obtain ();
- }
- }
-
- GST_INFO_OBJECT (camera, "Reset pipeline clock to %p(%s)",
- clock, GST_ELEMENT_NAME (clock));
-
- return clock;
-}
-
-static gpointer
-gst_camerabin_imgbin_finished (gpointer u_data)
-{
- GstCameraBin *camera = GST_CAMERABIN (u_data);
- gchar *filename = NULL;
-
- /* FIXME: should set a flag (and take a lock) when going to NULL, so we
- * short-circuit this bit if we got shut down between thread create and now */
-
- GST_DEBUG_OBJECT (camera, "Image encoding finished");
-
- /* Get the filename of the finished image */
- g_object_get (G_OBJECT (camera->imgbin), "filename", &filename, NULL);
-
- /* Close the file of saved image */
- gst_element_set_state (camera->imgbin, GST_STATE_READY);
- GST_DEBUG_OBJECT (camera, "Image pipeline set to READY");
-
- g_mutex_lock (camera->capture_mutex);
- if (camera->processing_counter) {
- CAMERABIN_PROCESSING_DEC_UNLOCKED (camera);
- } else {
- /* Camerabin state change to READY may have reset processing counter to
- * zero. This is possible as this functions is scheduled from another
- * thread.
- */
- GST_WARNING_OBJECT (camera, "camerabin has been forced to idle");
- }
- g_mutex_unlock (camera->capture_mutex);
-
- /* Set image bin back to PAUSED so that buffer-allocs don't fail */
- gst_element_set_state (camera->imgbin, GST_STATE_PAUSED);
-
- /* Unblock image queue pad to process next buffer */
- GST_STATE_LOCK (camera);
- if (camera->pad_src_queue) {
- gst_pad_set_blocked_async (camera->pad_src_queue, FALSE,
- (GstPadBlockCallback) camerabin_pad_blocked, camera);
- GST_DEBUG_OBJECT (camera, "Queue srcpad unblocked");
- } else {
- GST_DEBUG_OBJECT (camera, "Queue srcpad unreffed already, doesn't need "
- "to unblock");
- }
- GST_STATE_UNLOCK (camera);
-
- /* Send image-done signal */
- gst_camerabin_image_capture_continue (camera, filename);
- g_free (filename);
-
- GST_INFO_OBJECT (camera, "leaving helper thread");
- gst_object_unref (camera);
- return NULL;
-}
-
-/*
- * GstBin functions implementation
- */
-
-/* Peek eos messages but don't interfere with bin msg handling */
-static void
-gst_camerabin_handle_message_func (GstBin * bin, GstMessage * msg)
-{
- GstCameraBin *camera = GST_CAMERABIN (bin);
-
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->vidbin)) {
- /* Video eos */
- GST_DEBUG_OBJECT (camera,
- "got video eos message, stopping video capture");
- g_mutex_lock (camera->capture_mutex);
- camera->capturing = FALSE;
- g_cond_signal (camera->cond);
-
- CAMERABIN_PROCESSING_DEC_UNLOCKED (camera);
- g_mutex_unlock (camera->capture_mutex);
- } else if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->imgbin)) {
- /* Image eos */
- GST_DEBUG_OBJECT (camera, "got image eos message");
- /* Can't change state here, since we're in the streaming thread */
- if (!g_thread_create (gst_camerabin_imgbin_finished,
- gst_object_ref (camera), FALSE, NULL)) {
- /* FIXME: what do do if this fails? */
- gst_object_unref (camera);
- }
- }
- break;
- case GST_MESSAGE_ERROR:
- GST_DEBUG_OBJECT (camera, "error from child %" GST_PTR_FORMAT,
- GST_MESSAGE_SRC (msg));
- g_mutex_lock (camera->capture_mutex);
- if (camera->capturing) {
- camera->capturing = FALSE;
- g_cond_signal (camera->cond);
- }
-
- /* Ideally we should check what error was and only decrement the
- * counter if the error means that a 'processing' operation failed,
- * instead of a setting up error. But this can be quite tricky to do
- * and we expect the app to set the whole pipeline to READY/NULL
- * when an error happens. For now we just mention that the
- * processing counter and the 'idle' property are unreliable */
- GST_DEBUG_OBJECT (camera, "An error makes the processing counter "
- "unreliable");
-
- g_mutex_unlock (camera->capture_mutex);
- break;
- default:
- break;
- }
- GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
-}
-
-/*
- * Action signal function implementation
- */
-
-static void
-gst_camerabin_capture_start (GstCameraBin * camera)
-{
-
- GST_INFO_OBJECT (camera, "starting capture");
- if (camera->paused) {
- gst_camerabin_capture_pause (camera);
- return;
- }
-
- if (!camera->active_bin) {
- GST_INFO_OBJECT (camera, "mode not explicitly set by application");
- gst_camerabin_change_mode (camera, camera->mode);
- if (!camera->active_bin) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("starting capture failed"), (NULL));
- }
- }
-
- /* We need a filename unless it's a photo and preview_caps is set */
-
- if (g_str_equal (camera->filename->str, ""))
- if (camera->active_bin == camera->vidbin || !camera->preview_caps) {
- GST_ELEMENT_ERROR (camera, CORE, FAILED,
- ("set filename before starting capture"), (NULL));
- return;
- }
-
- g_mutex_lock (camera->capture_mutex);
- if (camera->capturing) {
- GST_WARNING_OBJECT (camera, "capturing \"%s\" ongoing, set new filename",
- camera->filename->str);
- /* FIXME: we need to send something more to the app, so that it does not for
- * for image-done */
- g_mutex_unlock (camera->capture_mutex);
- return;
- }
- CAMERABIN_PROCESSING_INC_UNLOCKED (camera);
- g_mutex_unlock (camera->capture_mutex);
-
- GST_OBJECT_LOCK (camera);
- camera->block_viewfinder_trigger = camera->block_viewfinder_prop;
- GST_OBJECT_UNLOCK (camera);
-
- if (camera->active_bin) {
- if (camera->active_bin == camera->imgbin) {
- GST_INFO_OBJECT (camera, "starting image capture");
- gst_camerabin_start_image_capture (camera);
- } else if (camera->active_bin == camera->vidbin) {
- GST_INFO_OBJECT (camera,
- "setting video filename and starting video capture");
- g_object_set (G_OBJECT (camera->active_bin), "filename",
- camera->filename->str, NULL);
- gst_camerabin_start_video_recording (camera);
- }
- }
- /* Capturing is now ongoing, notify that new capture isn't possible */
- g_object_notify (G_OBJECT (camera), "ready-for-capture");
-}
-
-static void
-gst_camerabin_capture_stop (GstCameraBin * camera)
-{
- if (camera->active_bin == camera->vidbin) {
- GST_INFO_OBJECT (camera, "stopping video capture");
- gst_camerabin_do_stop (camera);
- gst_camerabin_reset_to_view_finder (camera);
- /* Video capture stopped, notify that preparing a new capture is possible */
- g_object_notify (G_OBJECT (camera), "ready-for-capture");
- } else {
- GST_INFO_OBJECT (camera, "stopping image capture isn't needed");
- }
-}
-
-static void
-gst_camerabin_capture_pause (GstCameraBin * camera)
-{
- if (camera->active_bin == camera->vidbin) {
- if (!camera->paused) {
- GST_INFO_OBJECT (camera, "pausing capture");
-
- /* Bring all camerabin elements to PAUSED */
- gst_element_set_locked_state (camera->vidbin, FALSE);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
-
- /* Switch to view finder mode */
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
- "active-pad", camera->pad_src_view, NULL);
-
- /* Set view finder to PLAYING and leave videobin PAUSED */
- gst_element_set_locked_state (camera->vidbin, TRUE);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING);
-
- camera->paused = TRUE;
- } else {
- GST_INFO_OBJECT (camera, "unpausing capture");
-
- /* Bring all camerabin elements to PAUSED */
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
-
- /* Switch to video recording mode */
- g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE,
- "active-pad", camera->pad_src_vid, NULL);
-
- /* Bring all camerabin elements to PLAYING */
- gst_element_set_locked_state (camera->vidbin, FALSE);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING);
- gst_element_set_locked_state (camera->vidbin, TRUE);
-
- camera->paused = FALSE;
- }
- GST_DEBUG_OBJECT (camera, "pause done");
- } else {
- GST_WARNING ("pausing in image capture mode disabled");
- }
-}
-
-/*
- * Updates the properties (excluding the user preferred width/height/fps) and
- * tells camerabin to update the video capture caps.
- */
-static void
-do_set_video_resolution_fps (GstCameraBin * camera, gint width,
- gint height, gint fps_n, gint fps_d)
-{
- if (height != camera->height) {
- camera->height = height;
- camera->video_capture_caps_update = TRUE;
- }
- if (width != camera->width) {
- camera->width = width;
- camera->video_capture_caps_update = TRUE;
- }
- if (fps_n != camera->fps_n) {
- camera->fps_n = fps_n;
- camera->video_capture_caps_update = TRUE;
- }
- if (fps_d != camera->fps_d) {
- camera->fps_d = fps_d;
- camera->video_capture_caps_update = TRUE;
- }
-
- reset_video_capture_caps (camera);
-}
-
-/*
- * Updates the properties (including the user preferred width/height/fps) and
- * tells camerabin to update the video capture caps.
- */
-static void
-gst_camerabin_set_video_resolution_fps (GstCameraBin * camera, gint width,
- gint height, gint fps_n, gint fps_d)
-{
- g_object_set (camera, "video-capture-width", width, "video-capture-height",
- height, "video-capture-framerate", fps_n, fps_d, NULL);
-
- reset_video_capture_caps (camera);
-}
-
-static void
-gst_camerabin_set_image_capture_caps (GstCameraBin * camera, gint width,
- gint height)
-{
- GstStructure *structure;
- GstCaps *new_caps = NULL;
-
- g_return_if_fail (camera != NULL);
-
- if (width && height && camera->view_finder_caps) {
- /* Use view finder mode caps as a basis */
- structure = gst_caps_get_structure (camera->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. */
- gst_camerabin_set_allowed_framerate (camera, new_caps);
- }
-
- GST_INFO_OBJECT (camera,
- "init filter caps for image capture %" GST_PTR_FORMAT, new_caps);
- gst_caps_replace (&camera->image_capture_caps, new_caps);
- camera->image_capture_caps_update = FALSE;
- if (new_caps)
- gst_caps_unref (new_caps);
-}
-
-static void
-gst_camerabin_set_image_resolution (GstCameraBin * camera, gint width,
- gint height)
-{
- g_object_set (camera, "image-capture-width", (guint16) width,
- "image-capture-height", (guint16) height, NULL);
-}
-
-/* entry point to initialize the plug-in
- * initialize the plug-in itself
- * register the element factories and pad templates
- * register the features
- */
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_camerabin_debug, "camerabin", 0, "CameraBin");
-
- return gst_element_register (plugin, "camerabin",
- GST_RANK_NONE, GST_TYPE_CAMERABIN);
-}
-
-/* this is the structure that gstreamer looks for to register plugins
- */
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- camerabin,
- "High level api for DC (Digital Camera) application",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+++ /dev/null
-/*
- * 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 __GST_CAMERABIN_H__
-#define __GST_CAMERABIN_H__
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <gst/gstbin.h>
-#include <gst/interfaces/photography.h>
-
-#include "gstcamerabin-enum.h"
-#include "camerabinimage.h"
-#include "camerabinvideo.h"
-#include "camerabinpreview.h"
-
-G_BEGIN_DECLS
-/* #defines don't like whitespacey bits */
-#define GST_TYPE_CAMERABIN \
- (gst_camerabin_get_type())
-#define GST_CAMERABIN(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERABIN,GstCameraBin))
-#define GST_CAMERABIN_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERABIN,GstCameraBinClass))
-#define GST_IS_CAMERABIN(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERABIN))
-#define GST_IS_CAMERABIN_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERABIN))
-typedef struct _GstCameraBin GstCameraBin;
-typedef struct _GstCameraBinClass GstCameraBinClass;
-
-/**
- * GstCameraBin:
- *
- * The opaque #GstCameraBin structure.
- */
-
-struct _GstCameraBin
-{
- GstPipeline parent;
-
- /* private */
- GString *filename;
- gint mode; /* MODE_IMAGE or MODE_VIDEO */
- GstCameraBinFlags flags;
- gboolean stop_requested; /* TRUE if capturing stop needed */
- gboolean paused; /* TRUE if capturing paused */
-
- /*
- * Those 2 booleans work together.
- *
- * 'block_viewfinder_prop' is the property, 'block_viewfinder_trigger'
- * is the flag that actually makes the viewfinder block after capture.
- * We need both to avoid blocking the viewfinder if the application resets
- * the flag after issuing the 'capture-start', but before the actual
- * blocking happens. This causes the viewfinder to block even though
- * the application resetted the flag to keep it running already.
- *
- * Here's how this should work:
- * When a capture is started, the property is checked, if it is TRUE, the
- * trigger is set to TRUE. The blocking will only happen if
- * the trigger is TRUE after image capture finishes, ff the property
- * is reset before the blocking happens, the trigger goes to
- * FALSE and no blocking happens.
- */
- gboolean block_viewfinder_prop; /* TRUE if viewfinder blocks after capture */
- gboolean block_viewfinder_trigger;
-
- /* Resolution of the buffers configured to camerabin */
- gint width;
- gint height;
- /* Frames per second configured to camerabin */
- gint fps_n;
- gint fps_d;
-
- /* app configured resolution/framerate */
- gint app_width;
- gint app_height;
- gint app_fps_n;
- gint app_fps_d;
-
- gboolean video_capture_caps_update;
-
- /* Image capture resolution */
- gint image_capture_width;
- gint image_capture_height;
-
- /* Image tags are collected here first before sending to imgbin */
- GstTagList *event_tags;
-
- /* Caps applied to capsfilters when taking still image */
- GstCaps *image_capture_caps;
- gboolean image_capture_caps_update;
-
- /* Caps applied to capsfilters when in view finder mode */
- GstCaps *view_finder_caps;
-
- /* Caps that videosrc supports */
- GstCaps *allowed_caps;
-
- /* Caps used to create preview image */
- GstCaps *preview_caps;
-
- /* Caps used to create video preview image */
- GstCaps *video_preview_caps;
-
- /* The digital zoom (from 1.0 to 10.0) */
- gfloat zoom;
-
- /* concurrency control */
- GMutex *capture_mutex;
- GCond *cond;
- GCond *idle_cond;
- gboolean capturing;
- gboolean eos_handled;
- /* everytime a new capture is started this is incremented, when it is
- * finished/fails it is decremented. Used to know if camerabin is idle */
- gint processing_counter;
-
- /* pad names for output and input selectors */
- GstPad *pad_src_view;
- GstPad *pad_view_src;
- GstPad *pad_src_img;
- GstPad *pad_src_vid;
- GstPad *pad_view_vid;
- GstPad *pad_src_queue;
-
- GstElement *img_queue; /* queue for decoupling capture from
- image-postprocessing and saving */
- GstElement *imgbin; /* bin that holds image capturing elements */
- GstElement *vidbin; /* bin that holds video capturing elements */
- GstElement *active_bin; /* image or video bin that is currently in use */
- /* pipeline for creating preview images */
- GstCameraBinPreviewPipelineData *preview_pipeline;
- /* pipeline for creating video preview image */
- GstCameraBinPreviewPipelineData *video_preview_pipeline;
-
- GstBuffer *video_preview_buffer; /* buffer for storing video preview */
-
- /* 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;
-
- /* view finder elements */
- GstElement *view_in_sel;
- GstElement *aspect_filter;
- GstElement *view_scale;
- GstElement *view_sink;
-
- /* Application configurable elements */
- GstElement *app_vid_src;
- GstElement *app_vf_sink;
- GstElement *app_video_filter;
- GstElement *app_viewfinder_filter;
- GstElement *app_preview_source_filter;
- GstElement *app_video_preview_source_filter;
-
- /* Night mode handling */
- gboolean night_mode;
- gint pre_night_fps_n;
- gint pre_night_fps_d;
-
- /* Buffer probe id for captured image handling */
- gulong image_captured_id;
-
- /* 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;
-};
-
-/**
- * GstCameraBinClass:
- *
- * The #GstCameraBin class structure.
- */
-struct _GstCameraBinClass
-{
- GstPipelineClass parent_class;
-
- /* action signals */
-
- void (*capture_start) (GstCameraBin * camera);
- void (*capture_stop) (GstCameraBin * camera);
- void (*capture_pause) (GstCameraBin * camera);
- void (*set_video_resolution_fps) (GstCameraBin * camera, gint width,
- gint height, gint fps_n, gint fps_d);
- void (*set_image_resolution) (GstCameraBin * camera, gint width, gint height);
-
- /* signals (callback) */
-
- gboolean (*img_done) (GstCameraBin * camera, const gchar * filename);
-};
-
-/**
- * GstCameraBinMode:
- * @MODE_IMAGE: image capture
- * @MODE_VIDEO: video capture
- *
- * Capture mode to use.
- */
-typedef enum
-{
- MODE_IMAGE = 0,
- MODE_VIDEO
-} GstCameraBinMode;
-
-GType gst_camerabin_get_type (void);
-
-G_END_DECLS
-#endif /* #ifndef __GST_CAMERABIN_H__ */
+++ /dev/null
-/*
- * 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.
- */
-
-/*
- * Includes
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstcamerabincolorbalance.h"
-#include "gstcamerabin.h"
-
-/*
- * static functions implementation
- */
-
-static const GList *
-gst_camerabin_color_balance_list_channels (GstColorBalance * cb)
-{
- if (cb && GST_CAMERABIN (cb)->src_vid_src) {
- GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src);
- return gst_color_balance_list_channels (cbl);
- } else {
- return NULL;
- }
-}
-
-static void
-gst_camerabin_color_balance_set_value (GstColorBalance * cb,
- GstColorBalanceChannel * channel, gint value)
-{
- if (cb && GST_CAMERABIN (cb)->src_vid_src) {
- GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src);
- gst_color_balance_set_value (cbl, channel, value);
- }
-}
-
-static gint
-gst_camerabin_color_balance_get_value (GstColorBalance * cb,
- GstColorBalanceChannel * channel)
-{
- if (cb && GST_CAMERABIN (cb)->src_vid_src) {
- GstColorBalance *cbl = GST_COLOR_BALANCE (GST_CAMERABIN (cb)->src_vid_src);
- return gst_color_balance_get_value (cbl, channel);
- } else {
- return 0;
- }
-}
-
-/*
- * extern functions implementation
- */
-
-void
-gst_camerabin_color_balance_init (GstColorBalanceInterface * iface)
-{
- /* FIXME: to get the same type as v4l2src */
- GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE;
- iface->list_channels = gst_camerabin_color_balance_list_channels;
- iface->set_value = gst_camerabin_color_balance_set_value;
- iface->get_value = gst_camerabin_color_balance_get_value;
-}
+++ /dev/null
-/*
- * 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 __GST_CAMERA_COLOR_BALANCE_H__
-#define __GST_CAMERA_COLOR_BALANCE_H__
-
-#include <gst/interfaces/colorbalance.h>
-
-extern void gst_camerabin_color_balance_init (GstColorBalanceInterface * iface);
-
-#endif /* #ifndef __GST_CAMERA_COLOR_BALANCE_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
- * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2005 Jan Schmidt <thaytan@mad.scientist.com>
- * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
- * Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
- * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
- *
- * 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-input-selector
- * @see_also: #GstOutputSelector
- *
- * Direct one out of N input streams to the output pad.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <gst/glib-compat-private.h>
-#include "gstinputselector.h"
-#include "gstcamerabin-marshal.h"
-
-GST_DEBUG_CATEGORY_STATIC (input_selector_debug);
-#define GST_CAT_DEFAULT input_selector_debug
-
-static GstStaticPadTemplate gst_input_selector_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink_%u",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS_ANY);
-
-static GstStaticPadTemplate gst_input_selector_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-enum
-{
- PROP_0,
- PROP_N_PADS,
- PROP_ACTIVE_PAD,
- PROP_SELECT_ALL,
- PROP_LAST
-};
-
-#define DEFAULT_PAD_ALWAYS_OK TRUE
-
-enum
-{
- PROP_PAD_0,
- PROP_PAD_RUNNING_TIME,
- PROP_PAD_TAGS,
- PROP_PAD_ACTIVE,
- PROP_PAD_ALWAYS_OK,
- PROP_PAD_LAST
-};
-
-enum
-{
- /* methods */
- SIGNAL_BLOCK,
- SIGNAL_SWITCH,
- LAST_SIGNAL
-};
-static guint gst_input_selector_signals[LAST_SIGNAL] = { 0 };
-
-static inline gboolean gst_input_selector_is_active_sinkpad (GstInputSelector *
- sel, GstPad * pad);
-static GstPad *gst_input_selector_activate_sinkpad (GstInputSelector * sel,
- GstPad * pad);
-static GstPad *gst_input_selector_get_linked_pad (GstPad * pad,
- gboolean strict);
-static gboolean gst_input_selector_check_eos (GstElement * selector);
-
-#define GST_TYPE_SELECTOR_PAD \
- (gst_selector_pad_get_type())
-#define GST_SELECTOR_PAD(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SELECTOR_PAD, GstSelectorPad))
-#define GST_SELECTOR_PAD_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SELECTOR_PAD, GstSelectorPadClass))
-#define GST_IS_SELECTOR_PAD(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SELECTOR_PAD))
-#define GST_IS_SELECTOR_PAD_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SELECTOR_PAD))
-#define GST_SELECTOR_PAD_CAST(obj) \
- ((GstSelectorPad *)(obj))
-
-typedef struct _GstSelectorPad GstSelectorPad;
-typedef struct _GstSelectorPadClass GstSelectorPadClass;
-
-struct _GstSelectorPad
-{
- GstPad parent;
-
- gboolean active; /* when buffer have passed the pad */
- gboolean eos; /* when EOS has been received */
- gboolean discont; /* after switching we create a discont */
- gboolean always_ok;
- GstSegment segment; /* the current segment on the pad */
- GstTagList *tags; /* last tags received on the pad */
-
- gboolean segment_pending;
-};
-
-struct _GstSelectorPadClass
-{
- GstPadClass parent;
-};
-
-static void gst_selector_pad_class_init (GstSelectorPadClass * klass);
-static void gst_selector_pad_init (GstSelectorPad * pad);
-static void gst_selector_pad_finalize (GObject * object);
-static void gst_selector_pad_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-static void gst_selector_pad_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-
-static GstPadClass *selector_pad_parent_class = NULL;
-
-static gint64 gst_selector_pad_get_running_time (GstSelectorPad * pad);
-static void gst_selector_pad_reset (GstSelectorPad * pad);
-static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
-static gboolean gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps);
-static GstIterator *gst_selector_pad_iterate_linked_pads (GstPad * pad);
-static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
-static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-
-static GType
-gst_selector_pad_get_type (void)
-{
- static GType selector_pad_type = 0;
-
- if (!selector_pad_type) {
- static const GTypeInfo selector_pad_info = {
- sizeof (GstSelectorPadClass),
- NULL,
- NULL,
- (GClassInitFunc) gst_selector_pad_class_init,
- NULL,
- NULL,
- sizeof (GstSelectorPad),
- 0,
- (GInstanceInitFunc) gst_selector_pad_init,
- };
-
- selector_pad_type =
- g_type_register_static (GST_TYPE_PAD, "GstCamerabinSelectorPad",
- &selector_pad_info, 0);
- }
- return selector_pad_type;
-}
-
-static void
-gst_selector_pad_class_init (GstSelectorPadClass * klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
-
- selector_pad_parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_selector_pad_finalize;
-
- gobject_class->get_property = gst_selector_pad_get_property;
- gobject_class->set_property = gst_selector_pad_set_property;
-
- g_object_class_install_property (gobject_class, PROP_PAD_RUNNING_TIME,
- g_param_spec_int64 ("running-time", "Running time",
- "Running time of stream on pad", 0, G_MAXINT64, 0,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
- g_param_spec_boxed ("tags", "Tags",
- "The currently active tags on the pad", GST_TYPE_TAG_LIST,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
- g_param_spec_boolean ("active", "Active",
- "If the pad is currently active", FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PAD_ALWAYS_OK,
- g_param_spec_boolean ("always-ok", "Always OK",
- "Make an inactive pad return OK instead of NOT_LINKED",
- DEFAULT_PAD_ALWAYS_OK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_selector_pad_init (GstSelectorPad * pad)
-{
- pad->always_ok = DEFAULT_PAD_ALWAYS_OK;
- gst_selector_pad_reset (pad);
-}
-
-static void
-gst_selector_pad_finalize (GObject * object)
-{
- GstSelectorPad *pad;
-
- pad = GST_SELECTOR_PAD_CAST (object);
-
- if (pad->tags)
- gst_tag_list_free (pad->tags);
-
- G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
-}
-
-static void
-gst_selector_pad_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
-
- switch (prop_id) {
- case PROP_PAD_ALWAYS_OK:
- GST_OBJECT_LOCK (object);
- spad->always_ok = g_value_get_boolean (value);
- GST_OBJECT_UNLOCK (object);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_selector_pad_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstSelectorPad *spad = GST_SELECTOR_PAD_CAST (object);
-
- switch (prop_id) {
- case PROP_PAD_RUNNING_TIME:
- g_value_set_int64 (value, gst_selector_pad_get_running_time (spad));
- break;
- case PROP_PAD_TAGS:
- GST_OBJECT_LOCK (object);
- g_value_set_boxed (value, spad->tags);
- GST_OBJECT_UNLOCK (object);
- break;
- case PROP_PAD_ACTIVE:
- {
- GstInputSelector *sel;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (spad));
- g_value_set_boolean (value, gst_input_selector_is_active_sinkpad (sel,
- GST_PAD_CAST (spad)));
- gst_object_unref (sel);
- break;
- }
- case PROP_PAD_ALWAYS_OK:
- GST_OBJECT_LOCK (object);
- g_value_set_boolean (value, spad->always_ok);
- GST_OBJECT_UNLOCK (object);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static gint64
-gst_selector_pad_get_running_time (GstSelectorPad * pad)
-{
- gint64 ret = 0;
-
- GST_OBJECT_LOCK (pad);
- if (pad->active) {
- gint64 last_stop = pad->segment.last_stop;
-
- if (last_stop >= 0)
- ret = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME,
- last_stop);
- }
- GST_OBJECT_UNLOCK (pad);
-
- GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (ret));
-
- return ret;
-}
-
-static void
-gst_selector_pad_reset (GstSelectorPad * pad)
-{
- GST_OBJECT_LOCK (pad);
- pad->active = FALSE;
- pad->eos = FALSE;
- pad->segment_pending = FALSE;
- pad->discont = FALSE;
- gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED);
- GST_OBJECT_UNLOCK (pad);
-}
-
-/* strictly get the linked pad from the sinkpad. If the pad is active we return
- * the srcpad else we return NULL */
-static GstIterator *
-gst_selector_pad_iterate_linked_pads (GstPad * pad)
-{
- GstInputSelector *sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
- GstPad *otherpad;
- GstIterator *it;
-
- otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
- it = gst_iterator_new_single (GST_TYPE_PAD, otherpad,
- (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
-
- if (otherpad)
- gst_object_unref (otherpad);
- gst_object_unref (sel);
-
- return it;
-}
-
-static gboolean
-gst_selector_pad_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- gboolean forward = TRUE;
- GstInputSelector *sel;
- GstSelectorPad *selpad;
- GstPad *prev_active_sinkpad;
- GstPad *active_sinkpad;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
- selpad = GST_SELECTOR_PAD_CAST (pad);
-
- GST_INPUT_SELECTOR_LOCK (sel);
- prev_active_sinkpad = sel->active_sinkpad;
- active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
-
- /* only forward if we are dealing with the active sinkpad or if select_all
- * is enabled */
- if (pad != active_sinkpad && !sel->select_all)
- forward = FALSE;
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
- g_object_notify (G_OBJECT (sel), "active-pad");
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- /* FIXME, flush out the waiter */
- break;
- case GST_EVENT_FLUSH_STOP:
- GST_INPUT_SELECTOR_LOCK (sel);
- gst_selector_pad_reset (selpad);
- sel->pending_close = FALSE;
- GST_INPUT_SELECTOR_UNLOCK (sel);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- GST_DEBUG_OBJECT (pad,
- "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
-
- GST_INPUT_SELECTOR_LOCK (sel);
- GST_OBJECT_LOCK (selpad);
- gst_segment_set_newsegment_full (&selpad->segment, update,
- rate, arate, format, start, stop, time);
- GST_OBJECT_UNLOCK (selpad);
-
- /* If we aren't forwarding the event (because the pad is not the
- * active_sinkpad, and select_all is not set, then set the flag on the
- * that says a segment needs sending if/when that pad is activated.
- * For all other cases, we send the event immediately, which makes
- * sparse streams and other segment updates work correctly downstream.
- */
- if (!forward)
- selpad->segment_pending = TRUE;
-
- GST_INPUT_SELECTOR_UNLOCK (sel);
- break;
- }
- case GST_EVENT_TAG:
- {
- GstTagList *tags, *oldtags, *newtags;
-
- gst_event_parse_tag (event, &tags);
-
- GST_OBJECT_LOCK (selpad);
- oldtags = selpad->tags;
-
- newtags = gst_tag_list_merge (oldtags, tags, GST_TAG_MERGE_REPLACE);
- selpad->tags = newtags;
- if (oldtags)
- gst_tag_list_free (oldtags);
- GST_DEBUG_OBJECT (pad, "received tags %" GST_PTR_FORMAT, newtags);
- GST_OBJECT_UNLOCK (selpad);
-
- g_object_notify (G_OBJECT (selpad), "tags");
- break;
- }
- case GST_EVENT_EOS:
- selpad->eos = TRUE;
- GST_DEBUG_OBJECT (pad, "received EOS");
- /* don't forward eos in select_all mode until all sink pads have eos */
- if (sel->select_all && !gst_input_selector_check_eos (GST_ELEMENT (sel))) {
- forward = FALSE;
- }
- break;
- default:
- break;
- }
- if (forward) {
- GST_DEBUG_OBJECT (pad, "forwarding event");
- res = gst_pad_push_event (sel->srcpad, event);
- } else
- gst_event_unref (event);
-
- gst_object_unref (sel);
-
- return res;
-}
-
-static GstCaps *
-gst_selector_pad_getcaps (GstPad * pad)
-{
- GstInputSelector *sel;
- GstCaps *caps;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
- caps = gst_pad_peer_get_caps_reffed (sel->srcpad);
- if (caps == NULL)
- caps = gst_caps_new_any ();
-
- gst_object_unref (sel);
-
- return caps;
-}
-
-static gboolean
-gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps)
-{
- GstInputSelector *sel;
- gboolean res;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (sel, "Checking acceptcaps of srcpad peer");
- res = gst_pad_peer_accept_caps (sel->srcpad, caps);
- gst_object_unref (sel);
-
- return res;
-}
-
-static GstFlowReturn
-gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
- guint size, GstCaps * caps, GstBuffer ** buf)
-{
- GstInputSelector *sel;
- GstFlowReturn result;
- GstPad *active_sinkpad;
- GstPad *prev_active_sinkpad;
- GstSelectorPad *selpad;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
- selpad = GST_SELECTOR_PAD_CAST (pad);
-
- GST_LOG_OBJECT (pad, "received alloc");
-
- GST_INPUT_SELECTOR_LOCK (sel);
- prev_active_sinkpad = sel->active_sinkpad;
- active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
-
- if (pad != active_sinkpad)
- goto not_active;
-
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
- g_object_notify (G_OBJECT (sel), "active-pad");
-
- result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
-
-done:
- gst_object_unref (sel);
-
- return result;
-
- /* ERRORS */
-not_active:
- {
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- /* unselected pad, perform fallback alloc or return unlinked when
- * asked */
- GST_OBJECT_LOCK (selpad);
- if (selpad->always_ok) {
- GST_DEBUG_OBJECT (pad, "Not selected, performing fallback allocation");
- *buf = NULL;
- result = GST_FLOW_OK;
- } else {
- GST_DEBUG_OBJECT (pad, "Not selected, return NOT_LINKED");
- result = GST_FLOW_NOT_LINKED;
- }
- GST_OBJECT_UNLOCK (selpad);
-
- goto done;
- }
-}
-
-/* must be called with the SELECTOR_LOCK, will block while the pad is blocked
- * or return TRUE when flushing */
-static gboolean
-gst_input_selector_wait (GstInputSelector * self, GstPad * pad)
-{
- while (self->blocked && !self->flushing) {
- /* we can be unlocked here when we are shutting down (flushing) or when we
- * get unblocked */
- GST_INPUT_SELECTOR_WAIT (self);
- }
- return self->flushing;
-}
-
-static GstFlowReturn
-gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
-{
- GstInputSelector *sel;
- GstFlowReturn res;
- GstPad *active_sinkpad;
- GstPad *prev_active_sinkpad;
- GstSelectorPad *selpad;
- GstClockTime start_time;
- GstSegment *seg;
- GstEvent *close_event = NULL, *start_event = NULL;
- GstCaps *caps;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
- selpad = GST_SELECTOR_PAD_CAST (pad);
- seg = &selpad->segment;
-
- GST_INPUT_SELECTOR_LOCK (sel);
- /* wait or check for flushing */
- if (gst_input_selector_wait (sel, pad))
- goto flushing;
-
- GST_LOG_OBJECT (pad, "getting active pad");
-
- prev_active_sinkpad = sel->active_sinkpad;
- active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad);
-
- /* update the segment on the srcpad */
- start_time = GST_BUFFER_TIMESTAMP (buf);
- if (GST_CLOCK_TIME_IS_VALID (start_time)) {
- GST_LOG_OBJECT (pad, "received start time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start_time));
- if (GST_BUFFER_DURATION_IS_VALID (buf))
- GST_LOG_OBJECT (pad, "received end time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf)));
-
- GST_OBJECT_LOCK (pad);
- gst_segment_set_last_stop (seg, seg->format, start_time);
- GST_OBJECT_UNLOCK (pad);
- }
-
- /* Ignore buffers from pads except the selected one */
- if (pad != active_sinkpad)
- goto ignore;
-
- if (G_UNLIKELY (sel->pending_close)) {
- GstSegment *cseg = &sel->segment;
-
- GST_DEBUG_OBJECT (sel,
- "pushing close NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format,
- cseg->start, cseg->stop, cseg->time);
-
- /* create update segment */
- close_event = gst_event_new_new_segment_full (TRUE, cseg->rate,
- cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time);
-
- sel->pending_close = FALSE;
- }
- /* if we have a pending segment, push it out now */
- if (G_UNLIKELY (selpad->segment_pending)) {
- GST_DEBUG_OBJECT (pad,
- "pushing pending NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format,
- seg->start, seg->stop, seg->time);
-
- start_event = gst_event_new_new_segment_full (FALSE, seg->rate,
- seg->applied_rate, seg->format, seg->start, seg->stop, seg->time);
-
- selpad->segment_pending = FALSE;
- }
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad)
- g_object_notify (G_OBJECT (sel), "active-pad");
-
- if (close_event)
- gst_pad_push_event (sel->srcpad, close_event);
-
- if (start_event)
- gst_pad_push_event (sel->srcpad, start_event);
-
- if (selpad->discont) {
- buf = gst_buffer_make_metadata_writable (buf);
-
- GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf);
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- selpad->discont = FALSE;
- }
-
- /* forward */
- GST_LOG_OBJECT (pad, "Forwarding buffer %p", buf);
-
- if ((caps = GST_BUFFER_CAPS (buf))) {
- if (GST_PAD_CAPS (sel->srcpad) != caps)
- gst_pad_set_caps (sel->srcpad, caps);
- }
-
- res = gst_pad_push (sel->srcpad, buf);
-
-done:
- gst_object_unref (sel);
- return res;
-
- /* dropped buffers */
-ignore:
- {
- GST_DEBUG_OBJECT (pad, "Pad not active, discard buffer %p", buf);
- /* when we drop a buffer, we're creating a discont on this pad */
- selpad->discont = TRUE;
- GST_INPUT_SELECTOR_UNLOCK (sel);
- gst_buffer_unref (buf);
-
- /* figure out what to return upstream */
- GST_OBJECT_LOCK (selpad);
- if (selpad->always_ok)
- res = GST_FLOW_OK;
- else
- res = GST_FLOW_NOT_LINKED;
- GST_OBJECT_UNLOCK (selpad);
-
- goto done;
- }
-flushing:
- {
- GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf);
- GST_INPUT_SELECTOR_UNLOCK (sel);
- gst_buffer_unref (buf);
- res = GST_FLOW_FLUSHING;
- goto done;
- }
-}
-
-static void gst_input_selector_init (GstInputSelector * sel);
-static void gst_input_selector_base_init (GstInputSelectorClass * klass);
-static void gst_input_selector_class_init (GstInputSelectorClass * klass);
-
-static void gst_input_selector_dispose (GObject * object);
-
-static void gst_input_selector_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_input_selector_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-
-static GstPad *gst_input_selector_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * unused);
-static void gst_input_selector_release_pad (GstElement * element, GstPad * pad);
-
-static GstStateChangeReturn gst_input_selector_change_state (GstElement *
- element, GstStateChange transition);
-
-static GstCaps *gst_input_selector_getcaps (GstPad * pad);
-static gboolean gst_input_selector_event (GstPad * pad, GstEvent * event);
-static gboolean gst_input_selector_query (GstPad * pad, GstQuery * query);
-static gint64 gst_input_selector_block (GstInputSelector * self);
-static void gst_input_selector_switch (GstInputSelector * self,
- GstPad * pad, gint64 stop_time, gint64 start_time);
-
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_input_selector_get_type (void)
-{
- static GType input_selector_type = 0;
-
- if (!input_selector_type) {
- static const GTypeInfo input_selector_info = {
- sizeof (GstInputSelectorClass),
- (GBaseInitFunc) gst_input_selector_base_init,
- NULL,
- (GClassInitFunc) gst_input_selector_class_init,
- NULL,
- NULL,
- sizeof (GstInputSelector),
- 0,
- (GInstanceInitFunc) gst_input_selector_init,
- };
- input_selector_type =
- g_type_register_static (GST_TYPE_ELEMENT,
- "GstCamerabinInputSelector", &input_selector_info, 0);
- GST_DEBUG_CATEGORY_INIT (input_selector_debug,
- "camerabin-input-selector", 0, "Camerabin input selector element");
- }
-
- return input_selector_type;
-}
-
-static void
-gst_input_selector_base_init (GstInputSelectorClass * klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_set_details_simple (element_class,
- "Input selector", "Generic",
- "N-to-1 input stream selectoring",
- "Julien Moutte <julien@moutte.net>, "
- "Jan Schmidt <thaytan@mad.scientist.com>, "
- "Wim Taymans <wim.taymans@gmail.com>");
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_input_selector_sink_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_input_selector_src_factory));
-}
-
-static void
-gst_input_selector_class_init (GstInputSelectorClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- /* FIXME: remove after confirming it is safe now */
- g_type_class_ref (gst_selector_pad_get_type ());
-
- gobject_class->dispose = gst_input_selector_dispose;
-
- gobject_class->set_property = gst_input_selector_set_property;
- gobject_class->get_property = gst_input_selector_get_property;
-
- g_object_class_install_property (gobject_class, PROP_N_PADS,
- g_param_spec_uint ("n-pads", "Number of Pads",
- "The number of sink pads", 0, G_MAXUINT, 0,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
- g_param_spec_object ("active-pad", "Active pad",
- "The currently active sink pad", GST_TYPE_PAD,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_SELECT_ALL,
- g_param_spec_boolean ("select-all", "Select all mode",
- "Forwards data from all input pads", FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstInputSelector::block:
- * @inputselector: the #GstInputSelector
- *
- * Block all sink pads in preparation for a switch. Returns the stop time of
- * the current switch segment, as a running time, or 0 if there is no current
- * active pad or the current active pad never received data.
- */
- gst_input_selector_signals[SIGNAL_BLOCK] =
- g_signal_new ("block", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GstInputSelectorClass, block), NULL, NULL,
- __gst_camerabin_marshal_INT64__VOID, G_TYPE_INT64, 0);
- /**
- * GstInputSelector::switch:
- * @inputselector: the #GstInputSelector
- * @pad: the pad to switch to
- * @stop_time: running time at which to close the previous segment, or -1
- * to use the running time of the previously active sink pad
- * @start_time: running time at which to start the new segment, or -1 to
- * use the running time of the newly active sink pad
- *
- * Switch to a new feed. The segment opened by the previously active pad, if
- * any, will be closed, and a new segment opened before data flows again.
- *
- * This signal must be emitted when the element has been blocked via the <link
- * linkend="GstInputSelector-block">block</link> signal.
- *
- * If you have a stream with only one switch element, such as an audio-only
- * stream, a stream switch should be performed by first emitting the block
- * signal, and then emitting the switch signal with -1 for the stop and start
- * time values.
- *
- * The intention of the @stop_time and @start_time arguments is to allow
- * multiple switch elements to switch and maintain stream synchronization.
- * When switching a stream with multiple feeds, you will need as many switch
- * elements as you have feeds. For example, a feed with audio and video will
- * have one switch element between the audio feeds and one for video.
- *
- * A switch over multiple switch elements should be performed as follows:
- * First, emit the <link linkend="GstInputSelector-block">block</link>
- * signal, collecting the returned values. The maximum running time returned
- * by block should then be used as the time at which to close the previous
- * segment.
- *
- * Then, query the running times of the new audio and video pads that you will
- * switch to. Naturally, these pads are on separate switch elements. Take the
- * minimum running time for those streams and use it for the time at which to
- * open the new segment.
- *
- * If @pad is the same as the current active pad, the element will cancel any
- * previous block without adjusting segments.
- *
- * <note><simpara>
- * the signal changed from accepting the pad name to the pad object.
- * </simpara></note>
- *
- * Since: 0.10.7
- */
- gst_input_selector_signals[SIGNAL_SWITCH] =
- g_signal_new ("switch", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GstInputSelectorClass, switch_),
- NULL, NULL, __gst_camerabin_marshal_VOID__OBJECT_INT64_INT64,
- G_TYPE_NONE, 3, GST_TYPE_PAD, G_TYPE_INT64, G_TYPE_INT64);
-
- gstelement_class->request_new_pad = gst_input_selector_request_new_pad;
- gstelement_class->release_pad = gst_input_selector_release_pad;
- gstelement_class->change_state = gst_input_selector_change_state;
-
- klass->block = GST_DEBUG_FUNCPTR (gst_input_selector_block);
- /* note the underscore because switch is a keyword otherwise */
- klass->switch_ = GST_DEBUG_FUNCPTR (gst_input_selector_switch);
-}
-
-static void
-gst_input_selector_init (GstInputSelector * sel)
-{
- sel->srcpad = gst_pad_new ("src", GST_PAD_SRC);
- gst_pad_set_iterate_internal_links_function (sel->srcpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
- gst_pad_set_getcaps_function (sel->srcpad,
- GST_DEBUG_FUNCPTR (gst_input_selector_getcaps));
- gst_pad_set_query_function (sel->srcpad,
- GST_DEBUG_FUNCPTR (gst_input_selector_query));
- gst_pad_set_event_function (sel->srcpad,
- GST_DEBUG_FUNCPTR (gst_input_selector_event));
- gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
- /* sinkpad management */
- sel->active_sinkpad = NULL;
- sel->padcount = 0;
- gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
-
- sel->lock = g_mutex_new ();
- sel->cond = g_cond_new ();
- sel->blocked = FALSE;
-
- sel->select_all = FALSE;
-}
-
-static void
-gst_input_selector_dispose (GObject * object)
-{
- GstInputSelector *sel = GST_INPUT_SELECTOR (object);
-
- if (sel->active_sinkpad) {
- gst_object_unref (sel->active_sinkpad);
- sel->active_sinkpad = NULL;
- }
- if (sel->lock) {
- g_mutex_free (sel->lock);
- sel->lock = NULL;
- }
- if (sel->cond) {
- g_cond_free (sel->cond);
- sel->cond = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-/* Solve the following equation for B.timestamp, and set that as the segment
- * stop:
- * B.running_time = (B.timestamp - NS.start) / NS.abs_rate + NS.accum
- */
-static gint64
-gst_segment_get_timestamp (GstSegment * segment, gint64 running_time)
-{
- if (running_time <= segment->accum)
- return segment->start;
- else
- return (running_time - segment->accum) * segment->abs_rate + segment->start;
-}
-
-static void
-gst_segment_set_stop (GstSegment * segment, gint64 running_time)
-{
- segment->stop = gst_segment_get_timestamp (segment, running_time);
- segment->last_stop = -1;
-}
-
-static void
-gst_segment_set_start (GstSegment * segment, gint64 running_time)
-{
- gint64 new_start, duration;
-
- new_start = gst_segment_get_timestamp (segment, running_time);
-
- /* this is the duration we skipped */
- duration = new_start - segment->start;
- /* add the duration to the accumulated segment time */
- segment->accum += duration;
- /* move position in the segment */
- segment->time += duration;
- segment->start += duration;
-}
-
-/* this function must be called with the SELECTOR_LOCK. It returns TRUE when the
- * active pad changed. */
-static gboolean
-gst_input_selector_set_active_pad (GstInputSelector * self,
- GstPad * pad, gint64 stop_time, gint64 start_time)
-{
- GstSelectorPad *old, *new;
- GstPad **active_pad_p;
-
- if (pad == self->active_sinkpad)
- return FALSE;
-
- old = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
- new = GST_SELECTOR_PAD_CAST (pad);
-
- GST_DEBUG_OBJECT (self, "setting active pad to %s:%s",
- GST_DEBUG_PAD_NAME (new));
-
- if (!GST_CLOCK_TIME_IS_VALID (stop_time) && old) {
- /* no stop time given, get the latest running_time on the active pad to
- * close and open the new segment */
- stop_time = start_time = gst_selector_pad_get_running_time (old);
- GST_DEBUG_OBJECT (self, "using start/stop of %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start_time));
- }
-
- if (old && old->active && !self->pending_close && stop_time >= 0) {
- /* schedule a last_stop update if one isn't already scheduled, and a
- segment has been pushed before. */
- memcpy (&self->segment, &old->segment, sizeof (self->segment));
-
- GST_DEBUG_OBJECT (self, "setting stop_time to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stop_time));
- gst_segment_set_stop (&self->segment, stop_time);
- self->pending_close = TRUE;
- }
-
- if (new && new->active && start_time >= 0) {
- GST_DEBUG_OBJECT (self, "setting start_time to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start_time));
- /* schedule a new segment push */
- gst_segment_set_start (&new->segment, start_time);
- new->segment_pending = TRUE;
- }
-
- active_pad_p = &self->active_sinkpad;
- gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
- GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT,
- self->active_sinkpad);
-
- return TRUE;
-}
-
-static void
-gst_input_selector_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstInputSelector *sel = GST_INPUT_SELECTOR (object);
-
- switch (prop_id) {
- case PROP_ACTIVE_PAD:
- {
- GstPad *pad;
-
- pad = g_value_get_object (value);
-
- GST_INPUT_SELECTOR_LOCK (sel);
- gst_input_selector_set_active_pad (sel, pad,
- GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE);
- GST_INPUT_SELECTOR_UNLOCK (sel);
- break;
- }
- case PROP_SELECT_ALL:
- GST_INPUT_SELECTOR_LOCK (object);
- sel->select_all = g_value_get_boolean (value);
- GST_INPUT_SELECTOR_UNLOCK (object);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_input_selector_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstInputSelector *sel = GST_INPUT_SELECTOR (object);
-
- switch (prop_id) {
- case PROP_N_PADS:
- GST_INPUT_SELECTOR_LOCK (object);
- g_value_set_uint (value, sel->n_pads);
- GST_INPUT_SELECTOR_UNLOCK (object);
- break;
- case PROP_ACTIVE_PAD:
- GST_INPUT_SELECTOR_LOCK (object);
- g_value_set_object (value, sel->active_sinkpad);
- GST_INPUT_SELECTOR_UNLOCK (object);
- break;
- case PROP_SELECT_ALL:
- GST_INPUT_SELECTOR_LOCK (object);
- g_value_set_boolean (value, sel->select_all);
- GST_INPUT_SELECTOR_UNLOCK (object);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstPad *
-gst_input_selector_get_linked_pad (GstPad * pad, gboolean strict)
-{
- GstInputSelector *sel;
- GstPad *otherpad = NULL;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
-
- GST_INPUT_SELECTOR_LOCK (sel);
- if (pad == sel->srcpad)
- otherpad = sel->active_sinkpad;
- else if (pad == sel->active_sinkpad || !strict)
- otherpad = sel->srcpad;
- if (otherpad)
- gst_object_ref (otherpad);
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- gst_object_unref (sel);
-
- return otherpad;
-}
-
-static gboolean
-gst_input_selector_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = FALSE;
- GstPad *otherpad;
- GstInputSelector *sel;
- GstIterator *iter;
- gboolean done;
- gpointer nextpad;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
- otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
-
- if (otherpad) {
- res = gst_pad_push_event (otherpad, event);
-
- gst_object_unref (otherpad);
- } else if (sel->select_all) {
-
- /* If select-all is set, we should push the event to all pads.
- * The result will be TRUE if the push works for any of the pads, even if a
- * push fails. This is coherent with the way camerabin uses input-selector,
- * but might not be for other uses of it. */
-
- iter = gst_element_iterate_sink_pads (GST_ELEMENT (sel));
-
- done = FALSE;
- while (!done) {
- switch (gst_iterator_next (iter, &nextpad)) {
- case GST_ITERATOR_OK:
- res |= gst_pad_push_event (nextpad, gst_event_ref (event));
- gst_object_unref (nextpad);
- break;
- case GST_ITERATOR_RESYNC:
- gst_iterator_resync (iter);
- break;
- case GST_ITERATOR_ERROR:
- GST_WARNING_OBJECT (sel,
- "Wrong parameters when retrieving sink pads");
- done = TRUE;
- break;
- case GST_ITERATOR_DONE:
- done = TRUE;
- break;
- }
- }
- gst_event_unref (event);
- gst_iterator_free (iter);
- } else
- gst_event_unref (event);
-
- gst_object_unref (sel);
-
- return res;
-}
-
-/* query on the srcpad. We override this function because by default it will
- * only forward the query to one random sinkpad */
-static gboolean
-gst_input_selector_query (GstPad * pad, GstQuery * query)
-{
- gboolean res = TRUE;
- GstInputSelector *sel;
- GstPad *otherpad;
-
- sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad));
-
- otherpad = gst_input_selector_get_linked_pad (pad, TRUE);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_LATENCY:
- {
- GList *walk;
- GstClockTime resmin, resmax;
- gboolean reslive;
-
- resmin = 0;
- resmax = -1;
- reslive = FALSE;
-
- /* assume FALSE, we become TRUE if one query succeeds */
- res = FALSE;
-
- /* perform the query on all sinkpads and combine the results. We take the
- * max of min and the min of max for the result latency. */
- GST_INPUT_SELECTOR_LOCK (sel);
- for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk;
- walk = g_list_next (walk)) {
- GstPad *sinkpad = GST_PAD_CAST (walk->data);
-
- if (gst_pad_peer_query (sinkpad, query)) {
- GstClockTime min, max;
- gboolean live;
-
- /* one query succeeded, we succeed too */
- res = TRUE;
-
- gst_query_parse_latency (query, &live, &min, &max);
-
- GST_DEBUG_OBJECT (sinkpad,
- "peer latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
- ", live %d", GST_TIME_ARGS (min), GST_TIME_ARGS (max), live);
-
- if (live) {
- if (min > resmin)
- resmin = min;
- if (resmax == -1)
- resmax = max;
- else if (max < resmax)
- resmax = max;
- if (reslive == FALSE)
- reslive = live;
- }
- }
- }
- GST_INPUT_SELECTOR_UNLOCK (sel);
- if (res) {
- gst_query_set_latency (query, reslive, resmin, resmax);
-
- GST_DEBUG_OBJECT (sel,
- "total latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
- ", live %d", GST_TIME_ARGS (resmin), GST_TIME_ARGS (resmax),
- reslive);
- }
-
- break;
- }
- default:
- if (otherpad)
- res = gst_pad_peer_query (otherpad, query);
- break;
- }
- if (otherpad)
- gst_object_unref (otherpad);
- gst_object_unref (sel);
-
- return res;
-}
-
-static GstCaps *
-gst_input_selector_getcaps (GstPad * pad)
-{
- GstPad *otherpad;
- GstObject *parent;
- GstCaps *caps;
-
- parent = gst_object_get_parent (GST_OBJECT (pad));
-
- otherpad = gst_input_selector_get_linked_pad (pad, FALSE);
-
- if (!otherpad) {
- if (GST_INPUT_SELECTOR (parent)->select_all) {
- GST_DEBUG_OBJECT (parent,
- "Pad %s:%s not linked, returning merge of caps",
- GST_DEBUG_PAD_NAME (pad));
- caps = gst_pad_proxy_getcaps (pad);
- } else {
- GST_DEBUG_OBJECT (parent,
- "Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
- caps = gst_caps_new_any ();
- }
- } else {
- GST_DEBUG_OBJECT (parent,
- "Pad %s:%s is linked (to %s:%s), returning peer caps",
- GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
- /* if the peer has caps, use those. If the pad is not linked, this function
- * returns NULL and we return ANY */
- if (!(caps = gst_pad_peer_get_caps_reffed (otherpad)))
- caps = gst_caps_new_any ();
- gst_object_unref (otherpad);
- }
-
- gst_object_unref (parent);
- return caps;
-}
-
-/* check if the pad is the active sinkpad */
-static gboolean
-gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad)
-{
- gboolean res;
-
- GST_INPUT_SELECTOR_LOCK (sel);
- res = (pad == sel->active_sinkpad);
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- return res;
-}
-
-/* Get or create the active sinkpad, must be called with SELECTOR_LOCK */
-static GstPad *
-gst_input_selector_activate_sinkpad (GstInputSelector * sel, GstPad * pad)
-{
- GstPad *active_sinkpad;
- GstSelectorPad *selpad;
-
- selpad = GST_SELECTOR_PAD_CAST (pad);
-
- selpad->active = TRUE;
- active_sinkpad = sel->active_sinkpad;
- if (active_sinkpad == NULL || sel->select_all) {
- /* first pad we get activity on becomes the activated pad by default, if we
- * select all, we also remember the last used pad. */
- if (sel->active_sinkpad)
- gst_object_unref (sel->active_sinkpad);
- active_sinkpad = sel->active_sinkpad = gst_object_ref (pad);
- GST_DEBUG_OBJECT (sel, "Activating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
- }
-
- return active_sinkpad;
-}
-
-static GstPad *
-gst_input_selector_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * unused)
-{
- GstInputSelector *sel;
- gchar *name = NULL;
- GstPad *sinkpad = NULL;
-
- g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
-
- sel = GST_INPUT_SELECTOR (element);
-
- GST_INPUT_SELECTOR_LOCK (sel);
-
- GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
- name = g_strdup_printf ("sink_%u", sel->padcount++);
- sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
- "name", name, "direction", templ->direction, "template", templ, NULL);
- g_free (name);
-
- sel->n_pads++;
-
- gst_pad_set_event_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_event));
- gst_pad_set_getcaps_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_getcaps));
- gst_pad_set_acceptcaps_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_acceptcaps));
- gst_pad_set_chain_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
- gst_pad_set_iterate_internal_links_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_iterate_linked_pads));
- gst_pad_set_bufferalloc_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
-
- gst_pad_set_active (sinkpad, TRUE);
- gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
- GST_INPUT_SELECTOR_UNLOCK (sel);
-
- return sinkpad;
-}
-
-static void
-gst_input_selector_release_pad (GstElement * element, GstPad * pad)
-{
- GstInputSelector *sel;
-
- sel = GST_INPUT_SELECTOR (element);
- GST_LOG_OBJECT (sel, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-
- GST_INPUT_SELECTOR_LOCK (sel);
- /* if the pad was the active pad, makes us select a new one */
- if (sel->active_sinkpad == pad) {
- GST_DEBUG_OBJECT (sel, "Deactivating pad %s:%s", GST_DEBUG_PAD_NAME (pad));
- gst_object_unref (sel->active_sinkpad);
- sel->active_sinkpad = NULL;
- }
- sel->n_pads--;
-
- gst_pad_set_active (pad, FALSE);
- gst_element_remove_pad (GST_ELEMENT (sel), pad);
- GST_INPUT_SELECTOR_UNLOCK (sel);
-}
-
-static void
-gst_input_selector_reset (GstInputSelector * sel)
-{
- GList *walk;
-
- GST_INPUT_SELECTOR_LOCK (sel);
- /* clear active pad */
- if (sel->active_sinkpad) {
- gst_object_unref (sel->active_sinkpad);
- sel->active_sinkpad = NULL;
- }
- /* reset segment */
- gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
- sel->pending_close = FALSE;
- /* reset each of our sinkpads state */
- for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk; walk = g_list_next (walk)) {
- GstSelectorPad *selpad = GST_SELECTOR_PAD_CAST (walk->data);
-
- gst_selector_pad_reset (selpad);
-
- if (selpad->tags) {
- gst_tag_list_free (selpad->tags);
- selpad->tags = NULL;
- }
- }
- GST_INPUT_SELECTOR_UNLOCK (sel);
-}
-
-static GstStateChangeReturn
-gst_input_selector_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstInputSelector *self = GST_INPUT_SELECTOR (element);
- GstStateChangeReturn result;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_INPUT_SELECTOR_LOCK (self);
- self->blocked = FALSE;
- self->flushing = FALSE;
- GST_INPUT_SELECTOR_UNLOCK (self);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- /* first unlock before we call the parent state change function, which
- * tries to acquire the stream lock when going to ready. */
- GST_INPUT_SELECTOR_LOCK (self);
- self->blocked = FALSE;
- self->flushing = TRUE;
- GST_INPUT_SELECTOR_BROADCAST (self);
- GST_INPUT_SELECTOR_UNLOCK (self);
- break;
- default:
- break;
- }
-
- result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_input_selector_reset (self);
- break;
- default:
- break;
- }
-
- return result;
-}
-
-static gint64
-gst_input_selector_block (GstInputSelector * self)
-{
- gint64 ret = 0;
- GstSelectorPad *spad;
-
- GST_INPUT_SELECTOR_LOCK (self);
-
- if (self->blocked)
- GST_WARNING_OBJECT (self, "switch already blocked");
-
- self->blocked = TRUE;
- spad = GST_SELECTOR_PAD_CAST (self->active_sinkpad);
-
- if (spad)
- ret = gst_selector_pad_get_running_time (spad);
- else
- GST_DEBUG_OBJECT (self, "no active pad while blocking");
-
- GST_INPUT_SELECTOR_UNLOCK (self);
-
- return ret;
-}
-
-/* stop_time and start_time are running times */
-static void
-gst_input_selector_switch (GstInputSelector * self, GstPad * pad,
- gint64 stop_time, gint64 start_time)
-{
- gboolean changed;
-
- g_return_if_fail (self->blocked == TRUE);
-
- GST_INPUT_SELECTOR_LOCK (self);
- changed =
- gst_input_selector_set_active_pad (self, pad, stop_time, start_time);
-
- self->blocked = FALSE;
- GST_INPUT_SELECTOR_BROADCAST (self);
- GST_INPUT_SELECTOR_UNLOCK (self);
-
- if (changed)
- g_object_notify (G_OBJECT (self), "active-pad");
-}
-
-static gboolean
-gst_input_selector_check_eos (GstElement * selector)
-{
- GstIterator *it = gst_element_iterate_sink_pads (selector);
- GstIteratorResult ires;
- gpointer item;
- gboolean done = FALSE, is_eos = FALSE;
- GstSelectorPad *pad;
-
- while (!done) {
- ires = gst_iterator_next (it, &item);
- switch (ires) {
- case GST_ITERATOR_DONE:
- GST_INFO_OBJECT (selector, "all sink pads have eos");
- done = TRUE;
- is_eos = TRUE;
- break;
- case GST_ITERATOR_OK:
- pad = GST_SELECTOR_PAD_CAST (item);
- if (!pad->eos) {
- done = TRUE;
- }
- gst_object_unref (pad);
- break;
- case GST_ITERATOR_RESYNC:
- gst_iterator_resync (it);
- break;
- default:
- done = TRUE;
- break;
- }
- }
- gst_iterator_free (it);
-
- return is_eos;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
- * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
- *
- * 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_INPUT_SELECTOR_H__
-#define __GST_INPUT_SELECTOR_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_INPUT_SELECTOR \
- (gst_input_selector_get_type())
-#define GST_INPUT_SELECTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INPUT_SELECTOR, GstInputSelector))
-#define GST_INPUT_SELECTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INPUT_SELECTOR, GstInputSelectorClass))
-#define GST_IS_INPUT_SELECTOR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INPUT_SELECTOR))
-#define GST_IS_INPUT_SELECTOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INPUT_SELECTOR))
-
-typedef struct _GstInputSelector GstInputSelector;
-typedef struct _GstInputSelectorClass GstInputSelectorClass;
-
-#define GST_INPUT_SELECTOR_GET_LOCK(sel) (((GstInputSelector*)(sel))->lock)
-#define GST_INPUT_SELECTOR_GET_COND(sel) (((GstInputSelector*)(sel))->cond)
-#define GST_INPUT_SELECTOR_LOCK(sel) (g_mutex_lock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
-#define GST_INPUT_SELECTOR_UNLOCK(sel) (g_mutex_unlock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
-#define GST_INPUT_SELECTOR_WAIT(sel) (g_cond_wait (GST_INPUT_SELECTOR_GET_COND(sel), \
- GST_INPUT_SELECTOR_GET_LOCK(sel)))
-#define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel)))
-
-struct _GstInputSelector {
- GstElement element;
-
- GstPad *srcpad;
-
- GstPad *active_sinkpad;
- guint n_pads;
- guint padcount;
-
- GstSegment segment; /* the output segment */
- gboolean pending_close; /* if we should push a close first */
-
- GMutex *lock;
- GCond *cond;
- gboolean blocked;
- gboolean flushing;
-
- /* select all mode, send data from all input pads forward */
- gboolean select_all;
-};
-
-struct _GstInputSelectorClass {
- GstElementClass parent_class;
-
- gint64 (*block) (GstInputSelector *self);
- void (*switch_) (GstInputSelector *self, GstPad *pad,
- gint64 stop_time, gint64 start_time);
-};
-
-GType gst_input_selector_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_INPUT_SELECTOR_H__ */
GST_PLUGIN_SYSTEM_PATH= \
GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(GST_PLUGINS_FFMPEG_DIR):$(GST_PLUGINS_UGLY_DIR):$(GST_PLUGINS_GOOD_DIR):$(GST_PLUGINS_BASE_DIR):$(GST_PLUGINS_DIR) \
GST_PLUGIN_LOADING_WHITELIST="gstreamer@$(GST_PLUGINS_DIR):gst-plugins-base@$(GSTPB_PLUGINS_DIR):gst-plugins-good:gst-plugins-ugly:gst-ffmpeg:gst-plugins-bad@$(top_builddir)" \
- GST_STATE_IGNORE_ELEMENTS="apexsink camerabin camerabin2 cdaudio dc1394src \
+ GST_STATE_IGNORE_ELEMENTS="apexsink camerabin cdaudio dc1394src \
dccpclientsrc dccpclientsink dccpserversrc dccpserversink decklinksrc \
decklinksink dvbsrc dvbbasebin dfbvideosink festival gsettingsvideosrc \
gsettingsvideosink gsettingsaudiosrc gsettingsaudiosink linsyssdisrc linsyssdisink nassink \
elements/asfmux \
elements/baseaudiovisualizer \
elements/camerabin \
- elements/camerabin2 \
elements/dataurisrc \
elements/legacyresample \
$(check_jifmux) \
$(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API
elements_camerabin_LDADD = \
- $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_API_VERSION@.la \
- $(GST_PLUGINS_BASE_LIBS) \
- $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
-
-elements_camerabin_SOURCES = elements/camerabin.c
-
-elements_camerabin2_CFLAGS = \
- $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
- $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS) -DGST_USE_UNSTABLE_API
-elements_camerabin2_LDADD = \
$(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_API_VERSION@.la \
$(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@GST_API_VERSION@.la \
-lgstpbutils-$(GST_API_VERSION) \
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
-elements_camerabin2_SOURCES = elements/camerabin2.c
+elements_camerabin_SOURCES = elements/camerabin.c
elements_jifmux_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(EXIF_CFLAGS) $(AM_CFLAGS)
elements_jifmux_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_API_VERSION) $(GST_CHECK_LIBS) $(EXIF_LIBS) $(LDADD)
/* GStreamer
*
- * unit test for camerabin basic operations
- * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.org>
+ * unit test for camerabin2 basic operations
+ * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
+ * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
*
* This library is free software; you can redistribute it and/or
#include <glib.h>
#include <glib/gstdio.h>
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <gst/check/gstcheck.h>
-#include <gst/interfaces/photography.h>
+#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
+#include <gst/pbutils/encoding-profile.h>
-#define SINGLE_IMAGE_FILENAME "image"
-#define SINGLE_IMAGE_WITH_FLAGS_FILENAME "image_with_flags"
-#define SEQUENTIAL_IMAGES_FILENAME "sequential_image"
-#define BURST_IMAGE_FILENAME "burst_image"
+#define IMAGE_FILENAME "image"
#define VIDEO_FILENAME "video"
-#define VIDEO_WITH_FLAGS_FILENAME "video_with_flags"
-#define VIDEO_PAUSE_FILENAME "video_pause"
-#define VIDEO_NOAUDIO_FILENAME "video_noaudio"
-#define CYCLE_IMAGE_FILENAME "cycle_image"
-#define CYCLE_VIDEO_FILENAME "cycle_video"
-#define TAGLISTS_COUNT 3
-#define CYCLE_COUNT_MAX 2
-#define SEQUENTIAL_IMAGES_COUNT 3
-#define MAX_BURST_IMAGES 10
-#define PHOTO_SETTING_DELAY_US 0
+#define CAPTURE_COUNT 3
+#define VIDEO_DURATION 5
+
+#define VIDEO_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=600, height=480"
+#define IMAGE_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=800, height=600"
+
+/* custom test camera src element */
+#define GST_TYPE_TEST_CAMERA_SRC \
+ (gst_test_camera_src_get_type())
+#define GST_TEST_CAMERA_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrc))
+#define GST_TEST_CAMERA_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrcClass))
+#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_CAMERA_SRC))
+#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_CAMERA_SRC))
+#define GST_TEST_CAMERA_SRC_CAST(obj) ((GstTestCameraSrc *)obj)
+
+typedef struct _GstTestCameraSrc GstTestCameraSrc;
+typedef struct _GstTestCameraSrcClass GstTestCameraSrcClass;
+struct _GstTestCameraSrc
+{
+ GstBaseCameraSrc element;
-static GstElement *camera;
-static guint bus_source;
-static GMainLoop *main_loop;
-static guint cycle_count = 0;
-static gboolean received_preview_msg = FALSE;
-static GstTagList *taglists[TAGLISTS_COUNT];
-static GstTagList *validation_taglist;
+ GstPad *vfpad;
+ GstPad *vidpad;
+ GstPad *imgpad;
-/* helper function for filenames */
-static const gchar *
-make_test_file_name (const gchar * base_name, gint num)
+ GstCameraBinMode mode;
+};
+
+struct _GstTestCameraSrcClass
{
- static gchar file_name[1000];
+ GstBaseCameraSrcClass parent_class;
+};
- g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S
- "gstcamerabintest_%s_%03d.cap", g_get_tmp_dir (), base_name, num);
+GType gst_test_camera_src_get_type (void);
- GST_INFO ("capturing to: %s (cycle: %d)", file_name, cycle_count);
- return file_name;
-}
+#define gst_test_camera_src_parent_class parent_class
+G_DEFINE_TYPE (GstTestCameraSrc, gst_test_camera_src, GST_TYPE_BASE_CAMERA_SRC);
-/* burst capture is not supported in camerabin for the moment */
-#ifdef ENABLE_BURST_CAPTURE
-static const gchar *
-make_test_seq_file_name (const gchar * base_name)
+static gboolean
+gst_test_camera_src_set_mode (GstBaseCameraSrc * src, GstCameraBinMode mode)
{
- static gchar file_name[1000];
+ GstTestCameraSrc *self = GST_TEST_CAMERA_SRC (src);
- g_snprintf (file_name, 999, "%s" G_DIR_SEPARATOR_S "%02u_%s",
- g_get_tmp_dir (), captured_images, base_name);
-
- GST_INFO ("capturing to: %s", file_name);
- return file_name;
+ self->mode = mode;
+ return TRUE;
}
-#endif
-/* signal handlers */
static gboolean
-handle_image_captured_cb (gpointer data)
+gst_test_camera_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
- GMainLoop *loop = (GMainLoop *) data;
+ GstTestCameraSrc *self = (GstTestCameraSrc *) GST_PAD_PARENT (pad);
+ GstCaps *result = NULL;
+ gboolean ret = FALSE;
- /* unblock viewfinder */
- g_object_set (camera, "block-after-capture", FALSE, NULL);
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CAPS:
+ if (pad == self->vfpad) {
+ result = gst_caps_new_any ();
+ } else if (pad == self->vidpad) {
+ result = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS);
+ } else if (pad == self->imgpad) {
+ result = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS);
+ } else {
+ g_assert_not_reached ();
+ }
+ if (result) {
+ GstCaps *filter;
+
+ gst_query_parse_caps (query, &filter);
+ if (filter) {
+ GstCaps *tmp;
+ tmp = gst_caps_intersect (result, filter);
+ gst_caps_replace (&result, tmp);
+ gst_caps_unref (tmp);
+ }
+ gst_query_set_caps_result (query, result);
+ ret = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
- GST_DEBUG ("handle_image_captured_cb, cycle: %d", cycle_count);
- if (cycle_count == 0) {
- GST_DEBUG ("all cycles done");
- g_main_loop_quit (loop);
- } else {
- /* Set video recording mode */
- g_object_set (camera, "mode", 1,
- "filename", make_test_file_name (CYCLE_VIDEO_FILENAME, cycle_count),
- NULL);
- /* Record video */
- g_signal_emit_by_name (camera, "capture-start", NULL);
- g_usleep (G_USEC_PER_SEC);
- g_signal_emit_by_name (camera, "capture-stop", NULL);
- GST_DEBUG ("video captured");
-
- /* Set still image mode */
- g_object_set (camera, "mode", 0,
- "filename", make_test_file_name (CYCLE_IMAGE_FILENAME, cycle_count),
- NULL);
-
- cycle_count--;
- GST_DEBUG ("next cycle: %d", cycle_count);
-
- /* Take a picture */
- g_signal_emit_by_name (camera, "capture-start", NULL);
- }
- GST_DEBUG ("handle_image_captured_cb done");
- return FALSE;
+ return ret;
}
-static gboolean
-capture_done (GstElement * elem, const gchar * filename, gpointer user_data)
+static void
+gst_test_camera_src_class_init (GstTestCameraSrcClass * klass)
{
- GMainLoop *loop = (GMainLoop *) user_data;
+ GstBaseCameraSrcClass *gstbasecamera_class;
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- g_idle_add ((GSourceFunc) handle_image_captured_cb, loop);
+ gstbasecamera_class = GST_BASE_CAMERA_SRC_CLASS (klass);
+ gstbasecamera_class->set_mode = gst_test_camera_src_set_mode;
- GST_INFO ("image saved");
+ gst_element_class_set_details_simple (gstelement_class,
+ "Test Camera Src",
+ "Camera/Src",
+ "Some test camera src",
+ "Thiago Santos <thiago.sousa.santos@collabora.com>");
+}
- return FALSE;
+static void
+gst_test_camera_src_init (GstTestCameraSrc * self)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (parent_class);
+ GstPadTemplate *template;
+
+ /* create pads */
+ template = gst_element_class_get_pad_template (gstelement_class,
+ GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME);
+ self->vfpad = gst_pad_new_from_template (template,
+ GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME);
+ gst_element_add_pad (GST_ELEMENT_CAST (self), self->vfpad);
+
+ template = gst_element_class_get_pad_template (gstelement_class,
+ GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME);
+ self->imgpad = gst_pad_new_from_template (template,
+ GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME);
+ gst_element_add_pad (GST_ELEMENT_CAST (self), self->imgpad);
+
+ template = gst_element_class_get_pad_template (gstelement_class,
+ GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME);
+ self->vidpad = gst_pad_new_from_template (template,
+ GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME);
+ gst_element_add_pad (GST_ELEMENT_CAST (self), self->vidpad);
+
+ /* add get caps functions */
+ gst_pad_set_query_function (self->vfpad, gst_test_camera_src_query);
+ gst_pad_set_query_function (self->vidpad, gst_test_camera_src_query);
+ gst_pad_set_query_function (self->imgpad, gst_test_camera_src_query);
}
-/* configuration */
+/* end of custom test camera src element */
+
+
+static GstElement *camera;
+static guint bus_source;
+static GMainLoop *main_loop;
+static gint capture_count = 0;
+guint32 test_id = 0;
+static gchar *image_filename;
+static gchar *video_filename;
+
+static GstBuffer *preview_buffer;
+static gchar *preview_filename;
+static GstCaps *preview_caps;
+static GstTagList *tags_found;
static gboolean
-set_and_check_camerabin_element (GstElement * camera, const char *property,
- GstElement * element)
-{
- GstElement *element_check;
- gboolean ret = FALSE;
+validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data);
- if (element) {
- g_object_set (camera, property, element, NULL);
- g_object_get (camera, property, &element_check, NULL);
- if (element_check == element)
- ret = TRUE;
- if (element_check)
- g_object_unref (element_check);
- }
- return ret;
-}
+static GstMessage *wait_for_element_message (GstElement * camera,
+ const gchar * name, GstClockTime timeout);
static void
-setup_camerabin_elements (GstElement * camera)
+validate_taglist_foreach (const GstTagList * list, const gchar * tag,
+ gpointer user_data)
{
- GstElement *vfsink, *audiosrc, *videosrc, *audioenc, *videoenc, *imageenc,
- *videomux, *viewfinder_filter, *imagepp, *videopp, *formatter;
- GstCaps *audiocaps, *videocaps;
+ GstTagList *other = GST_TAG_LIST (user_data);
- /* Use fakesink for view finder */
- vfsink = gst_element_factory_make ("fakesink", NULL);
- g_object_set (vfsink, "sync", TRUE, NULL);
- audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
- g_object_set (audiosrc, "is-live", TRUE, NULL);
- videosrc = gst_element_factory_make ("videotestsrc", NULL);
- /* Set pattern to white (3) to avoid timeouts */
- g_object_set (videosrc, "is-live", TRUE, "pattern", 3, NULL);
- audioenc = gst_element_factory_make ("capsfilter", NULL);
- audiocaps = gst_caps_from_string ("audio/x-raw-int");
- g_object_set (audioenc, "caps", audiocaps, NULL);
- gst_caps_unref (audiocaps);
- videoenc = gst_element_factory_make ("capsfilter", NULL);
- videocaps = gst_caps_from_string ("video/x-raw-yuv");
- g_object_set (videoenc, "caps", videocaps, NULL);
- gst_caps_unref (videocaps);
- videomux = gst_element_factory_make ("avimux", NULL);
- imageenc = gst_element_factory_make ("jpegenc", NULL);
- viewfinder_filter = gst_element_factory_make ("identity", NULL);
- imagepp = gst_element_factory_make ("identity", NULL);
- videopp = gst_element_factory_make ("identity", NULL);
- formatter = gst_element_factory_make ("jifmux", NULL);
-
- if (set_and_check_camerabin_element (camera, "viewfinder-sink", vfsink)
- && set_and_check_camerabin_element (camera, "audio-source", audiosrc)
- && set_and_check_camerabin_element (camera, "video-source", videosrc)
- && set_and_check_camerabin_element (camera, "audio-encoder", audioenc)
- && set_and_check_camerabin_element (camera, "video-encoder", videoenc)
- && set_and_check_camerabin_element (camera, "image-encoder", imageenc)
- && set_and_check_camerabin_element (camera, "video-muxer", videomux)
- && set_and_check_camerabin_element (camera, "viewfinder-filter",
- viewfinder_filter)
- && set_and_check_camerabin_element (camera, "image-post-processing",
- imagepp)
- && set_and_check_camerabin_element (camera, "video-post-processing",
- videopp)
- && set_and_check_camerabin_element (camera, "image-formatter", formatter)) {
- GST_INFO ("element properties set and checked");
+ const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0);
+ const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0);
+
+ GST_DEBUG ("checking tag '%s'", tag);
+
+ fail_if (val1 == NULL);
+ fail_if (val2 == NULL);
+
+ fail_unless (gst_value_compare (val1, val2) == GST_VALUE_EQUAL);
+}
+
+
+/* helper function for filenames */
+static gchar *
+make_test_file_name (const gchar * base_name, gint num)
+{
+ /* num == -1 means to keep the %d in the resulting string to be used on
+ * multifilesink like location */
+ if (num == -1) {
+ return g_strdup_printf ("%s" G_DIR_SEPARATOR_S
+ "gstcamerabin2test_%s_%u_%%03d.cap", g_get_tmp_dir (), base_name,
+ test_id);
} else {
- GST_WARNING ("error setting up test plugins");
+ return g_strdup_printf ("%s" G_DIR_SEPARATOR_S
+ "gstcamerabin2test_%s_%u_%03d.cap", g_get_tmp_dir (), base_name,
+ test_id, num);
}
}
+static const gchar *
+make_const_file_name (const gchar * filename, gint num)
+{
+ static gchar file_name[1000];
+
+ /* num == -1 means to keep the %d in the resulting string to be used on
+ * multifilesink like location */
+ g_snprintf (file_name, 999, filename, num);
+
+ return file_name;
+}
+
+/* configuration */
+
static gboolean
capture_bus_cb (GstBus * bus, GstMessage * message, gpointer data)
{
break;
default:
st = gst_message_get_structure (message);
- if (st && gst_structure_has_name (st, "image-captured")) {
- gboolean ready = FALSE;
+ if (st && gst_structure_has_name (st, "image-done")) {
GST_INFO ("image captured");
- g_object_get (camera, "ready-for-capture", &ready, NULL);
- fail_if (!ready, "not ready for capture");
+ } else if (st && gst_structure_has_name (st,
+ GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) {
+ GstBuffer *buf;
+ const GValue *value;
+
+ value = gst_structure_get_value (st, "buffer");
+ fail_unless (value != NULL);
+ buf = gst_value_get_buffer (value);
+
+ if (preview_buffer)
+ gst_buffer_unref (preview_buffer);
+ preview_buffer = gst_buffer_ref (buf);
+ g_free (preview_filename);
+ preview_filename = g_strdup (gst_structure_get_string (st, "location"));
}
break;
}
return TRUE;
}
-static GstBusSyncReply
-bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
+static void
+check_preview_image (GstElement * camera, const gchar * filename, gint index)
{
- const GstStructure *st;
- st = gst_message_get_structure (message);
- if (st) {
- if (gst_structure_has_name (st, "preview-image")) {
- GST_DEBUG ("get preview-image message");
- received_preview_msg = TRUE;
+ gchar *prev_filename = NULL;
+
+ if (!preview_buffer && camera) {
+ GstMessage *msg = wait_for_element_message (camera,
+ GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME, GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+ }
+ fail_unless (preview_buffer != NULL);
+ if (filename) {
+ if (index >= 0) {
+ prev_filename = g_strdup_printf (filename, index);
+ } else {
+ prev_filename = g_strdup (filename);
}
+ fail_unless (preview_filename != NULL);
+ fail_unless (strcmp (preview_filename, prev_filename) == 0);
}
+ if (preview_caps) {
+ /* TODO porting
+ fail_unless (GST_BUFFER_CAPS (preview_buffer) != NULL);
+ fail_unless (gst_caps_can_intersect (GST_BUFFER_CAPS (preview_buffer),
+ preview_caps));
+ */
+ }
+ g_free (prev_filename);
+}
+static void
+extract_jpeg_tags (const gchar * filename, gint num)
+{
+ GstBus *bus;
+ GMainLoop *loop = g_main_loop_new (NULL, FALSE);
+ const gchar *filepath = make_const_file_name (filename, num);
+ gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! "
+ "jpegparse ! fakesink", filepath);
+ GstElement *pipeline;
+ guint source;
+
+ pipeline = gst_parse_launch (pipeline_str, NULL);
+ fail_unless (pipeline != NULL);
+ g_free (pipeline_str);
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
- return GST_BUS_PASS;
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ g_main_loop_run (loop);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_object_unref (bus);
+ g_source_remove (source);
+ gst_object_unref (pipeline);
+ g_main_loop_unref (loop);
}
static void
-setup (void)
+setup_wrappercamerabinsrc_videotestsrc (void)
{
- GstTagSetter *setter;
- gchar *desc_str;
- GstCaps *filter_caps;
GstBus *bus;
- gint i;
+ GstElement *vfbin;
+ GstElement *fakevideosink;
+ GstElement *src;
+ GstElement *testsrc;
+ GstElement *audiosrc;
GST_INFO ("init");
+ test_id = g_random_int ();
+ bus_source = 0;
+
main_loop = g_main_loop_new (NULL, TRUE);
- camera = gst_check_setup_element ("camerabin");
+ camera = gst_check_setup_element ("camerabin2");
+ fakevideosink = gst_element_factory_make ("fakesink", NULL);
+ src = gst_element_factory_make ("wrappercamerabinsrc", NULL);
+ testsrc = gst_element_factory_make ("videotestsrc", NULL);
+ audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
+
+ preview_caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+ 320, "height", G_TYPE_INT, 240, NULL);
- setup_camerabin_elements (camera);
+ g_object_set (G_OBJECT (testsrc), "is-live", TRUE, NULL);
+ g_object_set (G_OBJECT (audiosrc), "is-live", TRUE, NULL);
+ g_object_set (G_OBJECT (src), "video-source", testsrc, NULL);
+ g_object_set (G_OBJECT (camera), "camera-source", src, "preview-caps",
+ preview_caps, "post-previews", TRUE, "audio-source", audiosrc, NULL);
+ gst_object_unref (src);
+ gst_object_unref (testsrc);
+ gst_object_unref (audiosrc);
- g_signal_connect (camera, "image-done", G_CALLBACK (capture_done), main_loop);
+ vfbin = gst_bin_get_by_name (GST_BIN (camera), "vf-bin");
+ g_object_set (G_OBJECT (vfbin), "video-sink", fakevideosink, NULL);
+ gst_object_unref (vfbin);
+ gst_object_unref (fakevideosink);
bus = gst_pipeline_get_bus (GST_PIPELINE (camera));
bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop);
- gst_bus_set_sync_handler (bus, bus_sync_callback, main_loop);
gst_object_unref (bus);
- filter_caps = gst_caps_from_string ("video/x-raw-yuv,format=(fourcc)I420");
- g_object_set (G_OBJECT (camera), "filter-caps", filter_caps, NULL);
- gst_caps_unref (filter_caps);
-
- /* force a low framerate here to not timeout the tests because of the
- * encoders */
- g_signal_emit_by_name (camera, "set-video-resolution-fps", 320, 240, 5, 1,
- NULL);
-
- /* Set some default tags */
- setter = GST_TAG_SETTER (camera);
- desc_str = g_strdup_printf ("Created by %s", g_get_real_name ());
-
- gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
- GST_TAG_DESCRIPTION, desc_str, NULL);
- g_free (desc_str);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
-
- /* create the taglists */
- for (i = 0; i < TAGLISTS_COUNT; i++) {
- taglists[i] = gst_tag_list_new (GST_TAG_ARTIST, "test-artist",
- GST_TAG_GEO_LOCATION_LONGITUDE, g_random_double_range (-180, 180),
- GST_TAG_GEO_LOCATION_LATITUDE, g_random_double_range (-90, 90),
- GST_TAG_GEO_LOCATION_ELEVATION, g_random_double_range (0, 3000), NULL);
- }
+ tags_found = NULL;
+ capture_count = 0;
+ image_filename = make_test_file_name (IMAGE_FILENAME, -1);
+ video_filename = make_test_file_name (VIDEO_FILENAME, -1);
GST_INFO ("init finished");
}
static void
teardown (void)
{
- gint i;
-
- g_source_remove (bus_source);
+ gst_element_set_state (camera, GST_STATE_NULL);
if (camera)
gst_check_teardown_element (camera);
+ camera = NULL;
- for (i = 0; i < TAGLISTS_COUNT; i++) {
- gst_tag_list_free (taglists[i]);
- }
+ if (bus_source)
+ g_source_remove (bus_source);
- GST_INFO ("done");
-}
+ if (main_loop)
+ g_main_loop_unref (main_loop);
+ main_loop = NULL;
-static void
-test_camerabin_properties (GstElement * cam)
-{
- guint flags;
- gfloat zoom;
- gboolean mute;
+ if (preview_caps)
+ gst_caps_unref (preview_caps);
+ preview_caps = NULL;
+
+ if (preview_buffer)
+ gst_buffer_unref (preview_buffer);
+ preview_buffer = NULL;
+
+ g_free (preview_filename);
+ preview_filename = NULL;
+
+ if (tags_found)
+ gst_tag_list_free (tags_found);
+ tags_found = NULL;
- flags = 0x1f;
- g_object_set (G_OBJECT (cam), "flags", flags, NULL);
- g_object_get (G_OBJECT (cam), "flags", &flags, NULL);
- fail_if (flags != 0x1f, "setting camerabin flags failed");
+ g_free (video_filename);
+ video_filename = NULL;
- zoom = 2.0;
- g_object_set (G_OBJECT (cam), "zoom", zoom, NULL);
- g_object_get (G_OBJECT (cam), "zoom", &zoom, NULL);
- fail_if (zoom != 2.0, "setting camerabin zoom failed");
- g_object_set (G_OBJECT (cam), "zoom", 1.0f, NULL);
+ g_free (image_filename);
+ image_filename = NULL;
- mute = TRUE;
- g_object_set (G_OBJECT (cam), "mute", mute, NULL);
- g_object_get (G_OBJECT (cam), "mute", &mute, NULL);
- fail_if (mute != TRUE, "setting camerabin mute failed");
- g_object_set (G_OBJECT (cam), "mute", FALSE, NULL);
+ GST_INFO ("done");
}
static gboolean
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR:
+ case GST_MESSAGE_ERROR:{
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ gst_message_parse_error (message, &err, &debug);
+
+ GST_ERROR ("Error: %s : %s", err->message, debug);
+ g_error_free (err);
+ g_free (debug);
+
fail_if (TRUE, "validating captured data failed");
g_main_loop_quit (loop);
+ }
break;
case GST_MESSAGE_EOS:
g_main_loop_quit (loop);
GST_DEBUG ("eos");
break;
case GST_MESSAGE_TAG:{
- GstTagList *tags = NULL;
- gst_message_parse_tag (message, &tags);
- if (validation_taglist) {
- gst_tag_list_insert (validation_taglist, tags, GST_TAG_MERGE_REPLACE);
- gst_tag_list_free (tags);
- } else
- validation_taglist = tags;
- break;
+ GstTagList *taglist = NULL;
+
+ gst_message_parse_tag (message, &taglist);
+ if (tags_found) {
+ gst_tag_list_insert (tags_found, taglist, GST_TAG_MERGE_REPLACE);
+ gst_tag_list_free (taglist);
+ } else {
+ tags_found = taglist;
+ }
+ GST_DEBUG ("tags: %" GST_PTR_FORMAT, tags_found);
}
+ break;
default:
break;
}
return TRUE;
}
-static void
-validate_taglist_foreach (const GstTagList * list, const gchar * tag,
- gpointer user_data)
-{
- GstTagList *other = GST_TAG_LIST (user_data);
-
- const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0);
- const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0);
-
- fail_if (val1 == NULL);
- fail_if (val2 == NULL);
-
- fail_unless (gst_value_can_intersect (val1, val2));
-}
-
-static void
-extract_jpeg_tags (const gchar * filename, gint num)
+/* checks that tags in @tags_a are in @tags_b */
+static gboolean
+taglist_is_subset (GstTagList * tags_a, GstTagList * tags_b)
{
- guint source;
- GstBus *bus;
- GMainLoop *loop = g_main_loop_new (NULL, FALSE);
- const gchar *filepath = make_test_file_name (filename, num);
- gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! "
- "jpegparse ! fakesink", filepath);
- GstElement *pipeline;
-
- pipeline = gst_parse_launch (pipeline_str, NULL);
- fail_unless (pipeline != NULL);
- g_free (pipeline_str);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
- source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
-
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
- g_main_loop_run (loop);
- gst_element_set_state (pipeline, GST_STATE_NULL);
-
- g_main_loop_unref (loop);
- g_source_remove (source);
- gst_object_unref (bus);
- gst_object_unref (pipeline);
+ gst_tag_list_foreach (tags_a, validate_taglist_foreach, tags_b);
+ return TRUE;
}
/* Validate captured files by playing them with playbin
* and checking that no errors occur. */
+#define WITH_AUDIO TRUE
+#define NO_AUDIO FALSE
static gboolean
-check_file_validity (const gchar * filename, gint num, GstTagList * taglist)
+check_file_validity (const gchar * filename, gint num, GstTagList * taglist,
+ gint width, gint height, gboolean has_audio)
{
- guint source;
GstBus *bus;
+ GstPad *pad;
+ GstCaps *caps;
+ gint caps_width, caps_height;
+ GstState state;
+ guint source;
+
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
GstElement *playbin = gst_element_factory_make ("playbin2", NULL);
GstElement *fakevideo = gst_element_factory_make ("fakesink", NULL);
GstElement *fakeaudio = gst_element_factory_make ("fakesink", NULL);
- gchar *uri = g_strconcat ("file://", make_test_file_name (filename, num),
+ gchar *uri = g_strconcat ("file://", make_const_file_name (filename, num),
NULL);
GST_DEBUG ("checking uri: %s", uri);
g_object_set (G_OBJECT (playbin), "uri", uri, "video-sink", fakevideo,
"audio-sink", fakeaudio, NULL);
- validation_taglist = NULL;
bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
+ gst_element_set_state (playbin, GST_STATE_PAUSED);
+ gst_element_get_state (playbin, &state, NULL, GST_SECOND * 3);
+
+ if (width != 0 && height != 0) {
+ g_signal_emit_by_name (playbin, "get-video-pad", 0, &pad, NULL);
+ g_assert (pad != NULL);
+ caps = gst_pad_get_current_caps (pad);
+
+ g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0),
+ "width", &caps_width));
+ g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0),
+ "height", &caps_height));
+
+ g_assert (width == caps_width);
+ g_assert (height == caps_height);
+
+ gst_caps_unref (caps);
+ gst_object_unref (pad);
+ }
+ if (has_audio) {
+ g_signal_emit_by_name (playbin, "get-audio-pad", 0, &pad, NULL);
+ g_assert (pad != NULL);
+ gst_object_unref (pad);
+ }
+
gst_element_set_state (playbin, GST_STATE_PLAYING);
g_main_loop_run (loop);
gst_element_set_state (playbin, GST_STATE_NULL);
extract_jpeg_tags (filename, num);
}
- /* check taglist */
if (taglist) {
- fail_if (validation_taglist == NULL);
-
- GST_DEBUG ("Comparing taglists %" GST_PTR_FORMAT "; with %" GST_PTR_FORMAT,
- taglist, validation_taglist);
-
- gst_tag_list_foreach (taglist, validate_taglist_foreach,
- validation_taglist);
+ fail_unless (tags_found != NULL);
+ fail_unless (taglist_is_subset (taglist, tags_found));
}
- if (validation_taglist)
- gst_tag_list_free (validation_taglist);
g_free (uri);
g_source_remove (source);
{
const gchar *fn;
- fn = make_test_file_name (fn_template, num);
+ fn = make_const_file_name (fn_template, num);
GST_INFO ("removing %s", fn);
g_unlink (fn);
}
-GST_START_TEST (test_single_image_capture)
+static GstPadProbeReturn
+filter_buffer_count (GstPad * pad, GstPadProbeInfo * info, gpointer data)
{
- gboolean ready = FALSE;
- gboolean idle = FALSE;
- if (!camera)
- return;
+ gint *counter = data;
- /* Test photography iface settings */
- gst_element_get_state (GST_ELEMENT (camera), NULL, NULL, (2 * GST_SECOND));
- test_camerabin_properties (camera);
+ (*counter)++;
- /* set flags to disable additional elements */
- g_object_set (camera, "flags", 0, NULL);
+ return GST_PAD_PROBE_OK;
+}
- /* set still image mode */
- g_object_set (camera, "mode", 0,
- "filename", make_test_file_name (SINGLE_IMAGE_FILENAME, 0), NULL);
+static GstMessage *
+wait_for_element_message (GstElement * camera, const gchar * name,
+ GstClockTime timeout)
+{
+ GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (camera));
+ GstMessage *msg;
+
+ while (1) {
+ msg = gst_bus_timed_pop_filtered (bus, timeout, GST_MESSAGE_ERROR |
+ GST_MESSAGE_EOS | GST_MESSAGE_ELEMENT);
+
+ if (msg) {
+ if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
+ const GstStructure *st = gst_message_get_structure (msg);
+ if (gst_structure_has_name (st,
+ GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) {
+ GstBuffer *buf;
+ const GValue *value;
+
+ value = gst_structure_get_value (st, "buffer");
+ fail_unless (value != NULL);
+ buf = gst_value_get_buffer (value);
+
+ if (preview_buffer)
+ gst_buffer_unref (preview_buffer);
+ preview_buffer = gst_buffer_ref (buf);
+ g_free (preview_filename);
+ preview_filename =
+ g_strdup (gst_structure_get_string (st, "location"));
+ }
+
+ if (gst_structure_has_name (st, name))
+ break;
+ else
+ gst_message_unref (msg);
+ } else {
+ gst_message_unref (msg);
+ msg = NULL;
+ break;
+ }
+ }
+ }
- /* don't run viewfinder after capture */
- g_object_set (camera, "block-after-capture", TRUE, NULL);
+ gst_object_unref (bus);
+ return msg;
+}
- /* check that capturing is possible */
- g_object_get (camera, "ready-for-capture", &ready, NULL);
- fail_if (!ready, "not ready for capture");
+static void
+wait_for_idle_state (void)
+{
+ gboolean idle = FALSE;
- /* check that the camera is idle */
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (!idle, "camera should be idle");
+ /* not the ideal way, but should be enough for testing */
+ while (idle == FALSE) {
+ g_object_get (camera, "idle", &idle, NULL);
+ if (idle)
+ break;
- GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
+ GST_LOG ("waiting for idle state..");
+ g_usleep (G_USEC_PER_SEC / 5);
+ }
+ fail_unless (idle);
+}
- g_object_get (camera, "ready-for-capture", &ready, NULL);
- fail_if (ready, "ready for capture during capture");
+GST_START_TEST (test_single_image_capture)
+{
+ gboolean idle;
+ GstMessage *msg;
+ if (!camera)
+ return;
- g_main_loop_run (main_loop);
+ /* set still image mode */
+ g_object_set (camera, "mode", 1, "location", image_filename, NULL);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ GST_INFO ("starting capture");
+ fail_unless (camera != NULL);
g_object_get (camera, "idle", &idle, NULL);
- fail_if (!idle, "camera should be idle");
+ fail_unless (idle);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+
+ /* check that we got a preview image */
+ check_preview_image (camera, image_filename, 0);
- check_file_validity (SINGLE_IMAGE_FILENAME, 0, NULL);
- remove_file (SINGLE_IMAGE_FILENAME, 0);
+ wait_for_idle_state ();
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO);
+ remove_file (image_filename, 0);
}
GST_END_TEST;
-GST_START_TEST (test_single_image_capture_with_flags)
+
+GST_START_TEST (test_multiple_image_captures)
{
+ gboolean idle;
+ gint i;
+ gint widths[] = { 800, 640, 1280 };
+ gint heights[] = { 600, 480, 1024 };
+
if (!camera)
return;
- /* set flags to enable modifier elements */
- g_object_set (camera, "flags", 79, NULL);
-
/* set still image mode */
- g_object_set (camera, "mode", 0,
- "filename", make_test_file_name (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0),
- NULL);
+ g_object_set (camera, "mode", 1, "location", image_filename, NULL);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ fail_unless (camera != NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (idle);
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
- g_main_loop_run (main_loop);
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ for (i = 0; i < 3; i++) {
+ GstMessage *msg;
+ GstCaps *caps;
- check_file_validity (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0, NULL);
- remove_file (SINGLE_IMAGE_WITH_FLAGS_FILENAME, 0);
-}
+ caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+ widths[i], "height", G_TYPE_INT, heights[i], NULL);
-GST_END_TEST;
+ g_object_set (camera, "image-capture-caps", caps, NULL);
+ gst_caps_unref (caps);
-GST_START_TEST (test_video_recording)
-{
- GstCaps *preview_caps;
- gboolean idle = FALSE;
- preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240");
+ g_signal_emit_by_name (camera, "start-capture", NULL);
- if (!camera)
- return;
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
- /* set flags to disable additional elements */
- g_object_set (camera, "flags", 0, NULL);
+ check_preview_image (camera, image_filename, i);
+ }
- /* Set video recording mode */
- g_object_set (camera, "mode", 1,
- "filename", make_test_file_name (VIDEO_WITH_FLAGS_FILENAME, 0), NULL);
+ wait_for_idle_state ();
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ for (i = 0; i < 3; i++) {
+ check_file_validity (image_filename, i, NULL, widths[i], heights[i],
+ NO_AUDIO);
+ remove_file (image_filename, i);
+ }
+}
- /* Set preview-caps */
- g_object_set (camera, "preview-caps", preview_caps, NULL);
- gst_caps_unref (preview_caps);
+GST_END_TEST;
- /* check that the camera is idle */
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (!idle, "camera should be idle");
+GST_START_TEST (test_single_video_recording)
+{
+ GstMessage *msg;
+ gboolean idle;
+ if (!camera)
+ return;
+
+ /* Set video recording mode */
+ g_object_set (camera, "mode", 2, "location", video_filename, NULL);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
+ fail_unless (camera != NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (idle);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
g_object_get (camera, "idle", &idle, NULL);
- fail_if (idle, "camera should not be idle");
+ fail_unless (!idle);
/* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
+ g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
+ main_loop);
+ g_main_loop_run (main_loop);
- g_signal_emit_by_name (camera, "capture-stop", NULL);
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (!idle, "camera should be idle");
+ check_preview_image (camera, video_filename, 0);
- /* check if receiving the preview-image message */
- fail_if (!received_preview_msg,
- "creating video recording preview image failed");
+ msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+ wait_for_idle_state ();
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (VIDEO_WITH_FLAGS_FILENAME, 0, NULL);
- remove_file (VIDEO_WITH_FLAGS_FILENAME, 0);
+ check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
+ remove_file (video_filename, 0);
+
}
GST_END_TEST;
-GST_START_TEST (test_video_recording_with_flags)
+GST_START_TEST (test_multiple_video_recordings)
{
- GstCaps *preview_caps;
- preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240");
+ gboolean idle;
+ gint i;
+ gint widths[] = { 800, 640, 1280 };
+ gint heights[] = { 600, 480, 1024 };
+ gint fr[] = { 20, 30, 5 };
if (!camera)
return;
- /* set flags to enable modifier elements */
- g_object_set (camera, "flags", 95, NULL);
-
/* Set video recording mode */
- g_object_set (camera, "mode", 1,
- "filename", make_test_file_name (VIDEO_FILENAME, 0), NULL);
+ g_object_set (camera, "mode", 2, "location", video_filename, NULL);
- /* Set preview-caps */
- g_object_set (camera, "preview-caps", preview_caps, NULL);
- gst_caps_unref (preview_caps);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
- /* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
- g_signal_emit_by_name (camera, "capture-stop", NULL);
+ fail_unless (camera != NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (idle);
+ for (i = 0; i < 3; i++) {
+ GstMessage *msg;
+ GstCaps *caps;
+
+ caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+ widths[i], "height", G_TYPE_INT, heights[i], "framerate",
+ GST_TYPE_FRACTION, fr[i], 1, NULL);
+
+ g_object_set (camera, "video-capture-caps", caps, NULL);
- /*check if receiving the preview-image message */
- fail_if (!received_preview_msg,
- "creating video recording preview image failed");
+ gst_caps_unref (caps);
+ GST_LOG ("starting #%d with caps %" GST_PTR_FORMAT, i, caps);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (!idle);
+
+ g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
+ main_loop);
+ g_main_loop_run (main_loop);
+
+ GST_LOG ("stopping run %d", i);
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
+
+ msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+
+ GST_LOG ("video done, checking preview image");
+ check_preview_image (camera, video_filename, i);
+
+ GST_LOG ("waiting for idle state");
+ wait_for_idle_state ();
+ GST_LOG ("finished run %d", i);
+ }
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (VIDEO_FILENAME, 0, NULL);
- remove_file (VIDEO_FILENAME, 0);
+ for (i = 0; i < 3; i++) {
+ check_file_validity (video_filename, i, NULL, widths[i], heights[i],
+ WITH_AUDIO);
+ remove_file (video_filename, i);
+ }
}
GST_END_TEST;
-GST_START_TEST (test_video_recording_pause)
+GST_START_TEST (test_image_video_cycle)
{
- gboolean idle = FALSE;
+ gint i;
+
if (!camera)
return;
- /* Set video recording mode */
- g_object_set (camera, "mode", 1,
- "filename", make_test_file_name (VIDEO_PAUSE_FILENAME, 0), NULL);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle, "camera should be idle");
+ GST_INFO ("starting capture");
+ for (i = 0; i < 2; i++) {
+ GstMessage *msg;
+ const gchar *img_filename;
+ const gchar *vid_filename;
+
+ wait_for_idle_state ();
+
+ /* take a picture */
+ img_filename = make_const_file_name (image_filename, i);
+ g_object_set (camera, "mode", 1, NULL);
+ g_object_set (camera, "location", img_filename, NULL);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+
+ check_preview_image (camera, img_filename, i);
+
+ /* now go to video */
+ vid_filename = make_const_file_name (video_filename, i);
+ g_object_set (camera, "mode", 2, NULL);
+ g_object_set (camera, "location", vid_filename, NULL);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+ g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
+ main_loop);
+ g_main_loop_run (main_loop);
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
+
+ msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+
+ check_preview_image (camera, vid_filename, i);
+ }
+
+ wait_for_idle_state ();
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+
+ /* validate all the files */
+ for (i = 0; i < 2; i++) {
+ check_file_validity (image_filename, i, NULL, 0, 0, NO_AUDIO);
+ remove_file (image_filename, i);
+ check_file_validity (video_filename, i, NULL, 0, 0, WITH_AUDIO);
+ remove_file (video_filename, i);
+ }
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_image_capture_previews)
+{
+ gint i;
+ gint widths[] = { 800, 640, 1280 };
+ gint heights[] = { 600, 480, 1024 };
+
+ if (!camera)
+ return;
+
+ /* set still image mode */
+ g_object_set (camera, "mode", 1, "location", image_filename, NULL);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ fail_unless (camera != NULL);
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (idle, "camera shouldn't be idle when recording");
+ for (i = 0; i < 3; i++) {
+ GstMessage *msg;
+ GstCaps *caps;
- /* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
+ caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+ widths[i], "height", G_TYPE_INT, heights[i], NULL);
- GST_INFO ("pause capture");
- g_signal_emit_by_name (camera, "capture-pause", NULL);
+ g_object_set (camera, "preview-caps", caps, NULL);
+ gst_caps_replace (&preview_caps, caps);
+ gst_caps_unref (caps);
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (idle, "camera shouldn't be idle when recording and paused");
+ g_signal_emit_by_name (camera, "start-capture", NULL);
- /* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
- GST_INFO ("continue capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
+ check_preview_image (camera, image_filename, i);
+ remove_file (image_filename, i);
- g_object_get (camera, "idle", &idle, NULL);
- fail_if (idle, "camera shouldn't be idle when recording");
+ if (preview_buffer)
+ gst_buffer_unref (preview_buffer);
+ preview_buffer = NULL;
+ gst_caps_replace (&preview_caps, NULL);
+ }
- /* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
- g_signal_emit_by_name (camera, "capture-stop", NULL);
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+}
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle, "camera should be idle after capture-stop");
+GST_END_TEST;
+
+
+GST_START_TEST (test_image_capture_with_tags)
+{
+ gint i;
+ GstTagList *taglists[3];
+
+ if (!camera)
+ return;
+
+ taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1",
+ GST_TAG_GEO_LOCATION_LATITUDE, 36.6, GST_TAG_GEO_LOCATION_LONGITUDE,
+ -12.5,
+ GST_TAG_COPYRIGHT, "My copyright notice",
+ GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand",
+ GST_TAG_DEVICE_MODEL, "123v42.1",
+ GST_TAG_DESCRIPTION, "some description",
+ GST_TAG_APPLICATION_NAME, "camerabin2 test",
+ GST_TAG_GEO_LOCATION_ELEVATION, 300.85, NULL);
+ taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2",
+ GST_TAG_GEO_LOCATION_LATITUDE, 1.6, GST_TAG_GEO_LOCATION_LONGITUDE,
+ 0.0,
+ GST_TAG_COPYRIGHT, "some cp",
+ GST_TAG_DEVICE_MANUFACTURER, "ABRAND",
+ GST_TAG_DEVICE_MODEL, "abcd",
+ GST_TAG_DESCRIPTION, "desc",
+ GST_TAG_APPLICATION_NAME, "another cam test",
+ GST_TAG_GEO_LOCATION_ELEVATION, 10.0, NULL);
+ taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3",
+ GST_TAG_GEO_LOCATION_LATITUDE, 1.3, GST_TAG_GEO_LOCATION_LONGITUDE,
+ -5.0,
+ GST_TAG_COPYRIGHT, "CC",
+ GST_TAG_DEVICE_MANUFACTURER, "Homemade",
+ GST_TAG_DEVICE_MODEL, "xpto",
+ GST_TAG_DESCRIPTION, "another description",
+ GST_TAG_APPLICATION_NAME, "cam2 test",
+ GST_TAG_GEO_LOCATION_ELEVATION, 0.0, NULL);
+
+ /* set still image mode */
+ g_object_set (camera, "mode", 1, "location", image_filename, NULL);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ fail_unless (camera != NULL);
+ GST_INFO ("starting capture");
+
+ for (i = 0; i < 3; i++) {
+ GstMessage *msg;
+ gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
+ GST_TAG_MERGE_REPLACE);
+
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+ }
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (VIDEO_PAUSE_FILENAME, 0, NULL);
- remove_file (VIDEO_PAUSE_FILENAME, 0);
+ for (i = 0; i < 3; i++) {
+ check_file_validity (image_filename, i, taglists[i], 0, 0, NO_AUDIO);
+ gst_tag_list_free (taglists[i]);
+ remove_file (image_filename, i);
+ }
}
GST_END_TEST;
-GST_START_TEST (test_video_recording_no_audio)
+
+GST_START_TEST (test_video_capture_with_tags)
{
- GstCaps *preview_caps;
- preview_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240");
+ gint i;
+ GstTagList *taglists[3];
if (!camera)
return;
- /* set flags to disable audio elements */
- g_object_set (camera, "flags", 32, NULL);
+ taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1", NULL);
+ taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2", NULL);
+ taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3", NULL);
+
+ /* set video mode */
+ g_object_set (camera, "mode", 2, "location", video_filename, NULL);
+
+ /* set a profile that has xmp support for more tags being saved */
+ {
+ GstEncodingContainerProfile *profile;
+ GstCaps *caps;
+
+ caps =
+ gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING,
+ "apple", NULL);
+ profile = gst_encoding_container_profile_new ("qt", "jpeg+qt", caps, NULL);
+ gst_caps_unref (caps);
+
+ caps = gst_caps_new_simple ("image/jpeg", NULL, NULL);
+ if (!gst_encoding_container_profile_add_profile (profile,
+ (GstEncodingProfile *) gst_encoding_video_profile_new (caps,
+ NULL, NULL, 1))) {
+ GST_WARNING_OBJECT (camera, "Failed to create encoding profiles");
+ }
+ gst_caps_unref (caps);
+
+ g_object_set (camera, "video-profile", profile, NULL);
+ gst_encoding_profile_unref (profile);
+ }
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ fail_unless (camera != NULL);
+ GST_INFO ("starting capture");
+
+ for (i = 0; i < 3; i++) {
+ GstMessage *msg;
+
+ gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
+ GST_TAG_MERGE_REPLACE);
+
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+
+ g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
+ g_main_loop_run (main_loop);
+
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
+
+ msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+ }
+
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+
+ for (i = 0; i < 3; i++) {
+ check_file_validity (video_filename, i, taglists[i], 0, 0, NO_AUDIO);
+ gst_tag_list_free (taglists[i]);
+ remove_file (video_filename, i);
+ }
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_supported_caps)
+{
+ GstCaps *padcaps = NULL;
+ GstCaps *expectedcaps;
+ GstElement *src;
+
+ if (!camera)
+ return;
+
+ src = g_object_new (GST_TYPE_TEST_CAMERA_SRC, NULL);
+ g_object_set (camera, "camera-source", src, NULL);
+ gst_object_unref (src);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ g_assert (camera != NULL);
+
+ expectedcaps = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS);
+ g_object_get (G_OBJECT (camera), "video-capture-supported-caps", &padcaps,
+ NULL);
+ g_assert (expectedcaps != NULL);
+ g_assert (padcaps != NULL);
+ g_assert (gst_caps_is_equal (padcaps, expectedcaps));
+ gst_caps_unref (expectedcaps);
+ gst_caps_unref (padcaps);
+
+ expectedcaps = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS);
+ g_object_get (G_OBJECT (camera), "image-capture-supported-caps", &padcaps,
+ NULL);
+ g_assert (expectedcaps != NULL);
+ g_assert (padcaps != NULL);
+ g_assert (gst_caps_is_equal (padcaps, expectedcaps));
+ gst_caps_unref (expectedcaps);
+ gst_caps_unref (padcaps);
+
+ gst_element_set_state (camera, GST_STATE_NULL);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_idle_property)
+{
+ GstMessage *msg;
+ gboolean idle;
+ if (!camera)
+ return;
/* Set video recording mode */
- g_object_set (camera, "mode", 1,
- "filename", make_test_file_name (VIDEO_NOAUDIO_FILENAME, 0), NULL);
+ g_object_set (camera, "mode", 2, "location", video_filename, NULL);
- /* Set preview-caps */
- g_object_set (camera, "preview-caps", preview_caps, NULL);
- gst_caps_unref (preview_caps);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
+ fail_unless (camera != NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (idle);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (!idle);
+
+ /* emit a second start-capture that should be ignored */
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+ g_object_get (camera, "idle", &idle, NULL);
+ fail_unless (!idle);
+
/* Record for one seconds */
- g_usleep (G_USEC_PER_SEC);
- g_signal_emit_by_name (camera, "capture-stop", NULL);
+ g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
+ main_loop);
+ g_main_loop_run (main_loop);
+
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
+
+ msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
- /* check if receiving the preview-image message */
- fail_if (!received_preview_msg,
- "creating video recording preview image failed");
+ check_preview_image (camera, video_filename, 0);
+
+ wait_for_idle_state ();
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (VIDEO_NOAUDIO_FILENAME, 0, NULL);
- remove_file (VIDEO_NOAUDIO_FILENAME, 0);
+ check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
+ remove_file (video_filename, 0);
}
GST_END_TEST;
-GST_START_TEST (test_image_video_cycle)
+
+GST_START_TEST (test_image_custom_filter)
{
- gint i;
+ GstElement *vf_filter;
+ GstElement *image_filter;
+ GstElement *preview_filter;
+ GstPad *pad;
+ gint vf_probe_counter = 0;
+ gint image_probe_counter = 0;
+ gint preview_probe_counter = 0;
if (!camera)
return;
- cycle_count = CYCLE_COUNT_MAX;
+ vf_filter = gst_element_factory_make ("identity", "vf-filter");
+ image_filter = gst_element_factory_make ("identity", "img-filter");
+ preview_filter = gst_element_factory_make ("identity", "preview-filter");
- /* set still image mode */
- g_object_set (camera, "mode", 0,
- "filename", make_test_file_name (CYCLE_IMAGE_FILENAME, cycle_count),
- NULL);
+ pad = gst_element_get_static_pad (vf_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &vf_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (image_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &image_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (preview_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &preview_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ /* set still image mode and filters */
+ g_object_set (camera, "mode", 1,
+ "location", image_filename,
+ "viewfinder-filter", vf_filter, "image-filter", image_filter,
+ "preview-filter", preview_filter, NULL);
+
+ gst_object_unref (vf_filter);
+ gst_object_unref (preview_filter);
+ gst_object_unref (image_filter);
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
GST_INFO ("starting capture");
- g_signal_emit_by_name (camera, "capture-start", NULL);
+ fail_unless (camera != NULL);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+ g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
g_main_loop_run (main_loop);
+
+ /* check that we got a preview image */
+ check_preview_image (camera, image_filename, 0);
+
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO);
+ remove_file (image_filename, 0);
- /* validate all the files */
- for (i = 2; i > 0; i--) {
- check_file_validity (CYCLE_IMAGE_FILENAME, i, NULL);
- remove_file (CYCLE_IMAGE_FILENAME, i);
- check_file_validity (CYCLE_VIDEO_FILENAME, i, NULL);
- remove_file (CYCLE_VIDEO_FILENAME, i);
+ fail_unless (vf_probe_counter > 0);
+ fail_unless (image_probe_counter == 1);
+ fail_unless (preview_probe_counter == 1);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_video_custom_filter)
+{
+ GstElement *vf_filter;
+ GstElement *video_filter;
+ GstElement *preview_filter;
+ GstElement *audio_filter;
+ GstPad *pad;
+ gint vf_probe_counter = 0;
+ gint video_probe_counter = 0;
+ gint preview_probe_counter = 0;
+ gint audio_probe_counter = 0;
+
+ if (!camera)
+ return;
+
+ vf_filter = gst_element_factory_make ("identity", "vf-filter");
+ video_filter = gst_element_factory_make ("identity", "video-filter");
+ preview_filter = gst_element_factory_make ("identity", "preview-filter");
+ audio_filter = gst_element_factory_make ("identity", "audio-filter");
+
+ pad = gst_element_get_static_pad (vf_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &vf_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (video_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &video_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (audio_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &audio_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (preview_filter, "src");
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
+ &preview_probe_counter, NULL);
+ gst_object_unref (pad);
+
+ /* set still image mode and filters */
+ g_object_set (camera, "mode", 2,
+ "location", video_filename,
+ "viewfinder-filter", vf_filter, "video-filter", video_filter,
+ "preview-filter", preview_filter, "audio-filter", audio_filter, NULL);
+
+ gst_object_unref (vf_filter);
+ gst_object_unref (preview_filter);
+ gst_object_unref (video_filter);
+ gst_object_unref (audio_filter);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
}
+ GST_INFO ("starting capture");
+ fail_unless (camera != NULL);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+
+ g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
+ main_loop);
+ g_main_loop_run (main_loop);
+ g_signal_emit_by_name (camera, "stop-capture", NULL);
+
+ /* check that we got a preview image */
+ check_preview_image (camera, video_filename, 0);
+
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
+ remove_file (video_filename, 0);
+
+ fail_unless (vf_probe_counter > 0);
+ fail_unless (video_probe_counter > 0);
+ fail_unless (audio_probe_counter > 0);
+ fail_unless (preview_probe_counter == 1);
}
GST_END_TEST;
-GST_START_TEST (test_image_tags_setting)
+#define LOCATION_SWITCHING_FILENAMES_COUNT 5
+
+static gboolean
+image_location_switch_do_capture (gpointer data)
+{
+ gchar **filenames = data;
+ if (capture_count >= LOCATION_SWITCHING_FILENAMES_COUNT) {
+ g_main_loop_quit (main_loop);
+ }
+
+ g_object_set (camera, "location", filenames[capture_count], NULL);
+ g_signal_emit_by_name (camera, "start-capture", NULL);
+ capture_count++;
+ return FALSE;
+}
+
+static void
+image_location_switch_readyforcapture (GObject * obj, GParamSpec * pspec,
+ gpointer user_data)
+{
+ gboolean ready;
+
+ g_object_get (obj, "ready-for-capture", &ready, NULL);
+ if (ready) {
+ g_idle_add (image_location_switch_do_capture, user_data);
+ }
+};
+
+/*
+ * Tests that setting the location and then doing an image
+ * capture will set this capture resulting filename to the
+ * correct location.
+ *
+ * There was a bug in which setting the location, issuing a capture
+ * and then setting a new location would cause this capture to have
+ * the location set after this capture. This test should prevent it
+ * from happening again.
+ */
+GST_START_TEST (test_image_location_switching)
{
+ gchar *filenames[LOCATION_SWITCHING_FILENAMES_COUNT + 1];
gint i;
+ glong notify_id;
+ GstCaps *caps;
+ GstElement *src;
+ GstMessage *msg;
- g_object_set (camera, "flags", 0, NULL);
- g_object_set (camera, "block-after-capture", TRUE, NULL);
+ if (!camera)
+ return;
- GST_INFO ("starting capture series");
+ g_object_get (camera, "camera-source", &src, NULL);
- for (i = 0; i < SEQUENTIAL_IMAGES_COUNT; i++) {
- g_object_set (camera, "filename",
- make_test_file_name (SEQUENTIAL_IMAGES_FILENAME, i), NULL);
- gst_tag_setter_merge_tags (GST_TAG_SETTER (camera),
- taglists[i % TAGLISTS_COUNT],
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (camera)));
- g_signal_emit_by_name (camera, "capture-start", NULL);
- g_main_loop_run (main_loop);
+ for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
+ filenames[i] = make_test_file_name ("image-switching-filename-test", i);
}
+ filenames[LOCATION_SWITCHING_FILENAMES_COUNT] = NULL;
+
+ /* set still image mode */
+ g_object_set (camera, "mode", 1, NULL);
+ caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+ 800, "height", G_TYPE_INT, 600, NULL);
+ g_object_set (camera, "image-capture-caps", caps, NULL);
+ gst_caps_unref (caps);
+
+ if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ GST_WARNING ("setting camerabin to PLAYING failed");
+ gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
+ gst_object_unref (camera);
+ camera = NULL;
+ }
+ fail_unless (camera != NULL);
+ GST_INFO ("starting capture");
+
+ notify_id = g_signal_connect (G_OBJECT (src),
+ "notify::ready-for-capture",
+ G_CALLBACK (image_location_switch_readyforcapture), filenames);
+
+ g_idle_add (image_location_switch_do_capture, filenames);
+ g_main_loop_run (main_loop);
+
+ msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
+ fail_unless (msg != NULL);
+ gst_message_unref (msg);
+
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- for (i = 0; i < SEQUENTIAL_IMAGES_COUNT; i++) {
- check_file_validity (SEQUENTIAL_IMAGES_FILENAME, i,
- taglists[i % TAGLISTS_COUNT]);
- remove_file (SEQUENTIAL_IMAGES_FILENAME, i);
+ for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
+ GST_INFO ("Checking for file: %s", filenames[i]);
+ fail_unless (g_file_test (filenames[i], G_FILE_TEST_IS_REGULAR));
}
+
+ for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
+ g_unlink (filenames[i]);
+ g_free (filenames[i]);
+ }
+ g_signal_handler_disconnect (src, notify_id);
}
GST_END_TEST;
+
+typedef struct _TestCaseDef
+{
+ const gchar *name;
+ gpointer setup_func;
+} TestCaseDef;
+
+TestCaseDef tests[] = {
+ {"wrappercamerabinsrc", setup_wrappercamerabinsrc_videotestsrc}
+};
+
static Suite *
camerabin_suite (void)
{
- Suite *s = suite_create ("camerabin");
- TCase *tc_basic = tcase_create ("general");
-
- /* Test that basic operations run without errors */
- suite_add_tcase (s, tc_basic);
- /* Increase timeout due to video recording */
- tcase_set_timeout (tc_basic, 20);
- tcase_add_checked_fixture (tc_basic, setup, teardown);
- tcase_add_test (tc_basic, test_single_image_capture);
- tcase_add_test (tc_basic, test_single_image_capture_with_flags);
- tcase_add_test (tc_basic, test_video_recording);
- tcase_add_test (tc_basic, test_video_recording_with_flags);
- tcase_add_test (tc_basic, test_video_recording_pause);
- tcase_add_test (tc_basic, test_video_recording_no_audio);
- tcase_add_test (tc_basic, test_image_video_cycle);
- tcase_add_test (tc_basic, test_image_tags_setting);
+ GstElementFactory *jpegenc_factory;
+ Suite *s = suite_create ("camerabin2");
+ gint i;
+ TCase *tc_generic = tcase_create ("generic");
+
+ jpegenc_factory = gst_element_factory_find ("jpegenc");
+ if (jpegenc_factory == NULL) {
+ GST_WARNING ("Skipping camerabin2 tests because jpegenc is missing");
+ goto end;
+ }
+
+ suite_add_tcase (s, tc_generic);
+ tcase_add_checked_fixture (tc_generic, setup_wrappercamerabinsrc_videotestsrc,
+ teardown);
+ tcase_add_test (tc_generic, test_supported_caps);
+
+ for (i = 0; i < G_N_ELEMENTS (tests); i++) {
+ TCase *tc_basic = tcase_create (tests[i].name);
+ suite_add_tcase (s, tc_basic);
+
+ /* Increase timeout due to video recording */
+ tcase_set_timeout (tc_basic, 60);
+ tcase_add_checked_fixture (tc_basic, tests[i].setup_func, teardown);
+
+ tcase_add_test (tc_basic, test_single_image_capture);
+ tcase_add_test (tc_basic, test_single_video_recording);
+ tcase_add_test (tc_basic, test_image_video_cycle);
+ if (gst_plugin_feature_check_version ((GstPluginFeature *) jpegenc_factory,
+ 0, 10, 27))
+ tcase_add_test (tc_basic, test_multiple_image_captures);
+ else
+ GST_WARNING ("Skipping image capture test because -good 0.10.27 is "
+ "needed");
+ tcase_add_test (tc_basic, test_multiple_video_recordings);
+
+ tcase_add_test (tc_basic, test_image_capture_previews);
+ tcase_add_test (tc_basic, test_image_capture_with_tags);
+
+ tcase_add_test (tc_basic, test_video_capture_with_tags);
+
+ tcase_add_test (tc_basic, test_idle_property);
+
+ tcase_add_test (tc_basic, test_image_custom_filter);
+ tcase_add_test (tc_basic, test_video_custom_filter);
+
+ tcase_add_test (tc_basic, test_image_location_switching);
+ }
+end:
return s;
}
+++ /dev/null
-/* GStreamer
- *
- * unit test for camerabin2 basic operations
- * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
- * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
- *
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <gst/check/gstcheck.h>
-#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
-#include <gst/pbutils/encoding-profile.h>
-
-#define IMAGE_FILENAME "image"
-#define VIDEO_FILENAME "video"
-#define CAPTURE_COUNT 3
-#define VIDEO_DURATION 5
-
-#define VIDEO_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=600, height=480"
-#define IMAGE_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=800, height=600"
-
-/* custom test camera src element */
-#define GST_TYPE_TEST_CAMERA_SRC \
- (gst_test_camera_src_get_type())
-#define GST_TEST_CAMERA_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrc))
-#define GST_TEST_CAMERA_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_CAMERA_SRC,GstTestCameraSrcClass))
-#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEST_CAMERA_SRC))
-#define GST_IS_TEST_REVERSE_NEGOTIATION_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEST_CAMERA_SRC))
-#define GST_TEST_CAMERA_SRC_CAST(obj) ((GstTestCameraSrc *)obj)
-
-typedef struct _GstTestCameraSrc GstTestCameraSrc;
-typedef struct _GstTestCameraSrcClass GstTestCameraSrcClass;
-struct _GstTestCameraSrc
-{
- GstBaseCameraSrc element;
-
- GstPad *vfpad;
- GstPad *vidpad;
- GstPad *imgpad;
-
- GstCameraBinMode mode;
-};
-
-struct _GstTestCameraSrcClass
-{
- GstBaseCameraSrcClass parent_class;
-};
-
-GType gst_test_camera_src_get_type (void);
-
-#define gst_test_camera_src_parent_class parent_class
-G_DEFINE_TYPE (GstTestCameraSrc, gst_test_camera_src, GST_TYPE_BASE_CAMERA_SRC);
-
-static gboolean
-gst_test_camera_src_set_mode (GstBaseCameraSrc * src, GstCameraBinMode mode)
-{
- GstTestCameraSrc *self = GST_TEST_CAMERA_SRC (src);
-
- self->mode = mode;
- return TRUE;
-}
-
-static gboolean
-gst_test_camera_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
-{
- GstTestCameraSrc *self = (GstTestCameraSrc *) GST_PAD_PARENT (pad);
- GstCaps *result = NULL;
- gboolean ret = FALSE;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_CAPS:
- if (pad == self->vfpad) {
- result = gst_caps_new_any ();
- } else if (pad == self->vidpad) {
- result = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS);
- } else if (pad == self->imgpad) {
- result = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS);
- } else {
- g_assert_not_reached ();
- }
- if (result) {
- GstCaps *filter;
-
- gst_query_parse_caps (query, &filter);
- if (filter) {
- GstCaps *tmp;
- tmp = gst_caps_intersect (result, filter);
- gst_caps_replace (&result, tmp);
- gst_caps_unref (tmp);
- }
- gst_query_set_caps_result (query, result);
- ret = TRUE;
- }
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void
-gst_test_camera_src_class_init (GstTestCameraSrcClass * klass)
-{
- GstBaseCameraSrcClass *gstbasecamera_class;
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gstbasecamera_class = GST_BASE_CAMERA_SRC_CLASS (klass);
- gstbasecamera_class->set_mode = gst_test_camera_src_set_mode;
-
- gst_element_class_set_details_simple (gstelement_class,
- "Test Camera Src",
- "Camera/Src",
- "Some test camera src",
- "Thiago Santos <thiago.sousa.santos@collabora.com>");
-}
-
-static void
-gst_test_camera_src_init (GstTestCameraSrc * self)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (parent_class);
- GstPadTemplate *template;
-
- /* create pads */
- template = gst_element_class_get_pad_template (gstelement_class,
- GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME);
- self->vfpad = gst_pad_new_from_template (template,
- GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME);
- gst_element_add_pad (GST_ELEMENT_CAST (self), self->vfpad);
-
- template = gst_element_class_get_pad_template (gstelement_class,
- GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME);
- self->imgpad = gst_pad_new_from_template (template,
- GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME);
- gst_element_add_pad (GST_ELEMENT_CAST (self), self->imgpad);
-
- template = gst_element_class_get_pad_template (gstelement_class,
- GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME);
- self->vidpad = gst_pad_new_from_template (template,
- GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME);
- gst_element_add_pad (GST_ELEMENT_CAST (self), self->vidpad);
-
- /* add get caps functions */
- gst_pad_set_query_function (self->vfpad, gst_test_camera_src_query);
- gst_pad_set_query_function (self->vidpad, gst_test_camera_src_query);
- gst_pad_set_query_function (self->imgpad, gst_test_camera_src_query);
-}
-
-/* end of custom test camera src element */
-
-
-static GstElement *camera;
-static guint bus_source;
-static GMainLoop *main_loop;
-static gint capture_count = 0;
-guint32 test_id = 0;
-static gchar *image_filename;
-static gchar *video_filename;
-
-static GstBuffer *preview_buffer;
-static gchar *preview_filename;
-static GstCaps *preview_caps;
-static GstTagList *tags_found;
-
-static gboolean
-validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data);
-
-static GstMessage *wait_for_element_message (GstElement * camera,
- const gchar * name, GstClockTime timeout);
-
-static void
-validate_taglist_foreach (const GstTagList * list, const gchar * tag,
- gpointer user_data)
-{
- GstTagList *other = GST_TAG_LIST (user_data);
-
- const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0);
- const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0);
-
- GST_DEBUG ("checking tag '%s'", tag);
-
- fail_if (val1 == NULL);
- fail_if (val2 == NULL);
-
- fail_unless (gst_value_compare (val1, val2) == GST_VALUE_EQUAL);
-}
-
-
-/* helper function for filenames */
-static gchar *
-make_test_file_name (const gchar * base_name, gint num)
-{
- /* num == -1 means to keep the %d in the resulting string to be used on
- * multifilesink like location */
- if (num == -1) {
- return g_strdup_printf ("%s" G_DIR_SEPARATOR_S
- "gstcamerabin2test_%s_%u_%%03d.cap", g_get_tmp_dir (), base_name,
- test_id);
- } else {
- return g_strdup_printf ("%s" G_DIR_SEPARATOR_S
- "gstcamerabin2test_%s_%u_%03d.cap", g_get_tmp_dir (), base_name,
- test_id, num);
- }
-}
-
-static const gchar *
-make_const_file_name (const gchar * filename, gint num)
-{
- static gchar file_name[1000];
-
- /* num == -1 means to keep the %d in the resulting string to be used on
- * multifilesink like location */
- g_snprintf (file_name, 999, filename, num);
-
- return file_name;
-}
-
-/* configuration */
-
-static gboolean
-capture_bus_cb (GstBus * bus, GstMessage * message, gpointer data)
-{
- GMainLoop *loop = (GMainLoop *) data;
- const GstStructure *st;
-
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR:{
- GError *err = NULL;
- gchar *debug = NULL;
-
- gst_message_parse_error (message, &err, &debug);
- GST_WARNING ("ERROR: %s [%s]", err->message, debug);
- g_error_free (err);
- g_free (debug);
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera),
- GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
-
- fail_if (TRUE, "error while capturing");
- g_main_loop_quit (loop);
- break;
- }
- case GST_MESSAGE_WARNING:{
- GError *err = NULL;
- gchar *debug = NULL;
-
- gst_message_parse_warning (message, &err, &debug);
- GST_WARNING ("WARNING: %s [%s]", err->message, debug);
- g_error_free (err);
- g_free (debug);
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera),
- GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.warning");
- break;
- }
- case GST_MESSAGE_EOS:
- GST_DEBUG ("eos");
- g_main_loop_quit (loop);
- break;
- default:
- st = gst_message_get_structure (message);
- if (st && gst_structure_has_name (st, "image-done")) {
- GST_INFO ("image captured");
- } else if (st && gst_structure_has_name (st,
- GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) {
- GstBuffer *buf;
- const GValue *value;
-
- value = gst_structure_get_value (st, "buffer");
- fail_unless (value != NULL);
- buf = gst_value_get_buffer (value);
-
- if (preview_buffer)
- gst_buffer_unref (preview_buffer);
- preview_buffer = gst_buffer_ref (buf);
- g_free (preview_filename);
- preview_filename = g_strdup (gst_structure_get_string (st, "location"));
- }
- break;
- }
- return TRUE;
-}
-
-static void
-check_preview_image (GstElement * camera, const gchar * filename, gint index)
-{
- gchar *prev_filename = NULL;
-
- if (!preview_buffer && camera) {
- GstMessage *msg = wait_for_element_message (camera,
- GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME, GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
- }
- fail_unless (preview_buffer != NULL);
- if (filename) {
- if (index >= 0) {
- prev_filename = g_strdup_printf (filename, index);
- } else {
- prev_filename = g_strdup (filename);
- }
- fail_unless (preview_filename != NULL);
- fail_unless (strcmp (preview_filename, prev_filename) == 0);
- }
- if (preview_caps) {
- /* TODO porting
- fail_unless (GST_BUFFER_CAPS (preview_buffer) != NULL);
- fail_unless (gst_caps_can_intersect (GST_BUFFER_CAPS (preview_buffer),
- preview_caps));
- */
- }
- g_free (prev_filename);
-}
-
-static void
-extract_jpeg_tags (const gchar * filename, gint num)
-{
- GstBus *bus;
- GMainLoop *loop = g_main_loop_new (NULL, FALSE);
- const gchar *filepath = make_const_file_name (filename, num);
- gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! "
- "jpegparse ! fakesink", filepath);
- GstElement *pipeline;
- guint source;
-
- pipeline = gst_parse_launch (pipeline_str, NULL);
- fail_unless (pipeline != NULL);
- g_free (pipeline_str);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
- source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
-
- gst_element_set_state (pipeline, GST_STATE_PLAYING);
- g_main_loop_run (loop);
- gst_element_set_state (pipeline, GST_STATE_NULL);
-
- gst_object_unref (bus);
- g_source_remove (source);
- gst_object_unref (pipeline);
- g_main_loop_unref (loop);
-}
-
-static void
-setup_wrappercamerabinsrc_videotestsrc (void)
-{
- GstBus *bus;
- GstElement *vfbin;
- GstElement *fakevideosink;
- GstElement *src;
- GstElement *testsrc;
- GstElement *audiosrc;
-
- GST_INFO ("init");
-
- test_id = g_random_int ();
- bus_source = 0;
-
- main_loop = g_main_loop_new (NULL, TRUE);
-
- camera = gst_check_setup_element ("camerabin2");
- fakevideosink = gst_element_factory_make ("fakesink", NULL);
- src = gst_element_factory_make ("wrappercamerabinsrc", NULL);
- testsrc = gst_element_factory_make ("videotestsrc", NULL);
- audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
-
- preview_caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
- 320, "height", G_TYPE_INT, 240, NULL);
-
- g_object_set (G_OBJECT (testsrc), "is-live", TRUE, NULL);
- g_object_set (G_OBJECT (audiosrc), "is-live", TRUE, NULL);
- g_object_set (G_OBJECT (src), "video-source", testsrc, NULL);
- g_object_set (G_OBJECT (camera), "camera-source", src, "preview-caps",
- preview_caps, "post-previews", TRUE, "audio-source", audiosrc, NULL);
- gst_object_unref (src);
- gst_object_unref (testsrc);
- gst_object_unref (audiosrc);
-
- vfbin = gst_bin_get_by_name (GST_BIN (camera), "vf-bin");
- g_object_set (G_OBJECT (vfbin), "video-sink", fakevideosink, NULL);
- gst_object_unref (vfbin);
- gst_object_unref (fakevideosink);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (camera));
- bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop);
- gst_object_unref (bus);
-
- tags_found = NULL;
- capture_count = 0;
- image_filename = make_test_file_name (IMAGE_FILENAME, -1);
- video_filename = make_test_file_name (VIDEO_FILENAME, -1);
-
- GST_INFO ("init finished");
-}
-
-static void
-teardown (void)
-{
- gst_element_set_state (camera, GST_STATE_NULL);
-
- if (camera)
- gst_check_teardown_element (camera);
- camera = NULL;
-
- if (bus_source)
- g_source_remove (bus_source);
-
- if (main_loop)
- g_main_loop_unref (main_loop);
- main_loop = NULL;
-
- if (preview_caps)
- gst_caps_unref (preview_caps);
- preview_caps = NULL;
-
- if (preview_buffer)
- gst_buffer_unref (preview_buffer);
- preview_buffer = NULL;
-
- g_free (preview_filename);
- preview_filename = NULL;
-
- if (tags_found)
- gst_tag_list_free (tags_found);
- tags_found = NULL;
-
- g_free (video_filename);
- video_filename = NULL;
-
- g_free (image_filename);
- image_filename = NULL;
-
- GST_INFO ("done");
-}
-
-static gboolean
-validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data)
-{
- GMainLoop *loop = (GMainLoop *) data;
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR:{
- GError *err = NULL;
- gchar *debug = NULL;
-
- gst_message_parse_error (message, &err, &debug);
-
- GST_ERROR ("Error: %s : %s", err->message, debug);
- g_error_free (err);
- g_free (debug);
-
- fail_if (TRUE, "validating captured data failed");
- g_main_loop_quit (loop);
- }
- break;
- case GST_MESSAGE_EOS:
- g_main_loop_quit (loop);
- GST_DEBUG ("eos");
- break;
- case GST_MESSAGE_TAG:{
- GstTagList *taglist = NULL;
-
- gst_message_parse_tag (message, &taglist);
- if (tags_found) {
- gst_tag_list_insert (tags_found, taglist, GST_TAG_MERGE_REPLACE);
- gst_tag_list_free (taglist);
- } else {
- tags_found = taglist;
- }
- GST_DEBUG ("tags: %" GST_PTR_FORMAT, tags_found);
- }
- break;
- default:
- break;
- }
- return TRUE;
-}
-
-/* checks that tags in @tags_a are in @tags_b */
-static gboolean
-taglist_is_subset (GstTagList * tags_a, GstTagList * tags_b)
-{
- gst_tag_list_foreach (tags_a, validate_taglist_foreach, tags_b);
- return TRUE;
-}
-
-/* Validate captured files by playing them with playbin
- * and checking that no errors occur. */
-#define WITH_AUDIO TRUE
-#define NO_AUDIO FALSE
-static gboolean
-check_file_validity (const gchar * filename, gint num, GstTagList * taglist,
- gint width, gint height, gboolean has_audio)
-{
- GstBus *bus;
- GstPad *pad;
- GstCaps *caps;
- gint caps_width, caps_height;
- GstState state;
- guint source;
-
- GMainLoop *loop = g_main_loop_new (NULL, FALSE);
- GstElement *playbin = gst_element_factory_make ("playbin2", NULL);
- GstElement *fakevideo = gst_element_factory_make ("fakesink", NULL);
- GstElement *fakeaudio = gst_element_factory_make ("fakesink", NULL);
- gchar *uri = g_strconcat ("file://", make_const_file_name (filename, num),
- NULL);
-
- GST_DEBUG ("checking uri: %s", uri);
- g_object_set (G_OBJECT (playbin), "uri", uri, "video-sink", fakevideo,
- "audio-sink", fakeaudio, NULL);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
- source = gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
-
- gst_element_set_state (playbin, GST_STATE_PAUSED);
- gst_element_get_state (playbin, &state, NULL, GST_SECOND * 3);
-
- if (width != 0 && height != 0) {
- g_signal_emit_by_name (playbin, "get-video-pad", 0, &pad, NULL);
- g_assert (pad != NULL);
- caps = gst_pad_get_current_caps (pad);
-
- g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0),
- "width", &caps_width));
- g_assert (gst_structure_get_int (gst_caps_get_structure (caps, 0),
- "height", &caps_height));
-
- g_assert (width == caps_width);
- g_assert (height == caps_height);
-
- gst_caps_unref (caps);
- gst_object_unref (pad);
- }
- if (has_audio) {
- g_signal_emit_by_name (playbin, "get-audio-pad", 0, &pad, NULL);
- g_assert (pad != NULL);
- gst_object_unref (pad);
- }
-
- gst_element_set_state (playbin, GST_STATE_PLAYING);
- g_main_loop_run (loop);
- gst_element_set_state (playbin, GST_STATE_NULL);
-
- /* special handling for images (jpg) as jpegparse isn't plugged by
- * default due to its current low rank */
- if (taglist && strstr (filename, "image")) {
- extract_jpeg_tags (filename, num);
- }
-
- if (taglist) {
- fail_unless (tags_found != NULL);
- fail_unless (taglist_is_subset (taglist, tags_found));
- }
-
- g_free (uri);
- g_source_remove (source);
- gst_object_unref (bus);
- gst_object_unref (playbin);
- g_main_loop_unref (loop);
-
- return TRUE;
-}
-
-static void
-remove_file (const gchar * fn_template, guint num)
-{
- const gchar *fn;
-
- fn = make_const_file_name (fn_template, num);
- GST_INFO ("removing %s", fn);
- g_unlink (fn);
-}
-
-static GstPadProbeReturn
-filter_buffer_count (GstPad * pad, GstPadProbeInfo * info, gpointer data)
-{
- gint *counter = data;
-
- (*counter)++;
-
- return GST_PAD_PROBE_OK;
-}
-
-static GstMessage *
-wait_for_element_message (GstElement * camera, const gchar * name,
- GstClockTime timeout)
-{
- GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (camera));
- GstMessage *msg;
-
- while (1) {
- msg = gst_bus_timed_pop_filtered (bus, timeout, GST_MESSAGE_ERROR |
- GST_MESSAGE_EOS | GST_MESSAGE_ELEMENT);
-
- if (msg) {
- if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT) {
- const GstStructure *st = gst_message_get_structure (msg);
- if (gst_structure_has_name (st,
- GST_BASE_CAMERA_SRC_PREVIEW_MESSAGE_NAME)) {
- GstBuffer *buf;
- const GValue *value;
-
- value = gst_structure_get_value (st, "buffer");
- fail_unless (value != NULL);
- buf = gst_value_get_buffer (value);
-
- if (preview_buffer)
- gst_buffer_unref (preview_buffer);
- preview_buffer = gst_buffer_ref (buf);
- g_free (preview_filename);
- preview_filename =
- g_strdup (gst_structure_get_string (st, "location"));
- }
-
- if (gst_structure_has_name (st, name))
- break;
- else
- gst_message_unref (msg);
- } else {
- gst_message_unref (msg);
- msg = NULL;
- break;
- }
- }
- }
-
- gst_object_unref (bus);
- return msg;
-}
-
-static void
-wait_for_idle_state (void)
-{
- gboolean idle = FALSE;
-
- /* not the ideal way, but should be enough for testing */
- while (idle == FALSE) {
- g_object_get (camera, "idle", &idle, NULL);
- if (idle)
- break;
-
- GST_LOG ("waiting for idle state..");
- g_usleep (G_USEC_PER_SEC / 5);
- }
- fail_unless (idle);
-}
-
-GST_START_TEST (test_single_image_capture)
-{
- gboolean idle;
- GstMessage *msg;
- if (!camera)
- return;
-
- /* set still image mode */
- g_object_set (camera, "mode", 1, "location", image_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- /* check that we got a preview image */
- check_preview_image (camera, image_filename, 0);
-
- wait_for_idle_state ();
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO);
- remove_file (image_filename, 0);
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_multiple_image_captures)
-{
- gboolean idle;
- gint i;
- gint widths[] = { 800, 640, 1280 };
- gint heights[] = { 600, 480, 1024 };
-
- if (!camera)
- return;
-
- /* set still image mode */
- g_object_set (camera, "mode", 1, "location", image_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- fail_unless (camera != NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle);
- GST_INFO ("starting capture");
-
- for (i = 0; i < 3; i++) {
- GstMessage *msg;
- GstCaps *caps;
-
- caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
- widths[i], "height", G_TYPE_INT, heights[i], NULL);
-
- g_object_set (camera, "image-capture-caps", caps, NULL);
- gst_caps_unref (caps);
-
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- check_preview_image (camera, image_filename, i);
- }
-
- wait_for_idle_state ();
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- for (i = 0; i < 3; i++) {
- check_file_validity (image_filename, i, NULL, widths[i], heights[i],
- NO_AUDIO);
- remove_file (image_filename, i);
- }
-}
-
-GST_END_TEST;
-
-GST_START_TEST (test_single_video_recording)
-{
- GstMessage *msg;
- gboolean idle;
- if (!camera)
- return;
-
- /* Set video recording mode */
- g_object_set (camera, "mode", 2, "location", video_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
-
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (!idle);
-
- /* Record for one seconds */
- g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
- main_loop);
- g_main_loop_run (main_loop);
-
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- check_preview_image (camera, video_filename, 0);
-
- msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- wait_for_idle_state ();
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
- remove_file (video_filename, 0);
-
-}
-
-GST_END_TEST;
-
-GST_START_TEST (test_multiple_video_recordings)
-{
- gboolean idle;
- gint i;
- gint widths[] = { 800, 640, 1280 };
- gint heights[] = { 600, 480, 1024 };
- gint fr[] = { 20, 30, 5 };
-
- if (!camera)
- return;
-
- /* Set video recording mode */
- g_object_set (camera, "mode", 2, "location", video_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
-
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle);
- for (i = 0; i < 3; i++) {
- GstMessage *msg;
- GstCaps *caps;
-
- caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
- widths[i], "height", G_TYPE_INT, heights[i], "framerate",
- GST_TYPE_FRACTION, fr[i], 1, NULL);
-
- g_object_set (camera, "video-capture-caps", caps, NULL);
-
- gst_caps_unref (caps);
-
- GST_LOG ("starting #%d with caps %" GST_PTR_FORMAT, i, caps);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (!idle);
-
- g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
- main_loop);
- g_main_loop_run (main_loop);
-
- GST_LOG ("stopping run %d", i);
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- GST_LOG ("video done, checking preview image");
- check_preview_image (camera, video_filename, i);
-
- GST_LOG ("waiting for idle state");
- wait_for_idle_state ();
- GST_LOG ("finished run %d", i);
- }
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- for (i = 0; i < 3; i++) {
- check_file_validity (video_filename, i, NULL, widths[i], heights[i],
- WITH_AUDIO);
- remove_file (video_filename, i);
- }
-}
-
-GST_END_TEST;
-
-GST_START_TEST (test_image_video_cycle)
-{
- gint i;
-
- if (!camera)
- return;
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
-
- GST_INFO ("starting capture");
- for (i = 0; i < 2; i++) {
- GstMessage *msg;
- const gchar *img_filename;
- const gchar *vid_filename;
-
- wait_for_idle_state ();
-
- /* take a picture */
- img_filename = make_const_file_name (image_filename, i);
- g_object_set (camera, "mode", 1, NULL);
- g_object_set (camera, "location", img_filename, NULL);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- check_preview_image (camera, img_filename, i);
-
- /* now go to video */
- vid_filename = make_const_file_name (video_filename, i);
- g_object_set (camera, "mode", 2, NULL);
- g_object_set (camera, "location", vid_filename, NULL);
-
- g_signal_emit_by_name (camera, "start-capture", NULL);
- g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
- main_loop);
- g_main_loop_run (main_loop);
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- check_preview_image (camera, vid_filename, i);
- }
-
- wait_for_idle_state ();
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- /* validate all the files */
- for (i = 0; i < 2; i++) {
- check_file_validity (image_filename, i, NULL, 0, 0, NO_AUDIO);
- remove_file (image_filename, i);
- check_file_validity (video_filename, i, NULL, 0, 0, WITH_AUDIO);
- remove_file (video_filename, i);
- }
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_image_capture_previews)
-{
- gint i;
- gint widths[] = { 800, 640, 1280 };
- gint heights[] = { 600, 480, 1024 };
-
- if (!camera)
- return;
-
- /* set still image mode */
- g_object_set (camera, "mode", 1, "location", image_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- fail_unless (camera != NULL);
- GST_INFO ("starting capture");
-
- for (i = 0; i < 3; i++) {
- GstMessage *msg;
- GstCaps *caps;
-
- caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
- widths[i], "height", G_TYPE_INT, heights[i], NULL);
-
- g_object_set (camera, "preview-caps", caps, NULL);
- gst_caps_replace (&preview_caps, caps);
- gst_caps_unref (caps);
-
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- check_preview_image (camera, image_filename, i);
- remove_file (image_filename, i);
-
- if (preview_buffer)
- gst_buffer_unref (preview_buffer);
- preview_buffer = NULL;
- gst_caps_replace (&preview_caps, NULL);
- }
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_image_capture_with_tags)
-{
- gint i;
- GstTagList *taglists[3];
-
- if (!camera)
- return;
-
- taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1",
- GST_TAG_GEO_LOCATION_LATITUDE, 36.6, GST_TAG_GEO_LOCATION_LONGITUDE,
- -12.5,
- GST_TAG_COPYRIGHT, "My copyright notice",
- GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand",
- GST_TAG_DEVICE_MODEL, "123v42.1",
- GST_TAG_DESCRIPTION, "some description",
- GST_TAG_APPLICATION_NAME, "camerabin2 test",
- GST_TAG_GEO_LOCATION_ELEVATION, 300.85, NULL);
- taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2",
- GST_TAG_GEO_LOCATION_LATITUDE, 1.6, GST_TAG_GEO_LOCATION_LONGITUDE,
- 0.0,
- GST_TAG_COPYRIGHT, "some cp",
- GST_TAG_DEVICE_MANUFACTURER, "ABRAND",
- GST_TAG_DEVICE_MODEL, "abcd",
- GST_TAG_DESCRIPTION, "desc",
- GST_TAG_APPLICATION_NAME, "another cam test",
- GST_TAG_GEO_LOCATION_ELEVATION, 10.0, NULL);
- taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3",
- GST_TAG_GEO_LOCATION_LATITUDE, 1.3, GST_TAG_GEO_LOCATION_LONGITUDE,
- -5.0,
- GST_TAG_COPYRIGHT, "CC",
- GST_TAG_DEVICE_MANUFACTURER, "Homemade",
- GST_TAG_DEVICE_MODEL, "xpto",
- GST_TAG_DESCRIPTION, "another description",
- GST_TAG_APPLICATION_NAME, "cam2 test",
- GST_TAG_GEO_LOCATION_ELEVATION, 0.0, NULL);
-
- /* set still image mode */
- g_object_set (camera, "mode", 1, "location", image_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- fail_unless (camera != NULL);
- GST_INFO ("starting capture");
-
- for (i = 0; i < 3; i++) {
- GstMessage *msg;
- gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
- GST_TAG_MERGE_REPLACE);
-
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
- }
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- for (i = 0; i < 3; i++) {
- check_file_validity (image_filename, i, taglists[i], 0, 0, NO_AUDIO);
- gst_tag_list_free (taglists[i]);
- remove_file (image_filename, i);
- }
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_video_capture_with_tags)
-{
- gint i;
- GstTagList *taglists[3];
-
- if (!camera)
- return;
-
- taglists[0] = gst_tag_list_new (GST_TAG_COMMENT, "test1", NULL);
- taglists[1] = gst_tag_list_new (GST_TAG_COMMENT, "test2", NULL);
- taglists[2] = gst_tag_list_new (GST_TAG_COMMENT, "test3", NULL);
-
- /* set video mode */
- g_object_set (camera, "mode", 2, "location", video_filename, NULL);
-
- /* set a profile that has xmp support for more tags being saved */
- {
- GstEncodingContainerProfile *profile;
- GstCaps *caps;
-
- caps =
- gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING,
- "apple", NULL);
- profile = gst_encoding_container_profile_new ("qt", "jpeg+qt", caps, NULL);
- gst_caps_unref (caps);
-
- caps = gst_caps_new_simple ("image/jpeg", NULL, NULL);
- if (!gst_encoding_container_profile_add_profile (profile,
- (GstEncodingProfile *) gst_encoding_video_profile_new (caps,
- NULL, NULL, 1))) {
- GST_WARNING_OBJECT (camera, "Failed to create encoding profiles");
- }
- gst_caps_unref (caps);
-
- g_object_set (camera, "video-profile", profile, NULL);
- gst_encoding_profile_unref (profile);
- }
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- fail_unless (camera != NULL);
- GST_INFO ("starting capture");
-
- for (i = 0; i < 3; i++) {
- GstMessage *msg;
-
- gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
- GST_TAG_MERGE_REPLACE);
-
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
- g_main_loop_run (main_loop);
-
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
- }
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- for (i = 0; i < 3; i++) {
- check_file_validity (video_filename, i, taglists[i], 0, 0, NO_AUDIO);
- gst_tag_list_free (taglists[i]);
- remove_file (video_filename, i);
- }
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_supported_caps)
-{
- GstCaps *padcaps = NULL;
- GstCaps *expectedcaps;
- GstElement *src;
-
- if (!camera)
- return;
-
- src = g_object_new (GST_TYPE_TEST_CAMERA_SRC, NULL);
- g_object_set (camera, "camera-source", src, NULL);
- gst_object_unref (src);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- g_assert (camera != NULL);
-
- expectedcaps = gst_caps_from_string (VIDEO_PAD_SUPPORTED_CAPS);
- g_object_get (G_OBJECT (camera), "video-capture-supported-caps", &padcaps,
- NULL);
- g_assert (expectedcaps != NULL);
- g_assert (padcaps != NULL);
- g_assert (gst_caps_is_equal (padcaps, expectedcaps));
- gst_caps_unref (expectedcaps);
- gst_caps_unref (padcaps);
-
- expectedcaps = gst_caps_from_string (IMAGE_PAD_SUPPORTED_CAPS);
- g_object_get (G_OBJECT (camera), "image-capture-supported-caps", &padcaps,
- NULL);
- g_assert (expectedcaps != NULL);
- g_assert (padcaps != NULL);
- g_assert (gst_caps_is_equal (padcaps, expectedcaps));
- gst_caps_unref (expectedcaps);
- gst_caps_unref (padcaps);
-
- gst_element_set_state (camera, GST_STATE_NULL);
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_idle_property)
-{
- GstMessage *msg;
- gboolean idle;
- if (!camera)
- return;
-
- /* Set video recording mode */
- g_object_set (camera, "mode", 2, "location", video_filename, NULL);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
-
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (idle);
- g_signal_emit_by_name (camera, "start-capture", NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (!idle);
-
- /* emit a second start-capture that should be ignored */
- g_signal_emit_by_name (camera, "start-capture", NULL);
- g_object_get (camera, "idle", &idle, NULL);
- fail_unless (!idle);
-
- /* Record for one seconds */
- g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
- main_loop);
- g_main_loop_run (main_loop);
-
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- msg = wait_for_element_message (camera, "video-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- check_preview_image (camera, video_filename, 0);
-
- wait_for_idle_state ();
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
- remove_file (video_filename, 0);
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_image_custom_filter)
-{
- GstElement *vf_filter;
- GstElement *image_filter;
- GstElement *preview_filter;
- GstPad *pad;
- gint vf_probe_counter = 0;
- gint image_probe_counter = 0;
- gint preview_probe_counter = 0;
-
- if (!camera)
- return;
-
- vf_filter = gst_element_factory_make ("identity", "vf-filter");
- image_filter = gst_element_factory_make ("identity", "img-filter");
- preview_filter = gst_element_factory_make ("identity", "preview-filter");
-
- pad = gst_element_get_static_pad (vf_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &vf_probe_counter, NULL);
- gst_object_unref (pad);
-
- pad = gst_element_get_static_pad (image_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &image_probe_counter, NULL);
- gst_object_unref (pad);
-
- pad = gst_element_get_static_pad (preview_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &preview_probe_counter, NULL);
- gst_object_unref (pad);
-
- /* set still image mode and filters */
- g_object_set (camera, "mode", 1,
- "location", image_filename,
- "viewfinder-filter", vf_filter, "image-filter", image_filter,
- "preview-filter", preview_filter, NULL);
-
- gst_object_unref (vf_filter);
- gst_object_unref (preview_filter);
- gst_object_unref (image_filter);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
- g_main_loop_run (main_loop);
-
- /* check that we got a preview image */
- check_preview_image (camera, image_filename, 0);
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (image_filename, 0, NULL, 0, 0, NO_AUDIO);
- remove_file (image_filename, 0);
-
- fail_unless (vf_probe_counter > 0);
- fail_unless (image_probe_counter == 1);
- fail_unless (preview_probe_counter == 1);
-}
-
-GST_END_TEST;
-
-
-GST_START_TEST (test_video_custom_filter)
-{
- GstElement *vf_filter;
- GstElement *video_filter;
- GstElement *preview_filter;
- GstElement *audio_filter;
- GstPad *pad;
- gint vf_probe_counter = 0;
- gint video_probe_counter = 0;
- gint preview_probe_counter = 0;
- gint audio_probe_counter = 0;
-
- if (!camera)
- return;
-
- vf_filter = gst_element_factory_make ("identity", "vf-filter");
- video_filter = gst_element_factory_make ("identity", "video-filter");
- preview_filter = gst_element_factory_make ("identity", "preview-filter");
- audio_filter = gst_element_factory_make ("identity", "audio-filter");
-
- pad = gst_element_get_static_pad (vf_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &vf_probe_counter, NULL);
- gst_object_unref (pad);
-
- pad = gst_element_get_static_pad (video_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &video_probe_counter, NULL);
- gst_object_unref (pad);
-
- pad = gst_element_get_static_pad (audio_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &audio_probe_counter, NULL);
- gst_object_unref (pad);
-
- pad = gst_element_get_static_pad (preview_filter, "src");
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, filter_buffer_count,
- &preview_probe_counter, NULL);
- gst_object_unref (pad);
-
- /* set still image mode and filters */
- g_object_set (camera, "mode", 2,
- "location", video_filename,
- "viewfinder-filter", vf_filter, "video-filter", video_filter,
- "preview-filter", preview_filter, "audio-filter", audio_filter, NULL);
-
- gst_object_unref (vf_filter);
- gst_object_unref (preview_filter);
- gst_object_unref (video_filter);
- gst_object_unref (audio_filter);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- GST_INFO ("starting capture");
- fail_unless (camera != NULL);
- g_signal_emit_by_name (camera, "start-capture", NULL);
-
- g_timeout_add_seconds (VIDEO_DURATION, (GSourceFunc) g_main_loop_quit,
- main_loop);
- g_main_loop_run (main_loop);
- g_signal_emit_by_name (camera, "stop-capture", NULL);
-
- /* check that we got a preview image */
- check_preview_image (camera, video_filename, 0);
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- check_file_validity (video_filename, 0, NULL, 0, 0, WITH_AUDIO);
- remove_file (video_filename, 0);
-
- fail_unless (vf_probe_counter > 0);
- fail_unless (video_probe_counter > 0);
- fail_unless (audio_probe_counter > 0);
- fail_unless (preview_probe_counter == 1);
-}
-
-GST_END_TEST;
-
-#define LOCATION_SWITCHING_FILENAMES_COUNT 5
-
-static gboolean
-image_location_switch_do_capture (gpointer data)
-{
- gchar **filenames = data;
- if (capture_count >= LOCATION_SWITCHING_FILENAMES_COUNT) {
- g_main_loop_quit (main_loop);
- }
-
- g_object_set (camera, "location", filenames[capture_count], NULL);
- g_signal_emit_by_name (camera, "start-capture", NULL);
- capture_count++;
- return FALSE;
-}
-
-static void
-image_location_switch_readyforcapture (GObject * obj, GParamSpec * pspec,
- gpointer user_data)
-{
- gboolean ready;
-
- g_object_get (obj, "ready-for-capture", &ready, NULL);
- if (ready) {
- g_idle_add (image_location_switch_do_capture, user_data);
- }
-};
-
-/*
- * Tests that setting the location and then doing an image
- * capture will set this capture resulting filename to the
- * correct location.
- *
- * There was a bug in which setting the location, issuing a capture
- * and then setting a new location would cause this capture to have
- * the location set after this capture. This test should prevent it
- * from happening again.
- */
-GST_START_TEST (test_image_location_switching)
-{
- gchar *filenames[LOCATION_SWITCHING_FILENAMES_COUNT + 1];
- gint i;
- glong notify_id;
- GstCaps *caps;
- GstElement *src;
- GstMessage *msg;
-
- if (!camera)
- return;
-
- g_object_get (camera, "camera-source", &src, NULL);
-
- for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
- filenames[i] = make_test_file_name ("image-switching-filename-test", i);
- }
- filenames[LOCATION_SWITCHING_FILENAMES_COUNT] = NULL;
-
- /* set still image mode */
- g_object_set (camera, "mode", 1, NULL);
- caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
- 800, "height", G_TYPE_INT, 600, NULL);
- g_object_set (camera, "image-capture-caps", caps, NULL);
- gst_caps_unref (caps);
-
- if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
- GST_STATE_CHANGE_FAILURE) {
- GST_WARNING ("setting camerabin to PLAYING failed");
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
- gst_object_unref (camera);
- camera = NULL;
- }
- fail_unless (camera != NULL);
- GST_INFO ("starting capture");
-
- notify_id = g_signal_connect (G_OBJECT (src),
- "notify::ready-for-capture",
- G_CALLBACK (image_location_switch_readyforcapture), filenames);
-
- g_idle_add (image_location_switch_do_capture, filenames);
- g_main_loop_run (main_loop);
-
- msg = wait_for_element_message (camera, "image-done", GST_CLOCK_TIME_NONE);
- fail_unless (msg != NULL);
- gst_message_unref (msg);
-
- gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
-
- for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
- GST_INFO ("Checking for file: %s", filenames[i]);
- fail_unless (g_file_test (filenames[i], G_FILE_TEST_IS_REGULAR));
- }
-
- for (i = 0; i < LOCATION_SWITCHING_FILENAMES_COUNT; i++) {
- g_unlink (filenames[i]);
- g_free (filenames[i]);
- }
- g_signal_handler_disconnect (src, notify_id);
-}
-
-GST_END_TEST;
-
-
-typedef struct _TestCaseDef
-{
- const gchar *name;
- gpointer setup_func;
-} TestCaseDef;
-
-TestCaseDef tests[] = {
- {"wrappercamerabinsrc", setup_wrappercamerabinsrc_videotestsrc}
-};
-
-static Suite *
-camerabin_suite (void)
-{
- GstElementFactory *jpegenc_factory;
- Suite *s = suite_create ("camerabin2");
- gint i;
- TCase *tc_generic = tcase_create ("generic");
-
- jpegenc_factory = gst_element_factory_find ("jpegenc");
- if (jpegenc_factory == NULL) {
- GST_WARNING ("Skipping camerabin2 tests because jpegenc is missing");
- goto end;
- }
-
- suite_add_tcase (s, tc_generic);
- tcase_add_checked_fixture (tc_generic, setup_wrappercamerabinsrc_videotestsrc,
- teardown);
- tcase_add_test (tc_generic, test_supported_caps);
-
- for (i = 0; i < G_N_ELEMENTS (tests); i++) {
- TCase *tc_basic = tcase_create (tests[i].name);
- suite_add_tcase (s, tc_basic);
-
- /* Increase timeout due to video recording */
- tcase_set_timeout (tc_basic, 60);
- tcase_add_checked_fixture (tc_basic, tests[i].setup_func, teardown);
-
- tcase_add_test (tc_basic, test_single_image_capture);
- tcase_add_test (tc_basic, test_single_video_recording);
- tcase_add_test (tc_basic, test_image_video_cycle);
- if (gst_plugin_feature_check_version ((GstPluginFeature *) jpegenc_factory,
- 0, 10, 27))
- tcase_add_test (tc_basic, test_multiple_image_captures);
- else
- GST_WARNING ("Skipping image capture test because -good 0.10.27 is "
- "needed");
- tcase_add_test (tc_basic, test_multiple_video_recordings);
-
- tcase_add_test (tc_basic, test_image_capture_previews);
- tcase_add_test (tc_basic, test_image_capture_with_tags);
-
- tcase_add_test (tc_basic, test_video_capture_with_tags);
-
- tcase_add_test (tc_basic, test_idle_property);
-
- tcase_add_test (tc_basic, test_image_custom_filter);
- tcase_add_test (tc_basic, test_video_custom_filter);
-
- tcase_add_test (tc_basic, test_image_location_switching);
- }
-
-end:
- return s;
-}
-
-GST_CHECK_MAIN (camerabin);
if HAVE_GTK
-GTK_EXAMPLES=camerabin mxf scaletempo camerabin2
+GTK_EXAMPLES=mxf scaletempo camerabin2
else
GTK_EXAMPLES=
endif
OPENCV_EXAMPLES=opencv
SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(OPENCV_EXAMPLES)
-DIST_SUBDIRS= camerabin camerabin2 directfb mxf scaletempo opencv
+DIST_SUBDIRS= camerabin2 directfb mxf scaletempo opencv
include $(top_srcdir)/common/parallel-subdirs.mak
+++ /dev/null
-gst-camera
-gst-camera-perf
-gst-camerabin-test
-test_*.jpg
+++ /dev/null
-GST_CAMERABIN_UI_FILES = gst-camera.ui
-
-if HAVE_GTK
-
-GST_CAMERABIN_GTK_EXAMPLES = gst-camera
-
-gst_camera_SOURCES = gst-camera.h gst-camera.c
-gst_camera_CFLAGS = \
- $(GST_PLUGINS_BAD_CFLAGS) \
- $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
- $(GTK_CFLAGS) \
- $(GMODULE_EXPORT_CFLAGS) \
- -DGST_USE_UNSTABLE_API
-gst_camera_LDADD = \
- $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_API_VERSION@.la \
- $(GST_PLUGINS_BASE_LIBS) \
- -lgstvideo-@GST_API_VERSION@ \
- $(GST_LIBS) \
- $(GTK_LIBS) \
- $(GMODULE_EXPORT_LIBS)
-
-noinst_DATA = $(GST_CAMERABIN_UI_FILES)
-
-INCLUDES = -DCAMERA_APPS_UIDIR=\""$(srcdir)"\"
-
-else
-GST_CAMERABIN_GTK_EXAMPLES =
-endif
-
-gst_camera_perf_SOURCES = gst-camera-perf.c
-gst_camera_perf_CFLAGS = $(GST_CFLAGS)
-gst_camera_perf_LDADD = $(GST_LIBS)
-
-if HAVE_X11
-
-GST_CAMERABIN_X11_EXAMPLES = gst-camerabin-test
-
-gst_camerabin_test_SOURCES = gst-camerabin-test.c
-gst_camerabin_test_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_PLUGINS_BAD_CFLAGS)
-gst_camerabin_test_LDADD = \
- $(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_API_VERSION@.la \
- -lgstvideo-@GST_API_VERSION@ \
- $(GST_LIBS) \
- $(GST_PLUGINS_BASE_LIBS) \
- $(X11_LIBS)
-
-else
-GST_CAMERABIN_X11_EXAMPLES =
-endif
-
-noinst_PROGRAMS = gst-camera-perf $(GST_CAMERABIN_X11_EXAMPLES) $(GST_CAMERABIN_GTK_EXAMPLES)
-
-EXTRA_DIST = $(GST_CAMERABIN_UI_FILES)
-
+++ /dev/null
-/*
- * 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.
- */
-/*
- * This application runs various tests and messures how long it takes.
- * FIXME: It needs to figure sane defaults for different hardware or support
- * we could use GOption for specifying the parameters
- * The config should have:
- * - target times
- * - filter-caps
- * - preview-caps
- * - user-res-fps
- * - element-names: videoenc, audioenc, videomux, imageenc, videosrc, audiosrc
- * Most of it is interpreted in setup_pipeline()
- *
- * gcc `pkg-config --cflags --libs gstreamer-0.10` gst-camera-perf.c -ogst-camera-perf
- *
- * plain linux:
- * ./gst-camera-perf --src-colorspace=YUY2 --image-width=640 --image-height=480 --video-width=640 --video-height=480 --view-framerate-num=15 --view-framerate-den=1
- *
- * maemo:
- * ./gst-camera-perf --src-colorspace=UYVY --image-width=640 --image-height=480 --video-width=640 --video-height=480 --view-framerate-num=1491 --view-framerate-den=100 --video-src=v4l2camsrc --audio-enc=nokiaaacenc --video-enc=dspmpeg4enc --video-mux=hantromp4mux --image-enc=dspjpegenc --target-times=1000,1500,1500,2000,500,2000,3500,1000,1000
- * ./gst-camera-perf --src-colorspace=UYVY --image-width=2576 --image-height=1936 --video-width=640 --video-height=480 --view-framerate-num=2999 --view-framerate-den=100 --video-src=v4l2camsrc --audio-enc=nokiaaacenc --video-enc=dspmpeg4enc --video-mux=hantromp4mux
- * ./gst-camera-perf --src-colorspace=UYVY --image-width=2576 --image-height=1936 --video-width=640 --video-height=480 --view-framerate-num=126 --view-framerate-den=5 --video-src=v4l2camsrc --audio-enc=nokiaaacenc --video-enc=dspmpeg4enc --video-mux=hantromp4mux --image-enc=dspjpegenc
- */
-
-/*
- * Includes
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* save the snapshot images
- * gcc `pkg-config --cflags --libs gstreamer-0.10 gdk-pixbuf-2.0` gst-camera-perf.c -ogst-camera-perf
- *
-#define SAVE_SNAPSHOT 1
- **/
-#include <gst/gst.h>
-#ifdef SAVE_SNAPSHOT
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-/*
- * debug logging
- */
-GST_DEBUG_CATEGORY_STATIC (camera_perf);
-#define GST_CAT_DEFAULT camera_perf
-
-
-/*
- * enums, typedefs and defines
- */
-
-#define GET_TIME(t) \
-do { \
- t = gst_util_get_timestamp (); \
- GST_DEBUG("%2d ----------------------------------------", test_ix); \
-} while(0)
-
-#define DIFF_TIME(e,s,d) d=GST_CLOCK_DIFF(s,e)
-
-#define CONT_SHOTS 10
-#define TEST_CASES 9
-
-typedef struct _ResultType
-{
- GstClockTime avg;
- GstClockTime min;
- GstClockTime max;
- guint32 times;
-} ResultType;
-
-/*
- * Global vars
- */
-static GstElement *camera_bin = NULL;
-static GMainLoop *loop = NULL;
-
-/* commandline options */
-static gchar *audiosrc_name = NULL;
-static gchar *videosrc_name = NULL;
-static gchar *audioenc_name = NULL;
-static gchar *videoenc_name = NULL;
-static gchar *imageenc_name = NULL;
-static gchar *videomux_name = NULL;
-static gchar *src_csp = NULL;
-static gint image_width = 0;
-static gint image_height = 0;
-static gint video_width = 0;
-static gint video_height = 0;
-static gint view_framerate_num = 0;
-static gint view_framerate_den = 0;
-
-/* test configuration for common callbacks */
-static GString *filename = NULL;
-static guint32 num_pics = 0;
-static guint32 num_pics_cont = 0;
-//static guint32 num_vids = 0;
-static guint test_ix = 0;
-static gboolean signal_vf_sink = FALSE;
-static gboolean signal_vid_sink = FALSE;
-static gboolean signal_img_enc = FALSE;
-static gboolean signal_shot = FALSE;
-static gboolean signal_cont = FALSE;
-
-static gboolean need_pad_probe = FALSE;
-static gboolean need_ienc_pad_probe = FALSE;
-static gboolean need_vmux_pad_probe = FALSE;
-
-static gboolean have_img_captured = FALSE;
-static gboolean have_img_done = FALSE;
-
-/* time samples and test results */
-static GstClockTime t_initial = G_GUINT64_CONSTANT (0);
-static GstClockTime t_final[CONT_SHOTS] = { G_GUINT64_CONSTANT (0), };
-
-static GstClockTime test_06_taget, test_09_taget;
-static GstClockTimeDiff diff;
-static ResultType result;
-
-/* these can be overridden with commandline args --target-times */
-static GstClockTime target[TEST_CASES] = {
- 1000 * GST_MSECOND,
- 1500 * GST_MSECOND,
- 1500 * GST_MSECOND,
- 2000 * GST_MSECOND, /* this should be shorter, as we can take next picture before preview is ready */
- 500 * GST_MSECOND,
- 2000 * GST_MSECOND,
- 3500 * GST_MSECOND,
- 1000 * GST_MSECOND,
- 1000 * GST_MSECOND
-};
-
-static const gchar *test_names[TEST_CASES] = {
- "Camera OFF to VF on",
- "(3A latency)", /* time to get AF? */
- "Shot to snapshot",
- "Shot to shot",
- "Serial shooting",
- "Shutter lag",
- "Image saved",
- "Mode change",
- "Video recording"
-};
-
-/*
- * Prototypes
- */
-
-static void print_result (void);
-static gboolean run_test (gpointer user_data);
-static gboolean setup_add_pad_probe (GstElement * elem, const gchar * pad_name,
- GstPadProbeCallback handler, gpointer data);
-
-
-/*
- * Callbacks
- */
-
-static GstPadProbeReturn
-pad_has_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
-{
- gboolean *signal_sink = (gboolean *) user_data;
- gboolean print_and_restart = FALSE;
-
- if (*signal_sink) {
- *signal_sink = FALSE;
- GET_TIME (t_final[0]);
- GST_DEBUG_OBJECT (pad, "%2d pad has buffer", test_ix);
- switch (test_ix) {
- case 5: // shutter lag
- DIFF_TIME (t_final[num_pics_cont], t_initial, diff);
- result.avg = result.min = result.max = diff;
- print_and_restart = TRUE;
- break;
- case 8: // video recording start
- DIFF_TIME (t_final[num_pics_cont], t_initial, diff);
- result.avg = result.min = result.max = diff;
- //g_signal_emit_by_name (camera_bin, "capture-stop", 0);
- print_and_restart = TRUE;
- break;
- default:
- GST_WARNING_OBJECT (pad, "%2d pad has buffer, not handled", test_ix);
- break;
- }
- }
- if (print_and_restart) {
- print_result ();
- g_idle_add ((GSourceFunc) run_test, NULL);
- }
- return GST_PAD_PROBE_OK;
-}
-
-static void
-element_added (GstBin * bin, GstElement * element, gpointer user_data)
-{
- GstElement *elem;
-
- if (GST_IS_BIN (element)) {
- g_signal_connect (element, "element-added", (GCallback) element_added,
- NULL);
- }
-
- if (need_vmux_pad_probe) {
- g_object_get (camera_bin, "video-muxer", &elem, NULL);
- if (elem) {
- need_vmux_pad_probe = FALSE;
- GST_INFO_OBJECT (elem, "got default video muxer");
- if (setup_add_pad_probe (elem, "src", pad_has_buffer, &signal_vid_sink)) {
- /* enable test */
- target[8] = test_09_taget;
- }
- }
- }
- if (need_ienc_pad_probe) {
- g_object_get (camera_bin, "image-encoder", &elem, NULL);
- if (elem) {
- need_ienc_pad_probe = FALSE;
- GST_INFO_OBJECT (elem, "got default image encoder");
- if (setup_add_pad_probe (elem, "src", pad_has_buffer, &signal_img_enc)) {
- /* enable test */
- target[5] = test_06_taget;
- }
- }
- }
-}
-
-static gboolean
-img_capture_done (GstElement * camera, GString * fname, gpointer user_data)
-{
- gboolean ret = FALSE;
- gboolean print_and_restart = FALSE;
-
- GST_DEBUG ("shot %d, cont %d, num %d", signal_shot, signal_cont,
- num_pics_cont);
-
- if (signal_shot) {
- GET_TIME (t_final[num_pics_cont]);
- signal_shot = FALSE;
- switch (test_ix) {
- case 6:
- DIFF_TIME (t_final[num_pics_cont], t_initial, diff);
- result.avg = result.min = result.max = diff;
- print_and_restart = TRUE;
- break;
- }
- GST_DEBUG ("%2d shot done", test_ix);
- }
-
- if (signal_cont) {
- gint i;
-
- if (num_pics_cont < CONT_SHOTS) {
- gchar tmp[6];
-
- GET_TIME (t_final[num_pics_cont]);
- num_pics_cont++;
- for (i = filename->len - 1; i > 0; --i) {
- if (filename->str[i] == '_')
- break;
- }
- snprintf (tmp, 6, "_%04d", num_pics_cont);
- memcpy (filename->str + i, tmp, 5);
- GST_DEBUG ("%2d cont new filename '%s'", test_ix, filename->str);
- g_object_set (camera_bin, "filename", filename->str, NULL);
- // FIXME: is burst capture broken? new filename and return TRUE should be enough
- // as a workaround we will kick next image from here
- // but this needs sync so that we have received "image-captured" message already
- if (have_img_captured) {
- have_img_captured = FALSE;
- g_signal_emit_by_name (camera_bin, "capture-start", NULL);
- } else {
- have_img_done = TRUE;
- }
- ret = TRUE;
- } else {
- GstClockTime max = 0;
- GstClockTime min = -1;
- GstClockTime total = 0;
-
- num_pics_cont = 0;
- signal_cont = FALSE;
-
- DIFF_TIME (t_final[0], t_initial, diff);
- max < diff ? max = diff : max;
- min > diff ? min = diff : min;
- total += diff;
-
- DIFF_TIME (t_final[1], t_final[0], diff);
- max < diff ? max = diff : max;
- min > diff ? min = diff : min;
- total += diff;
-
- for (i = 2; i < CONT_SHOTS; ++i) {
- DIFF_TIME (t_final[i], t_final[i - 1], diff);
-
- max < diff ? max = diff : max;
- min > diff ? min = diff : min;
- total += diff;
- }
-
- result.avg = total / CONT_SHOTS;
- result.min = min;
- result.max = max;
- print_and_restart = TRUE;
- GST_DEBUG ("%2d cont done", test_ix);
- }
- }
-
- switch (test_ix) {
- case 2:
- case 3:
- print_and_restart = TRUE;
- break;
- }
-
- if (print_and_restart) {
- print_result ();
- g_idle_add ((GSourceFunc) run_test, NULL);
- return FALSE;
- }
- return ret;
-}
-
-static gboolean
-bus_callback (GstBus * bus, GstMessage * message, gpointer data)
-{
- const GstStructure *st;
-
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR:{
- GError *err;
- gchar *debug;
-
- gst_message_parse_error (message, &err, &debug);
- g_print ("Error: %s\n", err->message);
- g_error_free (err);
- g_free (debug);
-
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera_bin),
- GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
-
- g_main_loop_quit (loop);
- break;
- }
- case GST_MESSAGE_STATE_CHANGED:
- if (GST_IS_BIN (GST_MESSAGE_SRC (message))) {
- GstState oldstate, newstate;
-
- gst_message_parse_state_changed (message, &oldstate, &newstate, NULL);
- GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-changed: %s -> %s",
- gst_element_state_get_name (oldstate),
- gst_element_state_get_name (newstate));
- if (GST_MESSAGE_SRC (message) == GST_OBJECT (camera_bin)) {
- if (GST_STATE_TRANSITION (oldstate,
- newstate) == GST_STATE_CHANGE_PAUSED_TO_PLAYING) {
- switch (test_ix) {
- case 0: // camera on
- GET_TIME (t_final[0]);
- DIFF_TIME (t_final[0], t_initial, diff);
-
- result.avg = result.min = result.max = diff;
- print_result ();
- g_idle_add ((GSourceFunc) run_test, NULL);
- break;
- }
- }
- }
- }
- break;
- case GST_MESSAGE_EOS:
- /* end-of-stream */
- GST_INFO ("got eos() - should not happen");
- g_main_loop_quit (loop);
- break;
- default:
- st = gst_message_get_structure (message);
- if (st) {
- if (gst_structure_has_name (st, "image-captured")) {
- GST_DEBUG ("%2d image-captured", test_ix);
- switch (test_ix) {
- case 3:
- GET_TIME (t_final[num_pics_cont]);
- DIFF_TIME (t_final[num_pics_cont], t_initial, diff);
- result.avg = result.min = result.max = diff;
- break;
- case 4:
- // we need to have this received before we can take next one
- if (have_img_done) {
- have_img_done = FALSE;
- g_signal_emit_by_name (camera_bin, "capture-start", NULL);
- } else {
- have_img_captured = TRUE;
- }
- break;
- }
- } else if (gst_structure_has_name (st, "preview-image")) {
- GST_DEBUG ("%2d preview-image", test_ix);
- switch (test_ix) {
- case 2:
- GET_TIME (t_final[num_pics_cont]);
- DIFF_TIME (t_final[num_pics_cont], t_initial, diff);
- result.avg = result.min = result.max = diff;
- /* turn off preview image generation again */
- g_object_set (camera_bin, "preview-caps", NULL, NULL);
- break;
- }
-#ifdef SAVE_SNAPSHOT
- {
- const GValue *value = gst_structure_get_value (st, "buffer");
- GstBuffer *buf = gst_value_get_buffer (value);
- GstCaps *caps = GST_BUFFER_CAPS (buf);
- GstStructure *buf_st = gst_caps_get_structure (caps, 0);
- gint width, height, rowstride;
- GdkPixbuf *pixbuf;
- guchar *data;
-
- GST_INFO ("preview : buf=%p, size=%d, format=%" GST_PTR_FORMAT,
- buf, GST_BUFFER_SIZE (buf), caps);
-
- data = GST_BUFFER_DATA (buff);
- gst_structure_get_int (buf_st, "width", &width);
- gst_structure_get_int (buf_st, "height", &height);
- rowstride = GST_ROUND_UP_4 (width * 3);
-
- pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, FALSE,
- 8, width, height, rowstride, NULL, NULL);
- gdk_pixbuf_save (pixbuf, "/tmp/gst-camerabin-preview.png", "png",
- NULL, NULL);
- gdk_pixbuf_unref (pixbuf);
- }
-#endif
- }
- }
- /* unhandled message */
- break;
- }
- return TRUE;
-}
-
-
-/*
- * Helpers
- */
-
-static void
-cleanup_pipeline (void)
-{
- if (camera_bin) {
- GST_INFO_OBJECT (camera_bin, "stopping and destroying");
- gst_element_set_state (camera_bin, GST_STATE_NULL);
- gst_object_unref (camera_bin);
- camera_bin = NULL;
- }
-}
-
-static gboolean
-setup_add_pad_probe (GstElement * elem, const gchar * pad_name,
- GstPadProbeCallback handler, gpointer data)
-{
- GstPad *pad = NULL;
-
- if (!(pad = gst_element_get_static_pad (elem, pad_name))) {
- GST_WARNING ("sink has no pad named '%s'", pad_name);
- return FALSE;
- }
-
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
- handler, data, NULL);
- gst_object_unref (pad);
-
- return TRUE;
-}
-
-static gboolean
-setup_pipeline_element (const gchar * property_name, const gchar * element_name,
- GstElement ** res_elem)
-{
- gboolean res = TRUE;
- GstElement *elem = NULL;
-
- if (element_name) {
- elem = gst_element_factory_make (element_name, NULL);
- if (elem) {
- g_object_set (camera_bin, property_name, elem, NULL);
- } else {
- GST_WARNING ("can't create element '%s' for property '%s'", element_name,
- property_name);
- res = FALSE;
- }
- } else {
- GST_DEBUG ("no element for property '%s' given", property_name);
- }
- if (res_elem)
- *res_elem = elem;
- return res;
-}
-
-static gboolean
-setup_pipeline (void)
-{
- GstBus *bus;
- gboolean res = TRUE;
- GstElement *vmux, *ienc, *sink;
-
- g_string_printf (filename, "test_%04u.jpg", num_pics);
-
- camera_bin = gst_element_factory_make ("camerabin", NULL);
- if (NULL == camera_bin) {
- g_warning ("can't create camerabin element\n");
- goto error;
- }
-
- g_signal_connect (camera_bin, "image-done", (GCallback) img_capture_done,
- NULL);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (camera_bin));
- gst_bus_add_watch (bus, bus_callback, NULL);
- gst_object_unref (bus);
-
- GST_INFO_OBJECT (camera_bin, "camerabin created");
-
- /* configure used elements */
- res &= setup_pipeline_element ("viewfinder-sink", "fakesink", &sink);
- res &= setup_pipeline_element ("audio-source", audiosrc_name, NULL);
- res &= setup_pipeline_element ("video-source", videosrc_name, NULL);
- res &= setup_pipeline_element ("audio-encoder", audioenc_name, NULL);
- res &= setup_pipeline_element ("video-encoder", videoenc_name, NULL);
- res &= setup_pipeline_element ("image-encoder", imageenc_name, &ienc);
- res &= setup_pipeline_element ("video-muxer", videomux_name, &vmux);
- if (!res) {
- goto error;
- }
-
- GST_INFO_OBJECT (camera_bin, "elements created");
-
- if (GST_STATE_CHANGE_FAILURE ==
- gst_element_set_state (camera_bin, GST_STATE_READY)) {
- g_warning ("can't set camerabin to ready\n");
- goto error;
- }
- GST_INFO_OBJECT (camera_bin, "camera ready");
-
- /* set properties */
- g_object_set (camera_bin, "filename", filename->str, NULL);
-
- if (src_csp) {
- GstCaps *filter_caps;
-
- /* FIXME: why do we need to set this? */
- filter_caps = gst_caps_new_simple ("video/x-raw",
- "format", G_TYPE_STRING, src_csp, NULL);
- if (filter_caps) {
- g_object_set (camera_bin, "filter-caps", filter_caps, NULL);
- gst_caps_unref (filter_caps);
- } else {
- g_warning ("can't make filter-caps with format=%s\n", src_csp);
- goto error;
- }
- }
-
- g_object_set (sink, "sync", TRUE, NULL);
-
- GST_INFO_OBJECT (camera_bin, "elements configured");
-
- /* connect signal handlers */
- g_assert (sink);
- if (!setup_add_pad_probe (sink, "sink", pad_has_buffer, &signal_vf_sink)) {
- goto error;
- }
- if (!vmux) {
- g_object_get (camera_bin, "video-muxer", &vmux, NULL);
- if (!vmux) {
- need_pad_probe = need_vmux_pad_probe = TRUE;
- /* only run the test if we later get the element */
- test_09_taget = target[8];
- target[8] = G_GUINT64_CONSTANT (0);
- }
- }
- if (vmux) {
- if (!setup_add_pad_probe (vmux, "src", pad_has_buffer, &signal_vid_sink)) {
- goto error;
- }
- }
- if (!ienc) {
- g_object_get (camera_bin, "image-encoder", &ienc, NULL);
- if (!ienc) {
- need_pad_probe = need_ienc_pad_probe = TRUE;
- /* only run the test if we later get the element */
- test_06_taget = target[5];
- target[5] = G_GUINT64_CONSTANT (0);
- }
- }
- if (ienc) {
- if (!setup_add_pad_probe (ienc, "src", pad_has_buffer, &signal_img_enc)) {
- goto error;
- }
- }
- if (need_pad_probe) {
- g_signal_connect (camera_bin, "element-added", (GCallback) element_added,
- NULL);
- }
- GST_INFO_OBJECT (camera_bin, "probe signals connected");
-
- /* configure a resolution and framerate for video and viewfinder */
- if (image_width && image_height) {
- g_signal_emit_by_name (camera_bin, "set-image-resolution", image_width,
- image_height, NULL);
- }
- /* configure a resolution and framerate for video and viewfinder */
- if (video_width && video_height && view_framerate_num && view_framerate_den) {
- g_signal_emit_by_name (camera_bin, "set-video-resolution-fps", video_width,
- video_height, view_framerate_num, view_framerate_den, NULL);
- }
-
- if (GST_STATE_CHANGE_FAILURE ==
- gst_element_set_state (camera_bin, GST_STATE_PLAYING)) {
- g_warning ("can't set camerabin to playing\n");
- goto error;
- }
- GST_INFO_OBJECT (camera_bin, "camera started");
- return TRUE;
-error:
- cleanup_pipeline ();
- return FALSE;
-}
-
-/*
- * Tests
- */
-
-/* 01) Camera OFF to VF On
- *
- * This only tests the time it takes to create the pipeline and CameraBin
- * element and have the first video frame available in ViewFinder.
- * It is not testing the real init time. To do it, the timer must start before
- * the app.
- */
-static gboolean
-test_01 (void)
-{
- gboolean res;
-
- GET_TIME (t_initial);
- if (setup_pipeline ()) {
- /* the actual results are fetched in bus_callback::state-changed */
- res = FALSE;
- } else {
- GET_TIME (t_final[0]);
- DIFF_TIME (t_final[0], t_initial, diff);
-
- result.avg = result.min = result.max = diff;
- res = TRUE;
- }
- result.times = 1;
- return res;
-}
-
-
-/* 03) Shot to snapshot
- *
- * It tests the time between pressing the Shot button and having the photo shown
- * in ViewFinder
- */
-static gboolean
-test_03 (void)
-{
- GstCaps *snap_caps;
-
- /* FIXME: add options */
- snap_caps = gst_caps_from_string ("video/x-raw-rgb,width=320,height=240");
- g_object_set (camera_bin, "preview-caps", snap_caps, NULL);
- gst_caps_unref (snap_caps);
-
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- g_object_set (camera_bin, "filename", filename->str, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
- /* the actual results are fetched in bus_callback::preview-image */
- result.times = 1;
- return FALSE;
-}
-
-
-/* 04) Shot to shot
- * It tests the time for being able to take a second shot after the first one.
- */
-static gboolean
-test_04 (void)
-{
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
- /* the actual results are fetched in bus_callback::image-captured */
- result.times = 1;
- return FALSE;
-}
-
-
-/* 05) Serial shooting
- *
- * It tests the time between shots in continuous mode.
- */
-static gboolean
-test_05 (void)
-{
- signal_cont = TRUE;
- have_img_captured = have_img_done = FALSE;
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
- /* the actual results are fetched in img_capture_done */
- result.times = CONT_SHOTS;
- return FALSE;
-}
-
-
-/* 06) Shutter lag
- *
- * It tests the time from user-start signal to buffer reaching img-enc
- */
-static gboolean
-test_06 (void)
-{
- signal_img_enc = TRUE;
-
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- g_object_set (camera_bin, "filename", filename->str, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
- /* the actual results are fetched in pad_has_buffer */
- result.times = 1;
- return FALSE;
-}
-
-
-/* 07) Image saved
- *
- * It tests the time between pressing the Shot and the final image is saved to
- * file system.
- */
-static gboolean
-test_07 (void)
-{
- signal_shot = TRUE;
-
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- g_object_set (camera_bin, "filename", filename->str, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
- /* the actual results are fetched in img_capture_done */
- result.times = 1;
- return FALSE;
-}
-
-
-/* 08) Mode change
- *
- * It tests the time it takes to change between still image and video recording
- * mode (In this test we change the mode few times).
- */
-static gboolean
-test_08 (void)
-{
- GstClockTime total = 0;
- GstClockTime max = 0;
- GstClockTime min = -1;
- const gint count = 6;
- gint i;
-
- /* switch to image mode */
- g_object_set (camera_bin, "mode", 0, NULL);
- g_object_set (camera_bin, "filename", filename->str, NULL);
-
- for (i = 0; i < count; ++i) {
- GET_TIME (t_final[i]);
- g_object_set (camera_bin, "mode", (i + 1) & 1, NULL);
- GET_TIME (t_final[i + 1]);
- }
-
- for (i = 0; i < count; ++i) {
- DIFF_TIME (t_final[i + 1], t_final[i], diff);
- total += diff;
- if (diff > max)
- max = diff;
- if (diff < min)
- min = diff;
- }
-
- result.avg = total / count;
- result.min = min;
- result.max = max;
- result.times = count;
-
- /* just make sure we are back to still image mode again */
- g_object_set (camera_bin, "mode", 0, NULL);
- return TRUE;
-}
-
-
-/* 09) Video recording
- *
- * It tests the time it takes to start video recording.
- * FIXME: shouldn't we wait for the buffer arriving on the venc instead of sink?
- */
-static gboolean
-test_09 (void)
-{
- signal_vid_sink = TRUE;
-
- /* switch to video mode */
- g_object_set (camera_bin, "mode", 1, NULL);
- g_object_set (camera_bin, "filename", filename->str, NULL);
- GET_TIME (t_initial);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
- /* the actual results are fetched in pad_has_buffer */
- result.times = 1;
- return FALSE;
-}
-
-
-typedef gboolean (*test_case) (void);
-static test_case test_cases[TEST_CASES] = {
- test_01,
- NULL,
- test_03,
- test_04,
- test_05,
- test_06,
- test_07,
- test_08,
- test_09
-};
-
-static void
-print_result (void)
-{
- if (test_ix >= TEST_CASES) {
- GST_WARNING ("text case index overrun");
- return;
- }
- printf ("| %6.02f%% ", 100.0f * (float) result.avg / (float) target[test_ix]);
- printf ("|%5u ms ", (guint) GST_TIME_AS_MSECONDS (target[test_ix]));
- printf ("|%5u ms ", (guint) GST_TIME_AS_MSECONDS (result.avg));
- printf ("|%5u ms ", (guint) GST_TIME_AS_MSECONDS (result.min));
- printf ("|%5u ms ", (guint) GST_TIME_AS_MSECONDS (result.max));
- printf ("| %3d ", result.times);
- printf ("| %-19s |\n", test_names[test_ix]);
- test_ix++;
-}
-
-static gboolean
-run_test (gpointer user_data)
-{
- gboolean ret = TRUE;
- guint old_test_ix = test_ix;
-
- if (test_ix >= TEST_CASES) {
- GST_INFO ("done");
- g_main_loop_quit (loop);
- return FALSE;
- }
-
- printf ("| %02d ", test_ix + 1);
- fflush (stdout);
- if (test_cases[test_ix]) {
- if (target[test_ix]) {
- memset (&result, 0, sizeof (ResultType));
- ret = test_cases[test_ix] ();
-
- //while (g_main_context_pending (NULL)) g_main_context_iteration (NULL,FALSE);
- if (ret) {
- print_result ();
- }
- } else {
- printf ("| test skipped ");
- printf ("| %-19s |\n", test_names[test_ix]);
- test_ix++;
- }
- } else {
- printf ("| test not implemented ");
- printf ("| %-19s |\n", test_names[test_ix]);
- test_ix++;
- }
- fflush (stdout);
-
- if (old_test_ix == 0 && ret == TRUE && !camera_bin) {
- GST_INFO ("done (camerabin creation failed)");
- g_main_loop_quit (loop);
- return FALSE;
- }
- if (old_test_ix > 0 && !camera_bin) {
- GST_INFO ("done (camerabin was destroyed)");
- g_main_loop_quit (loop);
- return FALSE;
- }
- if (test_ix >= TEST_CASES) {
- GST_INFO ("done");
- g_main_loop_quit (loop);
- return FALSE;
- }
- GST_INFO ("%2d result: %d", test_ix, ret);
- return ret;
-}
-
-int
-main (int argc, char *argv[])
-{
- gchar *target_times = NULL;
- GOptionEntry options[] = {
- {"audio-src", '\0', 0, G_OPTION_ARG_STRING, &audiosrc_name,
- "audio source used in video recording", NULL},
- {"video-src", '\0', 0, G_OPTION_ARG_STRING, &videosrc_name,
- "video source used in still capture and video recording", NULL},
- {"audio-enc", '\0', 0, G_OPTION_ARG_STRING, &audioenc_name,
- "audio encoder used in video recording", NULL},
- {"video-enc", '\0', 0, G_OPTION_ARG_STRING, &videoenc_name,
- "video encoder used in video recording", NULL},
- {"image-enc", '\0', 0, G_OPTION_ARG_STRING, &imageenc_name,
- "image encoder used in still capture", NULL},
- {"video-mux", '\0', 0, G_OPTION_ARG_STRING, &videomux_name,
- "muxer used in video recording", NULL},
- {"image-width", '\0', 0, G_OPTION_ARG_INT, &image_width,
- "width for image capture", NULL},
- {"image-height", '\0', 0, G_OPTION_ARG_INT, &image_height,
- "height for image capture", NULL},
- {"video-width", '\0', 0, G_OPTION_ARG_INT, &video_width,
- "width for image capture", NULL},
- {"video-height", '\0', 0, G_OPTION_ARG_INT, &video_height,
- "height for image capture", NULL},
- {"view-framerate-num", '\0', 0, G_OPTION_ARG_INT, &view_framerate_num,
- "framerate numerator for viewfinder", NULL},
- {"view-framerate-den", '\0', 0, G_OPTION_ARG_INT, &view_framerate_den,
- "framerate denominator for viewfinder", NULL},
- {"src-colorspace", '\0', 0, G_OPTION_ARG_STRING, &src_csp,
- "colorspace format for videosource (e.g. YUY2, UYVY)", NULL},
- {"target-times", '\0', 0, G_OPTION_ARG_STRING, &target_times,
- "target test times in ms as comma separated values (0 to skip test)",
- NULL},
- {NULL}
- };
- GOptionContext *ctx;
- GError *err = NULL;
-
- ctx = g_option_context_new (NULL);
- g_option_context_add_main_entries (ctx, options, NULL);
- g_option_context_add_group (ctx, gst_init_get_option_group ());
- if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
- g_print ("Error initializing: %s\n", err->message);
- exit (1);
- }
- g_option_context_free (ctx);
-
- GST_DEBUG_CATEGORY_INIT (camera_perf, "camera-perf", 0,
- "camera performcance test");
-
- /* init */
- filename = g_string_new_len ("", 16);
- loop = g_main_loop_new (NULL, FALSE);
-
- if (target_times) {
- gchar **numbers;
- gint i;
-
- numbers = g_strsplit (target_times, ",", TEST_CASES);
- for (i = 0; (numbers[i] && i < TEST_CASES); i++) {
- target[i] = GST_MSECOND * atoi (numbers[i]);
- }
- g_strfreev (numbers);
- }
-
- /* run */
- puts ("");
- puts ("+---------------------------------------------------------------------------------------+");
- puts ("| test | rate | target | avg | min | max | trials | description |");
- puts ("+---------------------------------------------------------------------------------------+");
- g_idle_add ((GSourceFunc) run_test, NULL);
- g_main_loop_run (loop);
- puts ("+---------------------------------------------------------------------------------------+");
- puts ("");
-
- fflush (stdout);
-
- /* free */
- cleanup_pipeline ();
- g_main_loop_unref (loop);
- g_string_free (filename, TRUE);
- g_free (audiosrc_name);
- g_free (videosrc_name);
- g_free (audioenc_name);
- g_free (videoenc_name);
- g_free (imageenc_name);
- g_free (videomux_name);
- g_free (src_csp);
- g_free (target_times);
-
- return 0;
-}
+++ /dev/null
-<?xml version="1.0"?>
-<interface>
- <!-- interface-requires gtk+ 2.8 -->
- <!-- interface-naming-policy project-wide -->
- <object class="GtkWindow" id="wndMain">
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="default_width">400</property>
- <property name="default_height">600</property>
- <signal name="delete_event" handler="on_wndMain_delete_event"/>
- <child>
- <object class="GtkVPaned" id="vpnMain">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="position">200</property>
- <child>
- <object class="GtkDrawingArea" id="daMain">
- <property name="height_request">100</property>
- <property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- </object>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="vboxMain">
- <property name="visible">True</property>
- <child>
- <object class="GtkButton" id="btnStart">
- <property name="label" translatable="yes">start</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_btnStart_clicked"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrwndMain">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="GtkViewport" id="vpMain">
- <property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <child>
- <object class="GtkLabel" id="lbMain">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="yalign">0</property>
- <property name="label" translatable="yes">== Please wait few seconds after press start ==</property>
- <property name="use_markup">True</property>
- <property name="wrap">True</property>
- <property name="selectable">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="resize">True</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
-</interface>
+++ /dev/null
-/*
- * 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.
- */
-/*
- * This is a demo application to test the camerabin element.
- * If you have question don't hesitate in contact me edgard.lima@indt.org.br
- */
-
-/*
- * Includes
- */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gst-camera.h"
-
-#include <gst/gst.h>
-#include <gst/video/videooverlay.h>
-#include <gst/video/colorbalance.h>
-#include <gst/interfaces/photography.h>
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
-
-#include <string.h>
-
-#include <sys/time.h>
-#include <time.h>
-#include <glib/gstdio.h> // g_fopen()
-
-#if !GTK_CHECK_VERSION (2, 17, 7)
-static void
-gtk_widget_get_allocation (GtkWidget * w, GtkAllocation * a)
-{
- *a = w->allocation;
-}
-#endif
-
-/*
- * enums, typedefs and defines
- */
-
-#ifdef USE_MP4
-#define VID_FILE_EXT "mp4"
-#else
-#define VID_FILE_EXT "ogg"
-#endif
-
-#define PREVIEW_TIME_MS (2 * 1000)
-#define N_BURST_IMAGES 10
-#define UI_FILE CAMERA_APPS_UIDIR G_DIR_SEPARATOR_S "gst-camera.ui"
-
-/* Names of default elements */
-#define CAMERA_APP_VIDEOSRC "v4l2src"
-#define CAMERA_APP_IMAGE_POSTPROC "dummy"
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
-#define EV_COMP_MAX 3.0
-#define EV_COMP_MIN -3.0
-#define EV_COMP_STEP 0.5
-#endif
-
-#define DEFAULT_VF_CAPS \
- "video/x-raw-yuv, width = (int) 320, height = (int) 240, framerate = (fraction) 1496/100;" \
- "video/x-raw-yuv, width = (int) 640, height = (int) 480, framerate = (fraction) 1494/100;" \
- "video/x-raw-yuv, width = (int) 800, height = (int) 480, framerate = (fraction) 2503/100;" \
- "video/x-raw-yuv, width = (int) 800, height = (int) 480, framerate = (fraction) 2988/100;" \
- "video/x-raw-yuv, width = (int) 800, height = (int) 480, framerate = (fraction) 1494/100;" \
- "video/x-raw-yuv, width = (int) 720, height = (int) 480, framerate = (fraction) 1494/100"
-
-#define PREVIEW_CAPS \
- "video/x-raw-rgb, width = (int) 640, height = (int) 480"
-
-/* states:
- (image) <---> (video_stopped) <---> (video_recording)
-*/
-typedef enum _tag_CaptureState
-{
- CAP_STATE_IMAGE,
- CAP_STATE_VIDEO_STOPED,
- CAP_STATE_VIDEO_PAUSED,
- CAP_STATE_VIDEO_RECORDING,
-} CaptureState;
-
-/*
- * Global Vars
- */
-
-static GtkBuilder *builder = NULL;
-static GtkWidget *ui_main_window = NULL;
-static GtkWidget *ui_drawing = NULL;
-static GtkWidget *ui_drawing_frame = NULL;
-static GtkWidget *ui_chk_continous = NULL;
-static GtkButton *ui_bnt_shot = NULL;
-static GtkButton *ui_bnt_pause = NULL;
-static GtkWidget *ui_chk_mute = NULL;
-static GtkWidget *ui_vbox_color_controls = NULL;
-static GtkWidget *ui_chk_rawmsg = NULL;
-
-static GtkWidget *ui_rdbntImageCapture = NULL;
-static GtkWidget *ui_rdbntVideoCapture = NULL;
-static GtkWidget *ui_menuitem_photography = NULL;
-static GtkWidget *ui_menuitem_capture = NULL;
-
-static GtkComboBox *ui_cbbox_resolution = NULL;
-static guint ui_cbbox_resolution_count = 0;
-
-static CaptureState capture_state = CAP_STATE_IMAGE;
-
-static GstElement *gst_camera_bin = NULL;
-static GstElement *gst_videosrc = NULL;
-
-static GString *filename = NULL;
-static guint32 num_pics = 0;
-static guint32 num_pics_cont = 0;
-static guint32 num_vids = 0;
-
-static gint max_fr_n = 0;
-static gint max_fr_d = 0;
-static const gchar *video_post;
-static const gchar *image_post;
-
-static GList *video_caps_list = NULL;
-
-static guint bus_handler_id = 0;
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
-static gchar *iso_speed_labels[] = { "auto", "100", "200", "400" };
-
-static struct
-{
- const gchar *label;
- gint width;
- gint height;
-} image_resolution_label_map[] = {
- {
- "View finder resolution", 0, 0}, {
- "VGA", 640, 480}, {
- "1,3Mpix (1280x960)", 1280, 960}, {
- "3Mpix (2048x1536)", 2048, 1536}, {
- "3,7Mpix 16:9 (2592x1456)", 2592, 1456}, {
- "5Mpix (2592x1968)", 2592, 1968}
-};
-#endif
-
-/*
- * functions prototypes
- */
-static gboolean me_gst_setup_pipeline (const gchar * imagepost,
- const gchar * videopost);
-static void me_gst_cleanup_element (void);
-
-static gboolean capture_mode_set_state (CaptureState state);
-static void capture_mode_config_gui (void);
-static gboolean capture_mode_stop (void);
-
-static void ui_connect_signals (void);
-static gboolean ui_create (void);
-static void destroy_color_controls (void);
-static void create_color_controls (void);
-static void init_view_finder_resolution_combobox (void);
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
-static void menuitem_toggle_active (GtkWidget * widget, gpointer data);
-static void sub_menu_initialize (GtkWidget * widget, gpointer data);
-static void fill_photography_menu (GtkMenuItem * parent_item);
-#endif
-
-/*
- * functions implementation
- */
-
-static void
-set_filename (GString * name)
-{
- const gchar *datadir;
-
- if (capture_state == CAP_STATE_IMAGE) {
- g_string_printf (name, G_DIR_SEPARATOR_S "test_%04u.jpg", num_pics);
- datadir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
- } else {
- g_string_printf (name, G_DIR_SEPARATOR_S "test_%04u.%s", num_vids,
- VID_FILE_EXT);
- datadir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
- }
-
- if (datadir == NULL) {
- gchar *curdir = g_get_current_dir ();
- g_string_prepend (name, curdir);
- g_free (curdir);
- } else {
- g_string_prepend (name, datadir);
- }
- GST_INFO ("capture to %s", name->str);
-}
-
-/* Write raw image buffer to file if found from message */
-static void
-handle_element_message (GstMessage * msg)
-{
- const GstStructure *st;
- const GValue *image;
- GstBuffer *buf = NULL;
- gchar *filename = NULL;
- FILE *f = NULL;
- size_t written;
-
- st = gst_message_get_structure (msg);
- if (g_str_equal (gst_structure_get_name (st), "autofocus-done")) {
- gtk_button_set_label (ui_bnt_pause, "Focus");
- } else if (gst_structure_has_field_typed (st, "buffer", GST_TYPE_BUFFER)) {
- image = gst_structure_get_value (st, "buffer");
- if (image) {
- buf = gst_value_get_buffer (image);
- if (g_str_equal (gst_structure_get_name (st), "raw-image")) {
- filename = g_strdup_printf ("test_%04u.raw", num_pics);
- } else if (g_str_equal (gst_structure_get_name (st), "preview-image")) {
- filename = g_strdup_printf ("test_%04u_vga.rgb", num_pics);
- } else {
- /* for future purposes */
- g_print ("unknown buffer received\n");
- return;
- }
- g_print ("writing buffer to %s\n", filename);
- f = g_fopen (filename, "w");
- if (f) {
- GstMapInfo map;
-
- gst_buffer_map (buf, &map, GST_MAP_READ);
- written = fwrite (map.data, map.size, 1, f);
- gst_buffer_unmap (buf, &map);
- if (!written) {
- g_print ("errro writing file\n");
- }
- fclose (f);
- } else {
- g_print ("error opening file for raw image writing\n");
- }
- g_free (filename);
- }
- } else if (g_str_equal (gst_structure_get_name (st), "photo-capture-start")) {
- g_print ("=== CLICK ===\n");
- }
-}
-
-static GstBusSyncReply
-my_bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
-{
- if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
- return GST_BUS_PASS;
-
- if (!gst_message_has_name (message, "prepare-xwindow-id"))
- return GST_BUS_PASS;
-
- /* FIXME: make sure to get XID in main thread */
- gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (message->src),
-#if GTK_CHECK_VERSION (2, 91, 6)
- GDK_WINDOW_XID (gtk_widget_get_window (ui_drawing)));
-#else
- GDK_WINDOW_XWINDOW (gtk_widget_get_window (ui_drawing)));
-#endif
-
- gst_message_unref (message);
- return GST_BUS_DROP;
-}
-
-static void
-print_error_message (GstMessage * msg)
-{
- GError *err = NULL;
- gchar *dbg = NULL;
-
- gst_message_parse_error (msg, &err, &dbg);
-
- g_printerr ("Camerabin won't start up!\nError: %s\nDebug Info: %s\n",
- err->message, (dbg) ? dbg : "None");
-
- g_error_free (err);
- g_free (dbg);
-}
-
-static gboolean
-my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
-{
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_WARNING:{
- GError *err;
- gchar *debug;
-
- gst_message_parse_warning (message, &err, &debug);
- g_print ("Warning: %s\n", err->message);
- g_error_free (err);
- g_free (debug);
- break;
- }
- case GST_MESSAGE_ERROR:{
- print_error_message (message);
- me_gst_cleanup_element ();
- gtk_main_quit ();
- break;
- }
- case GST_MESSAGE_EOS:
- /* end-of-stream */
- gtk_main_quit ();
- break;
- case GST_MESSAGE_STATE_CHANGED:{
- GstState old, new, pending;
-
- gst_message_parse_state_changed (message, &old, &new, &pending);
-
- GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-change %s -> %s",
- gst_element_state_get_name (old), gst_element_state_get_name (new));
-
- /* Create/destroy color controls according videosrc state */
- if (GST_MESSAGE_SRC (message) == GST_OBJECT (gst_videosrc)) {
- GST_INFO_OBJECT (GST_MESSAGE_SRC (message), "state-change %s -> %s",
- gst_element_state_get_name (old), gst_element_state_get_name (new));
-
- if (old == GST_STATE_READY && new == GST_STATE_NULL) {
- destroy_color_controls ();
- } else if (old == GST_STATE_NULL && new == GST_STATE_READY) {
- create_color_controls ();
- }
- }
-
- /* we only care about pipeline state change messages */
- if (GST_IS_PIPELINE (GST_MESSAGE_SRC (message))) {
- /* dump graph for pipeline state changes */
- gchar *dump_name = g_strdup_printf ("camerabin.%s_%s",
- gst_element_state_get_name (old),
- gst_element_state_get_name (new));
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (GST_MESSAGE_SRC (message)),
- GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE |
- GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS, dump_name);
- g_free (dump_name);
- }
- break;
- }
- case GST_MESSAGE_ELEMENT:
- {
- handle_element_message (message);
- break;
- }
- default:
- /* unhandled message */
- break;
- }
- return TRUE;
-}
-
-static void
-me_set_next_cont_file_name (GString * filename)
-{
- /* FIXME: better file naming (possible with signal) */
- if (G_UNLIKELY (num_pics_cont == 1)) {
- gint i;
- for (i = filename->len - 1; i > 0; --i) {
- if (filename->str[i] == '.')
- break;
- }
- g_string_insert (filename, i, "_0001");
- } else {
- gchar tmp[6];
- gint i;
- for (i = filename->len - 1; i > 0; --i) {
- if (filename->str[i] == '_')
- break;
- }
- snprintf (tmp, 6, "_%04d", num_pics_cont);
- memcpy (filename->str + i, tmp, 5);
- }
-}
-
-static gboolean
-stop_image_preview (gpointer data)
-{
- g_return_val_if_fail (data != NULL, FALSE);
-
- g_signal_emit_by_name (data, "capture-stop", 0);
-
- return FALSE;
-}
-
-static gboolean
-me_image_capture_done (GstElement * camera, const gchar * fname,
- gpointer user_data)
-{
- gboolean cont =
- gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (ui_chk_continous));
- GString *filename = g_string_new (fname);
-
- if (num_pics_cont < N_BURST_IMAGES && cont) {
- num_pics_cont++;
- me_set_next_cont_file_name (filename);
- g_object_set (G_OBJECT (camera), "filename", filename->str, NULL);
- g_string_free (filename, TRUE);
- } else {
- gtk_widget_set_sensitive (GTK_WIDGET (ui_bnt_shot), TRUE);
- printf ("%u image(s) saved\n", num_pics_cont + 1);
- fflush (stdout);
- num_pics_cont = 0;
-
- g_timeout_add (PREVIEW_TIME_MS, (GSourceFunc) stop_image_preview, camera);
-
- cont = FALSE;
- }
- return cont;
-}
-
-static gboolean
-me_gst_setup_pipeline_create_post_bin (const gchar * post, gboolean video)
-{
- GstElement *vpp = NULL;
- GstElement *bin, *c1, *c2, *filter;
- GstPad *pad;
- GstCaps *caps;
-
- /* this function uses a bin just because it needs ffmpegcolorspace. For
- * performance reason one should provide an element without need for color
- * convertion */
-
- vpp = gst_element_factory_make (post, NULL);
- if (NULL == vpp) {
- fprintf (stderr, "cannot create \'%s\' element\n", post);
- fflush (stderr);
- goto done;
- }
- c1 = gst_element_factory_make ("ffmpegcolorspace", NULL);
- c2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
- if (NULL == c1 || NULL == c2) {
- fprintf (stderr, "cannot create \'ffmpegcolorspace\' element\n");
- fflush (stderr);
- goto done;
- }
- filter = gst_element_factory_make ("capsfilter", NULL);
- if (NULL == filter) {
- fprintf (stderr, "cannot create \'capsfilter\' element\n");
- fflush (stderr);
- goto done;
- }
- bin = gst_bin_new (video ? "vid_postproc_bin" : "img_postproc_bin");
- if (NULL == bin) {
- goto done;
- }
-
- caps = gst_caps_new_simple ("video/x-raw-yuv",
- "format", G_TYPE_STRING, "I420", NULL);
- g_object_set (G_OBJECT (filter), "caps", caps, NULL);
- gst_caps_unref (caps);
-
- gst_bin_add_many (GST_BIN (bin), c1, vpp, c2, filter, NULL);
- if (!gst_element_link_many (c1, vpp, c2, filter, NULL)) {
- fprintf (stderr, "cannot link video post proc elements\n");
- fflush (stderr);
- goto done;
- }
-
- pad = gst_element_get_static_pad (c1, "sink");
- gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- pad = gst_element_get_static_pad (filter, "src");
- gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- g_object_set (gst_camera_bin,
- (video ? "video-post-processing" : "image-post-processing"), bin, NULL);
- return TRUE;
-done:
- return FALSE;
-}
-
-static void
-me_gst_setup_pipeline_create_codecs (void)
-{
-#ifdef USE_MP4
- g_object_set (gst_camera_bin, "video-encoder",
- gst_element_factory_make ("omx_mpeg4enc", NULL), NULL);
-
- g_object_set (gst_camera_bin, "audio-encoder",
- gst_element_factory_make ("omx_aacenc", NULL), NULL);
-
- g_object_set (gst_camera_bin, "video-muxer",
- gst_element_factory_make ("hantromp4mux", NULL), NULL);
-#else
- /* using defaults theora, vorbis, ogg */
-#endif
-}
-
-static gboolean
-me_gst_setup_pipeline_create_img_post_bin (const gchar * imagepost)
-{
- return me_gst_setup_pipeline_create_post_bin (imagepost, FALSE);
-}
-
-static gboolean
-me_gst_setup_pipeline_create_vid_post_bin (const gchar * videopost)
-{
- return me_gst_setup_pipeline_create_post_bin (videopost, TRUE);
-}
-
-static gboolean
-me_gst_setup_pipeline (const gchar * imagepost, const gchar * videopost)
-{
- GstBus *bus;
- GstCaps *preview_caps;
-
- set_filename (filename);
-
- me_gst_cleanup_element ();
-
- gst_camera_bin = gst_element_factory_make ("camerabin", NULL);
- if (NULL == gst_camera_bin) {
- goto done;
- }
-
- g_signal_connect (gst_camera_bin, "image-done",
- (GCallback) me_image_capture_done, NULL);
-
- preview_caps = gst_caps_from_string (PREVIEW_CAPS);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (gst_camera_bin));
- bus_handler_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
- gst_bus_set_sync_handler (bus, my_bus_sync_callback, NULL);
- gst_object_unref (bus);
-
- /* set properties */
- g_object_set (gst_camera_bin, "filename", filename->str, NULL);
- g_object_set (gst_camera_bin, "preview-caps", preview_caps, NULL);
- g_object_set (gst_camera_bin, "flags", 0xdf, NULL);
- gst_caps_unref (preview_caps);
-
- gst_videosrc = gst_element_factory_make (CAMERA_APP_VIDEOSRC, NULL);
- if (gst_videosrc) {
- g_object_set (G_OBJECT (gst_camera_bin), "video-source", gst_videosrc,
- NULL);
- }
-
- if (imagepost) {
- if (!me_gst_setup_pipeline_create_img_post_bin (imagepost))
- goto done;
- } else {
- /* Use default image postprocessing element */
- GstElement *ipp =
- gst_element_factory_make (CAMERA_APP_IMAGE_POSTPROC, NULL);
- if (ipp) {
- g_object_set (G_OBJECT (gst_camera_bin), "image-post-processing", ipp,
- NULL);
- }
- }
-
- if (videopost) {
- if (!me_gst_setup_pipeline_create_vid_post_bin (videopost))
- goto done;
- }
-
- me_gst_setup_pipeline_create_codecs ();
-
- if (GST_STATE_CHANGE_FAILURE ==
- gst_element_set_state (gst_camera_bin, GST_STATE_READY)) {
- goto done;
- }
-
- if (!gst_videosrc) {
- g_object_get (G_OBJECT (gst_camera_bin), "video-source", &gst_videosrc,
- NULL);
- }
-
- init_view_finder_resolution_combobox ();
-
- gst_element_set_state (gst_camera_bin, GST_STATE_PLAYING);
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
- /* Initialize menus to default settings */
- GtkWidget *sub_menu =
- gtk_menu_item_get_submenu (GTK_MENU_ITEM (ui_menuitem_capture));
- gtk_container_foreach (GTK_CONTAINER (sub_menu), sub_menu_initialize, NULL);
- sub_menu =
- gtk_menu_item_get_submenu (GTK_MENU_ITEM (ui_menuitem_photography));
- gtk_container_foreach (GTK_CONTAINER (sub_menu), sub_menu_initialize, NULL);
-#endif
-
- capture_state = CAP_STATE_IMAGE;
- return TRUE;
-done:
- fprintf (stderr, "error to create pipeline\n");
- fflush (stderr);
- me_gst_cleanup_element ();
- return FALSE;
-}
-
-static gboolean
-me_gst_setup_default_pipeline (gpointer data)
-{
- if (!me_gst_setup_pipeline (NULL, NULL)) {
- gtk_main_quit ();
- }
- return FALSE;
-}
-
-static void
-me_gst_cleanup_element (void)
-{
- if (gst_camera_bin) {
- GstBus *bus;
-
- gst_element_set_state (gst_camera_bin, GST_STATE_NULL);
- gst_element_get_state (gst_camera_bin, NULL, NULL, GST_CLOCK_TIME_NONE);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (gst_camera_bin));
- gst_bus_set_sync_handler (bus, NULL, NULL);
- g_source_remove (bus_handler_id);
-
- gst_object_unref (gst_camera_bin);
- gst_camera_bin = NULL;
-
- g_list_foreach (video_caps_list, (GFunc) gst_caps_unref, NULL);
- g_list_free (video_caps_list);
- video_caps_list = NULL;
- }
-}
-
-static gboolean
-capture_mode_stop (void)
-{
- if (capture_state == CAP_STATE_VIDEO_PAUSED
- || capture_state == CAP_STATE_VIDEO_RECORDING) {
- return capture_mode_set_state (CAP_STATE_VIDEO_STOPED);
- } else {
- return TRUE;
- }
-}
-
-static void
-capture_mode_config_gui (void)
-{
- switch (capture_state) {
- case CAP_STATE_IMAGE:
- gtk_button_set_label (ui_bnt_shot, "Shot");
- gtk_button_set_label (ui_bnt_pause, "Focus");
- gtk_widget_set_sensitive (GTK_WIDGET (ui_bnt_pause), TRUE);
- gtk_widget_show (ui_chk_continous);
- gtk_widget_show (ui_chk_rawmsg);
- gtk_widget_hide (ui_chk_mute);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ui_rdbntImageCapture),
- TRUE);
- break;
- case CAP_STATE_VIDEO_STOPED:
- gtk_button_set_label (ui_bnt_shot, "Rec");
- gtk_button_set_label (ui_bnt_pause, "Pause");
- gtk_widget_set_sensitive (GTK_WIDGET (ui_bnt_pause), FALSE);
- gtk_widget_show (GTK_WIDGET (ui_bnt_pause));
- gtk_widget_show (ui_chk_mute);
- gtk_widget_hide (ui_chk_continous);
- gtk_widget_hide (ui_chk_rawmsg);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ui_rdbntVideoCapture),
- TRUE);
- break;
- case CAP_STATE_VIDEO_PAUSED:
- gtk_button_set_label (ui_bnt_pause, "Cont");
- break;
- case CAP_STATE_VIDEO_RECORDING:
- gtk_button_set_label (ui_bnt_shot, "Stop");
- gtk_button_set_label (ui_bnt_pause, "Pause");
- gtk_widget_set_sensitive (GTK_WIDGET (ui_bnt_pause), TRUE);
- break;
- default:
- break;
- }
-}
-
-static gboolean
-capture_mode_set_state (CaptureState state)
-{
- if (capture_state == state)
- return TRUE;
-
- switch (capture_state) {
- case CAP_STATE_IMAGE:
- if (state == CAP_STATE_VIDEO_PAUSED) {
- goto done;
- }
- g_object_set (gst_camera_bin, "mode", 1, NULL);
- capture_state = CAP_STATE_VIDEO_STOPED;
- if (state == CAP_STATE_VIDEO_RECORDING)
- capture_mode_set_state (state);
- break;
- case CAP_STATE_VIDEO_STOPED:
- if (state == CAP_STATE_VIDEO_PAUSED) {
- goto done;
- }
- capture_state = state;
- if (state == CAP_STATE_IMAGE)
- g_object_set (gst_camera_bin, "mode", 0, NULL);
- else { /* state == CAP_STATE_VIDEO_RECORDING */
- g_object_set (gst_camera_bin, "mode", 1, NULL);
- g_signal_emit_by_name (gst_camera_bin, "capture-start", 0);
- }
- break;
- case CAP_STATE_VIDEO_PAUSED:
- if (state == CAP_STATE_VIDEO_RECORDING) {
- g_signal_emit_by_name (gst_camera_bin, "capture-start", 0);
- capture_state = CAP_STATE_VIDEO_RECORDING;
- } else {
- g_signal_emit_by_name (gst_camera_bin, "capture-stop", 0);
- capture_state = CAP_STATE_VIDEO_STOPED;
- if (state == CAP_STATE_IMAGE)
- capture_mode_set_state (state);
- }
- break;
- case CAP_STATE_VIDEO_RECORDING:
- if (state == CAP_STATE_VIDEO_PAUSED) {
- g_signal_emit_by_name (gst_camera_bin, "capture-pause", 0);
- capture_state = CAP_STATE_VIDEO_PAUSED;
- } else {
- g_signal_emit_by_name (gst_camera_bin, "capture-stop", 0);
- capture_state = CAP_STATE_VIDEO_STOPED;
- if (state == CAP_STATE_IMAGE)
- capture_mode_set_state (state);
- }
- break;
- }
- return TRUE;
-done:
- return FALSE;
-}
-
-void
-on_windowMain_delete_event (GtkWidget * widget, GdkEvent * event, gpointer data)
-{
- capture_mode_set_state (CAP_STATE_IMAGE);
- capture_mode_config_gui ();
- me_gst_cleanup_element ();
- gtk_main_quit ();
-}
-
-static void
-set_metadata (void)
-{
- /* for more information about image metadata tags, see:
- * http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/tests/icles/metadata_editor.c
- * and for the mapping:
- * http://webcvs.freedesktop.org/gstreamer/gst-plugins-bad/ext/metadata/metadata_mapping.htm?view=co
- */
-
- GstTagSetter *setter = GST_TAG_SETTER (gst_camera_bin);
- GTimeVal time = { 0, 0 };
- gchar *date_str, *desc_str;
-
- g_get_current_time (&time);
- date_str = g_time_val_to_iso8601 (&time); /* this is UTC */
- desc_str = g_strdup_printf ("picture taken by %s", g_get_real_name ());
-
- gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
- "date-time-original", date_str,
- "date-time-modified", date_str,
- "creator-tool", "camerabin-demo",
- GST_TAG_DESCRIPTION, desc_str,
- GST_TAG_TITLE, "My picture", GST_TAG_COPYRIGHT, "LGPL", NULL);
-
- g_free (date_str);
- g_free (desc_str);
-}
-
-void
-on_buttonShot_clicked (GtkButton * button, gpointer user_data)
-{
- switch (capture_state) {
- case CAP_STATE_IMAGE:
- {
- gtk_widget_set_sensitive (GTK_WIDGET (ui_bnt_shot), FALSE);
- set_filename (filename);
- num_pics++;
- g_object_set (gst_camera_bin, "filename", filename->str, NULL);
-
- set_metadata ();
- g_signal_emit_by_name (gst_camera_bin, "capture-start", 0);
- }
- break;
- case CAP_STATE_VIDEO_STOPED:
- set_filename (filename);
- num_vids++;
- g_object_set (gst_camera_bin, "filename", filename->str, NULL);
- capture_mode_set_state (CAP_STATE_VIDEO_RECORDING);
- capture_mode_config_gui ();
- break;
- case CAP_STATE_VIDEO_PAUSED:
- /* fall trough */
- case CAP_STATE_VIDEO_RECORDING:
- capture_mode_set_state (CAP_STATE_VIDEO_STOPED);
- capture_mode_config_gui ();
- break;
- default:
- break;
- }
-}
-
-void
-on_buttonPause_clicked (GtkButton * button, gpointer user_data)
-{
- switch (capture_state) {
- case CAP_STATE_IMAGE:
- if (g_str_equal (gtk_button_get_label (ui_bnt_pause), "Focus")) {
- /* Start autofocus */
- gst_photography_set_autofocus (GST_PHOTOGRAPHY (gst_videosrc), TRUE);
- gtk_button_set_label (ui_bnt_pause, "Cancel Focus");
- } else {
- /* Cancel autofocus */
- gst_photography_set_autofocus (GST_PHOTOGRAPHY (gst_videosrc), FALSE);
- gtk_button_set_label (ui_bnt_pause, "Focus");
- }
- break;
- case CAP_STATE_VIDEO_STOPED:
- break;
- case CAP_STATE_VIDEO_PAUSED:
- capture_mode_set_state (CAP_STATE_VIDEO_RECORDING);
- capture_mode_config_gui ();
- break;
- case CAP_STATE_VIDEO_RECORDING:
- capture_mode_set_state (CAP_STATE_VIDEO_PAUSED);
- capture_mode_config_gui ();
- break;
- default:
- break;
- }
-}
-
-void
-on_drawingareaView_realize (GtkWidget * widget, gpointer data)
-{
-#if GTK_CHECK_VERSION (2, 18, 0)
- gdk_window_ensure_native (gtk_widget_get_window (widget));
-#endif
-}
-
-gboolean
-on_drawingareaView_configure_event (GtkWidget * widget,
- GdkEventConfigure * event, gpointer data)
-{
- GtkAllocation a;
-
- gtk_widget_get_allocation (widget, &a);
- gdk_window_move_resize (gtk_widget_get_window (widget),
- a.x, a.y, a.width, a.height);
- gdk_display_sync (gtk_widget_get_display (widget));
-
- return TRUE;
-}
-
-void
-on_comboboxResolution_changed (GtkComboBox * widget, gpointer user_data)
-{
- GstStructure *st;
- gint w = 0, h = 0;
- GstCaps *video_caps =
- g_list_nth_data (video_caps_list, gtk_combo_box_get_active (widget));
-
- if (video_caps) {
- GstState old;
-
- gst_element_get_state (gst_camera_bin, &old, NULL, GST_CLOCK_TIME_NONE);
- GST_DEBUG ("change resolution in %s", gst_element_state_get_name (old));
-
- if (old != GST_STATE_NULL) {
- gst_element_set_state (gst_camera_bin, GST_STATE_READY);
- /* source need to be NULL, otherwise changing the mode fails with device
- * busy:
- * - if src goes from NULL->PLAYING it sets new mode anyway
- * - if src goes form READY->PLAYIN new mode is activated via reverse caps
- * negotiation, but then the device is already streaming
- */
- gst_element_set_state (gst_videosrc, GST_STATE_NULL);
- }
-
- st = gst_caps_get_structure (video_caps, 0);
-
- gst_structure_get_int (st, "width", &w);
- gst_structure_get_int (st, "height", &h);
-
- if (w && h) {
- g_object_set (ui_drawing_frame, "ratio", (gfloat) w / (gfloat) h, NULL);
- }
-
- g_object_set (G_OBJECT (gst_camera_bin), "filter-caps", video_caps, NULL);
-
- if (old != GST_STATE_NULL) {
- gst_element_set_state (gst_camera_bin, old);
- }
- }
-}
-
-void
-on_radiobuttonImageCapture_toggled (GtkToggleButton * togglebutton,
- gpointer user_data)
-{
- if (gtk_toggle_button_get_active (togglebutton)) {
- if (capture_state != CAP_STATE_IMAGE) {
- capture_mode_set_state (CAP_STATE_IMAGE);
- capture_mode_config_gui ();
- }
- }
-}
-
-void
-on_radiobuttonVideoCapture_toggled (GtkToggleButton * togglebutton,
- gpointer user_data)
-{
- if (gtk_toggle_button_get_active (togglebutton)) {
- if (capture_state == CAP_STATE_IMAGE) {
- capture_mode_set_state (CAP_STATE_VIDEO_STOPED);
- capture_mode_config_gui ();
- }
- }
-}
-
-static void
-on_rbBntVidEff_toggled (GtkToggleButton * togglebutton, const gchar * effect)
-{
- if (gtk_toggle_button_get_active (togglebutton)) {
- /* lets also use those effects to image */
- video_post = effect;
- image_post = effect;
- capture_mode_stop ();
-
- me_gst_cleanup_element ();
- if (!me_gst_setup_pipeline (image_post, video_post))
- gtk_main_quit ();
- capture_mode_config_gui ();
- }
-}
-
-void
-on_rbBntVidEffNone_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, NULL);
-}
-
-void
-on_rbBntVidEffEdge_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "edgetv");
-}
-
-void
-on_rbBntVidEffAging_toggled (GtkToggleButton * togglebutton, gpointer user_data)
-{
- on_rbBntVidEff_toggled (togglebutton, "agingtv");
-}
-
-void
-on_rbBntVidEffDice_toggled (GtkToggleButton * togglebutton, gpointer user_data)
-{
- on_rbBntVidEff_toggled (togglebutton, "dicetv");
-}
-
-void
-on_rbBntVidEffWarp_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "warptv");
-}
-
-void
-on_rbBntVidEffShagadelic_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "shagadelictv");
-}
-
-void
-on_rbBntVidEffVertigo_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "vertigotv");
-}
-
-void
-on_rbBntVidEffRev_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "revtv");
-}
-
-void
-on_rbBntVidEffQuark_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- on_rbBntVidEff_toggled (togglebutton, "quarktv");
-}
-
-void
-on_chkbntMute_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- g_object_set (gst_camera_bin, "mute",
- gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton)), NULL);
-}
-
-void
-on_chkbtnRawMsg_toggled (GtkToggleButton * togglebutton, gpointer data)
-{
- const gchar *env_var = "CAMSRC_PUBLISH_RAW";
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton))) {
- g_setenv (env_var, "1", TRUE);
- } else {
- g_unsetenv (env_var);
- }
-}
-
-void
-on_hscaleZoom_value_changed (GtkRange * range, gpointer user_data)
-{
- gint zoom = gtk_range_get_value (range);
- g_object_set (gst_camera_bin, "zoom", zoom, NULL);
-}
-
-void
-on_color_control_value_changed (GtkRange * range, gpointer user_data)
-{
- GstColorBalance *balance = GST_COLOR_BALANCE (gst_camera_bin);
- gint val = gtk_range_get_value (range);
- GstColorBalanceChannel *channel = (GstColorBalanceChannel *) user_data;
- gst_color_balance_set_value (balance, channel, val);
-}
-
-#ifndef GDK_KEY_F11
-#define GDK_KEY_F11 GDK_F11
-#endif
-
-gboolean
-on_key_released (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
-{
- g_return_val_if_fail (event != NULL, FALSE);
-
- switch (event->keyval) {
- case GDK_KEY_F11:
-#ifdef HAVE_GST_PHOTO_IFACE_H
- gst_photography_set_autofocus (GST_PHOTOGRAPHY (gst_videosrc), FALSE);
-#endif
- break;
- default:
- break;
- }
-
- return FALSE;
-}
-
-gboolean
-on_key_pressed (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
-{
- g_return_val_if_fail (event != NULL, FALSE);
-
- switch (event->keyval) {
- case GDK_KEY_F11:
-#ifdef HAVE_GST_PHOTO_IFACE_H
- gst_photography_set_autofocus (GST_PHOTOGRAPHY (gst_videosrc), TRUE);
-#endif
- break;
- case 0x0:
- on_buttonShot_clicked (NULL, NULL);
- break;
- default:
- break;
- }
-
- return FALSE;
-}
-
-static void
-ui_connect_signals (void)
-{
- gtk_builder_connect_signals (builder, NULL);
-
- g_signal_connect (ui_main_window, "key-press-event",
- (GCallback) on_key_pressed, NULL);
-
- g_signal_connect (ui_main_window, "key-release-event",
- (GCallback) on_key_released, NULL);
-}
-
-static gchar *
-format_value_callback (GtkScale * scale, gdouble value, gpointer user_data)
-{
- GstColorBalanceChannel *channel = (GstColorBalanceChannel *) user_data;
-
- return g_strdup_printf ("%s: %d", channel->label, (gint) value);
-}
-
-static gint
-create_menu_items_from_structure (GstStructure * structure)
-{
- GtkListStore *store;
- const GValue *framerate_list = NULL;
- const gchar *structure_name;
- GString *item_str = NULL;
- guint j, num_items_created = 0, num_framerates = 1;
- gint w = 0, h = 0, n = 0, d = 1;
- const gchar *format = NULL;
-
- g_return_val_if_fail (structure != NULL, 0);
-
- structure_name = gst_structure_get_name (structure);
-
- /* lets filter yuv only */
- if (0 == strcmp (structure_name, "video/x-raw-yuv")) {
- item_str = g_string_new_len ("", 128);
-
- if (gst_structure_has_field_typed (structure, "format", G_TYPE_STRING)) {
- format = gst_structure_get_string (structure, "format");
- }
-
- if (gst_structure_has_field_typed (structure, "width", GST_TYPE_INT_RANGE)) {
- const GValue *wrange = gst_structure_get_value (structure, "width");
- /* If range found, use the maximum */
- w = gst_value_get_int_range_max (wrange);
- } else if (gst_structure_has_field_typed (structure, "width", G_TYPE_INT)) {
- gst_structure_get_int (structure, "width", &w);
- }
-
- if (gst_structure_has_field_typed (structure, "height", GST_TYPE_INT_RANGE)) {
- const GValue *hrange = gst_structure_get_value (structure, "height");
- /* If range found, use the maximum */
- h = gst_value_get_int_range_max (hrange);
- } else if (gst_structure_has_field_typed (structure, "height", G_TYPE_INT)) {
- gst_structure_get_int (structure, "height", &h);
- }
-
- if (gst_structure_has_field_typed (structure, "framerate",
- GST_TYPE_FRACTION)) {
- gst_structure_get_fraction (structure, "framerate", &n, &d);
- } else if (gst_structure_has_field_typed (structure, "framerate",
- GST_TYPE_LIST)) {
- framerate_list = gst_structure_get_value (structure, "framerate");
- num_framerates = gst_value_list_get_size (framerate_list);
- } else if (gst_structure_has_field_typed (structure, "framerate",
- GST_TYPE_FRACTION_RANGE)) {
- const GValue *fr = gst_structure_get_value (structure, "framerate");
- const GValue *frmax = gst_value_get_fraction_range_max (fr);
- max_fr_n = gst_value_get_fraction_numerator (frmax);
- max_fr_d = gst_value_get_fraction_denominator (frmax);
- }
-
- if (max_fr_n || max_fr_d) {
- goto range_found;
- }
-
- store = GTK_LIST_STORE (gtk_combo_box_get_model (ui_cbbox_resolution));
- for (j = 0; j < num_framerates; j++) {
- GstCaps *video_caps;
- GtkTreeIter iter;
-
- if (framerate_list) {
- const GValue *item = gst_value_list_get_value (framerate_list, j);
- n = gst_value_get_fraction_numerator (item);
- d = gst_value_get_fraction_denominator (item);
- }
- g_string_assign (item_str, structure_name);
- g_string_append_printf (item_str, " (%s)", format);
- g_string_append_printf (item_str, ", %dx%d at %d/%d", w, h, n, d);
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, item_str->str, -1);
-
- video_caps =
- gst_caps_new_simple (structure_name, "format", G_TYPE_STRING,
- format,
- "width", G_TYPE_INT, w, "height", G_TYPE_INT, h,
- "framerate", GST_TYPE_FRACTION, n, d, NULL);
- video_caps_list = g_list_append (video_caps_list, video_caps);
- num_items_created++;
- }
- }
-
-range_found:
-
- if (item_str) {
- g_string_free (item_str, TRUE);
- }
-
- return num_items_created;
-}
-
-static void
-fill_resolution_combo (GstCaps * caps)
-{
- guint size, num_items, i;
- GstStructure *st;
-
- max_fr_n = max_fr_d = 0;
-
- /* Create new items */
- size = gst_caps_get_size (caps);
-
- for (i = 0; i < size; i++) {
- st = gst_caps_get_structure (caps, i);
- num_items = create_menu_items_from_structure (st);
- ui_cbbox_resolution_count += num_items;
- }
-}
-
-static GstCaps *
-create_default_caps (void)
-{
- GstCaps *default_caps;
-
- default_caps = gst_caps_from_string (DEFAULT_VF_CAPS);
-
- return default_caps;
-}
-
-static void
-init_view_finder_resolution_combobox (void)
-{
- GstCaps *input_caps = NULL, *default_caps = NULL, *intersect = NULL;
-
- g_object_get (gst_camera_bin, "video-source-caps", &input_caps, NULL);
- if (input_caps) {
- fill_resolution_combo (input_caps);
- }
-
- /* Fill in default items if supported */
- default_caps = create_default_caps ();
- intersect = gst_caps_intersect (default_caps, input_caps);
- if (intersect) {
- fill_resolution_combo (intersect);
- gst_caps_unref (intersect);
- }
- gst_caps_unref (default_caps);
-
- if (input_caps) {
- gst_caps_unref (input_caps);
- }
-
- /* Set some item active */
- gtk_combo_box_set_active (ui_cbbox_resolution, ui_cbbox_resolution_count - 1);
-}
-
-static void
-destroy_color_controls (void)
-{
- GList *widgets, *item;
- GtkWidget *widget = NULL;
- gpointer user_data = NULL;
-
- widgets = gtk_container_get_children (GTK_CONTAINER (ui_vbox_color_controls));
- for (item = widgets; item; item = g_list_next (item)) {
- widget = GTK_WIDGET (item->data);
- user_data = g_object_get_data (G_OBJECT (widget), "channel");
- g_signal_handlers_disconnect_by_func (widget, (GFunc) format_value_callback,
- user_data);
- g_signal_handlers_disconnect_by_func (widget,
- (GFunc) on_color_control_value_changed, user_data);
- gtk_container_remove (GTK_CONTAINER (ui_vbox_color_controls), widget);
- }
- g_list_free (widgets);
-}
-
-static void
-create_color_controls (void)
-{
- GstColorBalance *balance = NULL;
- const GList *controls, *item;
- GstColorBalanceChannel *channel;
- GtkWidget *hscale;
-
- if (GST_IS_COLOR_BALANCE (gst_camera_bin)) {
- balance = GST_COLOR_BALANCE (gst_camera_bin);
- }
-
- if (NULL == balance) {
- goto done;
- }
-
- controls = gst_color_balance_list_channels (balance);
- for (item = controls; item; item = g_list_next (item)) {
- channel = item->data;
-
- hscale = gtk_hscale_new ((GtkAdjustment *)
- gtk_adjustment_new (gst_color_balance_get_value (balance, channel),
- channel->min_value, channel->max_value, 1, 10, 10));
-
- g_signal_connect (GTK_RANGE (hscale), "value-changed",
- (GCallback) on_color_control_value_changed, (gpointer) channel);
- g_signal_connect (GTK_SCALE (hscale), "format-value",
- (GCallback) format_value_callback, (gpointer) channel);
- g_object_set_data (G_OBJECT (hscale), "channel", (gpointer) channel);
-
- gtk_box_pack_start (GTK_BOX (ui_vbox_color_controls), GTK_WIDGET (hscale),
- FALSE, TRUE, 0);
- }
-
- gtk_widget_show_all (ui_vbox_color_controls);
-done:
- return;
-}
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
-static void
-menuitem_toggle_active (GtkWidget * widget, gpointer data)
-{
- gboolean active;
- g_object_get (G_OBJECT (widget), "active", &active, NULL);
- if (active) {
- gtk_check_menu_item_toggled (GTK_CHECK_MENU_ITEM (widget));
- }
-}
-
-static void
-sub_menu_initialize (GtkWidget * widget, gpointer data)
-{
- GtkWidget *submenu;
- submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
- gtk_container_foreach (GTK_CONTAINER (submenu), menuitem_toggle_active, NULL);
-}
-
-void
-photo_menuitem_toggled_cb (GtkRadioMenuItem * menuitem, gpointer user_data)
-{
- gboolean active = FALSE, ret = FALSE;
- GEnumClass *eclass = (GEnumClass *) user_data;
- GType etype = G_ENUM_CLASS_TYPE (eclass);
- GEnumValue *val;
- gint set_value = -1;
-
- /* Get value using menu item name */
- val =
- g_enum_get_value_by_nick (eclass,
- gtk_widget_get_name (GTK_WIDGET (menuitem)));
-
- g_object_get (G_OBJECT (menuitem), "active", &active, NULL);
- if (active) {
- if (etype == GST_TYPE_WHITE_BALANCE_MODE) {
- GstWhiteBalanceMode mode;
- ret =
- gst_photography_set_white_balance_mode (GST_PHOTOGRAPHY
- (gst_videosrc), val->value);
- gst_photography_get_white_balance_mode (GST_PHOTOGRAPHY (gst_videosrc),
- &mode);
- set_value = (gint) mode;
- } else if (etype == GST_TYPE_SCENE_MODE) {
- GstSceneMode mode;
- ret =
- gst_photography_set_scene_mode (GST_PHOTOGRAPHY (gst_videosrc),
- val->value);
- gst_photography_get_scene_mode (GST_PHOTOGRAPHY (gst_videosrc), &mode);
- set_value = (gint) mode;
- } else if (etype == GST_TYPE_COLOUR_TONE_MODE) {
- GstColourToneMode mode;
- ret =
- gst_photography_set_colour_tone_mode (GST_PHOTOGRAPHY
- (gst_videosrc), val->value);
- gst_photography_get_colour_tone_mode (GST_PHOTOGRAPHY (gst_videosrc),
- &mode);
- set_value = (gint) mode;
- } else if (etype == GST_TYPE_FLASH_MODE) {
- GstFlashMode mode;
- ret =
- gst_photography_set_flash_mode (GST_PHOTOGRAPHY (gst_videosrc),
- val->value);
- gst_photography_get_flash_mode (GST_PHOTOGRAPHY (gst_videosrc), &mode);
- set_value = (gint) mode;
- }
-
- if (!ret) {
- g_print ("%s setting failed\n", val->value_name);
- } else if (val->value != set_value) {
- g_print ("%s setting failed, got %d\n", val->value_nick, set_value);
- }
- }
-}
-
-void
-photo_iso_speed_toggled_cb (GtkRadioMenuItem * menuitem, gpointer user_data)
-{
- gboolean active;
- const gchar *name;
- guint val = 0, set_val = G_MAXUINT;
-
- g_object_get (G_OBJECT (menuitem), "active", &active, NULL);
- if (active) {
- name = gtk_widget_get_name (GTK_WIDGET (menuitem));
- /* iso auto setting = 0 */
- /* FIXME: check what values other than 0 can be set */
- if (!g_str_equal (name, "auto")) {
- sscanf (name, "%d", &val);
- }
- if (!gst_photography_set_iso_speed (GST_PHOTOGRAPHY (gst_videosrc), val)) {
- g_print ("ISO speed (%d) setting failed\n", val);
- } else {
- gst_photography_get_iso_speed (GST_PHOTOGRAPHY (gst_videosrc), &set_val);
- if (val != set_val) {
- g_print ("ISO speed (%d) setting failed, got %d\n", val, set_val);
- }
- }
- }
-}
-
-void
-photo_ev_comp_toggled_cb (GtkRadioMenuItem * menuitem, gpointer user_data)
-{
- gboolean active;
- const gchar *name;
- gfloat val = 0.0, set_val = G_MAXFLOAT;
-
- g_object_get (G_OBJECT (menuitem), "active", &active, NULL);
- if (active) {
- name = gtk_widget_get_name (GTK_WIDGET (menuitem));
- sscanf (name, "%f", &val);
- if (!gst_photography_set_ev_compensation (GST_PHOTOGRAPHY (gst_videosrc),
- val)) {
- g_print ("EV compensation (%.1f) setting failed\n", val);
- } else {
- gst_photography_get_ev_compensation (GST_PHOTOGRAPHY (gst_videosrc),
- &set_val);
- if (val != set_val) {
- g_print ("EV compensation (%.1f) setting failed, got %.1f\n", val,
- set_val);
- }
- }
- }
-}
-
-static void
-photo_add_submenu_from_enum (GtkMenuItem * parent_item, GType enum_type)
-{
- GTypeClass *tclass;
- GEnumClass *eclass;
- GtkWidget *new_item = NULL, *new_submenu = NULL;
- guint i;
- GEnumValue *val;
- GSList *group = NULL;
-
- g_return_if_fail (parent_item && enum_type && G_TYPE_IS_CLASSED (enum_type));
-
- tclass = g_type_class_ref (enum_type);
- eclass = G_ENUM_CLASS (tclass);
- new_submenu = gtk_menu_new ();
-
- for (i = 0; i < eclass->n_values; i++) {
- val = g_enum_get_value (eclass, i);
- new_item = gtk_radio_menu_item_new_with_label (group, val->value_nick);
- /* Store enum nick as the menu item name */
- gtk_widget_set_name (new_item, val->value_nick);
- group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (new_item));
- g_signal_connect (new_item, "toggled",
- (GCallback) photo_menuitem_toggled_cb, eclass);
- gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), new_item);
- gtk_widget_show (new_item);
- }
-
- gtk_menu_item_set_submenu (parent_item, new_submenu);
- g_type_class_unref (tclass);
-}
-
-static void
-add_submenu_from_list (GtkMenuItem * parent_item, GList * labels,
- GCallback toggled_cb)
-{
- GtkWidget *new_item = NULL, *new_submenu = NULL;
- GSList *group = NULL;
- GList *l;
-
- new_submenu = gtk_menu_new ();
-
- for (l = labels; l != NULL; l = g_list_next (l)) {
- const gchar *label = l->data;
- new_item = gtk_radio_menu_item_new_with_label (group, label);
- if (g_str_equal (label, "0")) {
- /* Let's set zero as default */
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (new_item), TRUE);
- }
- gtk_widget_set_name (new_item, label);
- group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (new_item));
- g_signal_connect (new_item, "toggled", toggled_cb, NULL);
- gtk_menu_shell_append (GTK_MENU_SHELL (new_submenu), new_item);
- gtk_widget_show (new_item);
- }
-
- gtk_menu_item_set_submenu (parent_item, new_submenu);
-}
-
-static GtkMenuItem *
-add_menuitem (GtkMenu * parent_menu, const gchar * item_name)
-{
- GtkWidget *new_item;
-
- new_item = gtk_menu_item_new_with_label (item_name);
- gtk_menu_shell_append (GTK_MENU_SHELL (parent_menu), new_item);
- gtk_widget_show (new_item);
-
- return GTK_MENU_ITEM (new_item);
-}
-
-GList *
-create_iso_speed_labels (void)
-{
- GList *labels = NULL;
- gint i;
- for (i = 0; i < G_N_ELEMENTS (iso_speed_labels); i++) {
- labels = g_list_append (labels, iso_speed_labels[i]);
- }
- return labels;
-}
-
-GList *
-create_ev_comp_labels (void)
-{
- GList *labels = NULL;
- gdouble comp;
- char buf[G_ASCII_DTOSTR_BUF_SIZE];
-
- for (comp = EV_COMP_MIN; comp <= EV_COMP_MAX; comp += EV_COMP_STEP) {
- g_ascii_dtostr (buf, sizeof (buf), comp);
- labels = g_list_append (labels, g_strdup (buf));
- }
- return labels;
-}
-
-static void
-fill_photography_menu (GtkMenuItem * parent_item)
-{
- GtkWidget *photo_menu = gtk_menu_new ();
- GtkMenuItem *item = NULL;
- GList *labels = NULL;
-
- /* Add menu items and create and associate submenus to each item */
- item = add_menuitem (GTK_MENU (photo_menu), "AWB");
- photo_add_submenu_from_enum (item, GST_TYPE_WHITE_BALANCE_MODE);
-
- item = add_menuitem (GTK_MENU (photo_menu), "Colour Tone");
- photo_add_submenu_from_enum (item, GST_TYPE_COLOUR_TONE_MODE);
-
- item = add_menuitem (GTK_MENU (photo_menu), "Scene");
- photo_add_submenu_from_enum (item, GST_TYPE_SCENE_MODE);
-
- item = add_menuitem (GTK_MENU (photo_menu), "Flash");
- photo_add_submenu_from_enum (item, GST_TYPE_FLASH_MODE);
-
- item = add_menuitem (GTK_MENU (photo_menu), "ISO");
- labels = create_iso_speed_labels ();
- add_submenu_from_list (item, labels, (GCallback) photo_iso_speed_toggled_cb);
- g_list_free (labels);
-
- item = add_menuitem (GTK_MENU (photo_menu), "EV comp");
- labels = create_ev_comp_labels ();
- add_submenu_from_list (item, labels, (GCallback) photo_ev_comp_toggled_cb);
- g_list_free (labels);
-
- gtk_menu_item_set_submenu (parent_item, photo_menu);
-}
-
-void
-capture_image_res_toggled_cb (GtkRadioMenuItem * menuitem, gpointer user_data)
-{
- gboolean active;
- const gchar *label;
- gint i;
-
- g_object_get (G_OBJECT (menuitem), "active", &active, NULL);
- if (active) {
- label = gtk_widget_get_name (GTK_WIDGET (menuitem));
- /* Look for width and height corresponding to the label */
- for (i = 0; i < G_N_ELEMENTS (image_resolution_label_map); i++) {
- if (g_str_equal (label, image_resolution_label_map[i].label)) {
- /* set found values */
- g_signal_emit_by_name (gst_camera_bin, "set-image-resolution",
- image_resolution_label_map[i].width,
- image_resolution_label_map[i].height, 0);
- break;
- }
- }
- }
-}
-
-GList *
-create_image_resolution_labels (void)
-{
- GList *labels = NULL;
- int i;
- for (i = 0; i < G_N_ELEMENTS (image_resolution_label_map); i++) {
- labels = g_list_append (labels, image_resolution_label_map[i].label);
- }
- return labels;
-}
-
-static void
-fill_capture_menu (GtkMenuItem * parent_item)
-{
- GtkWidget *capture_menu = gtk_menu_new ();
- GtkMenuItem *item = NULL;
- GList *labels = NULL;
-
- /* Add menu items and create and associate submenus to each item */
- item = add_menuitem (GTK_MENU (capture_menu), "Image resolution");
-
- labels = create_image_resolution_labels ();
- add_submenu_from_list (item, labels,
- (GCallback) capture_image_res_toggled_cb);
- g_list_free (labels);
-
- gtk_menu_item_set_submenu (parent_item, capture_menu);
-}
-#endif /* HAVE_GST_PHOTO_IFACE_H */
-
-static gboolean
-ui_create (void)
-{
- GError *error = NULL;
-
- builder = gtk_builder_new ();
- if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) {
- g_warning ("Couldn't load builder file: %s", error->message);
- g_error_free (error);
- goto done;
- }
-
- ui_main_window = GTK_WIDGET (gtk_builder_get_object (builder, "windowMain"));
- ui_drawing = GTK_WIDGET (gtk_builder_get_object (builder, "drawingareaView"));
- ui_drawing_frame =
- GTK_WIDGET (gtk_builder_get_object (builder, "drawingareaFrame"));
- ui_chk_continous =
- GTK_WIDGET (gtk_builder_get_object (builder, "chkbntContinous"));
- ui_chk_rawmsg = GTK_WIDGET (gtk_builder_get_object (builder, "chkbtnRawMsg"));
- ui_bnt_shot = GTK_BUTTON (gtk_builder_get_object (builder, "buttonShot"));
- ui_bnt_pause = GTK_BUTTON (gtk_builder_get_object (builder, "buttonPause"));
- ui_cbbox_resolution =
- GTK_COMBO_BOX (gtk_builder_get_object (builder, "comboboxResolution"));
- ui_chk_mute = GTK_WIDGET (gtk_builder_get_object (builder, "chkbntMute"));
- ui_vbox_color_controls =
- GTK_WIDGET (gtk_builder_get_object (builder, "vboxColorControls"));
- ui_rdbntImageCapture =
- GTK_WIDGET (gtk_builder_get_object (builder, "radiobuttonImageCapture"));
- ui_rdbntVideoCapture =
- GTK_WIDGET (gtk_builder_get_object (builder, "radiobuttonVideoCapture"));
- ui_menuitem_photography =
- GTK_WIDGET (gtk_builder_get_object (builder, "menuitemPhotography"));
- ui_menuitem_capture =
- GTK_WIDGET (gtk_builder_get_object (builder, "menuitemCapture"));
-
-#ifdef HAVE_GST_PHOTO_IFACE_H
- if (ui_menuitem_photography) {
- fill_photography_menu (GTK_MENU_ITEM (ui_menuitem_photography));
- }
-
- if (ui_menuitem_capture) {
- fill_capture_menu (GTK_MENU_ITEM (ui_menuitem_capture));
- }
-#endif
- if (!(ui_main_window && ui_drawing && ui_chk_continous && ui_bnt_shot &&
- ui_bnt_pause && ui_cbbox_resolution && ui_chk_mute &&
- ui_vbox_color_controls && ui_rdbntImageCapture &&
- ui_rdbntVideoCapture && ui_chk_rawmsg && ui_menuitem_photography &&
- ui_menuitem_capture)) {
- fprintf (stderr, "Some widgets couldn't be created\n");
- fflush (stderr);
- goto done;
- }
-
- gtk_widget_set_double_buffered (ui_drawing, FALSE);
- ui_connect_signals ();
- gtk_widget_show_all (ui_main_window);
- capture_mode_config_gui ();
- return TRUE;
-done:
- return FALSE;
-}
-
-/*
- * main
- */
-
-int
-main (int argc, char *argv[])
-{
- int ret = 0;
-
- gst_init (&argc, &argv);
- gtk_init (&argc, &argv);
-
- filename = g_string_new_len ("", 16);
-
- /* create UI */
- if (!ui_create ()) {
- ret = -1;
- goto done;
- }
- /* create pipeline and run */
- g_idle_add (me_gst_setup_default_pipeline, NULL);
- gtk_main ();
-
-done:
- me_gst_cleanup_element ();
- g_string_free (filename, TRUE);
- return ret;
-}
+++ /dev/null
-/*
- * 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.
- */
-/*
- * This is a demo application to test the camerabin element.
- * If you have question don't hesitate in contact me edgard.lima@indt.org.br
- */
-
-#ifndef __GST_CAMERA_BIN_H__
-#define __GST_CAMERA_BIN_H__
-
-#include <gtk/gtk.h>
-
-void
-on_windowMain_delete_event (GtkWidget * widget, GdkEvent * event, gpointer data);
-
-void
-on_buttonShot_clicked (GtkButton * button, gpointer user_data);
-
-void
-on_buttonPause_clicked (GtkButton * button, gpointer user_data);
-
-void
-on_drawingareaView_realize (GtkWidget * widget, gpointer data);
-
-gboolean
-on_drawingareaView_configure_event (GtkWidget * widget,
- GdkEventConfigure * event, gpointer data);
-
-void
-on_comboboxResolution_changed (GtkComboBox * widget, gpointer user_data);
-
-void
-on_radiobuttonImageCapture_toggled (GtkToggleButton * togglebutton,
- gpointer user_data);
-
-void
-on_radiobuttonVideoCapture_toggled (GtkToggleButton * togglebutton,
- gpointer user_data);
-
-void
-on_rbBntVidEffNone_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffEdge_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffAging_toggled (GtkToggleButton * togglebutton, gpointer user_data);
-
-void
-on_rbBntVidEffDice_toggled (GtkToggleButton * togglebutton, gpointer user_data);
-
-void
-on_rbBntVidEffWarp_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffShagadelic_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffVertigo_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffRev_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_rbBntVidEffQuark_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_chkbntMute_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_chkbtnRawMsg_toggled (GtkToggleButton * togglebutton, gpointer data);
-
-void
-on_hscaleZoom_value_changed (GtkRange * range, gpointer user_data);
-
-void
-on_color_control_value_changed (GtkRange * range, gpointer user_data);
-
-gboolean
-on_key_released (GtkWidget * widget, GdkEventKey * event, gpointer user_data);
-
-gboolean
-on_key_pressed (GtkWidget * widget, GdkEventKey * event, gpointer user_data);
-
-#endif /* __GST_CAMERA_BIN_H__ */
+++ /dev/null
-<?xml version="1.0"?>
-<interface>
- <requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy project-wide -->
- <object class="GtkWindow" id="windowMain">
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="title" translatable="yes">gst-camera</property>
- <signal name="delete_event" handler="on_windowMain_delete_event"/>
- <child>
- <object class="GtkVBox" id="vboxMain">
- <property name="visible">True</property>
- <child>
- <object class="GtkHBox" id="hbox2">
- <property name="visible">True</property>
- <child>
- <object class="GtkMenuBar" id="menubar1">
- <property name="visible">True</property>
- <child>
- <object class="GtkMenuItem" id="menuitemPhotography">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Photography</property>
- <property name="use_underline">True</property>
- <child type="submenu">
- <object class="GtkMenu" id="menu1">
- <property name="visible">True</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkMenuItem" id="menuitemCapture">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Capture</property>
- <property name="use_underline">True</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBox" id="comboboxResolution">
- <property name="visible">True</property>
- <property name="model">liststore1</property>
- <signal name="changed" handler="on_comboboxResolution_changed"/>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext1"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkHBox" id="hboxMode">
- <property name="visible">True</property>
- <child>
- <object class="GtkRadioButton" id="radiobuttonImageCapture">
- <property name="label" translatable="yes">Image capture</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_radiobuttonImageCapture_toggled"/>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="radiobuttonVideoCapture">
- <property name="label" translatable="yes">Video rec</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobuttonImageCapture</property>
- <signal name="toggled" handler="on_radiobuttonVideoCapture_toggled"/>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="buttonShot">
- <property name="label" translatable="yes">Shot</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_buttonShot_clicked"/>
- </object>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="buttonPause">
- <property name="label" translatable="yes">Pause</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_buttonPause_clicked"/>
- </object>
- <packing>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="chkbntMute">
- <property name="label" translatable="yes">mute</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_chkbntMute_toggled"/>
- </object>
- <packing>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="chkbntContinous">
- <property name="label" translatable="yes">continous</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="position">5</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="chkbtnRawMsg">
- <property name="label" translatable="yes">raw msg</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="tooltip_text" translatable="yes">Send raw image after still image capture as gstreamer message</property>
- <property name="use_underline">True</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_chkbtnRawMsg_toggled"/>
- </object>
- <packing>
- <property name="position">6</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkTable" id="tableOptions">
- <property name="visible">True</property>
- <property name="n_columns">3</property>
- <child>
- <object class="GtkVBox" id="vboxVidEffect">
- <property name="visible">True</property>
- <child>
- <object class="GtkLabel" id="labelVidEff">
- <property name="visible">True</property>
- <property name="label" translatable="yes">video effects:</property>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffNone">
- <property name="label" translatable="yes">none</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_rbBntVidEffNone_toggled"/>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffEdge">
- <property name="label" translatable="yes">edged</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffEdge_toggled"/>
- </object>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffAging">
- <property name="label" translatable="yes">aging</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffAging_toggled"/>
- </object>
- <packing>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffDice">
- <property name="label" translatable="yes">dice</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffDice_toggled"/>
- </object>
- <packing>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffWarp">
- <property name="label" translatable="yes">warp</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffWarp_toggled"/>
- </object>
- <packing>
- <property name="position">5</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffShaga">
- <property name="label" translatable="yes">shagadelic</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffShagadelic_toggled"/>
- </object>
- <packing>
- <property name="position">6</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffVertigo">
- <property name="label" translatable="yes">vertigo</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffVertigo_toggled"/>
- </object>
- <packing>
- <property name="position">7</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffRev">
- <property name="label" translatable="yes">rev</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffRev_toggled"/>
- </object>
- <packing>
- <property name="position">8</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="rbBntVidEffQuark">
- <property name="label" translatable="yes">quark</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">rbBntVidEffNone</property>
- <signal name="toggled" handler="on_rbBntVidEffQuark_toggled"/>
- </object>
- <packing>
- <property name="position">9</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrlWndColorControls">
- <property name="width_request">200</property>
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="GtkViewport" id="viewportColorControls">
- <property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <child>
- <object class="GtkVBox" id="vboxColorControls">
- <property name="visible">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <object class="GtkAspectFrame" id="drawingareaFrame">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">none</property>
- <property name="obey_child">False</property>
- <child>
- <object class="GtkAlignment" id="alignment1">
- <property name="visible">True</property>
- <child>
- <object class="GtkDrawingArea" id="drawingareaView">
- <property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <signal name="configure_event" handler="on_drawingareaView_configure_event"/>
- <signal name="realize" handler="on_drawingareaView_realize"/>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkHScale" id="hscaleZoom">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="adjustment">adjustment1</property>
- <property name="digits">0</property>
- <property name="value_pos">left</property>
- <signal name="value_changed" handler="on_hscaleZoom_value_changed"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkAdjustment" id="adjustment1">
- <property name="lower">100</property>
- <property name="upper">1100</property>
- <property name="value">100</property>
- <property name="step_increment">10</property>
- <property name="page_increment">100</property>
- <property name="page_size">100</property>
- </object>
- <object class="GtkListStore" id="liststore1">
- <columns>
- <!-- column-name item text -->
- <column type="gchararray"/>
- </columns>
- </object>
-</interface>
+++ /dev/null
-/*
- * GStreamer
- * Copyright (C) 2010 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.
- */
-
- /*
- Examples:
- ./gst-camerabin-test --image-width=2048 --image-height=1536 --image-enc=dspjpegenc
- ./gst-camerabin-test --mode=1 --capture-time=10 --image-width=848 --image-height=480 --view-framerate-num=2825 \
- --view-framerate-den=100 --audio-src=pulsesrc --audio-enc=nokiaaacenc --video-enc=dspmp4venc \
- --video-mux=mp4mux --src-colorspace=UYVY
-
- gst-camerabin-test --help
- Usage:
- gst-camerabin-test [OPTION...]
-
- camerabin command line test application.
-
- Help Options:
- -h, --help Show help options
- --help-all Show all help options
- --help-gst Show GStreamer Options
-
- Application Options:
- --ev-compensation EV compensation (-2.5..2.5, default = 0)
- --aperture Aperture (size of lens opening, default = 0 (auto))
- --flash-mode Flash mode (default = 0 (auto))
- --scene-mode Scene mode (default = 6 (auto))
- --exposure Exposure (default = 0 (auto))
- --iso-speed ISO speed (default = 0 (auto))
- --white-balance-mode White balance mode (default = 0 (auto))
- --colour-tone-mode Colour tone mode (default = 0 (auto))
- --directory Directory for capture file(s) (default is current directory)
- --mode Capture mode (default = 0 (image), 1 = video)
- --capture-time Time to capture video in seconds (default = 10)
- --capture-total Total number of captures to be done (default = 1)
- --flags Flags for camerabin, (default = 0x9)
- --mute Mute audio
- --zoom Zoom (100 = 1x (default), 200 = 2x etc.)
- --audio-src Audio source used in video recording
- --audio-bitrate Audio bitrate (default 128000)
- --audio-samplerate Audio samplerate (default 48000)
- --audio-channels Audio channels (default 1)
- --video-src Video source used in still capture and video recording
- --audio-enc Audio encoder used in video recording
- --video-enc Video encoder used in video recording
- --image-enc Image encoder used in still capture
- --image-pp Image post-processing element
- --image-formatter Image metadata formatter element
- --video-mux Muxer used in video recording
- --viewfinder-sink Viewfinder sink (default = fakesink)
- --image-width Width for image capture
- --image-height Height for image capture
- --view-framerate-num Framerate numerator for viewfinder
- --view-framerate-den Framerate denominator for viewfinder
- --src-colorspace Colorspace format for video source (e.g. YUY2, UYVY)
- --src-format Video format for video source
- --preview-caps Preview caps (e.g. video/x-raw-rgb,width=320,height=240)
- --video-source-filter Video filter to process all frames from video source
- --viewfinder-filter Filter to process all frames going to viewfinder sink
- --x-width X window width (default = 320)
- --x-height X window height (default = 240)
- --no-xwindow Do not create XWindow
-
- */
-
-/*
- * Includes
- */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#define GST_USE_UNSTABLE_API 1
-
-#include <gst/gst.h>
-#include <gst/video/videooverlay.h>
-#include <gst/interfaces/photography.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-/*
- * debug logging
- */
-GST_DEBUG_CATEGORY_STATIC (camerabin_test);
-#define GST_CAT_DEFAULT camerabin_test
-typedef struct _ResultType
-{
- GstClockTime avg;
- GstClockTime min;
- GstClockTime max;
- guint32 times;
-} ResultType;
-
-/*
- * Global vars
- */
-static GstElement *camera_bin = NULL;
-static GMainLoop *loop = NULL;
-
-/* commandline options */
-static gchar *audiosrc_name = NULL;
-static gchar *videosrc_name = NULL;
-static gchar *audioenc_name = NULL;
-static gchar *videoenc_name = NULL;
-static gchar *imageenc_name = NULL;
-static gchar *imagepp_name = NULL;
-static gchar *imageformatter_name = NULL;
-static gchar *videomux_name = NULL;
-static gchar *vfsink_name = NULL;
-static gchar *src_csp = NULL;
-static gchar *src_format = NULL;
-static gint image_width = 1280;
-static gint image_height = 720;
-static gint view_framerate_num = 2825;
-static gint view_framerate_den = 100;
-static gboolean no_xwindow = FALSE;
-
-static gint mode = 1;
-static gint flags = 0x4f;
-static gboolean mute = FALSE;
-static gint zoom = 100;
-
-static gint capture_time = 10;
-static gint capture_count = 0;
-static gint capture_total = 1;
-
-/* photography interface command line options */
-#define EV_COMPENSATION_NONE -G_MAXFLOAT
-#define APERTURE_NONE -G_MAXINT
-#define FLASH_MODE_NONE -G_MAXINT
-#define SCENE_MODE_NONE -G_MAXINT
-#define EXPOSURE_NONE -G_MAXINT64
-#define ISO_SPEED_NONE -G_MAXINT
-#define WHITE_BALANCE_MODE_NONE -G_MAXINT
-#define COLOR_TONE_MODE_NONE -G_MAXINT
-static gfloat ev_compensation = EV_COMPENSATION_NONE;
-static gint aperture = APERTURE_NONE;
-static gint flash_mode = FLASH_MODE_NONE;
-static gint scene_mode = SCENE_MODE_NONE;
-static gint64 exposure = EXPOSURE_NONE;
-static gint iso_speed = ISO_SPEED_NONE;
-static gint wb_mode = WHITE_BALANCE_MODE_NONE;
-static gint color_mode = COLOR_TONE_MODE_NONE;
-
-/* audio capsfilter options */
-static gint audio_bitrate = 128000;
-static gint audio_samplerate = 48000;
-static gint audio_channels = 1;
-
-static gchar *video_src_filter = NULL;
-static gchar *viewfinder_filter = NULL;
-
-static int x_width = 320;
-static int x_height = 240;
-
-/* test configuration for common callbacks */
-static GString *filename = NULL;
-
-static gchar *preview_caps_name = NULL;
-
-/* X window variables */
-static Display *display = NULL;
-static Window window = 0;
-
-GTimer *timer = NULL;
-
-/*
- * Prototypes
- */
-static gboolean run_pipeline (gpointer user_data);
-static void set_metadata (GstElement * camera);
-
-static void
-create_host_window (void)
-{
- unsigned long valuemask;
- XSetWindowAttributes attributes;
-
- display = XOpenDisplay (NULL);
- if (display) {
- window =
- XCreateSimpleWindow (display, DefaultRootWindow (display), 0, 0,
- x_width, x_height, 0, 0, 0);
- if (window) {
- valuemask = CWOverrideRedirect;
- attributes.override_redirect = True;
- XChangeWindowAttributes (display, window, valuemask, &attributes);
- XSetWindowBackgroundPixmap (display, window, None);
- XMapRaised (display, window);
- XSync (display, FALSE);
- } else {
- GST_DEBUG ("could not create X window!");
- }
- } else {
- GST_DEBUG ("could not open display!");
- }
-}
-
-static gboolean
-img_capture_done (GstElement * camera, const gchar * fname, gpointer user_data)
-{
- gboolean ret = FALSE;
-
- GST_DEBUG ("image done: %s", fname);
- if (capture_count < capture_total) {
- g_idle_add ((GSourceFunc) run_pipeline, NULL);
- } else {
- g_main_loop_quit (loop);
- }
- return ret;
-}
-
-static GstBusSyncReply
-sync_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
-{
- const GstStructure *st;
- const GValue *image;
- GstBuffer *buf = NULL;
- gchar *preview_filename = NULL;
- FILE *f = NULL;
- size_t written;
-
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ELEMENT:{
- st = gst_message_get_structure (message);
- if (st) {
- if (gst_structure_has_name (st, "prepare-xwindow-id")) {
- if (!no_xwindow && window) {
- gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY
- (GST_MESSAGE_SRC (message)), window);
- gst_message_unref (message);
- message = NULL;
- return GST_BUS_DROP;
- }
- } else if (gst_structure_has_name (st, "image-captured")) {
- GST_DEBUG ("image-captured");
- } else if (gst_structure_has_name (st, "preview-image")) {
- GST_DEBUG ("preview-image");
- //extract preview-image from msg
- image = gst_structure_get_value (st, "buffer");
- if (image) {
- GstMapInfo map;
-
- buf = gst_value_get_buffer (image);
- gst_buffer_map (buf, &map, GST_MAP_READ);
- preview_filename = g_strdup_printf ("test_vga.rgb");
- g_print ("writing buffer to %s, elapsed: %.2fs\n",
- preview_filename, g_timer_elapsed (timer, NULL));
- f = g_fopen (preview_filename, "w");
- if (f) {
- written = fwrite (map.data, map.size, 1, f);
- if (!written) {
- g_print ("error writing file\n");
- }
- fclose (f);
- } else {
- g_print ("error opening file for raw image writing\n");
- }
- g_free (preview_filename);
- gst_buffer_unmap (buf, &map);
- }
- }
- }
- break;
- }
- default:
- /* unhandled message */
- break;
- }
- return GST_BUS_PASS;
-}
-
-static gboolean
-bus_callback (GstBus * bus, GstMessage * message, gpointer data)
-{
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_ERROR:{
- GError *err;
- gchar *debug;
-
- gst_message_parse_error (message, &err, &debug);
- g_print ("Error: %s\n", err->message);
- g_error_free (err);
- g_free (debug);
-
- /* Write debug graph to file */
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera_bin),
- GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
-
- g_main_loop_quit (loop);
- break;
- }
- case GST_MESSAGE_STATE_CHANGED:
- if (GST_IS_BIN (GST_MESSAGE_SRC (message))) {
- GstState oldstate, newstate;
-
- gst_message_parse_state_changed (message, &oldstate, &newstate, NULL);
- GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-changed: %s -> %s",
- gst_element_state_get_name (oldstate),
- gst_element_state_get_name (newstate));
- }
- break;
- case GST_MESSAGE_EOS:
- /* end-of-stream */
- GST_INFO ("got eos() - should not happen");
- g_main_loop_quit (loop);
- break;
- default:
- /* unhandled message */
- break;
- }
- return TRUE;
-}
-
-/*
- * Helpers
- */
-
-static void
-cleanup_pipeline (void)
-{
- if (camera_bin) {
- GST_INFO_OBJECT (camera_bin, "stopping and destroying");
- gst_element_set_state (camera_bin, GST_STATE_NULL);
- gst_object_unref (camera_bin);
- camera_bin = NULL;
- }
-}
-
-static gboolean
-setup_pipeline_element (const gchar * property_name, const gchar * element_name,
- GstElement ** res_elem)
-{
- gboolean res = TRUE;
- GstElement *elem = NULL;
-
- if (element_name) {
- elem = gst_element_factory_make (element_name, NULL);
- if (elem) {
- g_object_set (camera_bin, property_name, elem, NULL);
- } else {
- GST_WARNING ("can't create element '%s' for property '%s'", element_name,
- property_name);
- res = FALSE;
- }
- } else {
- GST_DEBUG ("no element for property '%s' given", property_name);
- }
- if (res_elem)
- *res_elem = elem;
- return res;
-}
-
-static GstElement *
-create_audioencoder_bin (void)
-{
- GstElement *bin, *aenc, *filter;
- GstPad *pad;
- GstCaps *audio_caps;
-
- bin = gst_bin_new ("aebin");
- filter = gst_element_factory_make ("capsfilter", "aefilter");
- aenc = gst_element_factory_make (audioenc_name, "aenc");
-
- if (!g_ascii_strcasecmp (audioenc_name, "pulsesrc")) {
- g_object_set (G_OBJECT (aenc),
- "bitrate", audio_bitrate, "profile", 2, NULL);
- }
-
- audio_caps = gst_caps_new_simple ("audio/x-raw-int",
- "channels", G_TYPE_INT, audio_channels,
- "rate", G_TYPE_INT, audio_samplerate, NULL);
-
- if (!audio_caps) {
- g_warning ("error generating caps");
- }
-
- g_object_set (G_OBJECT (filter), "caps", audio_caps, NULL);
-
- gst_caps_unref (audio_caps);
-
- gst_bin_add_many (GST_BIN (bin), filter, aenc, NULL);
- gst_element_link (filter, aenc);
-
- pad = gst_element_get_static_pad (filter, "sink");
- gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- pad = gst_element_get_static_pad (aenc, "src");
- gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- return bin;
-}
-
-static GstElement *
-create_ipp_bin (void)
-{
- GstElement *bin = NULL, *element = NULL;
- GstPad *pad = NULL;
- gchar **elements;
- GList *element_list = NULL, *current = NULL, *next = NULL;
- int i;
-
- bin = gst_bin_new ("ippbin");
-
- elements = g_strsplit (imagepp_name, ",", 0);
-
- for (i = 0; elements[i] != NULL; i++) {
- element = gst_element_factory_make (elements[i], NULL);
- if (element) {
- element_list = g_list_append (element_list, element);
- gst_bin_add (GST_BIN (bin), element);
- } else
- GST_WARNING ("Could create element %s for ippbin", elements[i]);
- }
-
- for (i = 1; i < g_list_length (element_list); i++) {
- current = g_list_nth (element_list, i - 1);
- next = g_list_nth (element_list, i);
- gst_element_link (current->data, next->data);
- }
-
- current = g_list_first (element_list);
- pad = gst_element_get_static_pad (current->data, "sink");
- gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- current = g_list_last (element_list);
- pad = gst_element_get_static_pad (current->data, "src");
- gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
- gst_object_unref (GST_OBJECT (pad));
-
- g_list_free (element_list);
- g_strfreev (elements);
-
- return bin;
-}
-
-static gboolean
-setup_pipeline (void)
-{
- GstBus *bus;
- gboolean res = TRUE;
- GstElement *vmux = NULL, *ienc = NULL, *sink = NULL, *aenc = NULL, *ipp =
- NULL;
- GstCaps *filter_caps = NULL;
-
- camera_bin = gst_element_factory_make ("camerabin", NULL);
- if (NULL == camera_bin) {
- g_warning ("can't create camerabin element\n");
- goto error;
- }
- g_object_set (camera_bin, "flags", flags, NULL);
-
- g_signal_connect (camera_bin, "image-done", (GCallback) img_capture_done,
- NULL);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (camera_bin));
- /* Add sync handler for time critical messages that need to be handled fast */
- gst_bus_set_sync_handler (bus, sync_bus_callback, NULL);
- /* Handle normal messages asynchronously */
- gst_bus_add_watch (bus, bus_callback, NULL);
- gst_object_unref (bus);
-
- GST_INFO_OBJECT (camera_bin, "camerabin created");
-
- /* configure used elements */
- res &= setup_pipeline_element ("viewfinder-sink", vfsink_name, &sink);
- res &= setup_pipeline_element ("audio-source", audiosrc_name, NULL);
- res &= setup_pipeline_element ("video-source", videosrc_name, NULL);
- res &= setup_pipeline_element ("video-source-filter", video_src_filter, NULL);
- res &= setup_pipeline_element ("viewfinder-filter", viewfinder_filter, NULL);
-
- if (audioenc_name) {
- aenc = create_audioencoder_bin ();
- if (aenc)
- g_object_set (camera_bin, "audio-encoder", aenc, NULL);
- else
- GST_WARNING ("Could not make audio encoder element");
- }
-
- if (imagepp_name) {
- ipp = create_ipp_bin ();
- if (ipp)
- g_object_set (camera_bin, "image-post-processing", ipp, NULL);
- else
- GST_WARNING ("Could not create ipp elements");
- }
-
- res &= setup_pipeline_element ("video-encoder", videoenc_name, NULL);
- res &= setup_pipeline_element ("image-encoder", imageenc_name, &ienc);
- res &= setup_pipeline_element ("image-formatter", imageformatter_name, NULL);
- res &= setup_pipeline_element ("video-muxer", videomux_name, &vmux);
- if (!res) {
- goto error;
- }
- GST_INFO_OBJECT (camera_bin, "elements created");
-
- /* set properties */
- if (src_format) {
- filter_caps = gst_caps_from_string (src_format);
- } else if (src_csp) {
- /* Set requested colorspace format, this is needed if the default
- colorspace negotiated for viewfinder doesn't match with e.g. encoders. */
- filter_caps = gst_caps_new_simple ("video/x-raw",
- "format", G_TYPE_STRING, src_csp, NULL);
- }
-
- if (filter_caps) {
- g_object_set (camera_bin, "filter-caps", filter_caps, NULL);
- gst_caps_unref (filter_caps);
- }
-
- g_object_set (sink, "sync", TRUE, NULL);
-
- GST_INFO_OBJECT (camera_bin, "elements configured");
-
- /* configure a resolution and framerate */
- if (mode == 1) {
- g_signal_emit_by_name (camera_bin, "set-video-resolution-fps", image_width,
- image_height, view_framerate_num, view_framerate_den, NULL);
- } else {
- g_signal_emit_by_name (camera_bin, "set-image-resolution", image_width,
- image_height, NULL);
- }
-
- if (GST_STATE_CHANGE_FAILURE ==
- gst_element_set_state (camera_bin, GST_STATE_READY)) {
- g_warning ("can't set camerabin to ready\n");
- goto error;
- }
- GST_INFO_OBJECT (camera_bin, "camera ready");
-
- if (GST_STATE_CHANGE_FAILURE ==
- gst_element_set_state (camera_bin, GST_STATE_PLAYING)) {
- g_warning ("can't set camerabin to playing\n");
- goto error;
- }
-
- GST_INFO_OBJECT (camera_bin, "camera started");
- return TRUE;
-error:
- cleanup_pipeline ();
- return FALSE;
-}
-
-static gboolean
-stop_capture (gpointer user_data)
-{
- g_signal_emit_by_name (camera_bin, "capture-stop", 0);
- if (capture_count < capture_total) {
- g_idle_add ((GSourceFunc) run_pipeline, NULL);
- } else {
- g_main_loop_quit (loop);
- }
- return FALSE;
-}
-
-static void
-set_metadata (GstElement * camera)
-{
- GstTagSetter *setter = GST_TAG_SETTER (camera);
- GTimeVal time = { 0, 0 };
- gchar *desc_str;
- GDate *date = g_date_new ();
-
- g_get_current_time (&time);
- g_date_set_time_val (date, &time);
-
- desc_str = g_strdup_printf ("captured by %s", g_get_real_name ());
-
- gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
- GST_TAG_DATE, date,
- GST_TAG_DESCRIPTION, desc_str,
- GST_TAG_TITLE, "gst-camerabin-test capture",
- GST_TAG_GEO_LOCATION_LONGITUDE, 1.0,
- GST_TAG_GEO_LOCATION_LATITUDE, 2.0,
- GST_TAG_GEO_LOCATION_ELEVATION, 3.0,
- GST_TAG_DEVICE_MANUFACTURER, "gst-camerabin-test manufacturer",
- GST_TAG_DEVICE_MODEL, "gst-camerabin-test model", NULL);
-
- g_free (desc_str);
- g_date_free (date);
-}
-
-static gboolean
-run_pipeline (gpointer user_data)
-{
- GstCaps *preview_caps = NULL;
- gchar *filename_str = NULL;
- GstElement *video_source = NULL;
- const gchar *filename_suffix;
-
- g_object_set (camera_bin, "mode", mode, NULL);
-
- if (preview_caps_name != NULL) {
- preview_caps = gst_caps_from_string (preview_caps_name);
- if (preview_caps) {
- g_object_set (camera_bin, "preview-caps", preview_caps, NULL);
- GST_DEBUG ("Preview caps set");
- } else
- GST_DEBUG ("Preview caps set but could not create caps from string");
- }
-
- set_metadata (camera_bin);
-
- /* Construct filename */
- if (mode == 1)
- filename_suffix = ".mp4";
- else
- filename_suffix = ".jpg";
- filename_str =
- g_strdup_printf ("%s/test_%04u%s", filename->str, capture_count,
- filename_suffix);
- GST_DEBUG ("Setting filename: %s", filename_str);
- g_object_set (camera_bin, "filename", filename_str, NULL);
- g_free (filename_str);
-
- g_object_get (camera_bin, "video-source", &video_source, NULL);
- if (video_source) {
- if (GST_IS_ELEMENT (video_source) && GST_IS_PHOTOGRAPHY (video_source)) {
- /* Set GstPhotography interface options. If option not given as
- command-line parameter use default of the source element. */
- if (scene_mode != SCENE_MODE_NONE)
- g_object_set (video_source, "scene-mode", scene_mode, NULL);
- if (ev_compensation != EV_COMPENSATION_NONE)
- g_object_set (video_source, "ev-compensation", ev_compensation, NULL);
- if (aperture != APERTURE_NONE)
- g_object_set (video_source, "aperture", aperture, NULL);
- if (flash_mode != FLASH_MODE_NONE)
- g_object_set (video_source, "flash-mode", flash_mode, NULL);
- if (exposure != EXPOSURE_NONE)
- g_object_set (video_source, "exposure", exposure, NULL);
- if (iso_speed != ISO_SPEED_NONE)
- g_object_set (video_source, "iso-speed", iso_speed, NULL);
- if (wb_mode != WHITE_BALANCE_MODE_NONE)
- g_object_set (video_source, "white-balance-mode", wb_mode, NULL);
- if (color_mode != COLOR_TONE_MODE_NONE)
- g_object_set (video_source, "colour-tone-mode", color_mode, NULL);
- }
- g_object_unref (video_source);
- }
- g_object_set (camera_bin, "mute", mute, NULL);
- g_object_set (camera_bin, "zoom", zoom / 100.0f, NULL);
-
- capture_count++;
- g_timer_start (timer);
- g_signal_emit_by_name (camera_bin, "capture-start", 0);
-
-
- if (mode == 1) {
- g_timeout_add ((capture_time * 1000), (GSourceFunc) stop_capture, NULL);
- }
-
- return FALSE;
-}
-
-int
-main (int argc, char *argv[])
-{
- gchar *target_times = NULL;
- gchar *ev_option = NULL;
- gchar *fn_option = NULL;
-
- GOptionEntry options[] = {
- {"ev-compensation", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING,
- &ev_option,
- "EV compensation for source element GstPhotography interface", NULL},
- {"aperture", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &aperture,
- "Aperture (size of lens opening) for source element GstPhotography interface",
- NULL},
- {"flash-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &flash_mode,
- "Flash mode for source element GstPhotography interface", NULL},
- {"scene-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &scene_mode,
- "Scene mode for source element GstPhotography interface", NULL},
- {"exposure", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT64,
- &exposure,
- "Exposure time (in ms) for source element GstPhotography interface",
- NULL},
- {"iso-speed", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &iso_speed,
- "ISO speed for source element GstPhotography interface", NULL},
- {"white-balance-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &wb_mode,
- "White balance mode for source element GstPhotography interface", NULL},
- {"colour-tone-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &color_mode,
- "Colour tone mode for source element GstPhotography interface", NULL},
- {"directory", '\0', 0, G_OPTION_ARG_STRING, &fn_option,
- "Directory for capture file(s) (default is current directory)", NULL},
- {"mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mode,
- "Capture mode (default = 0 (image), 1 = video)", NULL},
- {"capture-time", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
- &capture_time,
- "Time to capture video in seconds (default = 10)", NULL},
- {"capture-total", '\0', 0, G_OPTION_ARG_INT, &capture_total,
- "Total number of captures to be done (default = 1)", NULL},
- {"flags", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &flags,
- "Flags for camerabin, (default = 0x9)", NULL},
- {"mute", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_NONE, &mute,
- "Mute audio", NULL},
- {"zoom", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &zoom,
- "Zoom (100 = 1x (default), 200 = 2x etc.)", NULL},
- {"audio-src", '\0', 0, G_OPTION_ARG_STRING, &audiosrc_name,
- "Audio source used in video recording", NULL},
- {"audio-bitrate", '\0', 0, G_OPTION_ARG_INT, &audio_bitrate,
- "Audio bitrate (default 128000)", NULL},
- {"audio-samplerate", '\0', 0, G_OPTION_ARG_INT, &audio_samplerate,
- "Audio samplerate (default 48000)", NULL},
- {"audio-channels", '\0', 0, G_OPTION_ARG_INT, &audio_channels,
- "Audio channels (default 1)", NULL},
- {"video-src", '\0', 0, G_OPTION_ARG_STRING, &videosrc_name,
- "Video source used in still capture and video recording", NULL},
- {"audio-enc", '\0', 0, G_OPTION_ARG_STRING, &audioenc_name,
- "Audio encoder used in video recording", NULL},
- {"video-enc", '\0', 0, G_OPTION_ARG_STRING, &videoenc_name,
- "Video encoder used in video recording", NULL},
- {"image-enc", '\0', 0, G_OPTION_ARG_STRING, &imageenc_name,
- "Image encoder used in still capture", NULL},
- {"image-pp", '\0', 0, G_OPTION_ARG_STRING, &imagepp_name,
- "List of image post-processing elements separated with comma", NULL},
- {"image-formatter", '\0', 0, G_OPTION_ARG_STRING, &imageformatter_name,
- "Image metadata formatter used in still image capture", NULL},
- {"video-mux", '\0', 0, G_OPTION_ARG_STRING, &videomux_name,
- "Muxer used in video recording", NULL},
- {"viewfinder-sink", '\0', 0, G_OPTION_ARG_STRING, &vfsink_name,
- "Viewfinder sink (default = fakesink)", NULL},
- {"image-width", '\0', 0, G_OPTION_ARG_INT, &image_width,
- "Width for image capture", NULL},
- {"image-height", '\0', 0, G_OPTION_ARG_INT, &image_height,
- "Height for image capture", NULL},
- {"view-framerate-num", '\0', 0, G_OPTION_ARG_INT, &view_framerate_num,
- "Framerate numerator for viewfinder", NULL},
- {"view-framerate-den", '\0', 0, G_OPTION_ARG_INT, &view_framerate_den,
- "Framerate denominator for viewfinder", NULL},
- {"src-colorspace", '\0', 0, G_OPTION_ARG_STRING, &src_csp,
- "Colorspace format for video source (e.g. YUY2, UYVY)", NULL},
- {"src-format", '\0', 0, G_OPTION_ARG_STRING, &src_format,
- "Video format for video source", NULL},
- {"preview-caps", '\0', 0, G_OPTION_ARG_STRING, &preview_caps_name,
- "Preview caps (e.g. video/x-raw-rgb,width=320,height=240)", NULL},
- {"video-source-filter", '\0', 0, G_OPTION_ARG_STRING, &video_src_filter,
- "Video filter to process all frames from video source", NULL},
- {"viewfinder-filter", '\0', 0, G_OPTION_ARG_STRING, &viewfinder_filter,
- "Filter to process all frames going to viewfinder sink", NULL},
- {"x-width", '\0', 0, G_OPTION_ARG_INT, &x_width,
- "X window width (default = 320)", NULL},
- {"x-height", '\0', 0, G_OPTION_ARG_INT, &x_height,
- "X window height (default = 240)", NULL},
- {"no-xwindow", '\0', 0, G_OPTION_ARG_NONE, &no_xwindow,
- "Do not create XWindow", NULL},
- {NULL}
- };
-
- GOptionContext *ctx;
- GError *err = NULL;
-
- ctx = g_option_context_new ("\n\ncamerabin command line test application.");
- g_option_context_add_main_entries (ctx, options, NULL);
- g_option_context_add_group (ctx, gst_init_get_option_group ());
- if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
- g_print ("Error initializing: %s\n", err->message);
- exit (1);
- }
- g_option_context_free (ctx);
-
- /* if we fail to create xwindow should we care? */
- if (!no_xwindow)
- create_host_window ();
-
- GST_DEBUG_CATEGORY_INIT (camerabin_test, "camerabin-test", 0,
- "camerabin test");
-
- /* FIXME: error handling */
- if (ev_option != NULL)
- ev_compensation = strtod (ev_option, (char **) NULL);
-
- if (vfsink_name == NULL)
- vfsink_name = g_strdup ("fakesink");
-
- filename = g_string_new (fn_option);
- if (filename->len == 0)
- filename = g_string_append (filename, ".");
-
- timer = g_timer_new ();
-
- /* init */
- if (setup_pipeline ()) {
- loop = g_main_loop_new (NULL, FALSE);
- g_idle_add ((GSourceFunc) run_pipeline, NULL);
- g_main_loop_run (loop);
- cleanup_pipeline ();
- g_main_loop_unref (loop);
- }
- /* free */
- g_string_free (filename, TRUE);
- g_free (ev_option);
- g_free (audiosrc_name);
- g_free (videosrc_name);
- g_free (audioenc_name);
- g_free (videoenc_name);
- g_free (imageenc_name);
- g_free (imageformatter_name);
- g_free (imagepp_name);
- g_free (videomux_name);
- g_free (vfsink_name);
- g_free (src_csp);
- g_free (src_format);
- g_free (target_times);
- g_timer_destroy (timer);
-
- if (window)
- XDestroyWindow (display, window);
-
- if (display)
- XCloseDisplay (display);
-
- return 0;
-}