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