camerabin2: examples: Add video-device argument
[gstreamer-omap:gst-plugins-bad.git] / tests / examples / camerabin2 / gst-camerabin2-test.c
1 /*
2  * GStreamer
3  * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
4  * Copyright (C) 2011 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22  /*
23     TODO review
24     Examples:
25     ./gst-camerabin2-test --image-width=2048 --image-height=1536
26     ./gst-camerabin2-test --mode=2 --capture-time=10 --image-width=848 --image-height=480 --view-framerate-num=2825 \
27     --view-framerate-den=100
28
29     gst-camerabin2-test --help
30     Usage:
31     gst-camerabin2-test [OPTION...]
32
33     camerabin command line test application.
34
35     Help Options:
36     -h, --help                        Show help options
37     --help-all                        Show all help options
38     --help-gst                        Show GStreamer Options
39
40     Application Options:
41     --ev-compensation                 EV compensation (-2.5..2.5, default = 0)
42     --aperture                        Aperture (size of lens opening, default = 0 (auto))
43     --flash-mode                      Flash mode (default = 0 (auto))
44     --scene-mode                      Scene mode (default = 6 (auto))
45     --exposure                        Exposure (default = 0 (auto))
46     --iso-speed                       ISO speed (default = 0 (auto))
47     --white-balance-mode              White balance mode (default = 0 (auto))
48     --colour-tone-mode                Colour tone mode (default = 0 (auto))
49     --directory                       Directory for capture file(s) (default is current directory)
50     --mode                            Capture mode (default = 0 (image), 1 = video)
51     --capture-time                    Time to capture video in seconds (default = 10)
52     --capture-total                   Total number of captures to be done (default = 1)
53     --zoom                            Zoom (100 = 1x (default), 200 = 2x etc.)
54     --wrapper-source                  Camera source wrapper used for setting the video source
55     --video-source                    Video source used in still capture and video recording
56     --video-device                    Video device to be set on the video source (e.g. /dev/video0)
57     --audio-source                    Audio source used in video recording
58     --image-pp                        List of image post-processing elements separated with comma
59     --viewfinder-sink                 Viewfinder sink (default = fakesink)
60     --image-width                     Width for capture (only used if the caps
61     arguments aren't set)
62     --image-height                    Height for capture (only used if the caps
63     arguments aren't set)
64     --view-framerate-num              Framerate numerator for viewfinder
65     --view-framerate-den              Framerate denominator for viewfinder
66     --preview-caps                    Preview caps (e.g. video/x-raw-rgb,width=320,height=240)
67     --viewfinder-filter               Filter to process all frames going to viewfinder sink
68     --x-width                         X window width (default = 320)
69     --x-height                        X window height (default = 240)
70     --no-xwindow                      Do not create XWindow
71     --encoding-target                 Video encoding target name
72     --encoding-profile                Video encoding profile name
73     --encoding-profile-filename       Video encoding profile filename
74     --image-capture-caps              Image capture caps (e.g. video/x-raw-rgb,width=640,height=480)
75     --viewfinder-caps                 Viewfinder caps (e.g. video/x-raw-rgb,width=640,height=480)
76     --video-capture-caps              Video capture caps (e.g. video/x-raw-rgb,width=640,height=480)
77
78   */
79
80 /*
81  * Includes
82  */
83 #ifdef HAVE_CONFIG_H
84 #  include "config.h"
85 #endif
86
87 #define GST_USE_UNSTABLE_API 1
88
89 #include <gst/gst.h>
90 #include <gst/interfaces/xoverlay.h>
91 #include <gst/interfaces/photography.h>
92 #include <string.h>
93 #include <sys/time.h>
94 #include <time.h>
95 #include <unistd.h>
96 #include <stdlib.h>
97 #include <glib.h>
98 #include <glib/gstdio.h>
99 #include <gst/pbutils/encoding-profile.h>
100 #include <gst/pbutils/encoding-target.h>
101 #include <X11/Xlib.h>
102 #include <X11/Xatom.h>
103 /*
104  * debug logging
105  */
106 GST_DEBUG_CATEGORY_STATIC (camerabin_test);
107 #define GST_CAT_DEFAULT camerabin_test
108 typedef struct _ResultType
109 {
110   GstClockTime avg;
111   GstClockTime min;
112   GstClockTime max;
113   guint32 times;
114 } ResultType;
115
116 /*
117  * Global vars
118  */
119 static GstElement *camerabin = NULL;
120 static GMainLoop *loop = NULL;
121
122 /* commandline options */
123 static gchar *videosrc_name = NULL;
124 static gchar *videodevice_name = NULL;
125 static gchar *audiosrc_name = NULL;
126 static gchar *wrappersrc_name = NULL;
127 static gchar *imagepp_name = NULL;
128 static gchar *vfsink_name = NULL;
129 static gint image_width = 0;
130 static gint image_height = 0;
131 static gint view_framerate_num = 0;
132 static gint view_framerate_den = 0;
133 static gboolean no_xwindow = FALSE;
134 static gchar *gep_targetname = NULL;
135 static gchar *gep_profilename = NULL;
136 static gchar *gep_filename = NULL;
137 static gchar *image_capture_caps_str = NULL;
138 static gchar *viewfinder_caps_str = NULL;
139 static gchar *video_capture_caps_str = NULL;
140
141
142 #define MODE_VIDEO 2
143 #define MODE_IMAGE 1
144 static gint mode = MODE_IMAGE;
145 static gint zoom = 100;
146
147 static gint capture_time = 10;
148 static gint capture_count = 0;
149 static gint capture_total = 1;
150 static gulong stop_capture_cb_id = 0;
151
152 /* photography interface command line options */
153 #define EV_COMPENSATION_NONE -G_MAXFLOAT
154 #define APERTURE_NONE -G_MAXINT
155 #define FLASH_MODE_NONE -G_MAXINT
156 #define SCENE_MODE_NONE -G_MAXINT
157 #define EXPOSURE_NONE -G_MAXINT64
158 #define ISO_SPEED_NONE -G_MAXINT
159 #define WHITE_BALANCE_MODE_NONE -G_MAXINT
160 #define COLOR_TONE_MODE_NONE -G_MAXINT
161 static gfloat ev_compensation = EV_COMPENSATION_NONE;
162 static gint aperture = APERTURE_NONE;
163 static gint flash_mode = FLASH_MODE_NONE;
164 static gint scene_mode = SCENE_MODE_NONE;
165 static gint64 exposure = EXPOSURE_NONE;
166 static gint iso_speed = ISO_SPEED_NONE;
167 static gint wb_mode = WHITE_BALANCE_MODE_NONE;
168 static gint color_mode = COLOR_TONE_MODE_NONE;
169
170 static gchar *viewfinder_filter = NULL;
171
172 static int x_width = 320;
173 static int x_height = 240;
174
175 /* test configuration for common callbacks */
176 static GString *filename = NULL;
177
178 static gchar *preview_caps_name = NULL;
179
180 /* X window variables */
181 static Display *display = NULL;
182 static Window window = 0;
183
184 GTimer *timer = NULL;
185
186 /*
187  * Prototypes
188  */
189 static gboolean run_pipeline (gpointer user_data);
190 static void set_metadata (GstElement * camera);
191
192 static void
193 create_host_window (void)
194 {
195   unsigned long valuemask;
196   XSetWindowAttributes attributes;
197
198   display = XOpenDisplay (NULL);
199   if (display) {
200     window =
201         XCreateSimpleWindow (display, DefaultRootWindow (display), 0, 0,
202         x_width, x_height, 0, 0, 0);
203     if (window) {
204       valuemask = CWOverrideRedirect;
205       attributes.override_redirect = True;
206       XChangeWindowAttributes (display, window, valuemask, &attributes);
207       XSetWindowBackgroundPixmap (display, window, None);
208       XMapRaised (display, window);
209       XSync (display, FALSE);
210     } else {
211       GST_DEBUG ("could not create X window!");
212     }
213   } else {
214     GST_DEBUG ("could not open display!");
215   }
216 }
217
218 static GstBusSyncReply
219 sync_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
220 {
221   const GstStructure *st;
222   const GValue *image;
223   GstBuffer *buf = NULL;
224   guint8 *data_buf = NULL;
225   gchar *caps_string;
226   guint size = 0;
227   gchar *preview_filename = NULL;
228   FILE *f = NULL;
229   size_t written;
230
231   switch (GST_MESSAGE_TYPE (message)) {
232     case GST_MESSAGE_ELEMENT:{
233       st = gst_message_get_structure (message);
234       if (st) {
235         if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
236           if (!no_xwindow && window) {
237             gst_x_overlay_set_window_handle (GST_X_OVERLAY (GST_MESSAGE_SRC
238                     (message)), window);
239             gst_message_unref (message);
240             message = NULL;
241             return GST_BUS_DROP;
242           }
243         } else if (gst_structure_has_name (st, "preview-image")) {
244           GST_DEBUG ("preview-image");
245           /* extract preview-image from msg */
246           image = gst_structure_get_value (st, "buffer");
247           if (image) {
248             buf = gst_value_get_buffer (image);
249             data_buf = GST_BUFFER_DATA (buf);
250             size = GST_BUFFER_SIZE (buf);
251             preview_filename = g_strdup_printf ("test_vga.rgb");
252             caps_string = gst_caps_to_string (GST_BUFFER_CAPS (buf));
253             g_print ("writing buffer to %s, elapsed: %.2fs, buffer caps: %s\n",
254                 preview_filename, g_timer_elapsed (timer, NULL), caps_string);
255             g_free (caps_string);
256             f = g_fopen (preview_filename, "w");
257             if (f) {
258               written = fwrite (data_buf, size, 1, f);
259               if (!written) {
260                 g_print ("error writing file\n");
261               }
262               fclose (f);
263             } else {
264               g_print ("error opening file for raw image writing\n");
265             }
266             g_free (preview_filename);
267           }
268         }
269       }
270       break;
271     }
272     default:
273       /* unhandled message */
274       break;
275   }
276   return GST_BUS_PASS;
277 }
278
279 static gboolean
280 bus_callback (GstBus * bus, GstMessage * message, gpointer data)
281 {
282   switch (GST_MESSAGE_TYPE (message)) {
283     case GST_MESSAGE_ERROR:{
284       GError *err;
285       gchar *debug;
286
287       gst_message_parse_error (message, &err, &debug);
288       g_print ("Error: %s\n", err->message);
289       g_error_free (err);
290       g_free (debug);
291
292       /* Write debug graph to file */
293       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camerabin),
294           GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
295
296       g_main_loop_quit (loop);
297       break;
298     }
299     case GST_MESSAGE_STATE_CHANGED:
300       if (GST_IS_BIN (GST_MESSAGE_SRC (message))) {
301         GstState oldstate, newstate;
302
303         gst_message_parse_state_changed (message, &oldstate, &newstate, NULL);
304         GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-changed: %s -> %s",
305             gst_element_state_get_name (oldstate),
306             gst_element_state_get_name (newstate));
307       }
308       break;
309     case GST_MESSAGE_EOS:
310       /* end-of-stream */
311       GST_INFO ("got eos() - should not happen");
312       g_main_loop_quit (loop);
313       break;
314     case GST_MESSAGE_ELEMENT:
315       if (GST_MESSAGE_SRC (message) == (GstObject *) camerabin) {
316         const GstStructure *structure = gst_message_get_structure (message);
317
318         if (gst_structure_has_name (structure, "image-done")) {
319 #ifndef GST_DISABLE_GST_DEBUG
320           const gchar *fname = gst_structure_get_string (structure, "filename");
321
322           GST_DEBUG ("image done: %s", fname);
323 #endif
324           if (capture_count < capture_total) {
325             g_idle_add ((GSourceFunc) run_pipeline, NULL);
326           } else {
327             g_main_loop_quit (loop);
328           }
329         }
330       }
331       break;
332     default:
333       /* unhandled message */
334       break;
335   }
336   return TRUE;
337 }
338
339 /*
340  * Helpers
341  */
342
343 static void
344 cleanup_pipeline (void)
345 {
346   if (camerabin) {
347     GST_INFO_OBJECT (camerabin, "stopping and destroying");
348     gst_element_set_state (camerabin, GST_STATE_NULL);
349     gst_object_unref (camerabin);
350     camerabin = NULL;
351   }
352 }
353
354 static GstElement *
355 create_ipp_bin (void)
356 {
357   GstElement *bin = NULL, *element = NULL;
358   GstPad *pad = NULL;
359   gchar **elements;
360   GList *element_list = NULL, *current = NULL, *next = NULL;
361   int i;
362
363   bin = gst_bin_new ("ippbin");
364
365   elements = g_strsplit (imagepp_name, ",", 0);
366
367   for (i = 0; elements[i] != NULL; i++) {
368     element = gst_element_factory_make (elements[i], NULL);
369     if (element) {
370       element_list = g_list_append (element_list, element);
371       gst_bin_add (GST_BIN (bin), element);
372     } else
373       GST_WARNING ("Could create element %s for ippbin", elements[i]);
374   }
375
376   for (i = 1; i < g_list_length (element_list); i++) {
377     current = g_list_nth (element_list, i - 1);
378     next = g_list_nth (element_list, i);
379     gst_element_link (current->data, next->data);
380   }
381
382   current = g_list_first (element_list);
383   pad = gst_element_get_static_pad (current->data, "sink");
384   gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
385   gst_object_unref (GST_OBJECT (pad));
386
387   current = g_list_last (element_list);
388   pad = gst_element_get_static_pad (current->data, "src");
389   gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
390   gst_object_unref (GST_OBJECT (pad));
391
392   g_list_free (element_list);
393   g_strfreev (elements);
394
395   return bin;
396 }
397
398 static GstEncodingProfile *
399 load_encoding_profile (void)
400 {
401   GstEncodingProfile *prof = NULL;
402   GstEncodingTarget *target = NULL;
403   GError *error = NULL;
404
405   /* if profile file was given, try to load profile from there */
406   if (gep_filename && gep_profilename) {
407     target = gst_encoding_target_load_from_file (gep_filename, &error);
408     if (!target) {
409       GST_WARNING ("Could not load target %s from file %s", gep_targetname,
410           gep_filename);
411       if (error) {
412         GST_WARNING ("Error from file loading: %s", error->message);
413         g_error_free (error);
414         error = NULL;
415       }
416     } else {
417       prof = gst_encoding_target_get_profile (target, gep_profilename);
418       if (prof)
419         GST_DEBUG ("Loaded encoding profile %s from %s", gep_profilename,
420             gep_filename);
421       else
422         GST_WARNING
423             ("Could not load specified encoding profile %s from file %s",
424             gep_profilename, gep_filename);
425     }
426     /* if we could not load profile from file then try to find one from system */
427   } else if (gep_profilename && gep_targetname) {
428     prof = gst_encoding_profile_find (gep_targetname, gep_profilename, NULL);
429     if (prof)
430       GST_DEBUG ("Loaded encoding profile %s from target %s", gep_profilename,
431           gep_targetname);
432   } else
433     GST_DEBUG
434         ("Encoding profile not set, using camerabin2 default encoding profile");
435
436   return prof;
437 }
438
439 static gboolean
440 setup_pipeline_element (GstElement * element, const gchar * property_name,
441     const gchar * element_name, GstElement ** res_elem)
442 {
443   gboolean res = TRUE;
444   GstElement *elem = NULL;
445
446   if (element_name) {
447     GError *error = NULL;
448
449     elem = gst_parse_launch (element_name, &error);
450     if (elem) {
451       g_object_set (element, property_name, elem, NULL);
452     } else {
453       GST_WARNING ("can't create element '%s' for property '%s'", element_name,
454           property_name);
455       if (error) {
456         GST_ERROR ("%s", error->message);
457         g_error_free (error);
458       }
459       res = FALSE;
460     }
461   } else {
462     GST_DEBUG ("no element for property '%s' given", property_name);
463   }
464   if (res_elem)
465     *res_elem = elem;
466   return res;
467 }
468
469 static void
470 set_camerabin2_caps_from_string (void)
471 {
472   GstCaps *caps = NULL;
473   if (image_capture_caps_str != NULL) {
474     caps = gst_caps_from_string (image_capture_caps_str);
475     if (GST_CAPS_IS_SIMPLE (caps) && image_width > 0 && image_height > 0) {
476       gst_caps_set_simple (caps, "width", G_TYPE_INT, image_width, "height",
477           G_TYPE_INT, image_height, NULL);
478     }
479     GST_DEBUG ("setting image-capture-caps: %" GST_PTR_FORMAT, caps);
480     g_object_set (camerabin, "image-capture-caps", caps, NULL);
481     gst_caps_unref (caps);
482   }
483
484   if (viewfinder_caps_str != NULL) {
485     caps = gst_caps_from_string (viewfinder_caps_str);
486     if (GST_CAPS_IS_SIMPLE (caps) && view_framerate_num > 0
487         && view_framerate_den > 0) {
488       gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
489           view_framerate_num, view_framerate_den, NULL);
490     }
491     GST_DEBUG ("setting viewfinder-caps: %" GST_PTR_FORMAT, caps);
492     g_object_set (camerabin, "viewfinder-caps", caps, NULL);
493     gst_caps_unref (caps);
494   }
495
496   if (video_capture_caps_str != NULL) {
497     caps = gst_caps_from_string (video_capture_caps_str);
498     GST_DEBUG ("setting video-capture-caps: %" GST_PTR_FORMAT, caps);
499     g_object_set (camerabin, "video-capture-caps", caps, NULL);
500     gst_caps_unref (caps);
501   }
502 }
503
504 static gboolean
505 setup_pipeline (void)
506 {
507   gboolean res = TRUE;
508   GstBus *bus;
509   GstElement *sink = NULL, *ipp = NULL;
510   GstEncodingProfile *prof = NULL;
511   camerabin = gst_element_factory_make ("camerabin2", NULL);
512   if (NULL == camerabin) {
513     g_warning ("can't create camerabin element\n");
514     goto error;
515   }
516
517   bus = gst_pipeline_get_bus (GST_PIPELINE (camerabin));
518   /* Add sync handler for time critical messages that need to be handled fast */
519   gst_bus_set_sync_handler (bus, sync_bus_callback, NULL);
520   /* Handle normal messages asynchronously */
521   gst_bus_add_watch (bus, bus_callback, NULL);
522   gst_object_unref (bus);
523
524   GST_INFO_OBJECT (camerabin, "camerabin2 created");
525
526   if (videosrc_name) {
527     GstElement *wrapper;
528     GstElement *videosrc;
529
530     if (wrappersrc_name)
531       wrapper = gst_element_factory_make (wrappersrc_name, NULL);
532     else
533       wrapper = gst_element_factory_make ("wrappercamerabinsrc", NULL);
534
535     if (setup_pipeline_element (wrapper, "video-src", videosrc_name, NULL)) {
536       g_object_set (camerabin, "camera-src", wrapper, NULL);
537     } else {
538       GST_WARNING ("Failed to set videosrc to %s", videosrc_name);
539     }
540
541     g_object_get (wrapper, "video-src", &videosrc, NULL);
542     if (videosrc && videodevice_name &&
543         g_object_class_find_property (G_OBJECT_GET_CLASS (videosrc),
544             "device")) {
545       g_object_set (videosrc, "device", videodevice_name, NULL);
546     }
547   }
548
549   /* configure used elements */
550   res &= setup_pipeline_element (camerabin, "audio-src", audiosrc_name, NULL);
551   res &= setup_pipeline_element (camerabin, "viewfinder-sink", vfsink_name,
552       &sink);
553   res &= setup_pipeline_element (camerabin, "viewfinder-filter",
554       viewfinder_filter, NULL);
555
556   if (imagepp_name) {
557     ipp = create_ipp_bin ();
558     if (ipp)
559       g_object_set (camerabin, "image-filter", ipp, NULL);
560     else
561       GST_WARNING ("Could not create ipp elements");
562   }
563
564   prof = load_encoding_profile ();
565   if (prof)
566     g_object_set (G_OBJECT (camerabin), "video-profile", prof, NULL);
567
568   GST_INFO_OBJECT (camerabin, "elements created");
569
570   if (sink)
571     g_object_set (sink, "sync", TRUE, NULL);
572
573   GST_INFO_OBJECT (camerabin, "elements configured");
574
575   /* configure a resolution and framerate */
576   if (image_width > 0 && image_height > 0) {
577     if (mode == MODE_VIDEO) {
578       GstCaps *caps = NULL;
579       if (view_framerate_num > 0)
580         caps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
581                 "width", G_TYPE_INT, image_width,
582                 "height", G_TYPE_INT, image_height,
583                 "framerate", GST_TYPE_FRACTION, view_framerate_num,
584                 view_framerate_den, NULL),
585             gst_structure_new ("video/x-raw-rgb",
586                 "width", G_TYPE_INT, image_width,
587                 "height", G_TYPE_INT, image_height,
588                 "framerate", GST_TYPE_FRACTION, view_framerate_num,
589                 view_framerate_den, NULL), NULL);
590       else
591         caps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
592                 "width", G_TYPE_INT, image_width,
593                 "height", G_TYPE_INT, image_height, NULL),
594             gst_structure_new ("video/x-raw-rgb",
595                 "width", G_TYPE_INT, image_width,
596                 "height", G_TYPE_INT, image_height, NULL), NULL);
597
598       g_object_set (camerabin, "video-capture-caps", caps, NULL);
599       gst_caps_unref (caps);
600     } else {
601       GstCaps *caps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
602               "width", G_TYPE_INT, image_width,
603               "height", G_TYPE_INT, image_height, NULL),
604           gst_structure_new ("video/x-raw-rgb",
605               "width", G_TYPE_INT, image_width,
606               "height", G_TYPE_INT, image_height, NULL), NULL);
607
608       g_object_set (camerabin, "image-capture-caps", caps, NULL);
609       gst_caps_unref (caps);
610     }
611   }
612
613   set_camerabin2_caps_from_string ();
614
615   if (GST_STATE_CHANGE_FAILURE ==
616       gst_element_set_state (camerabin, GST_STATE_READY)) {
617     g_warning ("can't set camerabin to ready\n");
618     goto error;
619   }
620   GST_INFO_OBJECT (camerabin, "camera ready");
621
622   if (GST_STATE_CHANGE_FAILURE ==
623       gst_element_set_state (camerabin, GST_STATE_PLAYING)) {
624     g_warning ("can't set camerabin to playing\n");
625     goto error;
626   }
627
628   GST_INFO_OBJECT (camerabin, "camera started");
629   return TRUE;
630 error:
631   cleanup_pipeline ();
632   return FALSE;
633 }
634
635 static void
636 stop_capture_cb (GObject * self, GParamSpec * pspec, gpointer user_data)
637 {
638   gboolean idle = FALSE;
639
640   g_object_get (camerabin, "idle", &idle, NULL);
641
642   if (idle) {
643     if (capture_count < capture_total) {
644       g_idle_add ((GSourceFunc) run_pipeline, NULL);
645     } else {
646       g_main_loop_quit (loop);
647     }
648   }
649
650   g_signal_handler_disconnect (camerabin, stop_capture_cb_id);
651 }
652
653 static gboolean
654 stop_capture (gpointer user_data)
655 {
656   stop_capture_cb_id = g_signal_connect (camerabin, "notify::idle",
657       (GCallback) stop_capture_cb, camerabin);
658   g_signal_emit_by_name (camerabin, "stop-capture", 0);
659   return FALSE;
660 }
661
662 static void
663 set_metadata (GstElement * camera)
664 {
665   GstTagSetter *setter = GST_TAG_SETTER (camera);
666   GTimeVal time = { 0, 0 };
667   gchar *desc_str;
668   GDate *date = g_date_new ();
669
670   g_get_current_time (&time);
671   g_date_set_time_val (date, &time);
672
673   desc_str = g_strdup_printf ("captured by %s", g_get_real_name ());
674
675   gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
676       GST_TAG_DATE, date,
677       GST_TAG_DESCRIPTION, desc_str,
678       GST_TAG_TITLE, "gst-camerabin-test capture",
679       GST_TAG_GEO_LOCATION_LONGITUDE, 1.0,
680       GST_TAG_GEO_LOCATION_LATITUDE, 2.0,
681       GST_TAG_GEO_LOCATION_ELEVATION, 3.0,
682       GST_TAG_DEVICE_MANUFACTURER, "gst-camerabin-test manufacturer",
683       GST_TAG_DEVICE_MODEL, "gst-camerabin-test model", NULL);
684
685   g_free (desc_str);
686   g_date_free (date);
687 }
688
689 static gboolean
690 run_pipeline (gpointer user_data)
691 {
692   GstCaps *preview_caps = NULL;
693   gchar *filename_str = NULL;
694   GstElement *video_source = NULL;
695   const gchar *filename_suffix;
696
697   g_object_set (camerabin, "mode", mode, NULL);
698
699   if (preview_caps_name != NULL) {
700     preview_caps = gst_caps_from_string (preview_caps_name);
701     if (preview_caps) {
702       g_object_set (camerabin, "preview-caps", preview_caps, NULL);
703       GST_DEBUG ("Preview caps set");
704     } else
705       GST_DEBUG ("Preview caps set but could not create caps from string");
706   }
707
708   set_metadata (camerabin);
709
710   /* Construct filename */
711   if (mode == MODE_VIDEO)
712     filename_suffix = ".mp4";
713   else
714     filename_suffix = ".jpg";
715   filename_str =
716       g_strdup_printf ("%s/test_%04u%s", filename->str, capture_count,
717       filename_suffix);
718   GST_DEBUG ("Setting filename: %s", filename_str);
719   g_object_set (camerabin, "location", filename_str, NULL);
720   g_free (filename_str);
721
722   g_object_get (camerabin, "camera-src", &video_source, NULL);
723   if (video_source) {
724     if (GST_IS_ELEMENT (video_source) &&
725         gst_element_implements_interface (video_source, GST_TYPE_PHOTOGRAPHY)) {
726       /* Set GstPhotography interface options. If option not given as
727          command-line parameter use default of the source element. */
728       if (scene_mode != SCENE_MODE_NONE)
729         g_object_set (video_source, "scene-mode", scene_mode, NULL);
730       if (ev_compensation != EV_COMPENSATION_NONE)
731         g_object_set (video_source, "ev-compensation", ev_compensation, NULL);
732       if (aperture != APERTURE_NONE)
733         g_object_set (video_source, "aperture", aperture, NULL);
734       if (flash_mode != FLASH_MODE_NONE)
735         g_object_set (video_source, "flash-mode", flash_mode, NULL);
736       if (exposure != EXPOSURE_NONE)
737         g_object_set (video_source, "exposure", exposure, NULL);
738       if (iso_speed != ISO_SPEED_NONE)
739         g_object_set (video_source, "iso-speed", iso_speed, NULL);
740       if (wb_mode != WHITE_BALANCE_MODE_NONE)
741         g_object_set (video_source, "white-balance-mode", wb_mode, NULL);
742       if (color_mode != COLOR_TONE_MODE_NONE)
743         g_object_set (video_source, "colour-tone-mode", color_mode, NULL);
744     }
745     g_object_unref (video_source);
746   }
747   g_object_set (camerabin, "zoom", zoom / 100.0f, NULL);
748
749   capture_count++;
750   g_timer_start (timer);
751   g_signal_emit_by_name (camerabin, "start-capture", 0);
752
753
754   if (mode == MODE_VIDEO) {
755     g_timeout_add ((capture_time * 1000), (GSourceFunc) stop_capture, NULL);
756   }
757
758   return FALSE;
759 }
760
761 int
762 main (int argc, char *argv[])
763 {
764   gchar *target_times = NULL;
765   gchar *ev_option = NULL;
766   gchar *fn_option = NULL;
767
768   GOptionEntry options[] = {
769     {"ev-compensation", '\0', 0, G_OPTION_ARG_STRING, &ev_option,
770         "EV compensation for source element GstPhotography interface", NULL},
771     {"aperture", '\0', 0, G_OPTION_ARG_INT, &aperture,
772           "Aperture (size of lens opening) for source element GstPhotography interface",
773         NULL},
774     {"flash-mode", '\0', 0, G_OPTION_ARG_INT,
775           &flash_mode,
776         "Flash mode for source element GstPhotography interface", NULL},
777     {"scene-mode", '\0', 0, G_OPTION_ARG_INT,
778           &scene_mode,
779         "Scene mode for source element GstPhotography interface", NULL},
780     {"exposure", '\0', 0, G_OPTION_ARG_INT64,
781           &exposure,
782           "Exposure time (in ms) for source element GstPhotography interface",
783         NULL},
784     {"iso-speed", '\0', 0, G_OPTION_ARG_INT,
785           &iso_speed,
786         "ISO speed for source element GstPhotography interface", NULL},
787     {"white-balance-mode", '\0', 0, G_OPTION_ARG_INT,
788           &wb_mode,
789         "White balance mode for source element GstPhotography interface", NULL},
790     {"colour-tone-mode", '\0', 0, G_OPTION_ARG_INT,
791           &color_mode,
792         "Colour tone mode for source element GstPhotography interface", NULL},
793     {"directory", '\0', 0, G_OPTION_ARG_STRING, &fn_option,
794         "Directory for capture file(s) (default is current directory)", NULL},
795     {"mode", '\0', 0, G_OPTION_ARG_INT, &mode,
796         "Capture mode (default = 1 (image), 2 = video)", NULL},
797     {"capture-time", '\0', 0, G_OPTION_ARG_INT,
798           &capture_time,
799         "Time to capture video in seconds (default = 10)", NULL},
800     {"capture-total", '\0', 0, G_OPTION_ARG_INT, &capture_total,
801         "Total number of captures to be done (default = 1)", NULL},
802     {"zoom", '\0', 0, G_OPTION_ARG_INT, &zoom,
803         "Zoom (100 = 1x (default), 200 = 2x etc.)", NULL},
804     {"wrapper-source", '\0', 0, G_OPTION_ARG_STRING, &wrappersrc_name,
805           "Camera source wrapper used for setting the video source (default is wrappercamerabinsrc)",
806         NULL},
807     {"video-source", '\0', 0, G_OPTION_ARG_STRING, &videosrc_name,
808         "Video source used in still capture and video recording", NULL},
809     {"video-device", '\0', 0, G_OPTION_ARG_STRING, &videodevice_name,
810         "Video device to be set on the video source", NULL},
811     {"audio-source", '\0', 0, G_OPTION_ARG_STRING, &audiosrc_name,
812         "Audio source used in video recording", NULL},
813     {"image-pp", '\0', 0, G_OPTION_ARG_STRING, &imagepp_name,
814         "List of image post-processing elements separated with comma", NULL},
815     {"viewfinder-sink", '\0', 0, G_OPTION_ARG_STRING, &vfsink_name,
816         "Viewfinder sink (default = fakesink)", NULL},
817     {"image-width", '\0', 0, G_OPTION_ARG_INT, &image_width,
818         "Width for image capture", NULL},
819     {"image-height", '\0', 0, G_OPTION_ARG_INT, &image_height,
820         "Height for image capture", NULL},
821     {"view-framerate-num", '\0', 0, G_OPTION_ARG_INT, &view_framerate_num,
822         "Framerate numerator for viewfinder", NULL},
823     {"view-framerate-den", '\0', 0, G_OPTION_ARG_INT, &view_framerate_den,
824         "Framerate denominator for viewfinder", NULL},
825     {"preview-caps", '\0', 0, G_OPTION_ARG_STRING, &preview_caps_name,
826         "Preview caps (e.g. video/x-raw-rgb,width=320,height=240)", NULL},
827     {"viewfinder-filter", '\0', 0, G_OPTION_ARG_STRING, &viewfinder_filter,
828         "Filter to process all frames going to viewfinder sink", NULL},
829     {"x-width", '\0', 0, G_OPTION_ARG_INT, &x_width,
830         "X window width (default = 320)", NULL},
831     {"x-height", '\0', 0, G_OPTION_ARG_INT, &x_height,
832         "X window height (default = 240)", NULL},
833     {"no-xwindow", '\0', 0, G_OPTION_ARG_NONE, &no_xwindow,
834         "Do not create XWindow", NULL},
835     {"encoding-target", '\0', 0, G_OPTION_ARG_STRING, &gep_targetname,
836         "Video encoding target name", NULL},
837     {"encoding-profile", '\0', 0, G_OPTION_ARG_STRING, &gep_profilename,
838         "Video encoding profile name", NULL},
839     {"encoding-profile-filename", '\0', 0, G_OPTION_ARG_STRING, &gep_filename,
840         "Video encoding profile filename", NULL},
841     {"image-capture-caps", '\0', 0,
842           G_OPTION_ARG_STRING, &image_capture_caps_str,
843         "Image capture caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
844     {"viewfinder-caps", '\0', 0, G_OPTION_ARG_STRING,
845           &viewfinder_caps_str,
846         "Viewfinder caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
847     {"video-capture-caps", '\0', 0,
848           G_OPTION_ARG_STRING, &video_capture_caps_str,
849         "Video capture caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
850     {NULL}
851   };
852
853   GOptionContext *ctx;
854   GError *err = NULL;
855
856   if (!g_thread_supported ())
857     g_thread_init (NULL);
858
859   ctx = g_option_context_new ("\n\ncamerabin command line test application.");
860   g_option_context_add_main_entries (ctx, options, NULL);
861   g_option_context_add_group (ctx, gst_init_get_option_group ());
862   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
863     g_print ("Error initializing: %s\n", err->message);
864     exit (1);
865   }
866   g_option_context_free (ctx);
867
868   GST_DEBUG_CATEGORY_INIT (camerabin_test, "camerabin-test", 0,
869       "camerabin test");
870
871   /* if we fail to create xwindow should we care? */
872   if (!no_xwindow)
873     create_host_window ();
874
875   /* FIXME: error handling */
876   if (ev_option != NULL)
877     ev_compensation = strtod (ev_option, (char **) NULL);
878
879   if (vfsink_name == NULL)
880     vfsink_name = g_strdup ("fakesink");
881
882   filename = g_string_new (fn_option);
883   if (filename->len == 0)
884     filename = g_string_append (filename, ".");
885
886   timer = g_timer_new ();
887
888   /* init */
889   if (setup_pipeline ()) {
890     loop = g_main_loop_new (NULL, FALSE);
891     g_idle_add ((GSourceFunc) run_pipeline, NULL);
892     g_main_loop_run (loop);
893     cleanup_pipeline ();
894     g_main_loop_unref (loop);
895   }
896   /* free */
897   g_string_free (filename, TRUE);
898   g_free (ev_option);
899   g_free (wrappersrc_name);
900   g_free (videosrc_name);
901   g_free (videodevice_name);
902   g_free (audiosrc_name);
903   g_free (imagepp_name);
904   g_free (vfsink_name);
905   g_free (target_times);
906   g_free (gep_targetname);
907   g_free (gep_profilename);
908   g_free (gep_filename);
909   g_timer_destroy (timer);
910
911   if (window)
912     XDestroyWindow (display, window);
913
914   if (display)
915     XCloseDisplay (display);
916
917   return 0;
918 }