gst_plugins_good/gst/camerabin/gstcamerabin.c
branchRCL_3
changeset 30 7e817e7e631c
parent 2 5505e8908944
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     1 /*
       
     2  * GStreamer
       
     3  * Copyright (C) 2008 Nokia Corporation <multimedia@maemo.org>
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Library General Public
       
    16  * License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 /**
       
    22  * SECTION:gstcamerabin
       
    23  * @short_description: camera capture bin
       
    24  *
       
    25  * <refsect2>
       
    26  * <para>
       
    27  * GstCameraBin is a high-level camera object that encapsulates the gstreamer
       
    28  * internals and provides a task based API for the application. It consists of
       
    29  * three main data paths: view-finder, image capture and video capture.
       
    30  * </para>
       
    31  * <informalfigure>
       
    32  *   <mediaobject>
       
    33  *     <imageobject><imagedata fileref="camerabin.png"/></imageobject>
       
    34  *     <textobject><phrase>CameraBin structure</phrase></textobject>
       
    35  *     <caption><para>Structural decomposition of CameraBin object.</para></caption>
       
    36  *   </mediaobject>
       
    37  * </informalfigure>
       
    38  * </refsect2>
       
    39  * <refsect2>
       
    40  * <title>Example launch line</title>
       
    41  * <para>
       
    42  * <programlisting>
       
    43  * gst-launch -v -m camerabin filename=test.jpeg
       
    44  * </programlisting>
       
    45  * </para>
       
    46  * </refsect2>
       
    47  * <refsect2>
       
    48  * <title>Image capture</title>
       
    49  * <para>
       
    50  * Taking still images is initiated with the #GstCameraBin::user-start action
       
    51  * signal. Once the image has captured, #GstCameraBin::img-done signal is fired.
       
    52  * It allows to decide wheter to take another picture (burst capture, bracketing
       
    53  * shot) or stop capturing. The last captured image is shown
       
    54  * until one switches back to view finder using #GstCameraBin::user-stop action
       
    55  * signal.
       
    56  * </para>
       
    57  * <para>
       
    58  * Available resolutions can be taken from the #GstCameraBin:inputcaps property.
       
    59  * Image capture resolution can be set with #GstCameraBin::user-image-res
       
    60  * action signal.
       
    61  * </para>
       
    62  * </refsect2>
       
    63  * <refsect2>
       
    64  * <title>Video capture</title>
       
    65  * <para>
       
    66  * Video capture is started with the #GstCameraBin::user-start action signal too.
       
    67  * In addition to image capture one can use #GstCameraBin::user-pause to
       
    68  * pause recording and #GstCameraBin::user-stop to end recording.
       
    69  * </para>
       
    70  * <para>
       
    71  * Available resolutions and fps can be taken from the #GstCameraBin:inputcaps
       
    72  * property. #GstCameraBin::user-res-fps action signal can be used to set frame
       
    73  * rate and resolution for the video recording and view finder as well.
       
    74  * </para>
       
    75  * </refsect2>
       
    76  * <refsect2>
       
    77  * <title>Photography interface</title>
       
    78  * <para>
       
    79  * GstCameraBin implements gst photography interface, which can be used to set
       
    80  * and get different settings related to digital imaging. Since currently many
       
    81  * of these settings require low-level support the photography interface support
       
    82  * is dependent on video src element. In practice photography interface settings
       
    83  * cannot be used successfully until in PAUSED state when the video src has
       
    84  * opened the video device.
       
    85  * </para>
       
    86  * </refsect2>
       
    87  * <refsect2>
       
    88  * <title>States</title>
       
    89  * <para>
       
    90  * Elements within GstCameraBin are created and destroyed when switching
       
    91  * between NULL and READY states. Therefore element properties should be set
       
    92  * in NULL state. User set elements are not unreffed until GstCameraBin is
       
    93  * unreffed or replaced by a new user set element. Initially only elements needed
       
    94  * for view finder mode are created to speed up startup. Image bin and video bin
       
    95  * elements are created when setting the mode or starting capture.
       
    96  * </para>
       
    97  * </refsect2>
       
    98  * <refsect2>
       
    99  * <note>
       
   100  * <para>
       
   101  * Since the muxers tested so far have problems with discontinous buffers, QoS
       
   102  * has been disabled, and then in order to record video, you MUST ensure that
       
   103  * there is enough CPU to encode the video. Thus choose smart resolution and
       
   104  * frames per second values. It is also highly recommended to avoid color
       
   105  * conversions; make sure all the elements involved work with the same colorspace
       
   106  * (i.e. rgb or yuv i420 or whatelse).
       
   107  * </para>
       
   108  * </note>
       
   109  * </refsect2>
       
   110  */
       
   111 
       
   112 /*
       
   113  * The pipeline in the camerabin is
       
   114  *
       
   115  *                                   "image bin"
       
   116  * videosrc ! crop ! scale ! out-sel <------> in-sel ! scale ! ffmpegcsp ! vfsink
       
   117  *                                   "video bin"
       
   118  *
       
   119  * it is possible to have 'ffmpegcolorspace' and 'capsfilter' just after
       
   120  * v4l2camsrc
       
   121  *
       
   122  * The properties of elements are:
       
   123  *
       
   124  *   vfsink - "sync", FALSE, "qos", FALSE
       
   125  *   output-selector - "resend-latest", FALSE
       
   126  *   input-selector - "select-all", TRUE
       
   127  */
       
   128 
       
   129 /*
       
   130  * includes
       
   131  */
       
   132 
       
   133 
       
   134 #ifdef HAVE_CONFIG_H
       
   135 #include <config.h>
       
   136 #endif
       
   137 
       
   138 
       
   139 #include <string.h>
       
   140 #include <stdlib.h>
       
   141 
       
   142 #include <gst/gst.h>
       
   143 /* FIXME: include #include <gst/gst-i18n-plugin.h> and use _(" ") */
       
   144 
       
   145 #ifndef __SYMBIAN32__
       
   146 #include <gst/gst-i18n-plugin.h>
       
   147 #else
       
   148 #include <gst/gst-i18n-plugin.h>
       
   149 #endif
       
   150 
       
   151 #ifdef __SYMBIAN32__
       
   152 #include <gst/gstinfo.h>
       
   153 #endif
       
   154 
       
   155 
       
   156 
       
   157 
       
   158 #include "gstcamerabin.h"
       
   159 #include "gstcamerabinxoverlay.h"
       
   160 #include "gstcamerabincolorbalance.h"
       
   161 #include "gstcamerabinphotography.h"
       
   162 
       
   163 #include "camerabingeneral.h"
       
   164 
       
   165 #include "gstcamerabin-marshal.h"
       
   166 
       
   167 #ifdef __SYMBIAN32__
       
   168 #include <glib_global.h>
       
   169 #endif
       
   170 /*
       
   171  * enum and types
       
   172  */
       
   173 
       
   174 enum
       
   175 {
       
   176   /* action signals */
       
   177   USER_START_SIGNAL,
       
   178   USER_STOP_SIGNAL,
       
   179   USER_PAUSE_SIGNAL,
       
   180   USER_RES_FPS_SIGNAL,
       
   181   USER_IMAGE_RES_SIGNAL,
       
   182   /* emit signals */
       
   183   IMG_DONE_SIGNAL,
       
   184   LAST_SIGNAL
       
   185 };
       
   186 
       
   187 enum
       
   188 {
       
   189   ARG_0,
       
   190   ARG_FILENAME,
       
   191   ARG_MODE,
       
   192   ARG_MUTE,
       
   193   ARG_ZOOM,
       
   194   ARG_IMAGE_POST,
       
   195   ARG_IMAGE_ENC,
       
   196   ARG_VIDEO_POST,
       
   197   ARG_VIDEO_ENC,
       
   198   ARG_AUDIO_ENC,
       
   199   ARG_VIDEO_MUX,
       
   200   ARG_VF_SINK,
       
   201   ARG_VIDEO_SRC,
       
   202   ARG_AUDIO_SRC,
       
   203   ARG_INPUT_CAPS,
       
   204   ARG_FILTER_CAPS
       
   205 };
       
   206 
       
   207 /*
       
   208  * defines and static global vars
       
   209  */
       
   210 
       
   211 static guint camerabin_signals[LAST_SIGNAL];
       
   212 
       
   213 #define GST_TYPE_CAMERABIN_MODE (gst_camerabin_mode_get_type ())
       
   214 
       
   215 /* default and range values for args */
       
   216 
       
   217 #define DEFAULT_MODE MODE_IMAGE
       
   218 #define DEFAULT_ZOOM 100
       
   219 #define DEFAULT_WIDTH 640
       
   220 #define DEFAULT_HEIGHT 480
       
   221 #define DEFAULT_CAPTURE_WIDTH 800
       
   222 #define DEFAULT_CAPTURE_HEIGHT 600
       
   223 #define DEFAULT_FPS_N 0         /* makes it use the default */
       
   224 #define DEFAULT_FPS_D 1
       
   225 #define CAMERABIN_DEFAULT_VF_CAPS "video/x-raw-yuv,format=(fourcc)I420"
       
   226 /* Using "bilinear" as default zoom method */
       
   227 #define CAMERABIN_DEFAULT_ZOOM_METHOD 1
       
   228 
       
   229 #define MIN_ZOOM 100
       
   230 #define MAX_ZOOM 1000
       
   231 #define ZOOM_1X MIN_ZOOM
       
   232 
       
   233 #define DEFAULT_V4L2CAMSRC_DRIVER_NAME "omap3cam"
       
   234 
       
   235 /* internal element names */
       
   236 
       
   237 #define USE_COLOR_CONVERTER 1
       
   238 
       
   239 /* FIXME: Make sure this can work with autovideosrc and use that. */
       
   240 #define DEFAULT_SRC_VID_SRC "v4l2src"
       
   241 
       
   242 #define DEFAULT_VIEW_SINK "autovideosink"
       
   243 
       
   244 /*
       
   245  * static helper functions declaration
       
   246  */
       
   247 
       
   248 static void camerabin_setup_src_elements (GstCameraBin * camera);
       
   249 
       
   250 static gboolean camerabin_create_src_elements (GstCameraBin * camera);
       
   251 
       
   252 static void camerabin_setup_view_elements (GstCameraBin * camera);
       
   253 
       
   254 static gboolean camerabin_create_view_elements (GstCameraBin * camera);
       
   255 
       
   256 static gboolean camerabin_create_elements (GstCameraBin * camera);
       
   257 
       
   258 static void camerabin_destroy_elements (GstCameraBin * camera);
       
   259 
       
   260 static void camerabin_dispose_elements (GstCameraBin * camera);
       
   261 
       
   262 static void gst_camerabin_change_mode (GstCameraBin * camera, gint mode);
       
   263 
       
   264 static void
       
   265 gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name);
       
   266 
       
   267 static void gst_camerabin_setup_zoom (GstCameraBin * camera);
       
   268 
       
   269 static GstCaps *gst_camerabin_get_allowed_input_caps (GstCameraBin * camera);
       
   270 
       
   271 static void gst_camerabin_rewrite_tags (GstCameraBin * camera);
       
   272 
       
   273 static void
       
   274 gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps);
       
   275 
       
   276 static void gst_camerabin_start_image_capture (GstCameraBin * camera);
       
   277 
       
   278 static void gst_camerabin_start_video_recording (GstCameraBin * camera);
       
   279 
       
   280 static gboolean
       
   281 gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer,
       
   282     gpointer u_data);
       
   283 static gboolean
       
   284 gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer,
       
   285     gpointer u_data);
       
   286 
       
   287 static void gst_camerabin_reset_to_view_finder (GstCameraBin * camera);
       
   288 
       
   289 static void gst_camerabin_do_stop (GstCameraBin * camera);
       
   290 
       
   291 static void
       
   292 gst_camerabin_set_allowed_framerate (GstCameraBin * camera,
       
   293     GstCaps * filter_caps);
       
   294 
       
   295 /*
       
   296  * GObject callback functions declaration
       
   297  */
       
   298 
       
   299 static void gst_camerabin_base_init (gpointer gclass);
       
   300 
       
   301 static void gst_camerabin_class_init (GstCameraBinClass * klass);
       
   302 
       
   303 static void
       
   304 gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass);
       
   305 
       
   306 static void gst_camerabin_dispose (GObject * object);
       
   307 
       
   308 static void gst_camerabin_finalize (GObject * object);
       
   309 
       
   310 static void gst_camerabin_set_property (GObject * object, guint prop_id,
       
   311     const GValue * value, GParamSpec * pspec);
       
   312 
       
   313 static void gst_camerabin_get_property (GObject * object, guint prop_id,
       
   314     GValue * value, GParamSpec * pspec);
       
   315 
       
   316 static const GValue *gst_camerabin_find_better_framerate (GstCameraBin * camera,
       
   317     GstStructure * st, const GValue * orig_framerate);
       
   318 /*
       
   319  * GstElement function declarations
       
   320  */
       
   321 
       
   322 static GstStateChangeReturn
       
   323 gst_camerabin_change_state (GstElement * element, GstStateChange transition);
       
   324 
       
   325 
       
   326 /*
       
   327  * GstBin function declarations
       
   328  */
       
   329 static void
       
   330 gst_camerabin_handle_message_func (GstBin * bin, GstMessage * message);
       
   331 
       
   332 
       
   333 /*
       
   334  * Action signal function declarations
       
   335  */
       
   336 
       
   337 static void gst_camerabin_user_start (GstCameraBin * camera);
       
   338 
       
   339 static void gst_camerabin_user_stop (GstCameraBin * camera);
       
   340 
       
   341 static void gst_camerabin_user_pause (GstCameraBin * camera);
       
   342 
       
   343 static void
       
   344 gst_camerabin_user_res_fps (GstCameraBin * camera, gint width, gint height,
       
   345     gint fps_n, gint fps_d);
       
   346 
       
   347 static void
       
   348 gst_camerabin_user_image_res (GstCameraBin * camera, gint width, gint height);
       
   349 
       
   350 
       
   351 /*
       
   352  * GST BOILERPLATE and GObject types
       
   353  */
       
   354 
       
   355 static GType
       
   356 gst_camerabin_mode_get_type (void)
       
   357 {
       
   358   static GType gtype = 0;
       
   359 
       
   360   if (gtype == 0) {
       
   361     static const GEnumValue values[] = {
       
   362       {MODE_IMAGE, "Still image capture (default)", "mode-image"},
       
   363       {MODE_VIDEO, "Video recording", "mode-video"},
       
   364       {0, NULL, NULL}
       
   365     };
       
   366 
       
   367     gtype = g_enum_register_static ("GstCameraBinMode", values);
       
   368   }
       
   369   return gtype;
       
   370 }
       
   371 
       
   372 static gboolean
       
   373 gst_camerabin_iface_supported (GstImplementsInterface * iface, GType iface_type)
       
   374 {
       
   375   GstCameraBin *camera = GST_CAMERABIN (iface);
       
   376 
       
   377   if (iface_type == GST_TYPE_X_OVERLAY) {
       
   378     if (camera->view_sink) {
       
   379       return GST_IS_X_OVERLAY (camera->view_sink);
       
   380     }
       
   381   } else if (iface_type == GST_TYPE_COLOR_BALANCE) {
       
   382     if (camera->src_vid_src) {
       
   383       return GST_IS_COLOR_BALANCE (camera->src_vid_src);
       
   384     }
       
   385   } else if (iface_type == GST_TYPE_TAG_SETTER) {
       
   386     /* Note: Tag setter elements aren't
       
   387        present when image and video bin in NULL */
       
   388     GstElement *setter;
       
   389     setter = gst_bin_get_by_interface (GST_BIN (camera), iface_type);
       
   390     if (setter) {
       
   391       gst_object_unref (setter);
       
   392       return TRUE;
       
   393     } else {
       
   394       return FALSE;
       
   395     }
       
   396   } else if (iface_type == GST_TYPE_PHOTOGRAPHY) {
       
   397     if (camera->src_vid_src) {
       
   398       return GST_IS_PHOTOGRAPHY (camera->src_vid_src);
       
   399     }
       
   400   }
       
   401 
       
   402   return FALSE;
       
   403 }
       
   404 
       
   405 static void
       
   406 gst_camerabin_interface_init (GstImplementsInterfaceClass * klass)
       
   407 {
       
   408   /*
       
   409    * default virtual functions
       
   410    */
       
   411   klass->supported = gst_camerabin_iface_supported;
       
   412 }
       
   413 
       
   414 static void
       
   415 camerabin_init_interfaces (GType type)
       
   416 {
       
   417 
       
   418   static const GInterfaceInfo camerabin_info = {
       
   419     (GInterfaceInitFunc) gst_camerabin_interface_init,
       
   420     NULL,
       
   421     NULL,
       
   422   };
       
   423 
       
   424   static const GInterfaceInfo camerabin_xoverlay_info = {
       
   425     (GInterfaceInitFunc) gst_camerabin_xoverlay_init,
       
   426     NULL,
       
   427     NULL,
       
   428   };
       
   429 
       
   430   static const GInterfaceInfo camerabin_color_balance_info = {
       
   431     (GInterfaceInitFunc) gst_camerabin_color_balance_init,
       
   432     NULL,
       
   433     NULL,
       
   434   };
       
   435 
       
   436   static const GInterfaceInfo camerabin_tagsetter_info = {
       
   437     NULL,
       
   438     NULL,
       
   439     NULL,
       
   440   };
       
   441   static const GInterfaceInfo camerabin_photography_info = {
       
   442     (GInterfaceInitFunc) gst_camerabin_photography_init,
       
   443     NULL,
       
   444     NULL,
       
   445   };
       
   446 
       
   447   g_type_add_interface_static (type,
       
   448       GST_TYPE_IMPLEMENTS_INTERFACE, &camerabin_info);
       
   449 
       
   450   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY,
       
   451       &camerabin_xoverlay_info);
       
   452 
       
   453   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
       
   454       &camerabin_color_balance_info);
       
   455 
       
   456   g_type_add_interface_static (type, GST_TYPE_TAG_SETTER,
       
   457       &camerabin_tagsetter_info);
       
   458 
       
   459   g_type_add_interface_static (type, GST_TYPE_PHOTOGRAPHY,
       
   460       &camerabin_photography_info);
       
   461 }
       
   462 
       
   463 GST_BOILERPLATE_FULL (GstCameraBin, gst_camerabin, GstPipeline,
       
   464     GST_TYPE_PIPELINE, camerabin_init_interfaces);
       
   465 
       
   466 /*
       
   467  * static helper functions implementation
       
   468  */
       
   469 
       
   470 /*
       
   471  * camerabin_setup_src_elements:
       
   472  * @camera: camerabin object
       
   473  *
       
   474  * This function updates camerabin capsfilters according
       
   475  * to fps, resolution and zoom that have been configured
       
   476  * to camerabin.
       
   477  */
       
   478 static void
       
   479 camerabin_setup_src_elements (GstCameraBin * camera)
       
   480 {
       
   481   GstStructure *st;
       
   482   GstCaps *new_caps;
       
   483   gboolean detect_framerate = FALSE;
       
   484 
       
   485   if (!camera->view_finder_caps) {
       
   486     st = gst_structure_from_string (CAMERABIN_DEFAULT_VF_CAPS, NULL);
       
   487   } else {
       
   488     st = gst_structure_copy (gst_caps_get_structure (camera->view_finder_caps,
       
   489             0));
       
   490   }
       
   491 
       
   492   if (camera->width > 0 && camera->height > 0) {
       
   493     gst_structure_set (st,
       
   494         "width", G_TYPE_INT, camera->width,
       
   495         "height", G_TYPE_INT, camera->height, NULL);
       
   496   }
       
   497 
       
   498   if (camera->fps_n > 0 && camera->fps_d > 0) {
       
   499     if (camera->night_mode) {
       
   500       GST_WARNING_OBJECT (camera,
       
   501           "night mode, lowest allowed fps will be forced");
       
   502       camera->pre_night_fps_n = camera->fps_n;
       
   503       camera->pre_night_fps_d = camera->fps_d;
       
   504       detect_framerate = TRUE;
       
   505     } else {
       
   506       gst_structure_set (st,
       
   507           "framerate", GST_TYPE_FRACTION, camera->fps_n, camera->fps_d, NULL);
       
   508       new_caps = gst_caps_new_full (st, NULL);
       
   509     }
       
   510   } else {
       
   511     GST_DEBUG_OBJECT (camera, "no framerate specified");
       
   512     detect_framerate = TRUE;
       
   513   }
       
   514 
       
   515   if (detect_framerate) {
       
   516     GST_DEBUG_OBJECT (camera, "detecting allowed framerate");
       
   517     /* Remove old framerate if any */
       
   518     if (gst_structure_has_field (st, "framerate")) {
       
   519       gst_structure_remove_field (st, "framerate");
       
   520     }
       
   521     new_caps = gst_caps_new_full (st, NULL);
       
   522 
       
   523     /* Set allowed framerate for the resolution */
       
   524     gst_camerabin_set_allowed_framerate (camera, new_caps);
       
   525   }
       
   526 
       
   527   /* Set default zoom method */
       
   528   g_object_set (camera->src_zoom_scale, "method",
       
   529       CAMERABIN_DEFAULT_ZOOM_METHOD, NULL);
       
   530 
       
   531   gst_caps_replace (&camera->view_finder_caps, new_caps);
       
   532 
       
   533   /* Set caps for view finder mode */
       
   534   gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps);
       
   535 }
       
   536 
       
   537 /*
       
   538  * camerabin_create_src_elements:
       
   539  * @camera: camerabin object
       
   540  *
       
   541  * This function creates and links upstream side elements for camerabin.
       
   542  * videosrc ! cspconv ! capsfilter ! crop ! scale ! capsfilter ! out-sel !
       
   543  *
       
   544  * Returns: TRUE, if elements were successfully created, FALSE otherwise
       
   545  */
       
   546 static gboolean
       
   547 camerabin_create_src_elements (GstCameraBin * camera)
       
   548 {
       
   549   gboolean ret = FALSE;
       
   550   GstBin *cbin = GST_BIN (camera);
       
   551   gchar *driver_name = NULL;
       
   552 
       
   553   if (camera->user_vid_src) {
       
   554     camera->src_vid_src = camera->user_vid_src;
       
   555 
       
   556     if (!gst_camerabin_add_element (cbin, camera->src_vid_src)) {
       
   557       camera->src_vid_src = NULL;
       
   558       goto done;
       
   559     }
       
   560   } else if (!(camera->src_vid_src =
       
   561           gst_camerabin_create_and_add_element (cbin, DEFAULT_SRC_VID_SRC)))
       
   562     goto done;
       
   563 #ifdef USE_COLOR_CONVERTER
       
   564   if (!gst_camerabin_create_and_add_element (cbin, "ffmpegcolorspace"))
       
   565     goto done;
       
   566 #endif
       
   567   if (!(camera->src_filter =
       
   568           gst_camerabin_create_and_add_element (cbin, "capsfilter")))
       
   569     goto done;
       
   570   if (!(camera->src_zoom_crop =
       
   571           gst_camerabin_create_and_add_element (cbin, "videocrop")))
       
   572     goto done;
       
   573   if (!(camera->src_zoom_scale =
       
   574           gst_camerabin_create_and_add_element (cbin, "videoscale")))
       
   575     goto done;
       
   576   if (!(camera->src_zoom_filter =
       
   577           gst_camerabin_create_and_add_element (cbin, "capsfilter")))
       
   578     goto done;
       
   579   if (!(camera->src_out_sel =
       
   580           gst_camerabin_create_and_add_element (cbin, "output-selector")))
       
   581     goto done;
       
   582 
       
   583   camera->srcpad_zoom_filter =
       
   584       gst_element_get_static_pad (camera->src_zoom_filter, "src");
       
   585 
       
   586   /* Set default "driver-name" for v4l2camsrc if not set */
       
   587   if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
       
   588           "driver-name")) {
       
   589     g_object_get (G_OBJECT (camera->src_vid_src), "driver-name",
       
   590         &driver_name, NULL);
       
   591     if (!driver_name) {
       
   592       g_object_set (G_OBJECT (camera->src_vid_src), "driver-name",
       
   593           DEFAULT_V4L2CAMSRC_DRIVER_NAME, NULL);
       
   594     }
       
   595   }
       
   596 
       
   597   ret = TRUE;
       
   598 done:
       
   599   return ret;
       
   600 }
       
   601 
       
   602 /*
       
   603  * camerabin_setup_view_elements:
       
   604  * @camera: camerabin object
       
   605  *
       
   606  * This function configures properties for view finder sink element.
       
   607  */
       
   608 static void
       
   609 camerabin_setup_view_elements (GstCameraBin * camera)
       
   610 {
       
   611   GST_DEBUG_OBJECT (camera, "setting view finder properties");
       
   612   g_object_set (G_OBJECT (camera->view_in_sel), "select-all", TRUE, NULL);
       
   613   /* Set properties for view finder sink */
       
   614   /* Find the actual sink if using bin like autovideosink */
       
   615   if (GST_IS_BIN (camera->view_sink)) {
       
   616     GList *child = NULL, *children = GST_BIN_CHILDREN (camera->view_sink);
       
   617     for (child = children; child != NULL; child = g_list_next (children)) {
       
   618       GObject *ch = G_OBJECT (child->data);
       
   619       if (g_object_class_find_property (G_OBJECT_GET_CLASS (ch), "sync")) {
       
   620         g_object_set (G_OBJECT (ch), "sync", FALSE, "qos", FALSE, "async",
       
   621             FALSE, NULL);
       
   622       }
       
   623     }
       
   624   } else {
       
   625     g_object_set (G_OBJECT (camera->view_sink), "sync", FALSE, "qos", FALSE,
       
   626         "async", FALSE, NULL);
       
   627   }
       
   628 }
       
   629 
       
   630 /*
       
   631  * camerabin_create_view_elements:
       
   632  * @camera: camerabin object
       
   633  *
       
   634  * This function creates and links downstream side elements for camerabin.
       
   635  * ! scale ! cspconv ! view finder sink
       
   636  *
       
   637  * Returns: TRUE, if elements were successfully created, FALSE otherwise
       
   638  */
       
   639 static gboolean
       
   640 camerabin_create_view_elements (GstCameraBin * camera)
       
   641 {
       
   642   const GList *pads;
       
   643 
       
   644   if (!(camera->view_in_sel =
       
   645           gst_camerabin_create_and_add_element (GST_BIN (camera),
       
   646               "input-selector"))) {
       
   647     goto error;
       
   648   }
       
   649 
       
   650   /* Look for recently added input selector sink pad, we need to release it later */
       
   651   pads = GST_ELEMENT_PADS (camera->view_in_sel);
       
   652   while (pads != NULL
       
   653       && (GST_PAD_DIRECTION (GST_PAD (pads->data)) != GST_PAD_SINK)) {
       
   654     pads = g_list_next (pads);
       
   655   }
       
   656   camera->pad_view_img = GST_PAD (pads->data);
       
   657 
       
   658   if (!(camera->view_scale =
       
   659           gst_camerabin_create_and_add_element (GST_BIN (camera),
       
   660               "videoscale"))) {
       
   661     goto error;
       
   662   }
       
   663 #ifdef USE_COLOR_CONVERTER
       
   664   if (!gst_camerabin_create_and_add_element (GST_BIN (camera),
       
   665           "ffmpegcolorspace")) {
       
   666     goto error;
       
   667   }
       
   668 #endif
       
   669   if (camera->user_vf_sink) {
       
   670     camera->view_sink = camera->user_vf_sink;
       
   671     if (!gst_camerabin_add_element (GST_BIN (camera), camera->view_sink)) {
       
   672       goto error;
       
   673     }
       
   674   } else if (!(camera->view_sink =
       
   675           gst_camerabin_create_and_add_element (GST_BIN (camera),
       
   676               DEFAULT_VIEW_SINK))) {
       
   677     goto error;
       
   678   }
       
   679 
       
   680   return TRUE;
       
   681 error:
       
   682   return FALSE;
       
   683 }
       
   684 
       
   685 /*
       
   686  * camerabin_create_elements:
       
   687  * @camera: camerabin object
       
   688  *
       
   689  * This function creates and links all elements for camerabin,
       
   690  *
       
   691  * Returns: TRUE, if elements were successfully created, FALSE otherwise
       
   692  */
       
   693 static gboolean
       
   694 camerabin_create_elements (GstCameraBin * camera)
       
   695 {
       
   696   gboolean ret = FALSE;
       
   697   GstPadLinkReturn link_ret = GST_PAD_LINK_REFUSED;
       
   698   GstPad *unconnected_pad;
       
   699 
       
   700   GST_LOG_OBJECT (camera, "creating elems");
       
   701 
       
   702   /* Create "src" elements */
       
   703   if (!camerabin_create_src_elements (camera)) {
       
   704     goto done;
       
   705   }
       
   706 
       
   707   /* Add image bin */
       
   708   camera->pad_src_img =
       
   709       gst_element_get_request_pad (camera->src_out_sel, "src%d");
       
   710   if (!gst_camerabin_add_element (GST_BIN (camera), camera->imgbin)) {
       
   711     goto done;
       
   712   }
       
   713   gst_pad_add_buffer_probe (camera->pad_src_img,
       
   714       G_CALLBACK (gst_camerabin_have_img_buffer), camera);
       
   715 
       
   716   /* Create view finder elements, this also links it to image bin */
       
   717   if (!camerabin_create_view_elements (camera)) {
       
   718     GST_WARNING_OBJECT (camera, "creating view failed");
       
   719     goto done;
       
   720   }
       
   721 
       
   722   /* Link output selector ! view_finder */
       
   723   camera->pad_src_view =
       
   724       gst_element_get_request_pad (camera->src_out_sel, "src%d");
       
   725   camera->pad_view_src =
       
   726       gst_element_get_request_pad (camera->view_in_sel, "sink%d");
       
   727   link_ret = gst_pad_link (camera->pad_src_view, camera->pad_view_src);
       
   728   if (GST_PAD_LINK_FAILED (link_ret)) {
       
   729     GST_ELEMENT_ERROR (camera, CORE, NEGOTIATION,
       
   730         ("linking view finder failed"), (NULL));
       
   731     goto done;
       
   732   }
       
   733 
       
   734   /* Set view finder active as default */
       
   735   g_object_set (G_OBJECT (camera->src_out_sel), "active-pad",
       
   736       camera->pad_src_view, NULL);
       
   737 
       
   738   /* Add video bin */
       
   739   camera->pad_src_vid =
       
   740       gst_element_get_request_pad (camera->src_out_sel, "src%d");
       
   741   if (!gst_camerabin_add_element (GST_BIN (camera), camera->vidbin)) {
       
   742     goto done;
       
   743   }
       
   744   gst_pad_add_buffer_probe (camera->pad_src_vid,
       
   745       G_CALLBACK (gst_camerabin_have_vid_buffer), camera);
       
   746 
       
   747   /* Link video bin ! view finder */
       
   748  // unconnected_pad = gst_bin_find_unlinked_pad (GST_BIN (camera), GST_PAD_SRC);
       
   749    unconnected_pad = gst_bin_find_unconnected_pad (GST_BIN (camera), GST_PAD_SRC);
       
   750   camera->pad_view_vid =
       
   751       gst_element_get_request_pad (camera->view_in_sel, "sink%d");
       
   752   link_ret = gst_pad_link (unconnected_pad, camera->pad_view_vid);
       
   753   gst_object_unref (unconnected_pad);
       
   754   if (GST_PAD_LINK_FAILED (link_ret)) {
       
   755     GST_ELEMENT_ERROR (camera, CORE, NEGOTIATION, (NULL),
       
   756         ("linking video bin and view finder failed"));
       
   757     goto done;
       
   758   }
       
   759 
       
   760   ret = TRUE;
       
   761 
       
   762 done:
       
   763 
       
   764   if (FALSE == ret)
       
   765     camerabin_destroy_elements (camera);
       
   766 
       
   767   return ret;
       
   768 }
       
   769 
       
   770 /*
       
   771  * camerabin_destroy_elements:
       
   772  * @camera: camerabin object
       
   773  *
       
   774  * This function removes all elements from camerabin.
       
   775  */
       
   776 static void
       
   777 camerabin_destroy_elements (GstCameraBin * camera)
       
   778 {
       
   779   GST_DEBUG_OBJECT (camera, "destroying elements");
       
   780 
       
   781   /* Release request pads */
       
   782   if (camera->pad_view_vid) {
       
   783     gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_vid);
       
   784     camera->pad_view_vid = NULL;
       
   785   }
       
   786   if (camera->pad_src_vid) {
       
   787     gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_vid);
       
   788     camera->pad_src_vid = NULL;
       
   789   }
       
   790   if (camera->pad_view_img) {
       
   791     gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_img);
       
   792     camera->pad_view_img = NULL;
       
   793   }
       
   794   if (camera->pad_src_img) {
       
   795     gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_img);
       
   796     camera->pad_src_img = NULL;
       
   797   }
       
   798   if (camera->pad_view_src) {
       
   799     gst_element_release_request_pad (camera->view_in_sel, camera->pad_view_src);
       
   800     camera->pad_view_src = NULL;
       
   801   }
       
   802   if (camera->pad_src_view) {
       
   803     gst_element_release_request_pad (camera->src_out_sel, camera->pad_src_view);
       
   804     camera->pad_src_view = NULL;
       
   805   }
       
   806 
       
   807   camera->view_sink = NULL;
       
   808   camera->view_scale = NULL;
       
   809   camera->view_in_sel = NULL;
       
   810 
       
   811   camera->src_out_sel = NULL;
       
   812   camera->src_filter = NULL;
       
   813   camera->src_zoom_crop = NULL;
       
   814   camera->src_zoom_scale = NULL;
       
   815   camera->src_zoom_filter = NULL;
       
   816   camera->src_vid_src = NULL;
       
   817 
       
   818   camera->active_bin = NULL;
       
   819 
       
   820   /* Remove elements */
       
   821   gst_camerabin_remove_elements_from_bin (GST_BIN (camera));
       
   822 }
       
   823 
       
   824 /*
       
   825  * camerabin_dispose_elements:
       
   826  * @camera: camerabin object
       
   827  *
       
   828  * This function releases all allocated camerabin resources.
       
   829  */
       
   830 static void
       
   831 camerabin_dispose_elements (GstCameraBin * camera)
       
   832 {
       
   833   if (camera->capture_mutex) {
       
   834     g_mutex_free (camera->capture_mutex);
       
   835     camera->capture_mutex = NULL;
       
   836   }
       
   837   if (camera->cond) {
       
   838     g_cond_free (camera->cond);
       
   839     camera->cond = NULL;
       
   840   }
       
   841   if (camera->filename) {
       
   842     g_string_free (camera->filename, TRUE);
       
   843     camera->filename = NULL;
       
   844   }
       
   845   /* Unref user set elements */
       
   846   if (camera->user_vf_sink) {
       
   847     gst_object_unref (camera->user_vf_sink);
       
   848     camera->user_vf_sink = NULL;
       
   849   }
       
   850   if (camera->user_vid_src) {
       
   851     gst_object_unref (camera->user_vid_src);
       
   852     camera->user_vid_src = NULL;
       
   853   }
       
   854 
       
   855   if (camera->image_capture_caps) {
       
   856     gst_caps_unref (camera->image_capture_caps);
       
   857     camera->image_capture_caps = NULL;
       
   858   }
       
   859 
       
   860   if (camera->view_finder_caps) {
       
   861     gst_caps_unref (camera->view_finder_caps);
       
   862     camera->view_finder_caps = NULL;
       
   863   }
       
   864 
       
   865   if (camera->allowed_caps) {
       
   866     gst_caps_unref (camera->allowed_caps);
       
   867     camera->allowed_caps = NULL;
       
   868   }
       
   869 }
       
   870 
       
   871 /*
       
   872  * gst_camerabin_image_capture_continue:
       
   873  * @camera: camerabin object
       
   874  * @filename: new filename set by user
       
   875  * @cont: TRUE to continue image capture, FALSE otherwise
       
   876  *
       
   877  * Check if user wants to continue image capturing by using g_signal.
       
   878  */
       
   879 static void
       
   880 gst_camerabin_image_capture_continue (GstCameraBin * camera, GString * filename,
       
   881     gboolean * cont)
       
   882 {
       
   883   GST_DEBUG_OBJECT (camera, "emitting img_done signal, filename: %s",
       
   884       filename->str);
       
   885   g_signal_emit (G_OBJECT (camera), camerabin_signals[IMG_DONE_SIGNAL], 0,
       
   886       filename, cont);
       
   887 
       
   888   GST_DEBUG_OBJECT (camera, "emitted img_done, new filename:%s, continue:%d",
       
   889       filename->str, *cont);
       
   890 }
       
   891 
       
   892 /*
       
   893  * gst_camerabin_change_mode:
       
   894  * @camera: camerabin object
       
   895  * @mode: image or video mode
       
   896  *
       
   897  * Change camerabin mode between image and video capture.
       
   898  * Changing mode will stop ongoing capture.
       
   899  */
       
   900 static void
       
   901 gst_camerabin_change_mode (GstCameraBin * camera, gint mode)
       
   902 {
       
   903   if (camera->mode != mode || !camera->active_bin) {
       
   904     GST_DEBUG_OBJECT (camera, "setting mode: %d", mode);
       
   905     /* Interrupt ongoing capture */
       
   906     gst_camerabin_do_stop (camera);
       
   907     camera->mode = mode;
       
   908     if (camera->active_bin) {
       
   909       gst_element_set_state (camera->active_bin, GST_STATE_NULL);
       
   910     }
       
   911     if (camera->mode == MODE_IMAGE) {
       
   912       camera->active_bin = camera->imgbin;
       
   913     } else if (camera->mode == MODE_VIDEO) {
       
   914       camera->active_bin = camera->vidbin;
       
   915     }
       
   916     gst_camerabin_reset_to_view_finder (camera);
       
   917   }
       
   918 }
       
   919 
       
   920 /*
       
   921  * gst_camerabin_change_filename:
       
   922  * @camera: camerabin object
       
   923  * @name: new filename for capture
       
   924  *
       
   925  * Change filename for image or video capture.
       
   926  * Changing filename will stop ongoing capture.
       
   927  */
       
   928 static void
       
   929 gst_camerabin_change_filename (GstCameraBin * camera, const gchar * name)
       
   930 {
       
   931   if (0 != strcmp (camera->filename->str, name)) {
       
   932     GST_DEBUG_OBJECT (camera, "changing filename from %s to %s",
       
   933         camera->filename->str, name);
       
   934     /* Interrupt ongoing capture */
       
   935     gst_camerabin_do_stop (camera);
       
   936     gst_camerabin_reset_to_view_finder (camera);
       
   937 
       
   938     if (camera->active_bin) {
       
   939       g_object_set (G_OBJECT (camera->active_bin), "filename", name, NULL);
       
   940     }
       
   941 
       
   942     g_string_assign (camera->filename, name);
       
   943   }
       
   944 }
       
   945 
       
   946 /*
       
   947  * gst_camerabin_setup_zoom:
       
   948  * @camera: camerabin object
       
   949  *
       
   950  * Apply zoom configured to camerabin to capture.
       
   951  */
       
   952 static void
       
   953 gst_camerabin_setup_zoom (GstCameraBin * camera)
       
   954 {
       
   955   gint zoom;
       
   956   gboolean done = FALSE;
       
   957 
       
   958   g_return_if_fail (camera != NULL);
       
   959   g_return_if_fail (camera->src_zoom_crop != NULL);
       
   960 
       
   961   zoom = g_atomic_int_get (&camera->zoom);
       
   962 
       
   963   g_return_if_fail (zoom);
       
   964 
       
   965   if (GST_IS_ELEMENT (camera->src_vid_src) &&
       
   966       gst_element_implements_interface (camera->src_vid_src,
       
   967           GST_TYPE_PHOTOGRAPHY)) {
       
   968     /* Try setting (hardware) zoom using photography interface */
       
   969     GstPhotography *photo;
       
   970     GstPhotoCaps pcaps;
       
   971 
       
   972     photo = GST_PHOTOGRAPHY (camera->src_vid_src);
       
   973     pcaps = gst_photography_get_capabilities (photo);
       
   974 
       
   975     if (pcaps & GST_PHOTOGRAPHY_CAPS_ZOOM) {
       
   976       done = gst_photography_set_zoom (photo, (gfloat) zoom / 100.0);
       
   977     }
       
   978   }
       
   979 
       
   980   if (!done) {
       
   981     /* Update capsfilters to apply the (software) zoom */
       
   982     gint w2_crop = 0;
       
   983     gint h2_crop = 0;
       
   984     GstPad *pad_zoom_sink = NULL;
       
   985 
       
   986     GST_INFO_OBJECT (camera, "zoom: %d, orig size: %dx%d", zoom,
       
   987         camera->width, camera->height);
       
   988 
       
   989     if (zoom != ZOOM_1X) {
       
   990       w2_crop = (camera->width - (camera->width * ZOOM_1X / zoom)) / 2;
       
   991       h2_crop = (camera->height - (camera->height * ZOOM_1X / zoom)) / 2;
       
   992     }
       
   993 
       
   994     pad_zoom_sink = gst_element_get_static_pad (camera->src_zoom_crop, "sink");
       
   995 
       
   996     GST_INFO_OBJECT (camera,
       
   997         "sw cropping: left:%d, right:%d, top:%d, bottom:%d", w2_crop, w2_crop,
       
   998         h2_crop, h2_crop);
       
   999 
       
  1000     GST_PAD_STREAM_LOCK (pad_zoom_sink);
       
  1001     g_object_set (camera->src_zoom_crop, "left", w2_crop, "right", w2_crop,
       
  1002         "top", h2_crop, "bottom", h2_crop, NULL);
       
  1003 
       
  1004     GST_PAD_STREAM_UNLOCK (pad_zoom_sink);
       
  1005     gst_object_unref (pad_zoom_sink);
       
  1006   }
       
  1007   GST_LOG_OBJECT (camera, "zoom set");
       
  1008 }
       
  1009 
       
  1010 /*
       
  1011  * gst_camerabin_get_allowed_input_caps:
       
  1012  * @camera: camerabin object
       
  1013  *
       
  1014  * Retrieve caps from videosrc describing formats it supports
       
  1015  *
       
  1016  * Returns: caps object from videosrc
       
  1017  */
       
  1018 static GstCaps *
       
  1019 gst_camerabin_get_allowed_input_caps (GstCameraBin * camera)
       
  1020 {
       
  1021   GstCaps *caps = NULL;
       
  1022   GstPad *pad = NULL, *peer_pad = NULL;
       
  1023   GstState state;
       
  1024   gboolean temp_videosrc_pause = FALSE;
       
  1025   GstElement *videosrc;
       
  1026 
       
  1027   g_return_val_if_fail (camera != NULL, NULL);
       
  1028 
       
  1029   videosrc = camera->src_vid_src ? camera->src_vid_src : camera->user_vid_src;
       
  1030 
       
  1031   if (!videosrc) {
       
  1032     GST_WARNING_OBJECT (camera, "no videosrc, can't get allowed caps");
       
  1033     goto failed;
       
  1034   }
       
  1035 
       
  1036   if (camera->allowed_caps) {
       
  1037     GST_DEBUG_OBJECT (camera, "returning cached caps");
       
  1038     goto done;
       
  1039   }
       
  1040 
       
  1041   pad = gst_element_get_static_pad (videosrc, "src");
       
  1042 
       
  1043   if (!pad) {
       
  1044     GST_WARNING_OBJECT (camera, "no srcpad in videosrc");
       
  1045     goto failed;
       
  1046   }
       
  1047 
       
  1048   state = GST_STATE (videosrc);
       
  1049 
       
  1050   /* Make this function work also in READY and NULL state */
       
  1051   if (state == GST_STATE_READY || state == GST_STATE_NULL) {
       
  1052     GST_DEBUG_OBJECT (camera, "setting videosrc to paused temporarily");
       
  1053     temp_videosrc_pause = TRUE;
       
  1054     peer_pad = gst_pad_get_peer (pad);
       
  1055     if (peer_pad) {
       
  1056       gst_pad_unlink (pad, peer_pad);
       
  1057     }
       
  1058     /* Set videosrc to PAUSED to open video device */
       
  1059     gst_element_set_locked_state (videosrc, TRUE);
       
  1060     gst_element_set_state (videosrc, GST_STATE_PAUSED);
       
  1061   }
       
  1062 
       
  1063   camera->allowed_caps = gst_pad_get_caps (pad);
       
  1064 
       
  1065   /* Restore state and re-link if necessary */
       
  1066   if (temp_videosrc_pause) {
       
  1067     GST_DEBUG_OBJECT (camera, "restoring videosrc state %d", state);
       
  1068     /* Reset videosrc to NULL state, some drivers seem to need this */
       
  1069     gst_element_set_state (videosrc, GST_STATE_NULL);
       
  1070     gst_element_set_state (videosrc, state);
       
  1071     if (peer_pad) {
       
  1072       gst_pad_link (pad, peer_pad);
       
  1073       gst_object_unref (peer_pad);
       
  1074     }
       
  1075     gst_element_set_locked_state (videosrc, FALSE);
       
  1076   }
       
  1077 
       
  1078   gst_object_unref (pad);
       
  1079 
       
  1080 done:
       
  1081   if (camera->allowed_caps) {
       
  1082     caps = gst_caps_copy (camera->allowed_caps);
       
  1083   }
       
  1084 failed:
       
  1085   GST_INFO_OBJECT (camera, "allowed caps:%" GST_PTR_FORMAT, caps);
       
  1086   return caps;
       
  1087 }
       
  1088 
       
  1089 /*
       
  1090  * gst_camerabin_rewrite_tags_to_bin:
       
  1091  * @bin: bin holding tag setter elements
       
  1092  * @list: tag list to be written
       
  1093  *
       
  1094  * This function looks for certain tag setters from given bin
       
  1095  * and REPLACES ALL setter tags with given tag list
       
  1096  *
       
  1097  */
       
  1098 static void
       
  1099 gst_camerabin_rewrite_tags_to_bin (GstBin * bin, const GstTagList * list)
       
  1100 {
       
  1101   GstElement *setter;
       
  1102   GstElementFactory *setter_factory;
       
  1103   const gchar *klass;
       
  1104   GstIterator *iter;
       
  1105   GstIteratorResult res = GST_ITERATOR_OK;
       
  1106   gpointer data;
       
  1107 
       
  1108   iter = gst_bin_iterate_all_by_interface (bin, GST_TYPE_TAG_SETTER);
       
  1109 
       
  1110   while (res == GST_ITERATOR_OK || res == GST_ITERATOR_RESYNC) {
       
  1111     res = gst_iterator_next (iter, &data);
       
  1112     switch (res) {
       
  1113       case GST_ITERATOR_DONE:
       
  1114         break;
       
  1115       case GST_ITERATOR_RESYNC:
       
  1116         gst_iterator_resync (iter);
       
  1117         break;
       
  1118       case GST_ITERATOR_ERROR:
       
  1119         GST_WARNING ("error iterating tag setters");
       
  1120         break;
       
  1121       case GST_ITERATOR_OK:
       
  1122         setter = GST_ELEMENT (data);
       
  1123         GST_LOG ("iterating tag setters: %" GST_PTR_FORMAT, setter);
       
  1124         setter_factory = gst_element_get_factory (setter);
       
  1125         klass = gst_element_factory_get_klass (setter_factory);
       
  1126         /* FIXME: check if tags should be written to all tag setters,
       
  1127            set tags only to Muxer elements for now */
       
  1128         if (g_strrstr (klass, "Muxer")) {
       
  1129           GST_DEBUG ("replacement tags %" GST_PTR_FORMAT, list);
       
  1130           gst_tag_setter_merge_tags (GST_TAG_SETTER (setter), list,
       
  1131               GST_TAG_MERGE_REPLACE_ALL);
       
  1132         }
       
  1133         gst_object_unref (setter);
       
  1134         break;
       
  1135       default:
       
  1136         break;
       
  1137     }
       
  1138   }
       
  1139 
       
  1140   gst_iterator_free (iter);
       
  1141 }
       
  1142 
       
  1143 /*
       
  1144  * gst_camerabin_get_internal_tags:
       
  1145  * @camera: the camera bin element
       
  1146  *
       
  1147  * Returns tag list containing metadata from camerabin
       
  1148  * and it's elements
       
  1149  */
       
  1150 static GstTagList *
       
  1151 gst_camerabin_get_internal_tags (GstCameraBin * camera)
       
  1152 {
       
  1153   GstTagList *list = gst_tag_list_new ();
       
  1154   GstColorBalance *balance = NULL;
       
  1155   const GList *controls = NULL, *item;
       
  1156   GstColorBalanceChannel *channel;
       
  1157   gint min_value, max_value, mid_value, cur_value;
       
  1158 
       
  1159 
       
  1160   if (camera->active_bin == camera->vidbin) {
       
  1161     /* FIXME: check if internal video tag setting is needed */
       
  1162     goto done;
       
  1163   }
       
  1164 
       
  1165   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1166       "image-width", camera->width, "image-height", camera->height, NULL);
       
  1167 
       
  1168   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1169       "capture-digital-zoom", camera->zoom, 100, NULL);
       
  1170 
       
  1171   if (gst_element_implements_interface (GST_ELEMENT (camera),
       
  1172           GST_TYPE_COLOR_BALANCE)) {
       
  1173     balance = GST_COLOR_BALANCE (camera);
       
  1174   }
       
  1175 
       
  1176   if (balance) {
       
  1177     controls = gst_color_balance_list_channels (balance);
       
  1178   }
       
  1179   for (item = controls; item; item = g_list_next (item)) {
       
  1180     channel = item->data;
       
  1181     min_value = channel->min_value;
       
  1182     max_value = channel->max_value;
       
  1183     /* the default value would probably better */
       
  1184     mid_value = min_value + ((max_value - min_value) / 2);
       
  1185     cur_value = gst_color_balance_get_value (balance, channel);
       
  1186 
       
  1187     if (!strcasecmp (channel->label, "brightness")) {
       
  1188       /* The value of brightness. The unit is the APEX value (Additive System of Photographic Exposure).
       
  1189        * Ordinarily it is given in the range of -99.99 to 99.99. Note that
       
  1190        * if the numerator of the recorded value is 0xFFFFFFFF, Unknown shall be indicated.
       
  1191        *
       
  1192        * BrightnessValue (Bv) = log2 ( B/NK )
       
  1193        * Note that: B:cd/cm² (candela per square centimeter), N,K: constant
       
  1194        *
       
  1195        * http://johnlind.tripod.com/science/scienceexposure.html
       
  1196        *
       
  1197        */
       
  1198       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1199           "capture-brightness", cur_value, 1, NULL);
       
  1200     } else if (!strcasecmp (channel->label, "contrast")) {
       
  1201       /* 0 = Normal, 1 = Soft, 2 = Hard */
       
  1202 
       
  1203       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1204           "capture-contrast",
       
  1205           (cur_value == mid_value) ? 0 : ((cur_value < mid_value) ? 1 : 2),
       
  1206           NULL);
       
  1207     } else if (!strcasecmp (channel->label, "gain")) {
       
  1208       /* 0 = Normal, 1 = Low Up, 2 = High Up, 3 = Low Down, 4 = Hight Down */
       
  1209       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1210           "capture-gain",
       
  1211           (guint) (cur_value == mid_value) ? 0 : ((cur_value <
       
  1212                   mid_value) ? 1 : 3), NULL);
       
  1213     } else if (!strcasecmp (channel->label, "saturation")) {
       
  1214       /* 0 = Normal, 1 = Low, 2 = High */
       
  1215       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  1216           "capture-saturation",
       
  1217           (cur_value == mid_value) ? 0 : ((cur_value < mid_value) ? 1 : 2),
       
  1218           NULL);
       
  1219     }
       
  1220   }
       
  1221 
       
  1222 done:
       
  1223 
       
  1224   return list;
       
  1225 }
       
  1226 
       
  1227 /*
       
  1228  * gst_camerabin_rewrite_tags:
       
  1229  * @camera: the camera bin element
       
  1230  *
       
  1231  * Merges application set tags to camerabin internal tags,
       
  1232  * and writes them using image or video bin tag setters.
       
  1233  */
       
  1234 static void
       
  1235 gst_camerabin_rewrite_tags (GstCameraBin * camera)
       
  1236 {
       
  1237   const GstTagList *app_tag_list = NULL;
       
  1238   GstTagList *list = NULL;
       
  1239 
       
  1240   /* Get application set tags */
       
  1241   app_tag_list = gst_tag_setter_get_tag_list (GST_TAG_SETTER (camera));
       
  1242 
       
  1243   /* Get tags from camerabin and it's elements */
       
  1244   list = gst_camerabin_get_internal_tags (camera);
       
  1245 
       
  1246   if (app_tag_list) {
       
  1247     gst_tag_list_insert (list, app_tag_list, GST_TAG_MERGE_REPLACE);
       
  1248   }
       
  1249 
       
  1250   /* Write tags */
       
  1251   gst_camerabin_rewrite_tags_to_bin (GST_BIN (camera->active_bin), list);
       
  1252 
       
  1253   gst_tag_list_free (list);
       
  1254 }
       
  1255 
       
  1256 /*
       
  1257  * gst_camerabin_set_capsfilter_caps:
       
  1258  * @camera: camerabin object
       
  1259  * @new_caps: pointer to caps object to set
       
  1260  *
       
  1261  * Set given caps to camerabin capsfilters.
       
  1262  */
       
  1263 static void
       
  1264 gst_camerabin_set_capsfilter_caps (GstCameraBin * camera, GstCaps * new_caps)
       
  1265 {
       
  1266   GstStructure *st;
       
  1267 
       
  1268   GST_INFO_OBJECT (camera, "new_caps:%" GST_PTR_FORMAT, new_caps);
       
  1269 
       
  1270   st = gst_caps_get_structure (new_caps, 0);
       
  1271 
       
  1272   gst_structure_get_int (st, "width", &camera->width);
       
  1273   gst_structure_get_int (st, "height", &camera->height);
       
  1274 
       
  1275   if (gst_structure_has_field (st, "framerate")) {
       
  1276     gst_structure_get_fraction (st, "framerate", &camera->fps_n,
       
  1277         &camera->fps_d);
       
  1278   }
       
  1279 
       
  1280   /* Update zoom */
       
  1281   gst_camerabin_setup_zoom (camera);
       
  1282 
       
  1283   /* Update capsfilters */
       
  1284   g_object_set (G_OBJECT (camera->src_filter), "caps", new_caps, NULL);
       
  1285   g_object_set (G_OBJECT (camera->src_zoom_filter), "caps", new_caps, NULL);
       
  1286 }
       
  1287 
       
  1288 /*
       
  1289  * img_capture_prepared:
       
  1290  * @data: camerabin object
       
  1291  *
       
  1292  * Callback which is called after image capture has been prepared.
       
  1293  */
       
  1294 static void
       
  1295 img_capture_prepared (gpointer data)
       
  1296 {
       
  1297   GstCameraBin *camera = GST_CAMERABIN (data);
       
  1298 
       
  1299   GST_INFO_OBJECT (camera, "image capture prepared");
       
  1300 
       
  1301   if (camera->image_capture_caps) {
       
  1302     /* Set capsfilters to match arriving image data */
       
  1303     gst_camerabin_set_capsfilter_caps (camera, camera->image_capture_caps);
       
  1304   }
       
  1305 
       
  1306   g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
       
  1307       "active-pad", camera->pad_src_img, NULL);
       
  1308   gst_camerabin_rewrite_tags (camera);
       
  1309   gst_element_set_state (GST_ELEMENT (camera->imgbin), GST_STATE_PLAYING);
       
  1310 }
       
  1311 
       
  1312 /*
       
  1313  * gst_camerabin_start_image_capture:
       
  1314  * @camera: camerabin object
       
  1315  *
       
  1316  * Initiates image capture.
       
  1317  */
       
  1318 static void
       
  1319 gst_camerabin_start_image_capture (GstCameraBin * camera)
       
  1320 {
       
  1321   GstStateChangeReturn state_ret;
       
  1322   gboolean wait_for_prepare = FALSE;
       
  1323   gint width = 0, height = 0, fps_n = 0, fps_d = 0;
       
  1324   GstStructure *st;
       
  1325 
       
  1326   GST_INFO_OBJECT (camera, "starting image capture");
       
  1327 
       
  1328   if (GST_IS_ELEMENT (camera->src_vid_src) &&
       
  1329       gst_element_implements_interface (camera->src_vid_src,
       
  1330           GST_TYPE_PHOTOGRAPHY)) {
       
  1331     /* Start image capture preparations using photography iface */
       
  1332     wait_for_prepare = TRUE;
       
  1333     g_mutex_lock (camera->capture_mutex);
       
  1334     if (camera->image_capture_caps) {
       
  1335       st = gst_caps_get_structure (camera->image_capture_caps, 0);
       
  1336     } else {
       
  1337       st = gst_caps_get_structure (camera->view_finder_caps, 0);
       
  1338     }
       
  1339     gst_structure_get_int (st, "width", &width);
       
  1340     gst_structure_get_int (st, "height", &height);
       
  1341     gst_structure_get_fraction (st, "framerate", &fps_n, &fps_d);
       
  1342     /* Set image capture resolution and frame rate */
       
  1343     g_signal_emit_by_name (camera->src_vid_src, "user-res-fps",
       
  1344         width, height, fps_n, fps_d, 0);
       
  1345 
       
  1346     /* Enable still image capture mode in v4l2camsrc */
       
  1347     if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
       
  1348             "capture-mode")) {
       
  1349       g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 1, NULL);
       
  1350     }
       
  1351 
       
  1352     /* Start preparations for image capture */
       
  1353     gst_photography_prepare_for_capture (GST_PHOTOGRAPHY (camera->src_vid_src),
       
  1354         (GstPhotoCapturePrepared) img_capture_prepared, camera);
       
  1355     camera->capturing = TRUE;
       
  1356     g_mutex_unlock (camera->capture_mutex);
       
  1357   }
       
  1358 
       
  1359   if (!wait_for_prepare) {
       
  1360     gst_camerabin_rewrite_tags (camera);
       
  1361     state_ret = gst_element_set_state (camera->imgbin, GST_STATE_PLAYING);
       
  1362     if (state_ret != GST_STATE_CHANGE_FAILURE) {
       
  1363       g_mutex_lock (camera->capture_mutex);
       
  1364       g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE,
       
  1365           "active-pad", camera->pad_src_img, NULL);
       
  1366       camera->capturing = TRUE;
       
  1367       g_mutex_unlock (camera->capture_mutex);
       
  1368     } else {
       
  1369       GST_WARNING_OBJECT (camera, "imagebin state change failed");
       
  1370       gst_element_set_state (camera->imgbin, GST_STATE_NULL);
       
  1371     }
       
  1372   }
       
  1373 }
       
  1374 
       
  1375 /*
       
  1376  * gst_camerabin_start_video_recording:
       
  1377  * @camera: camerabin object
       
  1378  *
       
  1379  * Initiates video recording.
       
  1380  */
       
  1381 static void
       
  1382 gst_camerabin_start_video_recording (GstCameraBin * camera)
       
  1383 {
       
  1384   GstStateChangeReturn state_ret;
       
  1385   /* FIXME: how to ensure resolution and fps is supported by CPU?
       
  1386    * use a queue overrun signal?
       
  1387    */
       
  1388   GST_INFO_OBJECT (camera, "starting video capture");
       
  1389 
       
  1390   gst_camerabin_rewrite_tags (camera);
       
  1391 
       
  1392   /* Pause the pipeline in order to distribute new clock in paused_to_playing */
       
  1393   /* audio src timestamps will be 0 without state change to READY. ??? */
       
  1394   gst_element_set_state (GST_ELEMENT (camera), GST_STATE_READY);
       
  1395   gst_element_set_locked_state (camera->vidbin, FALSE);
       
  1396   state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
       
  1397 
       
  1398   if (state_ret != GST_STATE_CHANGE_FAILURE) {
       
  1399     g_mutex_lock (camera->capture_mutex);
       
  1400     g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
       
  1401         "active-pad", camera->pad_src_vid, NULL);
       
  1402 
       
  1403     /* Enable video mode in v4l2camsrc */
       
  1404     if (g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
       
  1405             "capture-mode")) {
       
  1406       g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL);
       
  1407     }
       
  1408 
       
  1409     gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING);
       
  1410     gst_element_set_locked_state (camera->vidbin, TRUE);
       
  1411     camera->capturing = TRUE;
       
  1412     g_mutex_unlock (camera->capture_mutex);
       
  1413   } else {
       
  1414     GST_WARNING_OBJECT (camera, "videobin state change failed");
       
  1415     gst_element_set_state (camera->vidbin, GST_STATE_NULL);
       
  1416     gst_camerabin_reset_to_view_finder (camera);
       
  1417   }
       
  1418 }
       
  1419 
       
  1420 /*
       
  1421  * gst_camerabin_send_video_eos:
       
  1422  * @camera: camerabin object
       
  1423  *
       
  1424  * Generate and send eos event to video bin in order to
       
  1425  * finish recording properly.
       
  1426  */
       
  1427 static void
       
  1428 gst_camerabin_send_video_eos (GstCameraBin * camera)
       
  1429 {
       
  1430   GstPad *videopad;
       
  1431 
       
  1432   g_return_if_fail (camera != NULL);
       
  1433 
       
  1434   /* Send eos event to video bin */
       
  1435   GST_INFO_OBJECT (camera, "sending eos to videobin");
       
  1436   videopad = gst_element_get_static_pad (camera->vidbin, "sink");
       
  1437   gst_pad_send_event (videopad, gst_event_new_eos ());
       
  1438   gst_object_unref (videopad);
       
  1439 }
       
  1440 
       
  1441 /*
       
  1442  * image_pad_blocked:
       
  1443  * @pad: pad to block/unblock
       
  1444  * @blocked: TRUE to block, FALSE to unblock
       
  1445  * @u_data: camera bin object
       
  1446  *
       
  1447  * Sends eos event to image bin if blocking pad leading to image bin.
       
  1448  * The pad will be unblocked when image bin posts eos message.
       
  1449  */
       
  1450 static void
       
  1451 image_pad_blocked (GstPad * pad, gboolean blocked, gpointer user_data)
       
  1452 {
       
  1453   GstCameraBin *camera;
       
  1454 
       
  1455   camera = (GstCameraBin *) user_data;
       
  1456 
       
  1457   GST_DEBUG_OBJECT (camera, "%s %s:%s",
       
  1458       blocked ? "blocking" : "unblocking", GST_DEBUG_PAD_NAME (pad));
       
  1459 
       
  1460   if (blocked && (pad == camera->pad_src_img)) {
       
  1461     /* Send eos and block until image bin reaches eos */
       
  1462     GST_DEBUG_OBJECT (camera, "sending eos to image bin");
       
  1463     gst_element_send_event (camera->imgbin, gst_event_new_eos ());
       
  1464   }
       
  1465 }
       
  1466 
       
  1467 /*
       
  1468  * gst_camerabin_have_img_buffer:
       
  1469  * @pad: output-selector src pad leading to image bin
       
  1470  * @buffer: still image frame
       
  1471  * @u_data: camera bin object
       
  1472  *
       
  1473  * Buffer probe called before sending each buffer to image bin.
       
  1474  *
       
  1475  * First buffer is always passed directly to image bin. Then pad
       
  1476  * is blocked in order to interleave buffers with eos events.
       
  1477  * Interleaving eos events and buffers is needed when we have
       
  1478  * decoupled elements in the image bin capture pipeline.
       
  1479  * After image bin posts eos message, then pad is unblocked.
       
  1480  * Next, image bin is changed to READY state in order to save the
       
  1481  * file and the application is allowed to decide whether to
       
  1482  * continue image capture. If yes, only then the next buffer is
       
  1483  * passed to image bin.
       
  1484  */
       
  1485 static gboolean
       
  1486 gst_camerabin_have_img_buffer (GstPad * pad, GstBuffer * buffer,
       
  1487     gpointer u_data)
       
  1488 {
       
  1489   GstCameraBin *camera = (GstCameraBin *) u_data;
       
  1490   gboolean ret = TRUE;
       
  1491 
       
  1492   GST_LOG ("got buffer #%d %p with size %d", camera->num_img_buffers,
       
  1493       buffer, GST_BUFFER_SIZE (buffer));
       
  1494 
       
  1495   /* Image filename should be set by now */
       
  1496   if (g_str_equal (camera->filename->str, "")) {
       
  1497     GST_DEBUG_OBJECT (camera, "filename not set, dropping buffer");
       
  1498     ret = FALSE;
       
  1499     goto done;
       
  1500   }
       
  1501 
       
  1502   /* Check for first buffer after capture start, we want to
       
  1503      pass it forward directly. */
       
  1504   if (!camera->num_img_buffers) {
       
  1505     /* Restore filter caps for view finder mode if necessary.
       
  1506        The v4l2camsrc switches automatically to view finder
       
  1507        resolution after hi-res still image capture. */
       
  1508     if (camera->image_capture_caps) {
       
  1509       gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps);
       
  1510     }
       
  1511     goto done;
       
  1512   }
       
  1513 
       
  1514   /* Close the file of saved image */
       
  1515   gst_element_set_state (camera->imgbin, GST_STATE_READY);
       
  1516 
       
  1517   /* Check if the application wants to continue */
       
  1518   gst_camerabin_image_capture_continue (camera, camera->filename, &ret);
       
  1519 
       
  1520   if (ret && !camera->stop_requested) {
       
  1521     GST_DEBUG_OBJECT (camera, "capturing image \"%s\"", camera->filename->str);
       
  1522     g_object_set (G_OBJECT (camera->imgbin), "filename",
       
  1523         camera->filename->str, NULL);
       
  1524     gst_element_set_state (camera->imgbin, GST_STATE_PLAYING);
       
  1525   } else {
       
  1526     GST_DEBUG_OBJECT (camera, "not continuing (cont:%d, stop_req:%d)",
       
  1527         ret, camera->stop_requested);
       
  1528     /* Reset filename to force application set new filename */
       
  1529     g_string_assign (camera->filename, "");
       
  1530 
       
  1531     /* Block dataflow to the output-selector to show preview image in
       
  1532        view finder. Continue and unblock when capture is stopped */
       
  1533     gst_pad_set_blocked_async (camera->srcpad_zoom_filter, TRUE,
       
  1534         (GstPadBlockCallback) image_pad_blocked, camera);
       
  1535     ret = FALSE;                /* Drop the buffer */
       
  1536 
       
  1537     g_mutex_lock (camera->capture_mutex);
       
  1538     camera->capturing = FALSE;
       
  1539     g_cond_signal (camera->cond);
       
  1540     g_mutex_unlock (camera->capture_mutex);
       
  1541   }
       
  1542 
       
  1543 done:
       
  1544 
       
  1545   if (ret) {
       
  1546     camera->num_img_buffers++;
       
  1547     /* Block when next buffer arrives, we want to push eos event
       
  1548        between frames and make sure that eos reaches the filesink
       
  1549        before processing the next buffer. */
       
  1550     gst_pad_set_blocked_async (pad, TRUE,
       
  1551         (GstPadBlockCallback) image_pad_blocked, camera);
       
  1552   }
       
  1553 
       
  1554   return ret;
       
  1555 }
       
  1556 
       
  1557 /*
       
  1558  * gst_camerabin_have_vid_buffer:
       
  1559  * @pad: output-selector src pad leading to video bin
       
  1560  * @buffer: buffer pushed to the pad
       
  1561  * @u_data: camerabin object
       
  1562  *
       
  1563  * Buffer probe for src pad leading to video bin.
       
  1564  * Sends eos event to video bin if stop requested and drops
       
  1565  * all buffers after this.
       
  1566  */
       
  1567 static gboolean
       
  1568 gst_camerabin_have_vid_buffer (GstPad * pad, GstBuffer * buffer,
       
  1569     gpointer u_data)
       
  1570 {
       
  1571   GstCameraBin *camera = (GstCameraBin *) u_data;
       
  1572   gboolean ret = TRUE;
       
  1573   GST_LOG ("got video buffer %p with size %d",
       
  1574       buffer, GST_BUFFER_SIZE (buffer));
       
  1575   if (camera->stop_requested) {
       
  1576     gst_camerabin_send_video_eos (camera);
       
  1577     ret = FALSE;                /* Drop buffer */
       
  1578   }
       
  1579 
       
  1580   return ret;
       
  1581 }
       
  1582 
       
  1583 /*
       
  1584  * gst_camerabin_reset_to_view_finder:
       
  1585  * @camera: camerabin object
       
  1586  *
       
  1587  * Stop capturing and set camerabin to view finder mode.
       
  1588  * Reset capture counters and flags.
       
  1589  */
       
  1590 static void
       
  1591 gst_camerabin_reset_to_view_finder (GstCameraBin * camera)
       
  1592 {
       
  1593   GstStateChangeReturn state_ret;
       
  1594   GST_DEBUG_OBJECT (camera, "resetting");
       
  1595 
       
  1596   /* Set active bin to READY state */
       
  1597   if (camera->active_bin) {
       
  1598     state_ret = gst_element_set_state (camera->active_bin, GST_STATE_READY);
       
  1599     if (state_ret == GST_STATE_CHANGE_FAILURE) {
       
  1600       GST_WARNING_OBJECT (camera, "state change failed");
       
  1601       gst_element_set_state (camera->active_bin, GST_STATE_NULL);
       
  1602       camera->active_bin = NULL;
       
  1603     }
       
  1604   }
       
  1605 
       
  1606   /* Reset counters and flags */
       
  1607   camera->num_img_buffers = 0;
       
  1608   camera->stop_requested = FALSE;
       
  1609   camera->paused = FALSE;
       
  1610 
       
  1611   if (camera->src_out_sel) {
       
  1612     /* Set selector to forward data to view finder */
       
  1613     g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
       
  1614         "active-pad", camera->pad_src_view, NULL);
       
  1615   }
       
  1616 
       
  1617   /* Unblock, if dataflow to output-selector is blocked due to image preview */
       
  1618   if (camera->srcpad_zoom_filter &&
       
  1619       gst_pad_is_blocked (camera->srcpad_zoom_filter)) {
       
  1620     gst_pad_set_blocked_async (camera->srcpad_zoom_filter, FALSE,
       
  1621         (GstPadBlockCallback) image_pad_blocked, camera);
       
  1622   }
       
  1623   /* Unblock, if dataflow to image bin is blocked due to waiting for eos */
       
  1624   if (camera->pad_src_img && gst_pad_is_blocked (camera->pad_src_img)) {
       
  1625     gst_pad_set_blocked_async (camera->pad_src_img, FALSE,
       
  1626         (GstPadBlockCallback) image_pad_blocked, camera);
       
  1627   }
       
  1628 
       
  1629   /* Enable view finder mode in v4l2camsrc */
       
  1630   if (camera->src_vid_src &&
       
  1631       g_object_class_find_property (G_OBJECT_GET_CLASS (camera->src_vid_src),
       
  1632           "capture-mode")) {
       
  1633     g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 0, NULL);
       
  1634   }
       
  1635 
       
  1636   GST_DEBUG_OBJECT (camera, "reset done");
       
  1637 }
       
  1638 
       
  1639 /*
       
  1640  * gst_camerabin_do_stop:
       
  1641  * @camera: camerabin object
       
  1642  *
       
  1643  * Raise flag to indicate to image and video bin capture stop.
       
  1644  * Stopping paused video recording handled as a special case.
       
  1645  * Wait for ongoing capturing to finish.
       
  1646  */
       
  1647 static void
       
  1648 gst_camerabin_do_stop (GstCameraBin * camera)
       
  1649 {
       
  1650   g_mutex_lock (camera->capture_mutex);
       
  1651   if (camera->capturing) {
       
  1652     GST_DEBUG_OBJECT (camera, "mark stop");
       
  1653     camera->stop_requested = TRUE;
       
  1654 
       
  1655     /* Take special care when stopping paused video capture */
       
  1656     if ((camera->active_bin == camera->vidbin) && camera->paused) {
       
  1657       /* Send eos event to video bin before setting it to playing */
       
  1658       gst_camerabin_send_video_eos (camera);
       
  1659       /* We must change to playing now in order to get video bin eos events
       
  1660          and buffered data through and finish recording properly */
       
  1661       gst_element_set_state (GST_ELEMENT (camera->vidbin), GST_STATE_PLAYING);
       
  1662       camera->paused = FALSE;
       
  1663     }
       
  1664 
       
  1665     GST_DEBUG_OBJECT (camera, "waiting for capturing to finish");
       
  1666     g_cond_wait (camera->cond, camera->capture_mutex);
       
  1667     GST_DEBUG_OBJECT (camera, "capturing finished");
       
  1668   }
       
  1669   g_mutex_unlock (camera->capture_mutex);
       
  1670 }
       
  1671 
       
  1672 /*
       
  1673  * gst_camerabin_default_signal_img_done:
       
  1674  * @camera: camerabin object
       
  1675  * @fname: new filename
       
  1676  *
       
  1677  * Default handler for #GstCameraBin::img-done signal,
       
  1678  * stops always capture.
       
  1679  *
       
  1680  * Returns: FALSE always
       
  1681  */
       
  1682 static gboolean
       
  1683 gst_camerabin_default_signal_img_done (GstCameraBin * camera, GString * fname)
       
  1684 {
       
  1685   return FALSE;
       
  1686 }
       
  1687 
       
  1688 /*
       
  1689  * gst_camerabin_set_allowed_framerate:
       
  1690  * @camera: camerabin object
       
  1691  * @filter_caps: update allowed framerate to these caps
       
  1692  *
       
  1693  * Find allowed frame rate from video source that matches with
       
  1694  * resolution in @filter_caps. Set found frame rate to @filter_caps.
       
  1695  */
       
  1696 static void
       
  1697 gst_camerabin_set_allowed_framerate (GstCameraBin * camera,
       
  1698     GstCaps * filter_caps)
       
  1699 {
       
  1700   GstStructure *structure;
       
  1701   GstCaps *allowed_caps = NULL, *intersect = NULL;
       
  1702   const GValue *framerate = NULL;
       
  1703   guint caps_size, i;
       
  1704 
       
  1705   /* Get supported caps from video src that matches with new filter caps */
       
  1706   GST_INFO_OBJECT (camera, "filter caps:%" GST_PTR_FORMAT, filter_caps);
       
  1707   allowed_caps = gst_camerabin_get_allowed_input_caps (camera);
       
  1708   intersect = gst_caps_intersect (allowed_caps, filter_caps);
       
  1709   GST_INFO_OBJECT (camera, "intersect caps:%" GST_PTR_FORMAT, intersect);
       
  1710 
       
  1711   /* Find the best framerate from the caps */
       
  1712   caps_size = gst_caps_get_size (intersect);
       
  1713   for (i = 0; i < caps_size; i++) {
       
  1714     structure = gst_caps_get_structure (intersect, i);
       
  1715     framerate =
       
  1716         gst_camerabin_find_better_framerate (camera, structure, framerate);
       
  1717   }
       
  1718 
       
  1719   if (GST_VALUE_HOLDS_FRACTION (framerate)) {
       
  1720     gst_caps_set_simple (filter_caps,
       
  1721         "framerate", GST_TYPE_FRACTION,
       
  1722         gst_value_get_fraction_numerator (framerate),
       
  1723         gst_value_get_fraction_denominator (framerate), NULL);
       
  1724   }
       
  1725 
       
  1726   if (allowed_caps) {
       
  1727     gst_caps_unref (allowed_caps);
       
  1728   }
       
  1729   if (intersect) {
       
  1730     gst_caps_unref (intersect);
       
  1731   }
       
  1732 }
       
  1733 
       
  1734 
       
  1735 /**
       
  1736  * get_srcpad_current_format:
       
  1737  * @element: element to get the format from
       
  1738  *
       
  1739  * Helper function to get the negotiated fourcc
       
  1740  * format from @element src pad.
       
  1741  *
       
  1742  * Returns: negotiated format (fourcc), 0 if not found
       
  1743  */
       
  1744 static guint32
       
  1745 get_srcpad_current_format (GstElement * element)
       
  1746 {
       
  1747   GstPad *srcpad = NULL;
       
  1748   GstCaps *srccaps = NULL;
       
  1749   GstStructure *structure;
       
  1750   guint32 format = 0;
       
  1751 
       
  1752   g_return_val_if_fail (element != NULL, 0);
       
  1753 
       
  1754   if ((srcpad = gst_element_get_static_pad (element, "src")) == NULL) {
       
  1755     goto no_pad;
       
  1756   }
       
  1757 
       
  1758   if ((srccaps = gst_pad_get_negotiated_caps (srcpad)) == NULL) {
       
  1759     goto no_caps;
       
  1760   }
       
  1761 
       
  1762   GST_LOG ("negotiated caps %" GST_PTR_FORMAT, srccaps);
       
  1763 
       
  1764   structure = gst_caps_get_structure (srccaps, 0);
       
  1765   if (gst_structure_has_field (structure, "format")) {
       
  1766     gst_structure_get_fourcc (structure, "format", &format);
       
  1767   }
       
  1768 
       
  1769   gst_caps_unref (srccaps);
       
  1770 no_caps:
       
  1771   gst_object_unref (srcpad);
       
  1772 no_pad:
       
  1773   GST_DEBUG ("current format for %" GST_PTR_FORMAT ": %" GST_FOURCC_FORMAT,
       
  1774       element, GST_FOURCC_ARGS (format));
       
  1775   return format;
       
  1776 }
       
  1777 
       
  1778 /*
       
  1779  * gst_camerabin_find_better_framerate:
       
  1780  * @camera: camerabin object
       
  1781  * @st: structure that contains framerate candidates
       
  1782  * @orig_framerate: best framerate so far
       
  1783  *
       
  1784  * Looks for framerate better than @orig_framerate from @st structure.
       
  1785  * In night mode lowest framerate is considered best, otherwise highest is
       
  1786  * best.
       
  1787  *
       
  1788  * Returns: @orig_framerate or better if found
       
  1789  */
       
  1790 static const GValue *
       
  1791 gst_camerabin_find_better_framerate (GstCameraBin * camera, GstStructure * st,
       
  1792     const GValue * orig_framerate)
       
  1793 {
       
  1794   const GValue *framerate = NULL;
       
  1795   guint i, i_best, list_size;
       
  1796   gint res, comparison;
       
  1797 
       
  1798   if (camera->night_mode) {
       
  1799     GST_LOG_OBJECT (camera, "finding min framerate");
       
  1800     comparison = GST_VALUE_LESS_THAN;
       
  1801   } else {
       
  1802     GST_LOG_OBJECT (camera, "finding max framerate");
       
  1803     comparison = GST_VALUE_GREATER_THAN;
       
  1804   }
       
  1805 
       
  1806   if (gst_structure_has_field (st, "framerate")) {
       
  1807     framerate = gst_structure_get_value (st, "framerate");
       
  1808     /* Handle framerate lists */
       
  1809     if (GST_VALUE_HOLDS_LIST (framerate)) {
       
  1810       list_size = gst_value_list_get_size (framerate);
       
  1811       GST_LOG_OBJECT (camera, "finding framerate from list");
       
  1812       for (i = 0, i_best = 0; i < list_size; i++) {
       
  1813         res = gst_value_compare (gst_value_list_get_value (framerate, i),
       
  1814             gst_value_list_get_value (framerate, i_best));
       
  1815         if (comparison == res) {
       
  1816           i_best = i;
       
  1817         }
       
  1818       }
       
  1819       GST_LOG_OBJECT (camera, "found best framerate from index %d", i_best);
       
  1820       framerate = gst_value_list_get_value (framerate, i_best);
       
  1821     }
       
  1822     /* Handle framerate ranges */
       
  1823     if (GST_VALUE_HOLDS_FRACTION_RANGE (framerate)) {
       
  1824       if (camera->night_mode) {
       
  1825         GST_LOG_OBJECT (camera, "getting min framerate from range");
       
  1826         framerate = gst_value_get_fraction_range_min (framerate);
       
  1827       } else {
       
  1828         GST_LOG_OBJECT (camera, "getting max framerate from range");
       
  1829         framerate = gst_value_get_fraction_range_max (framerate);
       
  1830       }
       
  1831     }
       
  1832   }
       
  1833 
       
  1834   /* Check if we found better framerate */
       
  1835   if (orig_framerate && framerate) {
       
  1836     res = gst_value_compare (orig_framerate, framerate);
       
  1837     if (comparison == res) {
       
  1838       GST_LOG_OBJECT (camera, "original framerate was the best");
       
  1839       framerate = orig_framerate;
       
  1840     }
       
  1841   }
       
  1842 
       
  1843   return framerate;
       
  1844 }
       
  1845 
       
  1846 /*
       
  1847  * GObject callback functions implementation
       
  1848  */
       
  1849 
       
  1850 static void
       
  1851 gst_camerabin_base_init (gpointer gclass)
       
  1852 {
       
  1853   static GstElementDetails element_details = {
       
  1854     "Camera Bin",
       
  1855     "Generic/Bin/Camera",
       
  1856     "Handle lot of features present in DSC",
       
  1857     "Nokia Corporation <multimedia@maemo.org>\n"
       
  1858         "Edgard Lima <edgard.lima@indt.org.br>"
       
  1859   };
       
  1860   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
       
  1861 
       
  1862   gst_element_class_set_details (element_class, &element_details);
       
  1863 }
       
  1864 
       
  1865 static void
       
  1866 gst_camerabin_class_init (GstCameraBinClass * klass)
       
  1867 {
       
  1868   GObjectClass *gobject_class;
       
  1869   GstElementClass *gstelement_class;
       
  1870   GstBinClass *gstbin_class;
       
  1871 
       
  1872   gobject_class = G_OBJECT_CLASS (klass);
       
  1873   gstelement_class = GST_ELEMENT_CLASS (klass);
       
  1874   gstbin_class = GST_BIN_CLASS (klass);
       
  1875 
       
  1876   /* gobject */
       
  1877 
       
  1878   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_camerabin_dispose);
       
  1879   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_camerabin_finalize);
       
  1880 
       
  1881   gobject_class->set_property = gst_camerabin_set_property;
       
  1882   gobject_class->get_property = gst_camerabin_get_property;
       
  1883 
       
  1884   /**
       
  1885    * GstCameraBin:filename:
       
  1886    *
       
  1887    * Set filename for the still image capturing or video capturing.
       
  1888    */
       
  1889 
       
  1890   g_object_class_install_property (gobject_class, ARG_FILENAME,
       
  1891       g_param_spec_string ("filename", "Filename",
       
  1892           "Filename of the image or video to save", "", G_PARAM_READWRITE));
       
  1893 
       
  1894   /**
       
  1895    * GstCameraBin:mode:
       
  1896    *
       
  1897    * Set the mode of operation: still image capturing or video recording.
       
  1898    * Setting the mode will create and destroy image bin or video bin elements
       
  1899    * according to the mode. You can set this property at any time, changing
       
  1900    * the mode will stop ongoing capture.
       
  1901    */
       
  1902 
       
  1903   g_object_class_install_property (gobject_class, ARG_MODE,
       
  1904       g_param_spec_enum ("mode", "Mode",
       
  1905           "The capture mode (still image capture or video recording)",
       
  1906           GST_TYPE_CAMERABIN_MODE, DEFAULT_MODE, G_PARAM_READWRITE));
       
  1907 
       
  1908   /**
       
  1909    * GstCameraBin:mute:
       
  1910    *
       
  1911    * Mute audio in video recording mode.
       
  1912    * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING.
       
  1913    */
       
  1914 
       
  1915   g_object_class_install_property (gobject_class, ARG_MUTE,
       
  1916       g_param_spec_boolean ("mute", "Mute",
       
  1917           "True to mute the recording. False to record with audio",
       
  1918           ARG_DEFAULT_MUTE, G_PARAM_READWRITE));
       
  1919 
       
  1920   /**
       
  1921    * GstCameraBin:zoom:
       
  1922    *
       
  1923    * Set up the zoom applied to the frames.
       
  1924    * Set this property only when #GstCameraBin is in READY, PAUSED or PLAYING.
       
  1925    */
       
  1926 
       
  1927   g_object_class_install_property (gobject_class, ARG_ZOOM,
       
  1928       g_param_spec_int ("zoom", "Zoom",
       
  1929           "The zoom. 100 for 1x, 200 for 2x and so on",
       
  1930           MIN_ZOOM, MAX_ZOOM, DEFAULT_ZOOM, G_PARAM_READWRITE));
       
  1931 
       
  1932   /**
       
  1933    * GstCameraBin:imagepp:
       
  1934    *
       
  1935    * Set up an element to do image post processing.
       
  1936    * This property can only be set while #GstCameraBin is in NULL state.
       
  1937    * The ownership of the element will be taken by #GstCameraBin.
       
  1938    */
       
  1939   g_object_class_install_property (gobject_class, ARG_IMAGE_POST,
       
  1940       g_param_spec_object ("imagepp", "Image post processing element",
       
  1941           "Image Post-Processing GStreamer element (default is NULL)",
       
  1942           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  1943 
       
  1944   /**
       
  1945    *  GstCameraBin:imageenc:
       
  1946    *
       
  1947    * Set up an image encoder (for example, jpegenc or pngenc) element.
       
  1948    * This property can only be set while #GstCameraBin is in NULL state.
       
  1949    * The ownership of the element will be taken by #GstCameraBin.
       
  1950    */
       
  1951 
       
  1952   g_object_class_install_property (gobject_class, ARG_IMAGE_ENC,
       
  1953       g_param_spec_object ("imageenc", "Image encoder",
       
  1954           "Image encoder GStreamer element (default is jpegenc)",
       
  1955           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  1956 
       
  1957   /**
       
  1958    *  GstCameraBin:videopp:
       
  1959    *
       
  1960    * Set up an element to do video post processing.
       
  1961    * This property can only be set while #GstCameraBin is in NULL state.
       
  1962    * The ownership of the element will be taken by #GstCameraBin.
       
  1963    */
       
  1964 
       
  1965   g_object_class_install_property (gobject_class, ARG_VIDEO_POST,
       
  1966       g_param_spec_object ("videopp", "Video post processing element",
       
  1967           "Video post processing GStreamer element (default is NULL)",
       
  1968           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  1969 
       
  1970   /**
       
  1971    *  GstCameraBin:videoenc:
       
  1972    *
       
  1973    * Set up a video encoder element.
       
  1974    * This property can only be set while #GstCameraBin is in NULL state.
       
  1975    * The ownership of the element will be taken by #GstCameraBin.
       
  1976    */
       
  1977 
       
  1978   g_object_class_install_property (gobject_class, ARG_VIDEO_ENC,
       
  1979       g_param_spec_object ("videoenc", "Video encoder",
       
  1980           "Video encoder GStreamer element (default is theoraenc)",
       
  1981           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  1982 
       
  1983   /**
       
  1984    *  GstCameraBin:audioenc:
       
  1985    *
       
  1986    * Set up an audio encoder element.
       
  1987    * This property can only be set while #GstCameraBin is in NULL state.
       
  1988    * The ownership of the element will be taken by #GstCameraBin.
       
  1989    */
       
  1990 
       
  1991   g_object_class_install_property (gobject_class, ARG_AUDIO_ENC,
       
  1992       g_param_spec_object ("audioenc", "Audio encoder",
       
  1993           "Audio encoder GStreamer element (default is vorbisenc)",
       
  1994           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  1995 
       
  1996   /**
       
  1997    *  GstCameraBin:videomux:
       
  1998    *
       
  1999    * Set up a video muxer element.
       
  2000    * This property can only be set while #GstCameraBin is in NULL state.
       
  2001    * The ownership of the element will be taken by #GstCameraBin.
       
  2002    */
       
  2003 
       
  2004   g_object_class_install_property (gobject_class, ARG_VIDEO_MUX,
       
  2005       g_param_spec_object ("videomux", "Video muxer",
       
  2006           "Video muxer GStreamer element (default is oggmux)",
       
  2007           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  2008 
       
  2009   /**
       
  2010    *  GstCameraBin:vfsink:
       
  2011    *
       
  2012    * Set up a sink element to render frames in view finder.
       
  2013    * By default "autovideosink" will be the sink element.
       
  2014    * This property can only be set while #GstCameraBin is in NULL state.
       
  2015    * The ownership of the element will be taken by #GstCameraBin.
       
  2016    */
       
  2017 
       
  2018   g_object_class_install_property (gobject_class, ARG_VF_SINK,
       
  2019       g_param_spec_object ("vfsink", "View finder sink",
       
  2020           "View finder sink GStreamer element (default is " DEFAULT_VIEW_SINK
       
  2021           ")", GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  2022 
       
  2023   /**
       
  2024    *  GstCameraBin:videosrc:
       
  2025    *
       
  2026    * Set up a video source element.
       
  2027    * By default "v4l2src" will be the src element.
       
  2028    * This property can only be set while #GstCameraBin is in NULL state.
       
  2029    * The ownership of the element will be taken by #GstCameraBin.
       
  2030    */
       
  2031 
       
  2032   g_object_class_install_property (gobject_class, ARG_VIDEO_SRC,
       
  2033       g_param_spec_object ("videosrc", "Video source element",
       
  2034           "Video source GStreamer element (default is " DEFAULT_SRC_VID_SRC ")",
       
  2035           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  2036   /**
       
  2037    *  GstCameraBin:audiosrc:
       
  2038    *
       
  2039    * Set up an audio source element.
       
  2040    * By default "pulsesrc" will be the source element.
       
  2041    * This property can only be set while #GstCameraBin is in NULL state.
       
  2042    * The ownership of the element will be taken by #GstCameraBin.
       
  2043    */
       
  2044 
       
  2045   g_object_class_install_property (gobject_class, ARG_AUDIO_SRC,
       
  2046       g_param_spec_object ("audiosrc", "Audio source element",
       
  2047           "Audio source GStreamer element (default is pulsesrc)",
       
  2048           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
  2049 
       
  2050   /**
       
  2051    * GstCameraBin:inputcaps:
       
  2052    *
       
  2053    * The allowed modes of operation of the video source. Have in mind that it
       
  2054    * doesn't mean #GstCameraBin can operate in all those modes,
       
  2055    * it depends also on the other elements in the pipeline. Remember to
       
  2056    * gst_caps_unref after using it.
       
  2057    */
       
  2058 
       
  2059   g_object_class_install_property (gobject_class, ARG_INPUT_CAPS,
       
  2060       g_param_spec_boxed ("inputcaps", "Input caps",
       
  2061           "The allowed modes of the video source operation",
       
  2062           GST_TYPE_CAPS, G_PARAM_READABLE));
       
  2063 
       
  2064   /**
       
  2065    * GstCameraBin:filter-caps:
       
  2066    *
       
  2067    * Filter video source element caps using this property.
       
  2068    * This is an alternative to #GstCamerabin::user-res-fps action
       
  2069    * signal that allows more fine grained control of video source.
       
  2070    */
       
  2071 
       
  2072   g_object_class_install_property (gobject_class, ARG_FILTER_CAPS,
       
  2073       g_param_spec_boxed ("filter-caps", "Filter caps",
       
  2074           "Capsfilter caps used to control video source operation",
       
  2075           GST_TYPE_CAPS, G_PARAM_READWRITE));
       
  2076 
       
  2077   /**
       
  2078    * GstCameraBin::user-start:
       
  2079    * @camera: the camera bin element
       
  2080    *
       
  2081    * Starts image capture or video recording depending on the Mode.
       
  2082    * If there is a capture already going on, does nothing.
       
  2083    * Resumes video recording if it has been paused.
       
  2084    */
       
  2085 
       
  2086   camerabin_signals[USER_START_SIGNAL] =
       
  2087       g_signal_new ("user-start",
       
  2088       G_TYPE_FROM_CLASS (klass),
       
  2089       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
  2090       G_STRUCT_OFFSET (GstCameraBinClass, user_start),
       
  2091       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
       
  2092 
       
  2093   /**
       
  2094    * GstCameraBin::user-stop:
       
  2095    * @camera: the camera bin element
       
  2096    *
       
  2097    * Stops still image preview, continuous image capture and video
       
  2098    * recording and returns to the view finder mode.
       
  2099    */
       
  2100 
       
  2101   camerabin_signals[USER_STOP_SIGNAL] =
       
  2102       g_signal_new ("user-stop",
       
  2103       G_TYPE_FROM_CLASS (klass),
       
  2104       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
  2105       G_STRUCT_OFFSET (GstCameraBinClass, user_stop),
       
  2106       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
       
  2107 
       
  2108   /**
       
  2109    * GstCameraBin::user-pause:
       
  2110    * @camera: the camera bin element
       
  2111    *
       
  2112    * Pauses video recording or resumes paused video recording.
       
  2113    * If in image mode or not recording, does nothing.
       
  2114    */
       
  2115 
       
  2116   camerabin_signals[USER_PAUSE_SIGNAL] =
       
  2117       g_signal_new ("user-pause",
       
  2118       G_TYPE_FROM_CLASS (klass),
       
  2119       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
  2120       G_STRUCT_OFFSET (GstCameraBinClass, user_pause),
       
  2121       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
       
  2122 
       
  2123   /**
       
  2124    * GstCameraBin::user-res-fps:
       
  2125    * @camera: the camera bin element
       
  2126    * @width: number of horizontal pixels
       
  2127    * @height: number of vertical pixels
       
  2128    * @fps_n: frames per second numerator
       
  2129    * @fps_d: frames per second denominator
       
  2130    *
       
  2131    * Changes the frame resolution and frames per second of the video source.
       
  2132    * The application must be aware of the resolutions supported by the camera.
       
  2133    * Supported resolutions and frame rates can be get using input-caps property.
       
  2134    *
       
  2135    * Setting @fps_n or @fps_d to 0 configures maximum framerate for the
       
  2136    * given resolution, unless in night mode when minimum is configured.
       
  2137    */
       
  2138 
       
  2139   camerabin_signals[USER_RES_FPS_SIGNAL] =
       
  2140       g_signal_new ("user-res-fps",
       
  2141       G_TYPE_FROM_CLASS (klass),
       
  2142       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
  2143       G_STRUCT_OFFSET (GstCameraBinClass, user_res_fps),
       
  2144       NULL, NULL, gst_camerabin_marshal_VOID__INT_INT_INT_INT, G_TYPE_NONE, 4,
       
  2145       G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
       
  2146 
       
  2147   /**
       
  2148    * GstCameraBin::user-image-res:
       
  2149    * @camera: the camera bin element
       
  2150    * @width: number of horizontal pixels
       
  2151    * @height: number of vertical pixels
       
  2152    *
       
  2153    * Changes the resolution used for still image capture.
       
  2154    * Does not affect view finder mode and video recording.
       
  2155    * Use this action signal in PAUSED or PLAYING state.
       
  2156    */
       
  2157 
       
  2158   camerabin_signals[USER_IMAGE_RES_SIGNAL] =
       
  2159       g_signal_new ("user-image-res",
       
  2160       G_TYPE_FROM_CLASS (klass),
       
  2161       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
  2162       G_STRUCT_OFFSET (GstCameraBinClass, user_image_res),
       
  2163       NULL, NULL, gst_camerabin_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
       
  2164       G_TYPE_INT, G_TYPE_INT);
       
  2165 
       
  2166   /**
       
  2167    * GstCameraBin::img-done:
       
  2168    * @camera: the camera bin element
       
  2169    * @filename: the name of the file just saved
       
  2170    *
       
  2171    * Signal emited when the file has just been saved. To continue taking
       
  2172    * pictures just update @filename and return TRUE, otherwise return FALSE.
       
  2173    *
       
  2174    * Don't call any #GstCameraBin method from this signal, if you do so there
       
  2175    * will be a deadlock.
       
  2176    */
       
  2177 
       
  2178   camerabin_signals[IMG_DONE_SIGNAL] =
       
  2179       g_signal_new ("img-done", G_TYPE_FROM_CLASS (klass),
       
  2180       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstCameraBinClass, img_done),
       
  2181       g_signal_accumulator_true_handled, NULL, gst_marshal_BOOLEAN__POINTER,
       
  2182       G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
       
  2183 
       
  2184   klass->user_start = gst_camerabin_user_start;
       
  2185   klass->user_stop = gst_camerabin_user_stop;
       
  2186   klass->user_pause = gst_camerabin_user_pause;
       
  2187   klass->user_res_fps = gst_camerabin_user_res_fps;
       
  2188   klass->user_image_res = gst_camerabin_user_image_res;
       
  2189 
       
  2190   klass->img_done = gst_camerabin_default_signal_img_done;
       
  2191 
       
  2192   /* gstelement */
       
  2193 
       
  2194   gstelement_class->change_state =
       
  2195       GST_DEBUG_FUNCPTR (gst_camerabin_change_state);
       
  2196 
       
  2197   /* gstbin */
       
  2198   /* override handle_message to peek when video or image bin reaches eos */
       
  2199   gstbin_class->handle_message =
       
  2200       GST_DEBUG_FUNCPTR (gst_camerabin_handle_message_func);
       
  2201 
       
  2202 }
       
  2203 
       
  2204 /* initialize the new element
       
  2205  * instantiate pads and add them to element
       
  2206  * set functions
       
  2207  * initialize structure
       
  2208  */
       
  2209 static void
       
  2210 gst_camerabin_init (GstCameraBin * camera, GstCameraBinClass * gclass)
       
  2211 {
       
  2212   /* GstElementClass *klass = GST_ELEMENT_GET_CLASS (camera); */
       
  2213 
       
  2214   camera->filename = g_string_new ("");
       
  2215   camera->mode = DEFAULT_MODE;
       
  2216   camera->num_img_buffers = 0;
       
  2217   camera->stop_requested = FALSE;
       
  2218   camera->paused = FALSE;
       
  2219   camera->capturing = FALSE;
       
  2220   camera->night_mode = FALSE;
       
  2221 
       
  2222   camera->width = DEFAULT_WIDTH;
       
  2223   camera->height = DEFAULT_HEIGHT;
       
  2224   camera->fps_n = DEFAULT_FPS_N;
       
  2225   camera->fps_d = DEFAULT_FPS_D;
       
  2226 
       
  2227   camera->image_capture_caps = NULL;
       
  2228   camera->view_finder_caps = NULL;
       
  2229   camera->allowed_caps = NULL;
       
  2230 
       
  2231   camera->zoom = DEFAULT_ZOOM;
       
  2232 
       
  2233   /* concurrency control */
       
  2234   camera->capture_mutex = g_mutex_new ();
       
  2235   camera->cond = g_cond_new ();
       
  2236 
       
  2237   /* pad names for output and input selectors */
       
  2238   camera->pad_src_view = NULL;
       
  2239   camera->pad_view_src = NULL;
       
  2240   camera->pad_src_img = NULL;
       
  2241   camera->pad_view_img = NULL;
       
  2242   camera->pad_src_vid = NULL;
       
  2243   camera->pad_view_vid = NULL;
       
  2244   camera->srcpad_zoom_filter = NULL;
       
  2245 
       
  2246   /* source elements */
       
  2247   camera->src_vid_src = NULL;
       
  2248   camera->src_filter = NULL;
       
  2249   camera->src_zoom_crop = NULL;
       
  2250   camera->src_zoom_scale = NULL;
       
  2251   camera->src_zoom_filter = NULL;
       
  2252   camera->src_out_sel = NULL;
       
  2253 
       
  2254   camera->user_vf_sink = NULL;
       
  2255 
       
  2256   /* image capture bin */
       
  2257   camera->imgbin = g_object_new (GST_TYPE_CAMERABIN_IMAGE, NULL);
       
  2258   gst_object_ref (camera->imgbin);
       
  2259 
       
  2260   /* video capture bin */
       
  2261   camera->vidbin = g_object_new (GST_TYPE_CAMERABIN_VIDEO, NULL);
       
  2262   gst_object_ref (camera->vidbin);
       
  2263 
       
  2264   camera->active_bin = NULL;
       
  2265 
       
  2266   /* view finder elements */
       
  2267   camera->view_in_sel = NULL;
       
  2268   camera->view_scale = NULL;
       
  2269   camera->view_sink = NULL;
       
  2270 }
       
  2271 
       
  2272 static void
       
  2273 gst_camerabin_dispose (GObject * object)
       
  2274 {
       
  2275   GstCameraBin *camera;
       
  2276 
       
  2277   camera = GST_CAMERABIN (object);
       
  2278 
       
  2279   GST_DEBUG_OBJECT (camera, "disposing");
       
  2280 
       
  2281   gst_element_set_state (camera->imgbin, GST_STATE_NULL);
       
  2282   gst_object_unref (camera->imgbin);
       
  2283 
       
  2284   gst_element_set_state (camera->vidbin, GST_STATE_NULL);
       
  2285   gst_object_unref (camera->vidbin);
       
  2286 
       
  2287   camerabin_destroy_elements (camera);
       
  2288 
       
  2289   camerabin_dispose_elements (camera);
       
  2290 
       
  2291   G_OBJECT_CLASS (parent_class)->dispose (object);
       
  2292 }
       
  2293 
       
  2294 static void
       
  2295 gst_camerabin_finalize (GObject * object)
       
  2296 {
       
  2297   G_OBJECT_CLASS (parent_class)->finalize (object);
       
  2298 }
       
  2299 
       
  2300 static void
       
  2301 gst_camerabin_set_property (GObject * object, guint prop_id,
       
  2302     const GValue * value, GParamSpec * pspec)
       
  2303 {
       
  2304   GstCameraBin *camera = GST_CAMERABIN (object);
       
  2305 
       
  2306   switch (prop_id) {
       
  2307     case ARG_MUTE:
       
  2308       gst_camerabin_video_set_mute (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2309           g_value_get_boolean (value));
       
  2310       break;
       
  2311     case ARG_ZOOM:
       
  2312       g_atomic_int_set (&camera->zoom, g_value_get_int (value));
       
  2313       gst_camerabin_setup_zoom (camera);
       
  2314       break;
       
  2315     case ARG_MODE:
       
  2316       gst_camerabin_change_mode (camera, g_value_get_enum (value));
       
  2317       break;
       
  2318     case ARG_FILENAME:
       
  2319       gst_camerabin_change_filename (camera, g_value_get_string (value));
       
  2320       break;
       
  2321     case ARG_VIDEO_POST:
       
  2322       if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
       
  2323         GST_WARNING_OBJECT (camera,
       
  2324             "can't use set element until next video bin NULL to READY state change");
       
  2325       }
       
  2326       gst_camerabin_video_set_post (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2327           g_value_get_object (value));
       
  2328       break;
       
  2329     case ARG_VIDEO_ENC:
       
  2330       if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
       
  2331         GST_WARNING_OBJECT (camera,
       
  2332             "can't use set element until next video bin NULL to READY state change");
       
  2333       }
       
  2334       gst_camerabin_video_set_video_enc (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2335           g_value_get_object (value));
       
  2336       break;
       
  2337     case ARG_AUDIO_ENC:
       
  2338       if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
       
  2339         GST_WARNING_OBJECT (camera,
       
  2340             "can't use set element until next video bin NULL to READY state change");
       
  2341       }
       
  2342       gst_camerabin_video_set_audio_enc (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2343           g_value_get_object (value));
       
  2344       break;
       
  2345     case ARG_VIDEO_MUX:
       
  2346       if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
       
  2347         GST_WARNING_OBJECT (camera->vidbin,
       
  2348             "can't use set element until next video bin NULL to READY state change");
       
  2349       }
       
  2350       gst_camerabin_video_set_muxer (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2351           g_value_get_object (value));
       
  2352       break;
       
  2353     case ARG_IMAGE_POST:
       
  2354       if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
       
  2355         GST_WARNING_OBJECT (camera,
       
  2356             "can't use set element until next image bin NULL to READY state change");
       
  2357       }
       
  2358       gst_camerabin_image_set_postproc (GST_CAMERABIN_IMAGE (camera->imgbin),
       
  2359           g_value_get_object (value));
       
  2360       break;
       
  2361     case ARG_IMAGE_ENC:
       
  2362       if (GST_STATE (camera->imgbin) != GST_STATE_NULL) {
       
  2363         GST_WARNING_OBJECT (camera,
       
  2364             "can't use set element until next image bin NULL to READY state change");
       
  2365       }
       
  2366       gst_camerabin_image_set_encoder (GST_CAMERABIN_IMAGE (camera->imgbin),
       
  2367           g_value_get_object (value));
       
  2368       break;
       
  2369     case ARG_VF_SINK:
       
  2370       if (GST_STATE (camera) != GST_STATE_NULL) {
       
  2371         GST_ELEMENT_ERROR (camera, CORE, FAILED,
       
  2372             ("camerabin must be in NULL state when setting the view finder element"),
       
  2373             (NULL));
       
  2374       } else {
       
  2375         if (camera->user_vf_sink)
       
  2376           gst_object_unref (camera->user_vf_sink);
       
  2377         camera->user_vf_sink = g_value_get_object (value);
       
  2378         gst_object_ref (camera->user_vf_sink);
       
  2379       }
       
  2380       break;
       
  2381     case ARG_VIDEO_SRC:
       
  2382       if (GST_STATE (camera) != GST_STATE_NULL) {
       
  2383         GST_ELEMENT_ERROR (camera, CORE, FAILED,
       
  2384             ("camerabin must be in NULL state when setting the video source element"),
       
  2385             (NULL));
       
  2386       } else {
       
  2387         if (camera->user_vid_src)
       
  2388           gst_object_unref (camera->user_vid_src);
       
  2389         camera->user_vid_src = g_value_get_object (value);
       
  2390         gst_object_ref (camera->user_vid_src);
       
  2391       }
       
  2392       break;
       
  2393     case ARG_AUDIO_SRC:
       
  2394       if (GST_STATE (camera->vidbin) != GST_STATE_NULL) {
       
  2395         GST_WARNING_OBJECT (camera,
       
  2396             "can't use set element until next video bin NULL to READY state change");
       
  2397       }
       
  2398       gst_camerabin_video_set_audio_src (GST_CAMERABIN_VIDEO (camera->vidbin),
       
  2399           g_value_get_object (value));
       
  2400       break;
       
  2401     case ARG_FILTER_CAPS:
       
  2402       GST_OBJECT_LOCK (camera);
       
  2403       if (camera->view_finder_caps) {
       
  2404         gst_caps_unref (camera->view_finder_caps);
       
  2405       }
       
  2406       camera->view_finder_caps = gst_caps_copy (gst_value_get_caps (value));
       
  2407       GST_OBJECT_UNLOCK (camera);
       
  2408       gst_camerabin_set_capsfilter_caps (camera, camera->view_finder_caps);
       
  2409       break;
       
  2410     default:
       
  2411       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  2412       break;
       
  2413   }
       
  2414 }
       
  2415 
       
  2416 static void
       
  2417 gst_camerabin_get_property (GObject * object, guint prop_id,
       
  2418     GValue * value, GParamSpec * pspec)
       
  2419 {
       
  2420   GstCameraBin *camera = GST_CAMERABIN (object);
       
  2421 
       
  2422   switch (prop_id) {
       
  2423     case ARG_FILENAME:
       
  2424       g_value_set_string (value, camera->filename->str);
       
  2425       break;
       
  2426     case ARG_MODE:
       
  2427       g_value_set_enum (value, camera->mode);
       
  2428       break;
       
  2429     case ARG_MUTE:
       
  2430       g_value_set_boolean (value,
       
  2431           gst_camerabin_video_get_mute (GST_CAMERABIN_VIDEO (camera->vidbin)));
       
  2432       break;
       
  2433     case ARG_ZOOM:
       
  2434       g_value_set_int (value, g_atomic_int_get (&camera->zoom));
       
  2435       break;
       
  2436     case ARG_IMAGE_POST:
       
  2437       g_value_set_object (value,
       
  2438           gst_camerabin_image_get_postproc (GST_CAMERABIN_IMAGE
       
  2439               (camera->imgbin)));
       
  2440       break;
       
  2441     case ARG_IMAGE_ENC:
       
  2442       g_value_set_object (value,
       
  2443           gst_camerabin_image_get_encoder (GST_CAMERABIN_IMAGE
       
  2444               (camera->imgbin)));
       
  2445       break;
       
  2446     case ARG_VIDEO_POST:
       
  2447       g_value_set_object (value,
       
  2448           gst_camerabin_video_get_post (GST_CAMERABIN_VIDEO (camera->vidbin)));
       
  2449       break;
       
  2450     case ARG_VIDEO_ENC:
       
  2451       g_value_set_object (value,
       
  2452           gst_camerabin_video_get_video_enc (GST_CAMERABIN_VIDEO
       
  2453               (camera->vidbin)));
       
  2454       break;
       
  2455     case ARG_AUDIO_ENC:
       
  2456       g_value_set_object (value,
       
  2457           gst_camerabin_video_get_audio_enc (GST_CAMERABIN_VIDEO
       
  2458               (camera->vidbin)));
       
  2459       break;
       
  2460     case ARG_VIDEO_MUX:
       
  2461       g_value_set_object (value,
       
  2462           gst_camerabin_video_get_muxer (GST_CAMERABIN_VIDEO (camera->vidbin)));
       
  2463       break;
       
  2464     case ARG_VF_SINK:
       
  2465       g_value_set_object (value, camera->user_vf_sink);
       
  2466       break;
       
  2467     case ARG_VIDEO_SRC:
       
  2468       g_value_set_object (value, camera->src_vid_src);
       
  2469       break;
       
  2470     case ARG_AUDIO_SRC:
       
  2471       g_value_set_object (value,
       
  2472           gst_camerabin_video_get_audio_src (GST_CAMERABIN_VIDEO
       
  2473               (camera->vidbin)));
       
  2474       break;
       
  2475     case ARG_INPUT_CAPS:
       
  2476       gst_value_set_caps (value, gst_camerabin_get_allowed_input_caps (camera));
       
  2477       break;
       
  2478     case ARG_FILTER_CAPS:
       
  2479       gst_value_set_caps (value, camera->view_finder_caps);
       
  2480       break;
       
  2481     default:
       
  2482       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  2483       break;
       
  2484   }
       
  2485 }
       
  2486 
       
  2487 /*
       
  2488  * GstElement functions implementation
       
  2489  */
       
  2490 
       
  2491 static GstStateChangeReturn
       
  2492 gst_camerabin_change_state (GstElement * element, GstStateChange transition)
       
  2493 {
       
  2494   GstCameraBin *camera = GST_CAMERABIN (element);
       
  2495   GstStateChangeReturn ret;
       
  2496 
       
  2497   switch (transition) {
       
  2498     case GST_STATE_CHANGE_NULL_TO_READY:
       
  2499       if (!camerabin_create_elements (camera)) {
       
  2500         ret = GST_STATE_CHANGE_FAILURE;
       
  2501         goto done;
       
  2502       }
       
  2503       /* Lock to control image and video bin state separately
       
  2504          from view finder */
       
  2505       gst_element_set_locked_state (camera->imgbin, TRUE);
       
  2506       gst_element_set_locked_state (camera->vidbin, TRUE);
       
  2507       break;
       
  2508     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  2509       camerabin_setup_src_elements (camera);
       
  2510       break;
       
  2511     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
  2512       /* If using autovideosink, set view finder sink properties
       
  2513          now that actual sink has been created. */
       
  2514       camerabin_setup_view_elements (camera);
       
  2515       break;
       
  2516     case GST_STATE_CHANGE_READY_TO_NULL:
       
  2517       gst_element_set_locked_state (camera->imgbin, FALSE);
       
  2518       gst_element_set_locked_state (camera->vidbin, FALSE);
       
  2519       break;
       
  2520     default:
       
  2521       break;
       
  2522   }
       
  2523 
       
  2524   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
  2525 
       
  2526   switch (transition) {
       
  2527     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  2528       GST_LOG_OBJECT (camera, "PAUSED to READY");
       
  2529       g_mutex_lock (camera->capture_mutex);
       
  2530       if (camera->capturing) {
       
  2531         GST_WARNING_OBJECT (camera, "was capturing when changing to READY");
       
  2532         camera->capturing = FALSE;
       
  2533         /* Reset capture and don't wait for capturing to finish properly.
       
  2534            Proper capturing should have been finished before going to READY. */
       
  2535         gst_camerabin_reset_to_view_finder (camera);
       
  2536         g_cond_signal (camera->cond);
       
  2537       }
       
  2538       g_mutex_unlock (camera->capture_mutex);
       
  2539       break;
       
  2540     case GST_STATE_CHANGE_READY_TO_NULL:
       
  2541       camerabin_destroy_elements (camera);
       
  2542       break;
       
  2543     default:
       
  2544       break;
       
  2545   }
       
  2546 
       
  2547 done:
       
  2548 
       
  2549   return ret;
       
  2550 }
       
  2551 
       
  2552 /*
       
  2553  * GstBin functions implementation
       
  2554  */
       
  2555 
       
  2556 /* Peek eos messages but don't interfere with bin msg handling */
       
  2557 static void
       
  2558 gst_camerabin_handle_message_func (GstBin * bin, GstMessage * msg)
       
  2559 {
       
  2560   GstCameraBin *camera = GST_CAMERABIN (bin);
       
  2561 
       
  2562   switch (GST_MESSAGE_TYPE (msg)) {
       
  2563     case GST_MESSAGE_EOS:
       
  2564       if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->vidbin)) {
       
  2565         /* Video eos */
       
  2566         GST_DEBUG_OBJECT (camera,
       
  2567             "got video eos message, stopping video capture");
       
  2568         g_mutex_lock (camera->capture_mutex);
       
  2569         camera->capturing = FALSE;
       
  2570         g_cond_signal (camera->cond);
       
  2571         g_mutex_unlock (camera->capture_mutex);
       
  2572       } else if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->imgbin)) {
       
  2573         /* Image eos */
       
  2574         GST_DEBUG_OBJECT (camera, "got image eos message");
       
  2575         /* Unblock pad to process next buffer */
       
  2576         gst_pad_set_blocked_async (camera->pad_src_img, FALSE,
       
  2577             (GstPadBlockCallback) image_pad_blocked, camera);
       
  2578       }
       
  2579       break;
       
  2580     default:
       
  2581       break;
       
  2582   }
       
  2583   GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
       
  2584 }
       
  2585 
       
  2586 /*
       
  2587  * Action signal function implementation
       
  2588  */
       
  2589 
       
  2590 static void
       
  2591 gst_camerabin_user_start (GstCameraBin * camera)
       
  2592 {
       
  2593 
       
  2594   GST_INFO_OBJECT (camera, "starting capture");
       
  2595   if (camera->paused) {
       
  2596     gst_camerabin_user_pause (camera);
       
  2597     return;
       
  2598   }
       
  2599 
       
  2600   if (!camera->active_bin) {
       
  2601     GST_INFO_OBJECT (camera, "mode not explicitly set by application");
       
  2602     gst_camerabin_change_mode (camera, camera->mode);
       
  2603   }
       
  2604 
       
  2605   if (g_str_equal (camera->filename->str, "")) {
       
  2606     GST_ELEMENT_ERROR (camera, CORE, FAILED,
       
  2607         ("set filename before starting capture"), (NULL));
       
  2608     return;
       
  2609   }
       
  2610 
       
  2611   g_mutex_lock (camera->capture_mutex);
       
  2612   if (camera->capturing) {
       
  2613     GST_WARNING_OBJECT (camera, "capturing \"%s\" ongoing, set new filename",
       
  2614         camera->filename->str);
       
  2615     g_mutex_unlock (camera->capture_mutex);
       
  2616     return;
       
  2617   }
       
  2618   g_mutex_unlock (camera->capture_mutex);
       
  2619 
       
  2620   g_object_set (G_OBJECT (camera->active_bin), "filename",
       
  2621       camera->filename->str, NULL);
       
  2622 
       
  2623   if (camera->active_bin == camera->imgbin) {
       
  2624     gst_camerabin_start_image_capture (camera);
       
  2625   } else if (camera->active_bin == camera->vidbin) {
       
  2626     gst_camerabin_start_video_recording (camera);
       
  2627   }
       
  2628 }
       
  2629 
       
  2630 static void
       
  2631 gst_camerabin_user_stop (GstCameraBin * camera)
       
  2632 {
       
  2633   GST_INFO_OBJECT (camera, "stopping %s capture",
       
  2634       camera->mode ? "video" : "image");
       
  2635   gst_camerabin_do_stop (camera);
       
  2636   gst_camerabin_reset_to_view_finder (camera);
       
  2637 }
       
  2638 
       
  2639 static void
       
  2640 gst_camerabin_user_pause (GstCameraBin * camera)
       
  2641 {
       
  2642   if (camera->active_bin == camera->vidbin) {
       
  2643     if (!camera->paused) {
       
  2644       GST_INFO_OBJECT (camera, "pausing capture");
       
  2645 
       
  2646       /* Bring all camerabin elements to PAUSED */
       
  2647       gst_element_set_locked_state (camera->vidbin, FALSE);
       
  2648       gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
       
  2649 
       
  2650       /* Switch to view finder mode */
       
  2651       g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", FALSE,
       
  2652           "active-pad", camera->pad_src_view, NULL);
       
  2653 
       
  2654       /* Enable view finder mode in v4l2camsrc */
       
  2655       if (g_object_class_find_property (G_OBJECT_GET_CLASS
       
  2656               (camera->src_vid_src), "capture-mode")) {
       
  2657         g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 0, NULL);
       
  2658       }
       
  2659 
       
  2660       /* Set view finder to PLAYING and leave videobin PAUSED */
       
  2661       gst_element_set_locked_state (camera->vidbin, TRUE);
       
  2662       gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING);
       
  2663 
       
  2664       camera->paused = TRUE;
       
  2665     } else {
       
  2666       GST_INFO_OBJECT (camera, "unpausing capture");
       
  2667 
       
  2668       /* Bring all camerabin elements to PAUSED */
       
  2669       gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
       
  2670 
       
  2671       /* Switch to video recording mode */
       
  2672       g_object_set (G_OBJECT (camera->src_out_sel), "resend-latest", TRUE,
       
  2673           "active-pad", camera->pad_src_vid, NULL);
       
  2674 
       
  2675       /* Enable video recording mode in v4l2camsrc */
       
  2676       if (g_object_class_find_property (G_OBJECT_GET_CLASS
       
  2677               (camera->src_vid_src), "capture-mode")) {
       
  2678         g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL);
       
  2679       }
       
  2680 
       
  2681       /* Bring all camerabin elements to PLAYING */
       
  2682       gst_element_set_locked_state (camera->vidbin, FALSE);
       
  2683       gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING);
       
  2684       gst_element_set_locked_state (camera->vidbin, TRUE);
       
  2685 
       
  2686       camera->paused = FALSE;
       
  2687     }
       
  2688     GST_DEBUG_OBJECT (camera, "pause done");
       
  2689   } else {
       
  2690     GST_WARNING ("pausing in image capture mode disabled");
       
  2691   }
       
  2692 }
       
  2693 
       
  2694 static void
       
  2695 gst_camerabin_user_res_fps (GstCameraBin * camera, gint width, gint height,
       
  2696     gint fps_n, gint fps_d)
       
  2697 {
       
  2698   GstState state;
       
  2699 
       
  2700   GST_INFO_OBJECT (camera, "switching resolution to %dx%d and fps to %d/%d",
       
  2701       width, height, fps_n, fps_d);
       
  2702 
       
  2703   state = GST_STATE (camera);
       
  2704   gst_element_set_state (GST_ELEMENT (camera), GST_STATE_READY);
       
  2705   camera->width = width;
       
  2706   camera->height = height;
       
  2707   camera->fps_n = fps_n;
       
  2708   camera->fps_d = fps_d;
       
  2709   gst_element_set_state (GST_ELEMENT (camera), state);
       
  2710 }
       
  2711 
       
  2712 static void
       
  2713 gst_camerabin_user_image_res (GstCameraBin * camera, gint width, gint height)
       
  2714 {
       
  2715   GstStructure *structure;
       
  2716   GstCaps *new_caps = NULL;
       
  2717   guint32 format = 0;
       
  2718 
       
  2719   g_return_if_fail (camera != NULL);
       
  2720 
       
  2721   if (width && height && camera->view_finder_caps) {
       
  2722     /* Use view finder mode caps as a basis */
       
  2723     structure = gst_caps_get_structure (camera->view_finder_caps, 0);
       
  2724 
       
  2725     /* Set new resolution for image capture */
       
  2726     new_caps = gst_caps_new_simple (gst_structure_get_name (structure),
       
  2727         "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
       
  2728 
       
  2729     /* Set format according to current videosrc format */
       
  2730     format = get_srcpad_current_format (camera->src_vid_src);
       
  2731     if (format) {
       
  2732       gst_caps_set_simple (new_caps, "format", GST_TYPE_FOURCC, format, NULL);
       
  2733     }
       
  2734 
       
  2735     /* Set allowed framerate for the resolution. */
       
  2736     gst_camerabin_set_allowed_framerate (camera, new_caps);
       
  2737 
       
  2738     /* Reset the format to match with view finder mode caps */
       
  2739     if (gst_structure_get_fourcc (structure, "format", &format)) {
       
  2740       gst_caps_set_simple (new_caps, "format", GST_TYPE_FOURCC, format, NULL);
       
  2741     }
       
  2742   }
       
  2743 
       
  2744   GST_INFO_OBJECT (camera,
       
  2745       "init filter caps for image capture %" GST_PTR_FORMAT, new_caps);
       
  2746   gst_caps_replace (&camera->image_capture_caps, new_caps);
       
  2747 }
       
  2748 
       
  2749 /* entry point to initialize the plug-in
       
  2750  * initialize the plug-in itself
       
  2751  * register the element factories and pad templates
       
  2752  * register the features
       
  2753  */
       
  2754 static gboolean
       
  2755 plugin_init (GstPlugin * plugin)
       
  2756 {
       
  2757   GST_DEBUG_CATEGORY_INIT (gst_camerabin_debug, "camerabin", 0, "CameraBin");
       
  2758 
       
  2759   return gst_element_register (plugin, "camerabin",
       
  2760       GST_RANK_NONE, GST_TYPE_CAMERABIN);
       
  2761 }
       
  2762 
       
  2763 /* this is the structure that gstreamer looks for to register plugins
       
  2764  */
       
  2765 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
  2766     GST_VERSION_MINOR,
       
  2767     "camerabin",
       
  2768     "High level api for DC (Digital Camera) application",
       
  2769     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)