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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, 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 --performance-measure Collect timing information about the
78 captures and provides performance statistics at the end
79 --performance-targets A list of doubles that are the performance target
80 times for each of the measured timestamps. The order is
81 startup time, change mode time, shot to save, shot to snapshot,
82 shot to shot, preview to precapture, shot to buffer.
83 e.g. 3.5,1.0,5.0,2.5,5.0,1.5,1.0
84 * Startup time -> time it takes for camerabin to reach playing
85 * Change mode time -> time it takes for camerabin to change to the selected
86 mode in playing
87 * Shot to save -> time it takes from start-capture to having the image saved
88 to disk
89 * Shot to snapshot -> time it takes from start-capture to getting a snapshot
90 * Shot to shot -> time from one start-capture to the next one
91 * Preview to precapture -> time it takes from getting the snapshot to the
92 next buffer that reaches the viewfinder
93 * Shot to buffer -> time it takes from start-capture to the moment a buffer
94 is pushed out of the camera source
95
96 */
97
98 /*
99 * Includes
100 */
101 #ifdef HAVE_CONFIG_H
102 # include "config.h"
103 #endif
104
105 #define GST_USE_UNSTABLE_API 1
106
107 #include <gst/gst.h>
108 #include <gst/video/videooverlay.h>
109 #include <gst/interfaces/photography.h>
110 #include <string.h>
111 #include <sys/time.h>
112 #include <time.h>
113 #include <unistd.h>
114 #include <stdlib.h>
115 #include <glib.h>
116 #include <glib/gstdio.h>
117 #include <gst/pbutils/encoding-profile.h>
118 #include <gst/pbutils/encoding-target.h>
119 #include <X11/Xlib.h>
120 #include <X11/Xatom.h>
121 /*
122 * debug logging
123 */
124 GST_DEBUG_CATEGORY_STATIC (camerabin_test);
125 #define GST_CAT_DEFAULT camerabin_test
126
127 #define TIME_DIFF(a,b) ((((gint64)(a)) - ((gint64)(b))) / (gdouble) GST_SECOND)
128
129 #define TIME_FORMAT "02d.%09u"
130 #define TIMEDIFF_FORMAT "0.6lf"
131
132 #define TIME_ARGS(t) \
133 (GST_CLOCK_TIME_IS_VALID (t) && (t) < 99 * GST_SECOND) ? \
134 (gint) ((((GstClockTime)(t)) / GST_SECOND) % 60) : 99, \
135 (GST_CLOCK_TIME_IS_VALID (t) && ((t) < 99 * GST_SECOND)) ? \
136 (guint) (((GstClockTime)(t)) % GST_SECOND) : 999999999
137
138 #define TIMEDIFF_ARGS(t) (t)
139
140 typedef struct _CaptureTiming
141 {
142 GstClockTime start_capture;
143 GstClockTime got_preview;
144 GstClockTime capture_done;
145 GstClockTime precapture;
146 GstClockTime camera_capture;
147 } CaptureTiming;
148
149 typedef struct _CaptureTimingStats
150 {
151 GstClockTime shot_to_shot;
152 GstClockTime shot_to_save;
153 GstClockTime shot_to_snapshot;
154 GstClockTime preview_to_precapture;
155 GstClockTime shot_to_buffer;
156 } CaptureTimingStats;
157
158 static void
capture_timing_stats_add(CaptureTimingStats * a,CaptureTimingStats * b)159 capture_timing_stats_add (CaptureTimingStats * a, CaptureTimingStats * b)
160 {
161 a->shot_to_shot += b->shot_to_shot;
162 a->shot_to_snapshot += b->shot_to_snapshot;
163 a->shot_to_save += b->shot_to_save;
164 a->preview_to_precapture += b->preview_to_precapture;
165 a->shot_to_buffer += b->shot_to_buffer;
166 }
167
168 static void
capture_timing_stats_div(CaptureTimingStats * stats,gint div)169 capture_timing_stats_div (CaptureTimingStats * stats, gint div)
170 {
171 stats->shot_to_shot /= div;
172 stats->shot_to_snapshot /= div;
173 stats->shot_to_save /= div;
174 stats->preview_to_precapture /= div;
175 stats->shot_to_buffer /= div;
176 }
177
178 #define PRINT_STATS(d,s) g_print ("%02d | %" TIME_FORMAT " | %" \
179 TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT \
180 " | %" TIME_FORMAT "\n", d, \
181 TIME_ARGS ((s)->shot_to_save), TIME_ARGS ((s)->shot_to_snapshot), \
182 TIME_ARGS ((s)->shot_to_shot), \
183 TIME_ARGS ((s)->preview_to_precapture), \
184 TIME_ARGS ((s)->shot_to_buffer))
185
186 #define SHOT_TO_SAVE(t) ((t)->capture_done - (t)->start_capture)
187 #define SHOT_TO_SNAPSHOT(t) ((t)->got_preview - (t)->start_capture)
188 #define PREVIEW_TO_PRECAPTURE(t) ((t)->precapture - (t)->got_preview)
189 #define SHOT_TO_BUFFER(t) ((t)->camera_capture - (t)->start_capture)
190
191 /*
192 * Global vars
193 */
194 static GstElement *camerabin = NULL;
195 static GstElement *viewfinder_sink = NULL;
196 static gulong camera_probe_id = 0;
197 static gulong viewfinder_probe_id = 0;
198 static GMainLoop *loop = NULL;
199
200 /* commandline options */
201 static gchar *videosrc_name = NULL;
202 static gchar *videodevice_name = NULL;
203 static gchar *audiosrc_name = NULL;
204 static gchar *wrappersrc_name = NULL;
205 static gchar *imagepp_name = NULL;
206 static gchar *vfsink_name = NULL;
207 static gint image_width = 0;
208 static gint image_height = 0;
209 static gint view_framerate_num = 0;
210 static gint view_framerate_den = 0;
211 static gboolean no_xwindow = FALSE;
212 static gchar *gep_targetname = NULL;
213 static gchar *gep_profilename = NULL;
214 static gchar *gep_filename = NULL;
215 static gchar *image_capture_caps_str = NULL;
216 static gchar *viewfinder_caps_str = NULL;
217 static gchar *video_capture_caps_str = NULL;
218 static gchar *audio_capture_caps_str = NULL;
219 static gboolean performance_measure = FALSE;
220 static gchar *performance_targets_str = NULL;
221 static gchar *camerabin_flags = NULL;
222
223
224 #define MODE_VIDEO 2
225 #define MODE_IMAGE 1
226 static gint mode = MODE_IMAGE;
227 static gint zoom = 100;
228
229 static gint capture_time = 10;
230 static gint capture_count = 0;
231 static gint capture_total = 1;
232 static gulong stop_capture_cb_id = 0;
233
234 /* photography interface command line options */
235 #define EV_COMPENSATION_NONE -G_MAXFLOAT
236 #define APERTURE_NONE -G_MAXINT
237 #define FLASH_MODE_NONE -G_MAXINT
238 #define SCENE_MODE_NONE -G_MAXINT
239 #define EXPOSURE_NONE -G_MAXINT64
240 #define ISO_SPEED_NONE -G_MAXINT
241 #define WHITE_BALANCE_MODE_NONE -G_MAXINT
242 #define COLOR_TONE_MODE_NONE -G_MAXINT
243 static gfloat ev_compensation = EV_COMPENSATION_NONE;
244 static gint aperture = APERTURE_NONE;
245 static gint flash_mode = FLASH_MODE_NONE;
246 static gint scene_mode = SCENE_MODE_NONE;
247 static gint64 exposure = EXPOSURE_NONE;
248 static gint iso_speed = ISO_SPEED_NONE;
249 static gint wb_mode = WHITE_BALANCE_MODE_NONE;
250 static gint color_mode = COLOR_TONE_MODE_NONE;
251
252 static gchar *viewfinder_filter = NULL;
253
254 static int x_width = 320;
255 static int x_height = 240;
256
257 /* test configuration for common callbacks */
258 static GString *filename = NULL;
259
260 static gchar *preview_caps_name = NULL;
261
262 /* X window variables */
263 static Display *display = NULL;
264 static Window window = 0;
265
266 /* timing data */
267 static GstClockTime initial_time = 0;
268 static GstClockTime startup_time = 0;
269 static GstClockTime change_mode_before = 0;
270 static GstClockTime change_mode_after = 0;
271 static GList *capture_times = NULL;
272
273 static GstClockTime target_startup;
274 static GstClockTime target_change_mode;
275 static GstClockTime target_shot_to_shot;
276 static GstClockTime target_shot_to_save;
277 static GstClockTime target_shot_to_snapshot;
278 static GstClockTime target_preview_to_precapture;
279 static GstClockTime target_shot_to_buffer;
280
281
282 /*
283 * Prototypes
284 */
285 static gboolean run_pipeline (gpointer user_data);
286 static void set_metadata (GstElement * camera);
287
288 static void
create_host_window(void)289 create_host_window (void)
290 {
291 unsigned long valuemask;
292 XSetWindowAttributes attributes;
293
294 display = XOpenDisplay (NULL);
295 if (display) {
296 window =
297 XCreateSimpleWindow (display, DefaultRootWindow (display), 0, 0,
298 x_width, x_height, 0, 0, 0);
299 if (window) {
300 valuemask = CWOverrideRedirect;
301 attributes.override_redirect = True;
302 XChangeWindowAttributes (display, window, valuemask, &attributes);
303 XSetWindowBackgroundPixmap (display, window, None);
304 XMapRaised (display, window);
305 XSync (display, FALSE);
306 } else {
307 GST_DEBUG ("could not create X window!");
308 }
309 } else {
310 GST_DEBUG ("could not open display!");
311 }
312 }
313
314 static GstPadProbeReturn
camera_src_get_timestamp_probe(GstPad * pad,GstPadProbeInfo * info,gpointer udata)315 camera_src_get_timestamp_probe (GstPad * pad, GstPadProbeInfo * info,
316 gpointer udata)
317 {
318 CaptureTiming *timing;
319
320 timing = (CaptureTiming *) g_list_first (capture_times)->data;
321 timing->camera_capture = gst_util_get_timestamp ();
322
323 return GST_PAD_PROBE_REMOVE;
324 }
325
326 static GstPadProbeReturn
viewfinder_get_timestamp_probe(GstPad * pad,GstPadProbeInfo * info,gpointer udata)327 viewfinder_get_timestamp_probe (GstPad * pad, GstPadProbeInfo * info,
328 gpointer udata)
329 {
330 CaptureTiming *timing;
331
332 timing = (CaptureTiming *) g_list_first (capture_times)->data;
333 timing->precapture = gst_util_get_timestamp ();
334
335 return GST_PAD_PROBE_REMOVE;
336 }
337
338 static GstBusSyncReply
sync_bus_callback(GstBus * bus,GstMessage * message,gpointer data)339 sync_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
340 {
341 const GstStructure *st;
342 const GValue *image;
343 GstBuffer *buf = NULL;
344 gchar *preview_filename = NULL;
345 FILE *f = NULL;
346 size_t written;
347
348 switch (GST_MESSAGE_TYPE (message)) {
349 case GST_MESSAGE_ELEMENT:{
350 st = gst_message_get_structure (message);
351 if (st) {
352 if (gst_message_has_name (message, "prepare-xwindow-id")) {
353 if (!no_xwindow && window) {
354 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY
355 (GST_MESSAGE_SRC (message)), window);
356 gst_message_unref (message);
357 message = NULL;
358 return GST_BUS_DROP;
359 }
360 } else if (gst_structure_has_name (st, "preview-image")) {
361 CaptureTiming *timing;
362
363 GST_DEBUG ("preview-image");
364
365 timing = (CaptureTiming *) g_list_first (capture_times)->data;
366 timing->got_preview = gst_util_get_timestamp ();
367
368 {
369 /* set up probe to check when the viewfinder gets data */
370 GstPad *pad = gst_element_get_static_pad (viewfinder_sink, "sink");
371
372 viewfinder_probe_id =
373 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
374 viewfinder_get_timestamp_probe, NULL, NULL);
375
376 gst_object_unref (pad);
377 }
378
379 /* extract preview-image from msg */
380 image = gst_structure_get_value (st, "buffer");
381 if (image) {
382 buf = gst_value_get_buffer (image);
383 preview_filename = g_strdup_printf ("test_vga.rgb");
384 f = g_fopen (preview_filename, "w");
385 if (f) {
386 GstMapInfo map;
387
388 gst_buffer_map (buf, &map, GST_MAP_READ);
389 written = fwrite (map.data, map.size, 1, f);
390 gst_buffer_unmap (buf, &map);
391 if (!written) {
392 g_print ("error writing file\n");
393 }
394 fclose (f);
395 } else {
396 g_print ("error opening file for raw image writing\n");
397 }
398 g_free (preview_filename);
399 }
400 }
401 }
402 break;
403 }
404 case GST_MESSAGE_STATE_CHANGED:
405 if (GST_MESSAGE_SRC (message) == (GstObject *) camerabin) {
406 GstState newstate;
407
408 gst_message_parse_state_changed (message, NULL, &newstate, NULL);
409 if (newstate == GST_STATE_PLAYING) {
410 startup_time = gst_util_get_timestamp ();
411 }
412 }
413 break;
414 default:
415 /* unhandled message */
416 break;
417 }
418 return GST_BUS_PASS;
419 }
420
421 static gboolean
bus_callback(GstBus * bus,GstMessage * message,gpointer data)422 bus_callback (GstBus * bus, GstMessage * message, gpointer data)
423 {
424 switch (GST_MESSAGE_TYPE (message)) {
425 case GST_MESSAGE_ERROR:{
426 GError *err;
427 gchar *debug;
428
429 gst_message_parse_error (message, &err, &debug);
430 g_print ("Error: %s\n", err->message);
431 g_clear_error (&err);
432 g_free (debug);
433
434 /* Write debug graph to file */
435 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (camerabin),
436 GST_DEBUG_GRAPH_SHOW_ALL, "camerabin.error");
437
438 g_main_loop_quit (loop);
439 break;
440 }
441 case GST_MESSAGE_STATE_CHANGED:
442 if (GST_IS_BIN (GST_MESSAGE_SRC (message))) {
443 GstState oldstate, newstate;
444
445 gst_message_parse_state_changed (message, &oldstate, &newstate, NULL);
446 GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message), "state-changed: %s -> %s",
447 gst_element_state_get_name (oldstate),
448 gst_element_state_get_name (newstate));
449 }
450 break;
451 case GST_MESSAGE_EOS:
452 /* end-of-stream */
453 GST_INFO ("got eos() - should not happen");
454 g_main_loop_quit (loop);
455 break;
456 case GST_MESSAGE_ELEMENT:
457 if (GST_MESSAGE_SRC (message) == (GstObject *) camerabin) {
458 const GstStructure *structure = gst_message_get_structure (message);
459
460 if (gst_structure_has_name (structure, "image-done")) {
461 CaptureTiming *timing;
462 #ifndef GST_DISABLE_GST_DEBUG
463 const gchar *fname = gst_structure_get_string (structure, "filename");
464
465 GST_DEBUG ("image done: %s", fname);
466 #endif
467 timing = (CaptureTiming *) g_list_first (capture_times)->data;
468 timing->capture_done = gst_util_get_timestamp ();
469
470 if (capture_count < capture_total) {
471 g_idle_add ((GSourceFunc) run_pipeline, NULL);
472 } else {
473 g_main_loop_quit (loop);
474 }
475 }
476 }
477 break;
478 default:
479 /* unhandled message */
480 break;
481 }
482 return TRUE;
483 }
484
485 /*
486 * Helpers
487 */
488
489 static void
cleanup_pipeline(void)490 cleanup_pipeline (void)
491 {
492 if (camerabin) {
493 GST_INFO_OBJECT (camerabin, "stopping and destroying");
494 gst_element_set_state (camerabin, GST_STATE_NULL);
495 gst_object_unref (camerabin);
496 camerabin = NULL;
497 }
498 }
499
500 static GstElement *
create_ipp_bin(void)501 create_ipp_bin (void)
502 {
503 GstElement *bin = NULL, *element = NULL;
504 GstPad *pad = NULL;
505 gchar **elements;
506 GList *element_list = NULL, *current = NULL, *next = NULL;
507 int i;
508
509 bin = gst_bin_new ("ippbin");
510
511 elements = g_strsplit (imagepp_name, ",", 0);
512
513 for (i = 0; elements[i] != NULL; i++) {
514 element = gst_element_factory_make (elements[i], NULL);
515 if (element) {
516 element_list = g_list_append (element_list, element);
517 gst_bin_add (GST_BIN (bin), element);
518 } else
519 GST_WARNING ("Could create element %s for ippbin", elements[i]);
520 }
521
522 for (i = 1; i < g_list_length (element_list); i++) {
523 current = g_list_nth (element_list, i - 1);
524 next = g_list_nth (element_list, i);
525 gst_element_link (current->data, next->data);
526 }
527
528 current = g_list_first (element_list);
529 pad = gst_element_get_static_pad (current->data, "sink");
530 gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
531 gst_object_unref (GST_OBJECT (pad));
532
533 current = g_list_last (element_list);
534 pad = gst_element_get_static_pad (current->data, "src");
535 gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
536 gst_object_unref (GST_OBJECT (pad));
537
538 g_list_free (element_list);
539 g_strfreev (elements);
540
541 return bin;
542 }
543
544 static GstEncodingProfile *
load_encoding_profile(void)545 load_encoding_profile (void)
546 {
547 GstEncodingProfile *prof = NULL;
548 GstEncodingTarget *target = NULL;
549 GError *error = NULL;
550
551 /* if profile file was given, try to load profile from there */
552 if (gep_filename && gep_profilename) {
553 target = gst_encoding_target_load_from_file (gep_filename, &error);
554 if (!target) {
555 GST_WARNING ("Could not load target %s from file %s", gep_targetname,
556 gep_filename);
557 if (error) {
558 GST_WARNING ("Error from file loading: %s", error->message);
559 g_clear_error (&error);
560 }
561 } else {
562 prof = gst_encoding_target_get_profile (target, gep_profilename);
563 if (prof)
564 GST_DEBUG ("Loaded encoding profile %s from %s", gep_profilename,
565 gep_filename);
566 else
567 GST_WARNING
568 ("Could not load specified encoding profile %s from file %s",
569 gep_profilename, gep_filename);
570 }
571 /* if we could not load profile from file then try to find one from system */
572 } else if (gep_profilename && gep_targetname) {
573 prof = gst_encoding_profile_find (gep_targetname, gep_profilename, NULL);
574 if (prof)
575 GST_DEBUG ("Loaded encoding profile %s from target %s", gep_profilename,
576 gep_targetname);
577 } else
578 GST_DEBUG
579 ("Encoding profile not set, using camerabin default encoding profile");
580
581 return prof;
582 }
583
584 static gboolean
setup_pipeline_element(GstElement * element,const gchar * property_name,const gchar * element_name,GstElement ** res_elem)585 setup_pipeline_element (GstElement * element, const gchar * property_name,
586 const gchar * element_name, GstElement ** res_elem)
587 {
588 gboolean res = TRUE;
589 GstElement *elem = NULL;
590
591 if (element_name) {
592 GError *error = NULL;
593
594 elem = gst_parse_launch (element_name, &error);
595 if (elem) {
596 g_object_set (element, property_name, elem, NULL);
597 g_object_unref (elem);
598 } else {
599 GST_WARNING ("can't create element '%s' for property '%s'", element_name,
600 property_name);
601 if (error) {
602 GST_ERROR ("%s", error->message);
603 g_clear_error (&error);
604 }
605 res = FALSE;
606 }
607 } else {
608 GST_DEBUG ("no element for property '%s' given", property_name);
609 }
610 if (res_elem)
611 *res_elem = elem;
612 return res;
613 }
614
615 static void
set_camerabin_caps_from_string(void)616 set_camerabin_caps_from_string (void)
617 {
618 GstCaps *caps = NULL;
619 if (image_capture_caps_str != NULL) {
620 caps = gst_caps_from_string (image_capture_caps_str);
621 if (GST_CAPS_IS_SIMPLE (caps) && image_width > 0 && image_height > 0) {
622 gst_caps_set_simple (caps, "width", G_TYPE_INT, image_width, "height",
623 G_TYPE_INT, image_height, NULL);
624 }
625 GST_DEBUG ("setting image-capture-caps: %" GST_PTR_FORMAT, caps);
626 g_object_set (camerabin, "image-capture-caps", caps, NULL);
627 gst_caps_unref (caps);
628 }
629
630 if (viewfinder_caps_str != NULL) {
631 caps = gst_caps_from_string (viewfinder_caps_str);
632 if (GST_CAPS_IS_SIMPLE (caps) && view_framerate_num > 0
633 && view_framerate_den > 0) {
634 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
635 view_framerate_num, view_framerate_den, NULL);
636 }
637 GST_DEBUG ("setting viewfinder-caps: %" GST_PTR_FORMAT, caps);
638 g_object_set (camerabin, "viewfinder-caps", caps, NULL);
639 gst_caps_unref (caps);
640 }
641
642 if (video_capture_caps_str != NULL) {
643 caps = gst_caps_from_string (video_capture_caps_str);
644 GST_DEBUG ("setting video-capture-caps: %" GST_PTR_FORMAT, caps);
645 g_object_set (camerabin, "video-capture-caps", caps, NULL);
646 gst_caps_unref (caps);
647 }
648
649 if (audio_capture_caps_str != NULL) {
650 caps = gst_caps_from_string (audio_capture_caps_str);
651 GST_DEBUG ("setting audio-capture-caps: %" GST_PTR_FORMAT, caps);
652 g_object_set (camerabin, "audio-capture-caps", caps, NULL);
653 gst_caps_unref (caps);
654 }
655 }
656
657 static gboolean
setup_pipeline(void)658 setup_pipeline (void)
659 {
660 gboolean res = TRUE;
661 GstBus *bus;
662 GstElement *sink = NULL, *ipp = NULL;
663 GstEncodingProfile *prof = NULL;
664
665 initial_time = gst_util_get_timestamp ();
666
667 camerabin = gst_element_factory_make ("camerabin", NULL);
668 if (NULL == camerabin) {
669 g_warning ("can't create camerabin element\n");
670 goto error;
671 }
672
673 bus = gst_pipeline_get_bus (GST_PIPELINE (camerabin));
674 /* Add sync handler for time critical messages that need to be handled fast */
675 gst_bus_set_sync_handler (bus, sync_bus_callback, NULL, NULL);
676 /* Handle normal messages asynchronously */
677 gst_bus_add_watch (bus, bus_callback, NULL);
678 gst_object_unref (bus);
679
680 GST_INFO_OBJECT (camerabin, "camerabin created");
681
682 if (camerabin_flags)
683 gst_util_set_object_arg (G_OBJECT (camerabin), "flags", camerabin_flags);
684 else
685 gst_util_set_object_arg (G_OBJECT (camerabin), "flags", "");
686
687 if (videosrc_name) {
688 GstElement *wrapper;
689 GstElement *videosrc;
690
691 if (wrappersrc_name)
692 wrapper = gst_element_factory_make (wrappersrc_name, NULL);
693 else
694 wrapper = gst_element_factory_make ("wrappercamerabinsrc", NULL);
695
696 if (setup_pipeline_element (wrapper, "video-source", videosrc_name, NULL)) {
697 g_object_set (camerabin, "camera-source", wrapper, NULL);
698 g_object_unref (wrapper);
699 } else {
700 GST_WARNING ("Failed to set videosrc to %s", videosrc_name);
701 }
702
703 g_object_get (wrapper, "video-source", &videosrc, NULL);
704 if (videosrc && videodevice_name &&
705 g_object_class_find_property (G_OBJECT_GET_CLASS (videosrc),
706 "device")) {
707 g_object_set (videosrc, "device", videodevice_name, NULL);
708 }
709 }
710
711 /* configure used elements */
712 res &=
713 setup_pipeline_element (camerabin, "audio-source", audiosrc_name, NULL);
714 res &=
715 setup_pipeline_element (camerabin, "viewfinder-sink", vfsink_name, &sink);
716 res &=
717 setup_pipeline_element (camerabin, "viewfinder-filter", viewfinder_filter,
718 NULL);
719
720 if (imagepp_name) {
721 ipp = create_ipp_bin ();
722 if (ipp) {
723 g_object_set (camerabin, "image-filter", ipp, NULL);
724 g_object_unref (ipp);
725 } else
726 GST_WARNING ("Could not create ipp elements");
727 }
728
729 prof = load_encoding_profile ();
730 if (prof) {
731 g_object_set (G_OBJECT (camerabin), "video-profile", prof, NULL);
732 gst_encoding_profile_unref (prof);
733 }
734
735 GST_INFO_OBJECT (camerabin, "elements created");
736
737 if (sink) {
738 g_object_set (sink, "sync", TRUE, NULL);
739 } else {
740 /* Get the inner viewfinder sink, this uses fixed names given
741 * by default in camerabin */
742 sink = gst_bin_get_by_name (GST_BIN (camerabin), "vf-bin");
743 g_assert (sink);
744 gst_object_unref (sink);
745
746 sink = gst_bin_get_by_name (GST_BIN (sink), "vfbin-sink");
747 g_assert (sink);
748 gst_object_unref (sink);
749 }
750 viewfinder_sink = sink;
751
752 GST_INFO_OBJECT (camerabin, "elements configured");
753
754 /* configure a resolution and framerate */
755 if (image_width > 0 && image_height > 0) {
756 if (mode == MODE_VIDEO) {
757 GstCaps *caps = NULL;
758 if (view_framerate_num > 0)
759 caps = gst_caps_new_full (gst_structure_new ("video/x-raw",
760 "width", G_TYPE_INT, image_width,
761 "height", G_TYPE_INT, image_height,
762 "framerate", GST_TYPE_FRACTION, view_framerate_num,
763 view_framerate_den, NULL), NULL);
764 else
765 caps = gst_caps_new_full (gst_structure_new ("video/x-raw",
766 "width", G_TYPE_INT, image_width,
767 "height", G_TYPE_INT, image_height, NULL), NULL);
768
769 g_object_set (camerabin, "video-capture-caps", caps, NULL);
770 gst_caps_unref (caps);
771 } else {
772 GstCaps *caps = gst_caps_new_full (gst_structure_new ("video/x-raw",
773 "width", G_TYPE_INT, image_width,
774 "height", G_TYPE_INT, image_height, NULL), NULL);
775
776 g_object_set (camerabin, "image-capture-caps", caps, NULL);
777 gst_caps_unref (caps);
778 }
779 }
780
781 set_camerabin_caps_from_string ();
782
783 /* change to the wrong mode if timestamping if performance mode is on so
784 * we can change it back and measure the time after in playing */
785 if (performance_measure) {
786 g_object_set (camerabin, "mode",
787 mode == MODE_VIDEO ? MODE_IMAGE : MODE_VIDEO, NULL);
788 }
789
790 if (GST_STATE_CHANGE_FAILURE ==
791 gst_element_set_state (camerabin, GST_STATE_READY)) {
792 g_warning ("can't set camerabin to ready\n");
793 goto error;
794 }
795 GST_INFO_OBJECT (camerabin, "camera ready");
796
797 if (GST_STATE_CHANGE_FAILURE ==
798 gst_element_set_state (camerabin, GST_STATE_PLAYING)) {
799 g_warning ("can't set camerabin to playing\n");
800 goto error;
801 }
802
803 GST_INFO_OBJECT (camerabin, "camera started");
804
805 /* do the mode change timestamping if performance mode is on */
806 if (performance_measure) {
807 change_mode_before = gst_util_get_timestamp ();
808 g_object_set (camerabin, "mode", mode, NULL);
809 change_mode_after = gst_util_get_timestamp ();
810 }
811
812 return res;
813 error:
814 cleanup_pipeline ();
815 return FALSE;
816 }
817
818 static void
stop_capture_cb(GObject * self,GParamSpec * pspec,gpointer user_data)819 stop_capture_cb (GObject * self, GParamSpec * pspec, gpointer user_data)
820 {
821 gboolean idle = FALSE;
822
823 g_object_get (camerabin, "idle", &idle, NULL);
824
825 if (idle) {
826 if (capture_count < capture_total) {
827 g_idle_add ((GSourceFunc) run_pipeline, NULL);
828 } else {
829 g_main_loop_quit (loop);
830 }
831 }
832
833 g_signal_handler_disconnect (camerabin, stop_capture_cb_id);
834 }
835
836 static gboolean
stop_capture(gpointer user_data)837 stop_capture (gpointer user_data)
838 {
839 stop_capture_cb_id = g_signal_connect (camerabin, "notify::idle",
840 (GCallback) stop_capture_cb, camerabin);
841 g_signal_emit_by_name (camerabin, "stop-capture", 0);
842 return FALSE;
843 }
844
845 static void
set_metadata(GstElement * camera)846 set_metadata (GstElement * camera)
847 {
848 GstTagSetter *setter = GST_TAG_SETTER (camera);
849 GstDateTime *datetime;
850 gchar *desc_str;
851
852 datetime = gst_date_time_new_now_local_time ();
853
854 desc_str = g_strdup_printf ("captured by %s", g_get_real_name ());
855
856 gst_tag_setter_add_tags (setter, GST_TAG_MERGE_REPLACE,
857 GST_TAG_DATE_TIME, datetime,
858 GST_TAG_DESCRIPTION, desc_str,
859 GST_TAG_TITLE, "gst-camerabin-test capture",
860 GST_TAG_GEO_LOCATION_LONGITUDE, 1.0,
861 GST_TAG_GEO_LOCATION_LATITUDE, 2.0,
862 GST_TAG_GEO_LOCATION_ELEVATION, 3.0,
863 GST_TAG_DEVICE_MANUFACTURER, "gst-camerabin-test manufacturer",
864 GST_TAG_DEVICE_MODEL, "gst-camerabin-test model", NULL);
865
866 g_free (desc_str);
867 gst_date_time_unref (datetime);
868 }
869
870 static gboolean
run_pipeline(gpointer user_data)871 run_pipeline (gpointer user_data)
872 {
873 GstCaps *preview_caps = NULL;
874 gchar *filename_str = NULL;
875 GstElement *video_source = NULL;
876 const gchar *filename_suffix;
877 CaptureTiming *timing;
878
879 g_object_set (camerabin, "mode", mode, NULL);
880
881 if (preview_caps_name != NULL) {
882 preview_caps = gst_caps_from_string (preview_caps_name);
883 if (preview_caps) {
884 g_object_set (camerabin, "preview-caps", preview_caps, NULL);
885 GST_DEBUG ("Preview caps set");
886 } else
887 GST_DEBUG ("Preview caps set but could not create caps from string");
888 }
889
890 set_metadata (camerabin);
891
892 /* Construct filename */
893 if (mode == MODE_VIDEO)
894 filename_suffix = ".mp4";
895 else
896 filename_suffix = ".jpg";
897 filename_str =
898 g_strdup_printf ("%s/test_%04u%s", filename->str, capture_count,
899 filename_suffix);
900 GST_DEBUG ("Setting filename: %s", filename_str);
901 g_object_set (camerabin, "location", filename_str, NULL);
902 g_free (filename_str);
903
904 g_object_get (camerabin, "camera-source", &video_source, NULL);
905 if (video_source) {
906 if (GST_IS_ELEMENT (video_source) && GST_IS_PHOTOGRAPHY (video_source)) {
907 /* Set GstPhotography interface options. If option not given as
908 command-line parameter use default of the source element. */
909 if (scene_mode != SCENE_MODE_NONE)
910 g_object_set (video_source, "scene-mode", scene_mode, NULL);
911 if (ev_compensation != EV_COMPENSATION_NONE)
912 g_object_set (video_source, "ev-compensation", ev_compensation, NULL);
913 if (aperture != APERTURE_NONE)
914 g_object_set (video_source, "aperture", aperture, NULL);
915 if (flash_mode != FLASH_MODE_NONE)
916 g_object_set (video_source, "flash-mode", flash_mode, NULL);
917 if (exposure != EXPOSURE_NONE)
918 g_object_set (video_source, "exposure", exposure, NULL);
919 if (iso_speed != ISO_SPEED_NONE)
920 g_object_set (video_source, "iso-speed", iso_speed, NULL);
921 if (wb_mode != WHITE_BALANCE_MODE_NONE)
922 g_object_set (video_source, "white-balance-mode", wb_mode, NULL);
923 if (color_mode != COLOR_TONE_MODE_NONE)
924 g_object_set (video_source, "colour-tone-mode", color_mode, NULL);
925 }
926 g_object_unref (video_source);
927 } else {
928 video_source = gst_bin_get_by_name (GST_BIN (camerabin), "camerasrc");
929 gst_object_unref (video_source);
930 }
931 g_object_set (camerabin, "zoom", zoom / 100.0f, NULL);
932
933 capture_count++;
934
935 timing = g_slice_new0 (CaptureTiming);
936 capture_times = g_list_prepend (capture_times, timing);
937
938 /* set pad probe to check when buffer leaves the camera source */
939 if (mode == MODE_IMAGE) {
940 GstPad *pad;
941
942 pad = gst_element_get_static_pad (video_source, "imgsrc");
943 camera_probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
944 camera_src_get_timestamp_probe, NULL, NULL);
945
946 gst_object_unref (pad);
947 }
948 timing->start_capture = gst_util_get_timestamp ();
949 g_signal_emit_by_name (camerabin, "start-capture", 0);
950
951 if (mode == MODE_VIDEO) {
952 g_timeout_add ((capture_time * 1000), (GSourceFunc) stop_capture, NULL);
953 }
954
955 return FALSE;
956 }
957
958 static void
parse_target_values(void)959 parse_target_values (void)
960 {
961 gdouble startup = 0, change_mode = 0, shot_to_save = 0, shot_to_snapshot = 0;
962 gdouble shot_to_shot = 0, preview_to_precapture = 0, shot_to_buffer = 0;
963
964 if (performance_targets_str == NULL)
965 return;
966
967 /*
968 startup time, change mode time, shot to save, shot to snapshot,
969 shot to shot, preview to precapture, shot to buffer.
970 */
971 sscanf (performance_targets_str, "%lf,%lf,%lf,%lf,%lf,%lf,%lf",
972 &startup, &change_mode, &shot_to_save,
973 &shot_to_snapshot, &shot_to_shot, &preview_to_precapture,
974 &shot_to_buffer);
975
976 target_startup = (GstClockTime) (startup * GST_SECOND);
977 target_change_mode = (GstClockTime) (change_mode * GST_SECOND);
978 target_shot_to_save = (GstClockTime) (shot_to_save * GST_SECOND);
979 target_shot_to_snapshot = (GstClockTime) (shot_to_snapshot * GST_SECOND);
980 target_shot_to_shot = (GstClockTime) (shot_to_shot * GST_SECOND);
981 target_preview_to_precapture =
982 (GstClockTime) (preview_to_precapture * GST_SECOND);
983 target_shot_to_buffer = (GstClockTime) (shot_to_buffer * GST_SECOND);
984 }
985
986 static void
print_performance_data(void)987 print_performance_data (void)
988 {
989 GList *iter;
990 gint i = 0;
991 GstClockTime last_start = 0;
992 CaptureTimingStats max;
993 CaptureTimingStats min;
994 CaptureTimingStats avg;
995 CaptureTimingStats avg_wo_first;
996 GstClockTime shot_to_shot;
997
998 if (!performance_measure)
999 return;
1000
1001 parse_target_values ();
1002
1003 /* Initialize stats */
1004 min.shot_to_shot = -1;
1005 min.shot_to_save = -1;
1006 min.shot_to_snapshot = -1;
1007 min.preview_to_precapture = -1;
1008 min.shot_to_buffer = -1;
1009 memset (&avg, 0, sizeof (CaptureTimingStats));
1010 memset (&avg_wo_first, 0, sizeof (CaptureTimingStats));
1011 memset (&max, 0, sizeof (CaptureTimingStats));
1012
1013 g_print ("-- Performance results --\n");
1014 g_print ("Startup time: %" TIME_FORMAT "; Target: %" TIME_FORMAT "\n",
1015 TIME_ARGS (startup_time - initial_time), TIME_ARGS (target_startup));
1016 g_print ("Change mode time: %" TIME_FORMAT "; Target: %" TIME_FORMAT "\n",
1017 TIME_ARGS (change_mode_after - change_mode_before),
1018 TIME_ARGS (target_change_mode));
1019
1020 g_print
1021 ("\n | Shot to save |Shot to snapshot| Shot to shot |"
1022 "Preview to precap| Shot to buffer\n");
1023 capture_times = g_list_reverse (capture_times);
1024 for (iter = capture_times; iter; iter = g_list_next (iter)) {
1025 CaptureTiming *t = (CaptureTiming *) iter->data;
1026 CaptureTimingStats stats;
1027
1028 stats.shot_to_save = SHOT_TO_SAVE (t);
1029 stats.shot_to_snapshot = SHOT_TO_SNAPSHOT (t);
1030 stats.shot_to_shot = i == 0 ? 0 : t->start_capture - last_start;
1031 stats.preview_to_precapture = PREVIEW_TO_PRECAPTURE (t);
1032 stats.shot_to_buffer = SHOT_TO_BUFFER (t);
1033
1034 PRINT_STATS (i, &stats);
1035
1036 if (i != 0) {
1037 capture_timing_stats_add (&avg_wo_first, &stats);
1038 }
1039 capture_timing_stats_add (&avg, &stats);
1040
1041 if (stats.shot_to_save < min.shot_to_save) {
1042 min.shot_to_save = stats.shot_to_save;
1043 }
1044 if (stats.shot_to_snapshot < min.shot_to_snapshot) {
1045 min.shot_to_snapshot = stats.shot_to_snapshot;
1046 }
1047 if (stats.shot_to_shot < min.shot_to_shot && stats.shot_to_shot > 0) {
1048 min.shot_to_shot = stats.shot_to_shot;
1049 }
1050 if (stats.preview_to_precapture < min.preview_to_precapture) {
1051 min.preview_to_precapture = stats.preview_to_precapture;
1052 }
1053 if (stats.shot_to_buffer < min.shot_to_buffer) {
1054 min.shot_to_buffer = stats.shot_to_buffer;
1055 }
1056
1057
1058 if (stats.shot_to_save > max.shot_to_save) {
1059 max.shot_to_save = stats.shot_to_save;
1060 }
1061 if (stats.shot_to_snapshot > max.shot_to_snapshot) {
1062 max.shot_to_snapshot = stats.shot_to_snapshot;
1063 }
1064 if (stats.shot_to_shot > max.shot_to_shot) {
1065 max.shot_to_shot = stats.shot_to_shot;
1066 }
1067 if (stats.preview_to_precapture > max.preview_to_precapture) {
1068 max.preview_to_precapture = stats.preview_to_precapture;
1069 }
1070 if (stats.shot_to_buffer > max.shot_to_buffer) {
1071 max.shot_to_buffer = stats.shot_to_buffer;
1072 }
1073
1074 last_start = t->start_capture;
1075 i++;
1076 }
1077
1078 if (i == 0)
1079 return;
1080
1081 if (i > 1)
1082 shot_to_shot = avg.shot_to_shot / (i - 1);
1083 else
1084 shot_to_shot = GST_CLOCK_TIME_NONE;
1085 capture_timing_stats_div (&avg, i);
1086 avg.shot_to_shot = shot_to_shot;
1087 if (i > 1)
1088 capture_timing_stats_div (&avg_wo_first, i - 1);
1089 else {
1090 memset (&avg_wo_first, 0, sizeof (CaptureTimingStats));
1091 }
1092
1093 g_print ("\n Stats | MIN | MAX |"
1094 " AVG | AVG wo First | Target | Diff \n");
1095 g_print ("Shot to shot | %" TIME_FORMAT " | %" TIME_FORMAT
1096 " | %" TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT
1097 " | %" TIMEDIFF_FORMAT "\n",
1098 TIME_ARGS (min.shot_to_shot), TIME_ARGS (max.shot_to_shot),
1099 TIME_ARGS (avg.shot_to_shot),
1100 TIME_ARGS (avg_wo_first.shot_to_shot),
1101 TIME_ARGS (target_shot_to_shot),
1102 TIMEDIFF_ARGS (TIME_DIFF (avg.shot_to_shot, target_shot_to_shot)));
1103 g_print ("Shot to save | %" TIME_FORMAT " | %" TIME_FORMAT
1104 " | %" TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT
1105 " | %" TIMEDIFF_FORMAT "\n",
1106 TIME_ARGS (min.shot_to_save), TIME_ARGS (max.shot_to_save),
1107 TIME_ARGS (avg.shot_to_save),
1108 TIME_ARGS (avg_wo_first.shot_to_save),
1109 TIME_ARGS (target_shot_to_save),
1110 TIMEDIFF_ARGS (TIME_DIFF (avg.shot_to_save, target_shot_to_save)));
1111 g_print ("Shot to snapshot | %" TIME_FORMAT " | %" TIME_FORMAT
1112 " | %" TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT
1113 " | %" TIMEDIFF_FORMAT "\n",
1114 TIME_ARGS (min.shot_to_snapshot),
1115 TIME_ARGS (max.shot_to_snapshot),
1116 TIME_ARGS (avg.shot_to_snapshot),
1117 TIME_ARGS (avg_wo_first.shot_to_snapshot),
1118 TIME_ARGS (target_shot_to_snapshot),
1119 TIMEDIFF_ARGS (TIME_DIFF (avg.shot_to_snapshot,
1120 target_shot_to_snapshot)));
1121 g_print ("Preview to precapture | %" TIME_FORMAT " | %" TIME_FORMAT " | %"
1122 TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT " | %" TIMEDIFF_FORMAT
1123 "\n", TIME_ARGS (min.preview_to_precapture),
1124 TIME_ARGS (max.preview_to_precapture),
1125 TIME_ARGS (avg.preview_to_precapture),
1126 TIME_ARGS (avg_wo_first.preview_to_precapture),
1127 TIME_ARGS (target_preview_to_precapture),
1128 TIMEDIFF_ARGS (TIME_DIFF (avg.preview_to_precapture,
1129 target_preview_to_precapture)));
1130 g_print ("Shot to buffer | %" TIME_FORMAT " | %" TIME_FORMAT " | %"
1131 TIME_FORMAT " | %" TIME_FORMAT " | %" TIME_FORMAT " | %" TIMEDIFF_FORMAT
1132 "\n", TIME_ARGS (min.shot_to_buffer), TIME_ARGS (max.shot_to_buffer),
1133 TIME_ARGS (avg.shot_to_buffer), TIME_ARGS (avg_wo_first.shot_to_buffer),
1134 TIME_ARGS (target_shot_to_buffer),
1135 TIMEDIFF_ARGS (TIME_DIFF (avg.shot_to_buffer, target_shot_to_buffer)));
1136 }
1137
1138 int
main(int argc,char * argv[])1139 main (int argc, char *argv[])
1140 {
1141 gchar *target_times = NULL;
1142 gchar *ev_option = NULL;
1143 gchar *fn_option = NULL;
1144
1145 GOptionEntry options[] = {
1146 {"ev-compensation", '\0', 0, G_OPTION_ARG_STRING, &ev_option,
1147 "EV compensation for source element GstPhotography interface", NULL},
1148 {"aperture", '\0', 0, G_OPTION_ARG_INT, &aperture,
1149 "Aperture (size of lens opening) for source element GstPhotography interface",
1150 NULL},
1151 {"flash-mode", '\0', 0, G_OPTION_ARG_INT,
1152 &flash_mode,
1153 "Flash mode for source element GstPhotography interface", NULL},
1154 {"scene-mode", '\0', 0, G_OPTION_ARG_INT,
1155 &scene_mode,
1156 "Scene mode for source element GstPhotography interface", NULL},
1157 {"exposure", '\0', 0, G_OPTION_ARG_INT64,
1158 &exposure,
1159 "Exposure time (in ms) for source element GstPhotography interface",
1160 NULL},
1161 {"iso-speed", '\0', 0, G_OPTION_ARG_INT,
1162 &iso_speed,
1163 "ISO speed for source element GstPhotography interface", NULL},
1164 {"white-balance-mode", '\0', 0, G_OPTION_ARG_INT,
1165 &wb_mode,
1166 "White balance mode for source element GstPhotography interface", NULL},
1167 {"colour-tone-mode", '\0', 0, G_OPTION_ARG_INT,
1168 &color_mode,
1169 "Colour tone mode for source element GstPhotography interface", NULL},
1170 {"directory", '\0', 0, G_OPTION_ARG_STRING, &fn_option,
1171 "Directory for capture file(s) (default is current directory)", NULL},
1172 {"mode", '\0', 0, G_OPTION_ARG_INT, &mode,
1173 "Capture mode (default = 1 (image), 2 = video)", NULL},
1174 {"capture-time", '\0', 0, G_OPTION_ARG_INT,
1175 &capture_time,
1176 "Time to capture video in seconds (default = 10)", NULL},
1177 {"capture-total", '\0', 0, G_OPTION_ARG_INT, &capture_total,
1178 "Total number of captures to be done (default = 1)", NULL},
1179 {"zoom", '\0', 0, G_OPTION_ARG_INT, &zoom,
1180 "Zoom (100 = 1x (default), 200 = 2x etc.)", NULL},
1181 {"wrapper-source", '\0', 0, G_OPTION_ARG_STRING, &wrappersrc_name,
1182 "Camera source wrapper used for setting the video source (default is wrappercamerabinsrc)",
1183 NULL},
1184 {"video-source", '\0', 0, G_OPTION_ARG_STRING, &videosrc_name,
1185 "Video source used in still capture and video recording", NULL},
1186 {"video-device", '\0', 0, G_OPTION_ARG_STRING, &videodevice_name,
1187 "Video device to be set on the video source", NULL},
1188 {"audio-source", '\0', 0, G_OPTION_ARG_STRING, &audiosrc_name,
1189 "Audio source used in video recording", NULL},
1190 {"image-pp", '\0', 0, G_OPTION_ARG_STRING, &imagepp_name,
1191 "List of image post-processing elements separated with comma", NULL},
1192 {"viewfinder-sink", '\0', 0, G_OPTION_ARG_STRING, &vfsink_name,
1193 "Viewfinder sink (default = fakesink)", NULL},
1194 {"image-width", '\0', 0, G_OPTION_ARG_INT, &image_width,
1195 "Width for image capture", NULL},
1196 {"image-height", '\0', 0, G_OPTION_ARG_INT, &image_height,
1197 "Height for image capture", NULL},
1198 {"view-framerate-num", '\0', 0, G_OPTION_ARG_INT, &view_framerate_num,
1199 "Framerate numerator for viewfinder", NULL},
1200 {"view-framerate-den", '\0', 0, G_OPTION_ARG_INT, &view_framerate_den,
1201 "Framerate denominator for viewfinder", NULL},
1202 {"preview-caps", '\0', 0, G_OPTION_ARG_STRING, &preview_caps_name,
1203 "Preview caps (e.g. video/x-raw-rgb,width=320,height=240)", NULL},
1204 {"viewfinder-filter", '\0', 0, G_OPTION_ARG_STRING, &viewfinder_filter,
1205 "Filter to process all frames going to viewfinder sink", NULL},
1206 {"x-width", '\0', 0, G_OPTION_ARG_INT, &x_width,
1207 "X window width (default = 320)", NULL},
1208 {"x-height", '\0', 0, G_OPTION_ARG_INT, &x_height,
1209 "X window height (default = 240)", NULL},
1210 {"no-xwindow", '\0', 0, G_OPTION_ARG_NONE, &no_xwindow,
1211 "Do not create XWindow", NULL},
1212 {"encoding-target", '\0', 0, G_OPTION_ARG_STRING, &gep_targetname,
1213 "Video encoding target name", NULL},
1214 {"encoding-profile", '\0', 0, G_OPTION_ARG_STRING, &gep_profilename,
1215 "Video encoding profile name", NULL},
1216 {"encoding-profile-filename", '\0', 0, G_OPTION_ARG_STRING, &gep_filename,
1217 "Video encoding profile filename", NULL},
1218 {"image-capture-caps", '\0', 0,
1219 G_OPTION_ARG_STRING, &image_capture_caps_str,
1220 "Image capture caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
1221 {"viewfinder-caps", '\0', 0, G_OPTION_ARG_STRING,
1222 &viewfinder_caps_str,
1223 "Viewfinder caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
1224 {"video-capture-caps", '\0', 0,
1225 G_OPTION_ARG_STRING, &video_capture_caps_str,
1226 "Video capture caps (e.g. video/x-raw-rgb,width=640,height=480)", NULL},
1227 {"audio-capture-caps", '\0', 0,
1228 G_OPTION_ARG_STRING, &audio_capture_caps_str,
1229 "Audio capture caps (e.g. audio/x-raw-int,width=16,depth=16,rate=44100,channels=2)",
1230 NULL},
1231 {"performance-measure", '\0', 0,
1232 G_OPTION_ARG_NONE, &performance_measure,
1233 "If performance information should be printed at the end of execution",
1234 NULL},
1235 {"performance-targets", '\0', 0,
1236 G_OPTION_ARG_STRING, &performance_targets_str,
1237 "Comma separated list of doubles representing the target values in "
1238 "seconds. The order is: startup time, change mode time, shot to save"
1239 ", shot to snapshot, shot to shot, preview to shot, shot to buffer. "
1240 "e.g. 3.5,1.0,5.0,2.5,5.0,1.5,1.0",
1241 NULL},
1242 {"flags", '\0', 0, G_OPTION_ARG_STRING, &camerabin_flags,
1243 "camerabin element flags (default = 0)", NULL},
1244 {NULL}
1245 };
1246
1247 GOptionContext *ctx;
1248 GError *err = NULL;
1249
1250 ctx = g_option_context_new ("\n\ncamerabin command line test application.");
1251 g_option_context_add_main_entries (ctx, options, NULL);
1252 g_option_context_add_group (ctx, gst_init_get_option_group ());
1253 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
1254 g_print ("Error initializing: %s\n", err->message);
1255 g_option_context_free (ctx);
1256 g_clear_error (&err);
1257 exit (1);
1258 }
1259 g_option_context_free (ctx);
1260
1261 GST_DEBUG_CATEGORY_INIT (camerabin_test, "camerabin-test", 0,
1262 "camerabin test");
1263
1264 /* if we fail to create xwindow should we care? */
1265 if (!no_xwindow)
1266 create_host_window ();
1267
1268 /* FIXME: error handling */
1269 if (ev_option != NULL)
1270 ev_compensation = strtod (ev_option, (char **) NULL);
1271
1272 if (vfsink_name == NULL)
1273 vfsink_name = g_strdup ("fakesink");
1274
1275 filename = g_string_new (fn_option);
1276 if (filename->len == 0)
1277 filename = g_string_append (filename, ".");
1278
1279 /* init */
1280 if (setup_pipeline ()) {
1281 loop = g_main_loop_new (NULL, FALSE);
1282 g_idle_add ((GSourceFunc) run_pipeline, NULL);
1283 g_main_loop_run (loop);
1284 cleanup_pipeline ();
1285 g_main_loop_unref (loop);
1286 }
1287
1288 /* performance */
1289 if (performance_measure) {
1290 print_performance_data ();
1291 }
1292
1293 /* free */
1294 {
1295 GList *iter;
1296
1297 for (iter = capture_times; iter; iter = g_list_next (iter)) {
1298 g_slice_free (CaptureTiming, iter->data);
1299 }
1300 g_list_free (capture_times);
1301 }
1302
1303 g_string_free (filename, TRUE);
1304 g_free (ev_option);
1305 g_free (wrappersrc_name);
1306 g_free (videosrc_name);
1307 g_free (videodevice_name);
1308 g_free (audiosrc_name);
1309 g_free (imagepp_name);
1310 g_free (vfsink_name);
1311 g_free (target_times);
1312 g_free (gep_targetname);
1313 g_free (gep_profilename);
1314 g_free (gep_filename);
1315 g_free (performance_targets_str);
1316
1317 if (window)
1318 XDestroyWindow (display, window);
1319
1320 if (display)
1321 XCloseDisplay (display);
1322
1323 return 0;
1324 }
1325