418b9b9f16b4fe254f13e021ed96405e770886e0
[platform/upstream/gstreamer.git] / tests / examples / camerabin / gst-camerabin-test.c
1 /*
2  * GStreamer
3  * Copyright (C) 2010 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     Compile using:
23     gcc -Wall `pkg-config --cflags --libs gstreamer-0.10` gst-camerabin-test.c -o gst-camerabin-test
24
25     Examples:
26     ./gst-camerabin-test --image-width=2048 --image-height=1536 --image-enc=dspjpegenc
27     ./gst-camerabin-test --mode=1 --capture-time=10 --image-width=848 --image-height=480 --view-framerate-num=2825 \
28     --view-framerate-den=100 --audio-src=pulsesrc --audio-enc=nokiaaacenc --video-enc=dspmp4venc \
29     --video-mux=mp4mux --src-colorspace=UYVY
30
31     ./gst-camerabin-test --help
32     Usage:
33     gst-camerabin-test [OPTION...]
34
35     camerabin command line test application
36
37     Help Options:
38     -h, --help                        Show help options
39     --help-all                        Show all help options
40     --help-gst                        Show GStreamer Options
41
42     Application Options:
43     --ev-compensation                 EV compensation (-2.5..2.5, default = 0)
44     --aperture                        Aperture (size of lens opening, default = 0 (auto))
45     --flash-mode                      Flash mode (default = 0 (auto))
46     --scene-mode                      Scene mode (default = 6 (auto))
47     --exposure                        Exposure (default = 0 (auto))
48     --iso-speed                       ISO speed (default = 0 (auto))
49     --white-balance-mode              White balance mode (default = 0 (auto))
50     --colour-tone-mode                Colour tone mode (default = 0 (auto))
51     --directory                       Directory for capture file(s) (default is current directory)
52     --mode                            Capture mode (default = 0 (image), 1 = video)
53     --capture-time                    Time to capture video in seconds (default = 10)
54     --capture-total                   Total number of captures to be done
55     --flags                           Flags for camerabin, (default = 0x9)
56     --mute                            Mute audio (default = 0 (no))
57     --zoom                            Zoom (100 = 1x (default), 200 = 2x etc.)
58     --audio-src                       Audio source used in video recording
59     --audio-bitrate                   Audio bitrate (default 128000)
60     --audio-samplerate                Audio samplerate (default 48000)
61     --audio-channels                  Audio channels (default 1)
62     --video-src                       Video source used in still capture and video recording
63     --audio-enc                       Audio encoder used in video recording
64     --video-enc                       Video encoder used in video recording
65     --image-enc                       Image encoder used in still capture
66     --image-pp                        Image post-processing element
67     --video-mux                       Muxer used in video recording
68     --viewfinder-sink                 Viewfinder sink (default = fakesink)
69     --image-width                     Width for image capture
70     --image-height                    Height for image capture
71     --view-framerate-num              Framerate numerator for viewfinder
72     --view-framerate-den              Framerate denominator for viewfinder
73     --src-colorspace                  Colorspace format for videosource (e.g. YUY2, UYVY)
74     --preview-caps                    Preview caps (e.g. video/x-raw-rgb,width=320,height=240)
75     --video-source-filter                    Video filter to process all frames from video source
76     --viewfinder-filter               Filter to process all frames going to viewfinder sink
77
78   */
79
80 /*
81  * Includes
82  */
83 #ifdef HAVE_CONFIG_H
84 #  include "config.h"
85 #endif
86
87 #include <gst/gst.h>
88 #include <gst/interfaces/xoverlay.h>
89 #include <string.h>
90 #include <sys/time.h>
91 #include <time.h>
92 #include <unistd.h>
93 #include <stdlib.h>
94 #include <glib.h>
95 #include <glib/gstdio.h>
96
97 #include <X11/Xlib.h>
98 #include <X11/Xatom.h>
99 /*
100  * debug logging
101  */
102 GST_DEBUG_CATEGORY_STATIC (camerabin_test);
103 #define GST_CAT_DEFAULT camerabin_test
104
105 typedef struct _ResultType
106 {
107   GstClockTime avg;
108   GstClockTime min;
109   GstClockTime max;
110   guint32 times;
111 } ResultType;
112
113 /*
114  * Global vars
115  */
116 static GstElement *camera_bin = NULL;
117 static GMainLoop *loop = NULL;
118
119 /* commandline options */
120 static gchar *audiosrc_name = NULL;
121 static gchar *videosrc_name = NULL;
122 static gchar *audioenc_name = NULL;
123 static gchar *videoenc_name = NULL;
124 static gchar *imageenc_name = NULL;
125 static gchar *imagepp_name = NULL;
126 static gchar *videomux_name = NULL;
127 static gchar *vfsink_name = NULL;
128 static gchar *src_csp = NULL;
129 static gchar *src_format = NULL;
130 static gint image_width = 1280;
131 static gint image_height = 720;
132 static gint view_framerate_num = 2825;
133 static gint view_framerate_den = 100;
134
135 /* photography interface command line options */
136 static gfloat ev_compensation = 0.0;
137 static gint aperture = 0;
138 static gint flash_mode = 0;
139 static gint scene_mode = 6;
140 static gint64 exposure = 0;
141 static gint iso_speed = 0;
142 static gint wb_mode = 0;
143 static gint color_mode = 0;
144 static gint mode = 1;
145 static gint flags = 0x4f;
146 static gint mute = 0;
147 static gint zoom = 100;
148
149 static gint capture_time = 10;
150 static gint capture_count = 0;
151 static gint capture_total = 1;
152
153 /* audio capsfilter options */
154 static gint audio_bitrate = 128000;
155 static gint audio_samplerate = 48000;
156 static gint audio_channels = 1;
157
158 static gchar *video_src_filter = NULL;
159 static gchar *viewfinder_filter = NULL;
160
161 static int x_width = 320;
162 static int x_height = 240;
163
164 /* test configuration for common callbacks */
165 static GString *filename = NULL;
166
167 static gchar *preview_caps_name = NULL;
168
169 /* X window variables */
170 static Display *display = NULL;
171 static Window window = 0;
172
173 /*
174  * Prototypes
175  */
176 static gboolean run_pipeline (gpointer user_data);
177 static void set_metadata (GstElement * camera);
178
179 static void
180 create_host_window (void)
181 {
182   unsigned long valuemask;
183   XSetWindowAttributes attributes;
184
185   display = XOpenDisplay (NULL);
186   if (display) {
187     window =
188         XCreateSimpleWindow (display, DefaultRootWindow (display), 0, 0,
189         x_width, x_height, 0, 0, 0);
190     if (window) {
191       valuemask = CWOverrideRedirect;
192       attributes.override_redirect = True;
193       XChangeWindowAttributes (display, window, valuemask, &attributes);
194       XSetWindowBackgroundPixmap (display, window, None);
195       XMapRaised (display, window);
196       XSync (display, FALSE);
197     } else {
198       GST_DEBUG ("could not create X window!");
199     }
200   } else {
201     GST_DEBUG ("could not open display!");
202   }
203 }
204
205 static gboolean
206 img_capture_done (GstElement * camera, const gchar * fname, gpointer user_data)
207 {
208   gboolean ret = FALSE;
209
210   GST_DEBUG ("image done: %s", fname);
211   if (capture_count < capture_total) {
212     g_idle_add ((GSourceFunc) run_pipeline, NULL);
213   } else {
214     g_main_loop_quit (loop);
215   }
216   return ret;
217 }
218
219 static GstBusSyncReply
220 bus_callback (GstBus * bus, GstMessage * message, gpointer data)
221 {
222   const GstStructure *st;
223   const GValue *image;
224   GstBuffer *buf = NULL;
225   guint8 *data_buf = NULL;
226   gchar *caps_string;
227   guint size = 0;
228   gchar *preview_filename = NULL;
229   FILE *f = NULL;
230   size_t written;
231
232   switch (GST_MESSAGE_TYPE (message)) {
233     case GST_MESSAGE_ERROR:{
234       GError *err;
235       gchar *debug;
236
237       gst_message_parse_error (message, &err, &debug);
238       g_print ("Error: %s\n", err->message);
239       g_error_free (err);
240       g_free (debug);
241
242       /* Write debug graph to file */
243       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camera_bin),
244           GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
245
246       g_main_loop_quit (loop);
247       break;
248     }
249     case GST_MESSAGE_STATE_CHANGED:
250       if (GST_IS_BIN (GST_MESSAGE_SRC (message))) {
251         GstState oldstate, newstate;
252
253         gst_message_parse_state_changed (message, &oldstate, &newstate, NULL);
254         GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-changed: %s -> %s",
255             gst_element_state_get_name (oldstate),
256             gst_element_state_get_name (newstate));
257       }
258       break;
259     case GST_MESSAGE_EOS:
260       /* end-of-stream */
261       GST_INFO ("got eos() - should not happen");
262       g_main_loop_quit (loop);
263       break;
264     default:
265       st = gst_message_get_structure (message);
266       if (st) {
267         if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
268           if (window) {
269             gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC
270                     (message)), window);
271             gst_message_unref (message);
272             message = NULL;
273             return GST_BUS_DROP;
274           }
275         } else if (gst_structure_has_name (st, "image-captured")) {
276           GST_DEBUG ("image-captured");
277         } else if (gst_structure_has_name (st, "preview-image")) {
278           GST_DEBUG ("preview-image");
279           //extract preview-image from msg
280           image = gst_structure_get_value (st, "buffer");
281           if (image) {
282             buf = gst_value_get_buffer (image);
283             data_buf = GST_BUFFER_DATA (buf);
284             size = GST_BUFFER_SIZE (buf);
285             preview_filename = g_strdup_printf ("test_vga.rgb");
286             caps_string = gst_caps_to_string (GST_BUFFER_CAPS (buf));
287             g_print ("writing buffer to %s, buffer caps: %s\n",
288                 preview_filename, caps_string);
289             g_free (caps_string);
290             f = g_fopen (preview_filename, "w");
291             if (f) {
292               written = fwrite (data_buf, size, 1, f);
293               if (!written) {
294                 g_print ("errro writing file\n");
295               }
296               fclose (f);
297             } else {
298               g_print ("error opening file for raw image writing\n");
299             }
300             g_free (preview_filename);
301           }
302         }
303       }
304       /* unhandled message */
305       break;
306   }
307   return GST_BUS_PASS;
308 }
309
310 /*
311  * Helpers
312  */
313
314 static void
315 cleanup_pipeline (void)
316 {
317   if (camera_bin) {
318     GST_INFO_OBJECT (camera_bin, "stopping and destroying");
319     gst_element_set_state (camera_bin, GST_STATE_NULL);
320     gst_object_unref (camera_bin);
321     camera_bin = NULL;
322   }
323 }
324
325 static gboolean
326 setup_pipeline_element (const gchar * property_name, const gchar * element_name,
327     GstElement ** res_elem)
328 {
329   gboolean res = TRUE;
330   GstElement *elem = NULL;
331
332   if (element_name) {
333     elem = gst_element_factory_make (element_name, NULL);
334     if (elem) {
335       g_object_set (camera_bin, property_name, elem, NULL);
336     } else {
337       GST_WARNING ("can't create element '%s' for property '%s'", element_name,
338           property_name);
339       res = FALSE;
340     }
341   } else {
342     GST_DEBUG ("no element for property '%s' given", property_name);
343   }
344   if (res_elem)
345     *res_elem = elem;
346   return res;
347 }
348
349 static GstElement *
350 create_audioencoder_bin (void)
351 {
352   GstElement *bin, *aenc, *filter;
353   GstPad *pad;
354   GstCaps *audio_caps;
355
356   bin = gst_bin_new ("aebin");
357   filter = gst_element_factory_make ("capsfilter", "aefilter");
358   aenc = gst_element_factory_make (audioenc_name, "aenc");
359
360   if (!g_ascii_strcasecmp (audioenc_name, "pulsesrc")) {
361     g_object_set (G_OBJECT (aenc),
362         "bitrate", audio_bitrate, "profile", 2, NULL);
363   }
364
365   audio_caps = gst_caps_new_simple ("audio/x-raw-int",
366       "channels", G_TYPE_INT, audio_channels,
367       "rate", G_TYPE_INT, audio_samplerate, NULL);
368
369   if (!audio_caps) {
370     g_warning ("error generating caps");
371   }
372
373   g_object_set (G_OBJECT (filter), "caps", audio_caps, NULL);
374
375   gst_caps_unref (audio_caps);
376
377   gst_bin_add_many (GST_BIN (bin), filter, aenc, NULL);
378   gst_element_link (filter, aenc);
379
380   pad = gst_element_get_static_pad (filter, "sink");
381   gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
382   gst_object_unref (GST_OBJECT (pad));
383
384   pad = gst_element_get_static_pad (aenc, "src");
385   gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
386   gst_object_unref (GST_OBJECT (pad));
387
388   return bin;
389 }
390
391 static gboolean
392 setup_pipeline (void)
393 {
394   GstBus *bus;
395   gboolean res = TRUE;
396   GstElement *vmux = NULL, *ienc = NULL, *sink = NULL, *aenc = NULL, *ipp =
397       NULL;
398   GstCaps *filter_caps = NULL;
399
400   camera_bin = gst_element_factory_make ("camerabin", NULL);
401   if (NULL == camera_bin) {
402     g_warning ("can't create camerabin element\n");
403     goto error;
404   }
405   g_object_set (camera_bin, "flags", flags, NULL);
406
407   g_signal_connect (camera_bin, "image-done", (GCallback) img_capture_done,
408       NULL);
409
410   bus = gst_pipeline_get_bus (GST_PIPELINE (camera_bin));
411   gst_bus_set_sync_handler (bus, bus_callback, NULL);
412   gst_object_unref (bus);
413
414   GST_INFO_OBJECT (camera_bin, "camerabin created");
415
416   /* configure used elements */
417   res &= setup_pipeline_element ("viewfinder-sink", vfsink_name, &sink);
418   res &= setup_pipeline_element ("audio-source", audiosrc_name, NULL);
419   res &= setup_pipeline_element ("video-source", videosrc_name, NULL);
420   res &= setup_pipeline_element ("video-source-filter", video_src_filter, NULL);
421   res &= setup_pipeline_element ("viewfinder-filter", viewfinder_filter, NULL);
422
423   if (audioenc_name) {
424     aenc = create_audioencoder_bin ();
425     if (aenc)
426       g_object_set (camera_bin, "audio-encoder", aenc, NULL);
427     else
428       GST_WARNING ("Could not make audio encoder element");
429   }
430
431   res &= setup_pipeline_element ("video-encoder", videoenc_name, NULL);
432   res &= setup_pipeline_element ("image-encoder", imageenc_name, &ienc);
433   res &= setup_pipeline_element ("image-post-processing", imagepp_name, &ipp);
434   res &= setup_pipeline_element ("video-muxer", videomux_name, &vmux);
435   if (!res) {
436     goto error;
437   }
438   GST_INFO_OBJECT (camera_bin, "elements created");
439
440   /* set properties */
441   if (src_format) {
442     filter_caps = gst_caps_from_string (src_format);
443   } else if (src_csp && strlen (src_csp) == 4) {
444     /* Set requested colorspace format, this is needed if the default 
445        colorspace negotiated for viewfinder doesn't match with e.g. encoders. */
446     filter_caps = gst_caps_new_simple ("video/x-raw-yuv",
447         "format", GST_TYPE_FOURCC,
448         GST_MAKE_FOURCC (src_csp[0], src_csp[1], src_csp[2], src_csp[3]), NULL);
449   }
450
451   if (filter_caps) {
452     g_object_set (camera_bin, "filter-caps", filter_caps, NULL);
453     gst_caps_unref (filter_caps);
454   }
455
456   g_object_set (sink, "sync", TRUE, NULL);
457
458   GST_INFO_OBJECT (camera_bin, "elements configured");
459
460   /* configure a resolution and framerate */
461   if (mode == 1) {
462     g_signal_emit_by_name (camera_bin, "set-video-resolution-fps", image_width,
463         image_height, view_framerate_num, view_framerate_den, NULL);
464   } else {
465     g_signal_emit_by_name (camera_bin, "set-image-resolution", image_width,
466         image_height, NULL);
467   }
468
469   if (GST_STATE_CHANGE_FAILURE ==
470       gst_element_set_state (camera_bin, GST_STATE_READY)) {
471     g_warning ("can't set camerabin to ready\n");
472     goto error;
473   }
474   GST_INFO_OBJECT (camera_bin, "camera ready");
475
476   if (GST_STATE_CHANGE_FAILURE ==
477       gst_element_set_state (camera_bin, GST_STATE_PLAYING)) {
478     g_warning ("can't set camerabin to playing\n");
479     goto error;
480   }
481   GST_INFO_OBJECT (camera_bin, "camera started");
482   return TRUE;
483 error:
484   cleanup_pipeline ();
485   return FALSE;
486 }
487
488 static gboolean
489 stop_capture (gpointer user_data)
490 {
491   g_signal_emit_by_name (camera_bin, "capture-stop", 0);
492   if (capture_count < capture_total) {
493     g_idle_add ((GSourceFunc) run_pipeline, NULL);
494   } else {
495     g_main_loop_quit (loop);
496   }
497   return FALSE;
498 }
499
500 static void
501 set_metadata (GstElement * camera)
502 {
503   GstTagSetter *setter = GST_TAG_SETTER (camera);
504   GTimeVal time = { 0, 0 };
505   gchar *desc_str;
506   GDate *date = g_date_new ();
507
508   g_get_current_time (&time);
509   g_date_set_time_val (date, &time);
510
511   desc_str = g_strdup_printf ("captured by %s", g_get_real_name ());
512
513   gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
514       GST_TAG_DATE, date,
515       GST_TAG_DESCRIPTION, desc_str,
516       GST_TAG_TITLE, "gst-camerabin-test capture",
517       GST_TAG_GEO_LOCATION_LONGITUDE, 1.0,
518       GST_TAG_GEO_LOCATION_LATITUDE, 2.0,
519       GST_TAG_GEO_LOCATION_ELEVATION, 3.0,
520       "device-make", "gst-camerabin-test make",
521       "device-model", "gst-camerabin-test model", NULL);
522
523   g_free (desc_str);
524   g_date_free (date);
525 }
526
527 static gboolean
528 run_pipeline (gpointer user_data)
529 {
530   GstCaps *preview_caps = NULL;
531
532   g_object_set (camera_bin, "mode", mode, NULL);
533
534   if (preview_caps_name != NULL) {
535     preview_caps = gst_caps_from_string (preview_caps_name);
536     if (preview_caps) {
537       g_object_set (camera_bin, "preview-caps", preview_caps, NULL);
538       GST_DEBUG ("Preview caps set");
539     } else
540       GST_DEBUG ("Preview caps set but could not create caps from string");
541   }
542
543   set_metadata (camera_bin);
544
545   if (capture_total) {
546     gchar *filename_str = filename->str;
547     filename_str = g_strdup_printf ("%s%d", filename->str, capture_count);
548     g_object_set (camera_bin, "filename", filename_str, NULL);
549     g_free (filename_str);
550   } else {
551     g_object_set (camera_bin, "filename", filename->str, NULL);
552   }
553
554   g_object_set (camera_bin, "ev-compensation", ev_compensation, NULL);
555   g_object_set (camera_bin, "aperture", aperture, NULL);
556   g_object_set (camera_bin, "flash-mode", flash_mode, NULL);
557   g_object_set (camera_bin, "scene-mode", scene_mode, NULL);
558   g_object_set (camera_bin, "exposure", exposure, NULL);
559   g_object_set (camera_bin, "iso-speed", iso_speed, NULL);
560   g_object_set (camera_bin, "white-balance-mode", wb_mode, NULL);
561   g_object_set (camera_bin, "colour-tone-mode", color_mode, NULL);
562   g_object_set (camera_bin, "mute", mute, NULL);
563   g_object_set (camera_bin, "zoom", zoom, NULL);
564
565   capture_count++;
566   g_signal_emit_by_name (camera_bin, "capture-start", 0);
567
568
569   if (mode == 1) {
570     g_timeout_add ((capture_time * 1000), (GSourceFunc) stop_capture, NULL);
571   }
572
573   return FALSE;
574 }
575
576 int
577 main (int argc, char *argv[])
578 {
579   gchar *target_times = NULL;
580   gchar *ev_option = NULL;
581   gchar *fn_option = NULL;
582
583   GOptionEntry options[] = {
584     {"ev-compensation", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING,
585           &ev_option,
586         "EV compensation (-2.5..2.5, default = 0)", NULL},
587     {"aperture", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &aperture,
588         "Aperture (size of lens opening, default = 0 (auto))", NULL},
589     {"flash-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
590           &flash_mode,
591         "Flash mode (default = 0 (auto))", NULL},
592     {"scene-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
593           &scene_mode,
594         "Scene mode (default = 6 (auto))", NULL},
595     {"exposure", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT64,
596           &exposure,
597         "Exposure (default = 0 (auto))", NULL},
598     {"iso-speed", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
599           &iso_speed,
600         "ISO speed (default = 0 (auto))", NULL},
601     {"white-balance-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
602           &wb_mode,
603         "White balance mode (default = 0 (auto))", NULL},
604     {"colour-tone-mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
605           &color_mode,
606         "Colour tone mode (default = 0 (auto))", NULL},
607     {"directory", '\0', 0, G_OPTION_ARG_STRING, &fn_option,
608         "Directory for capture file(s) (default is current directory)", NULL},
609     {"mode", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mode,
610         "Capture mode (default = 0 (image), 1 = video)", NULL},
611     {"capture-time", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT,
612           &capture_time,
613         "Time to capture video in seconds (default = 10)", NULL},
614     {"capture-total", '\0', 0, G_OPTION_ARG_INT, &capture_total,
615         "Total number of captures to be done (default = 1)", NULL},
616     {"flags", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &flags,
617         "Flags for camerabin, (default = 0x9)", NULL},
618     {"mute", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &mute,
619         "Mute audio (default = 0 (no))", NULL},
620     {"zoom", '\0', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_STRING, &zoom,
621         "Zoom (100 = 1x (default), 200 = 2x etc.)", NULL},
622     {"audio-src", '\0', 0, G_OPTION_ARG_STRING, &audiosrc_name,
623         "Audio source used in video recording", NULL},
624     {"audio-bitrate", '\0', 0, G_OPTION_ARG_INT, &audio_bitrate,
625         "Audio bitrate (default 128000)", NULL},
626     {"audio-samplerate", '\0', 0, G_OPTION_ARG_INT, &audio_samplerate,
627         "Audio samplerate (default 48000)", NULL},
628     {"audio-channels", '\0', 0, G_OPTION_ARG_INT, &audio_channels,
629         "Audio channels (default 1)", NULL},
630     {"video-src", '\0', 0, G_OPTION_ARG_STRING, &videosrc_name,
631         "Video source used in still capture and video recording", NULL},
632     {"audio-enc", '\0', 0, G_OPTION_ARG_STRING, &audioenc_name,
633         "Audio encoder used in video recording", NULL},
634     {"video-enc", '\0', 0, G_OPTION_ARG_STRING, &videoenc_name,
635         "Video encoder used in video recording", NULL},
636     {"image-enc", '\0', 0, G_OPTION_ARG_STRING, &imageenc_name,
637         "Image encoder used in still capture", NULL},
638     {"image-pp", '\0', 0, G_OPTION_ARG_STRING, &imagepp_name,
639         "Image post-processing element", NULL},
640     {"video-mux", '\0', 0, G_OPTION_ARG_STRING, &videomux_name,
641         "Muxer used in video recording", NULL},
642     {"viewfinder-sink", '\0', 0, G_OPTION_ARG_STRING, &vfsink_name,
643         "Viewfinder sink (default = fakesink)", NULL},
644     {"image-width", '\0', 0, G_OPTION_ARG_INT, &image_width,
645         "Width for image capture", NULL},
646     {"image-height", '\0', 0, G_OPTION_ARG_INT, &image_height,
647         "Height for image capture", NULL},
648     {"view-framerate-num", '\0', 0, G_OPTION_ARG_INT, &view_framerate_num,
649         "Framerate numerator for viewfinder", NULL},
650     {"view-framerate-den", '\0', 0, G_OPTION_ARG_INT, &view_framerate_den,
651         "Framerate denominator for viewfinder", NULL},
652     {"src-colorspace", '\0', 0, G_OPTION_ARG_STRING, &src_csp,
653         "Colorspace format for video source (e.g. YUY2, UYVY)", NULL},
654     {"src-format", '\0', 0, G_OPTION_ARG_STRING, &src_format,
655         "Video format for video source", NULL},
656     {"preview-caps", '\0', 0, G_OPTION_ARG_STRING, &preview_caps_name,
657         "Preview caps (e.g. video/x-raw-rgb,width=320,height=240)", NULL},
658     {"video-source-filter", '\0', 0, G_OPTION_ARG_STRING, &video_src_filter,
659         "Video filter to process all frames from video source", NULL},
660     {"viewfinder-filter", '\0', 0, G_OPTION_ARG_STRING, &viewfinder_filter,
661         "Filter to process all frames going to viewfinder sink", NULL},
662     {"x-width", '\0', 0, G_OPTION_ARG_INT, &x_width,
663         "X window width (default = 320)", NULL},
664     {"x-height", '\0', 0, G_OPTION_ARG_INT, &x_height,
665         "X window height (default = 240)", NULL},
666     {NULL}
667   };
668
669   GOptionContext *ctx;
670   GError *err = NULL;
671
672   /* if we fail to create xwindow should we care? */
673   create_host_window ();
674
675   if (!g_thread_supported ())
676     g_thread_init (NULL);
677
678   ctx = g_option_context_new ("\n\ncamerabin command line test application.");
679   g_option_context_add_main_entries (ctx, options, NULL);
680   g_option_context_add_group (ctx, gst_init_get_option_group ());
681   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
682     g_print ("Error initializing: %s\n", err->message);
683     exit (1);
684   }
685   g_option_context_free (ctx);
686
687   GST_DEBUG_CATEGORY_INIT (camerabin_test, "camerabin-test", 0,
688       "camerabin test");
689
690   /* FIXME: error handling */
691   if (ev_option != NULL)
692     ev_compensation = strtod (ev_option, (char **) NULL);
693
694   if (vfsink_name == NULL)
695     vfsink_name = g_strdup ("fakesink");
696
697   filename = g_string_new (fn_option);
698   if (filename->len == 0)
699     filename = g_string_append (filename, ".");
700
701   filename = g_string_append (filename, "/test_%04u");
702   if (mode == 1)
703     filename = g_string_append (filename, ".mp4");
704   else
705     filename = g_string_append (filename, ".jpg");
706
707   /* init */
708   if (setup_pipeline ()) {
709     loop = g_main_loop_new (NULL, FALSE);
710     g_idle_add ((GSourceFunc) run_pipeline, NULL);
711     g_main_loop_run (loop);
712     cleanup_pipeline ();
713     g_main_loop_unref (loop);
714   }
715   /* free */
716   g_string_free (filename, TRUE);
717   g_free (ev_option);
718   g_free (audiosrc_name);
719   g_free (videosrc_name);
720   g_free (audioenc_name);
721   g_free (videoenc_name);
722   g_free (imageenc_name);
723   g_free (imagepp_name);
724   g_free (videomux_name);
725   g_free (vfsink_name);
726   g_free (src_csp);
727   g_free (src_format);
728   g_free (target_times);
729
730   if (window)
731     XDestroyWindow (display, window);
732
733   if (display)
734     XCloseDisplay (display);
735
736   return 0;
737 }