1 /* GStreamer android.hardware.Camera Source
2  *
3  * Copyright (C) 2012, Cisco Systems, Inc.
4  *   Author: Youness Alaoui <youness.alaoui@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
22 /**
23  * SECTION:element-ahcsrc
24  * @title: ahcsrc
25  *
26  * ahcsrc can be used to capture video from android devices. It uses the
27  * android.hardware.Camera Java API to capture from the system's cameras.
28  *
29  * In order for the plugin to get registered, it must be able to find its
30  * Java callbacks class. That class is embedded as a jar file inside the source
31  * element (if properly compiled) and will be written to a temporary directory
32  * so it can be loaded into the virtual machine.
33  * In order for it to work, an environment variable must be set to a writable
34  * directory.
35  * The source will look for the environment variable “TMPâ€� which must contain
36  * the absolute path to a writable directory.
37  * It can be retreived using the following Java code :
38  * |[
39  *   context.getCacheDir().getAbsolutePath();
40  * ]|
41  * Where the @context variable is an object of type android.content.Context
42  * (including its subclasses android.app.Activity or android.app.Application).
43  * Another optional environment variable can be set for pointing to the
44  * optimized dex classes directory. If the environment variable “DEXâ€� is
45  * available, it will be used, otherwise, the directory in the “TMPâ€� environment
46  * variable will be used for the optimized dex directory.
47  * The system dex directory can be obtained using the following Java code :
48  * |[
49  *   context.getDir("dex", 0).getAbsolutePath();
50  * ]|
51  *
52  * > Those environment variable must be set before gst_init is called from
53  * > the native code.
54  *
55  * > If the "TMP" environment variable is not available or the directory is not
56  * > writable or any other issue happens while trying to load the embedded jar
57  * > file, then the source will fallback on trying to load the class directly
58  * > from the running application.
59  * > The file com/gstreamer/GstAhcCallback.java in the source's directory can be
60  * > copied into the Android application so it can be loaded at runtime
61  * > as a fallback mechanism.
62  *
63  */
64 
65 #ifdef HAVE_CONFIG_H
66 #  include "config.h"
67 #endif
68 
69 #include <gst/video/video.h>
70 #include <gst/interfaces/photography.h>
71 
72 #include "gstjniutils.h"
73 
74 #include "gstahcsrc.h"
75 
76 /* GObject */
77 static void gst_ahc_src_set_property (GObject * object, guint prop_id,
78     const GValue * value, GParamSpec * pspec);
79 static void gst_ahc_src_get_property (GObject * object, guint prop_id,
80     GValue * value, GParamSpec * pspec);
81 static void gst_ahc_src_finalize (GObject * object);
82 
83 /* GstElement */
84 static GstStateChangeReturn gst_ahc_src_change_state (GstElement * element,
85     GstStateChange transition);
86 
87 /* GstBaseSrc */
88 static GstCaps *gst_ahc_src_getcaps (GstBaseSrc * src, GstCaps * filter);
89 static gboolean gst_ahc_src_setcaps (GstBaseSrc * src, GstCaps * caps);
90 static GstCaps *gst_ahc_src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
91 static gboolean gst_ahc_src_start (GstBaseSrc * bsrc);
92 static gboolean gst_ahc_src_stop (GstBaseSrc * bsrc);
93 static gboolean gst_ahc_src_unlock (GstBaseSrc * bsrc);
94 static gboolean gst_ahc_src_unlock_stop (GstBaseSrc * bsrc);
95 static GstFlowReturn gst_ahc_src_create (GstPushSrc * src, GstBuffer ** buffer);
96 static gboolean gst_ahc_src_query (GstBaseSrc * bsrc, GstQuery * query);
97 
98 /* GstPhotography  */
99 static void gst_ahc_src_photography_init (gpointer g_iface,
100     gpointer iface_data);
101 static gboolean gst_ahc_src_get_ev_compensation (GstPhotography * photo,
102     gfloat * ev_comp);
103 static gboolean _white_balance_to_enum (const gchar * white_balance,
104     GstPhotographyWhiteBalanceMode * mode);
105 static gboolean gst_ahc_src_get_white_balance_mode (GstPhotography * photo,
106     GstPhotographyWhiteBalanceMode * wb_mode);
107 static gboolean _color_effects_to_enum (const gchar * color_effect,
108     GstPhotographyColorToneMode * mode);
109 static gboolean gst_ahc_src_get_colour_tone_mode (GstPhotography * photo,
110     GstPhotographyColorToneMode * tone_mode);
111 static gboolean _scene_modes_to_enum (const gchar * scene,
112     GstPhotographySceneMode * mode);
113 static gboolean gst_ahc_src_get_scene_mode (GstPhotography * photo,
114     GstPhotographySceneMode * scene_mode);
115 static gboolean _flash_modes_to_enum (const gchar * flash,
116     GstPhotographyFlashMode * mode);
117 static gboolean gst_ahc_src_get_flash_mode (GstPhotography * photo,
118     GstPhotographyFlashMode * flash_mode);
119 static gboolean gst_ahc_src_get_zoom (GstPhotography * photo, gfloat * zoom);
120 static gboolean _antibanding_to_enum (const gchar * antibanding,
121     GstPhotographyFlickerReductionMode * mode);
122 static gboolean gst_ahc_src_get_flicker_mode (GstPhotography * photo,
123     GstPhotographyFlickerReductionMode * flicker_mode);
124 static gboolean _focus_modes_to_enum (const gchar * focus,
125     GstPhotographyFocusMode * mode);
126 static gboolean gst_ahc_src_get_focus_mode (GstPhotography * photo,
127     GstPhotographyFocusMode * focus_mode);
128 
129 static gboolean gst_ahc_src_set_ev_compensation (GstPhotography * photo,
130     gfloat ev_comp);
131 static gboolean gst_ahc_src_set_white_balance_mode (GstPhotography * photo,
132     GstPhotographyWhiteBalanceMode wb_mode);
133 static gboolean gst_ahc_src_set_colour_tone_mode (GstPhotography * photo,
134     GstPhotographyColorToneMode tone_mode);
135 static gboolean gst_ahc_src_set_scene_mode (GstPhotography * photo,
136     GstPhotographySceneMode scene_mode);
137 static gboolean gst_ahc_src_set_flash_mode (GstPhotography * photo,
138     GstPhotographyFlashMode flash_mode);
139 static gboolean gst_ahc_src_set_zoom (GstPhotography * photo, gfloat zoom);
140 static gboolean gst_ahc_src_set_flicker_mode (GstPhotography * photo,
141     GstPhotographyFlickerReductionMode flicker_mode);
142 static gboolean gst_ahc_src_set_focus_mode (GstPhotography * photo,
143     GstPhotographyFocusMode focus_mode);
144 
145 static GstPhotographyCaps gst_ahc_src_get_capabilities (GstPhotography * photo);
146 static void gst_ahc_src_set_autofocus (GstPhotography * photo, gboolean on);
147 
148 /* GstAHCSrc */
149 static void gst_ahc_src_close (GstAHCSrc * self);
150 static void gst_ahc_src_on_preview_frame (jbyteArray data, gpointer user_data);
151 static void gst_ahc_src_on_error (gint error, gpointer user_data);
152 static void gst_ahc_src_on_auto_focus (gboolean success, gpointer user_data);
153 
154 #define NUM_CALLBACK_BUFFERS 5
155 
156 #define GST_AHC_SRC_CAPS_STR                                    \
157   GST_VIDEO_CAPS_MAKE_WITH_FEATURES("ANY", " { YV12, YUY2, NV21, NV16, RGB16 }")
158 
159 static GstStaticPadTemplate gst_ahc_src_pad_template =
160 GST_STATIC_PAD_TEMPLATE ("src",
161     GST_PAD_SRC,
162     GST_PAD_ALWAYS,
163     GST_STATIC_CAPS (GST_AHC_SRC_CAPS_STR));
164 
165 GST_DEBUG_CATEGORY_STATIC (gst_ahc_src_debug);
166 #define GST_CAT_DEFAULT gst_ahc_src_debug
167 
168 #define parent_class gst_ahc_src_parent_class
169 
170 enum
171 {
172   PROP_0,
173   PROP_DEVICE,
174   PROP_DEVICE_NAME,
175   PROP_DEVICE_FACING,
176   PROP_DEVICE_ORIENTATION,
177   PROP_FOCAL_LENGTH,
178   PROP_HORIZONTAL_VIEW_ANGLE,
179   PROP_VERTICAL_VIEW_ANGLE,
180   PROP_VIDEO_STABILIZATION,
181   PROP_WB_MODE,
182   PROP_COLOUR_TONE,
183   PROP_SCENE_MODE,
184   PROP_FLASH_MODE,
185   PROP_NOISE_REDUCTION,
186   PROP_CAPABILITIES,
187   PROP_EV_COMP,
188   PROP_ISO_SPEED,
189   PROP_APERTURE,
190   PROP_EXPOSURE_MODE,
191   PROP_IMAGE_CAPTURE_SUPPORTED_CAPS,
192   PROP_IMAGE_PREVIEW_SUPPORTED_CAPS,
193   PROP_FLICKER_MODE,
194   PROP_FOCUS_MODE,
195   PROP_ZOOM,
196   PROP_SMOOTH_ZOOM,
197   PROP_WHITE_POINT,
198   PROP_MIN_EXPOSURE_TIME,
199   PROP_MAX_EXPOSURE_TIME,
200   PROP_LENS_FOCUS,
201   PROP_EXPOSURE_TIME,
202   PROP_COLOR_TEMPERATURE,
203   PROP_ANALOG_GAIN,
204   PROP_LAST
205 };
206 
207 static GParamSpec *properties[PROP_LAST];
208 
209 #define DEFAULT_DEVICE "0"
210 
211 G_DEFINE_TYPE_WITH_CODE (GstAHCSrc, gst_ahc_src, GST_TYPE_PUSH_SRC,
212     G_IMPLEMENT_INTERFACE (GST_TYPE_PHOTOGRAPHY, gst_ahc_src_photography_init));
213 
214 #define CAMERA_FACING_BACK 0
215 #define CAMERA_FACING_FRONT 1
216 
217 static GType
gst_ahc_src_facing_get_type(void)218 gst_ahc_src_facing_get_type (void)
219 {
220   static GType type = 0;
221   static const GEnumValue types[] = {
222     {CAMERA_FACING_BACK, "Back", "back"},
223     {CAMERA_FACING_FRONT, "Front", "front"},
224     {0, NULL, NULL}
225   };
226 
227   if (!type) {
228     type = g_enum_register_static ("GstAHCSrcFacing", types);
229   }
230   return type;
231 }
232 
233 #define GST_AHC_SRC_FACING_TYPE (gst_ahc_src_facing_get_type())
234 
235 static void
gst_ahc_src_photography_init(gpointer g_iface,gpointer iface_data)236 gst_ahc_src_photography_init (gpointer g_iface, gpointer iface_data)
237 {
238   GstPhotographyInterface *iface = g_iface;
239 
240   iface->get_ev_compensation = gst_ahc_src_get_ev_compensation;
241   iface->get_white_balance_mode = gst_ahc_src_get_white_balance_mode;
242   iface->get_color_tone_mode = gst_ahc_src_get_colour_tone_mode;
243   iface->get_scene_mode = gst_ahc_src_get_scene_mode;
244   iface->get_flash_mode = gst_ahc_src_get_flash_mode;
245   iface->get_zoom = gst_ahc_src_get_zoom;
246   iface->get_flicker_mode = gst_ahc_src_get_flicker_mode;
247   iface->get_focus_mode = gst_ahc_src_get_focus_mode;
248 
249   iface->set_ev_compensation = gst_ahc_src_set_ev_compensation;
250   iface->set_white_balance_mode = gst_ahc_src_set_white_balance_mode;
251   iface->set_color_tone_mode = gst_ahc_src_set_colour_tone_mode;
252   iface->set_scene_mode = gst_ahc_src_set_scene_mode;
253   iface->set_flash_mode = gst_ahc_src_set_flash_mode;
254   iface->set_zoom = gst_ahc_src_set_zoom;
255   iface->set_flicker_mode = gst_ahc_src_set_flicker_mode;
256   iface->set_focus_mode = gst_ahc_src_set_focus_mode;
257 
258   iface->get_capabilities = gst_ahc_src_get_capabilities;
259   iface->set_autofocus = gst_ahc_src_set_autofocus;
260 }
261 
262 static void
gst_ahc_src_class_init(GstAHCSrcClass * klass)263 gst_ahc_src_class_init (GstAHCSrcClass * klass)
264 {
265   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
266   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
267   GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
268   GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
269 
270   gobject_class->set_property = gst_ahc_src_set_property;
271   gobject_class->get_property = gst_ahc_src_get_property;
272   gobject_class->finalize = gst_ahc_src_finalize;
273 
274   element_class->change_state = gst_ahc_src_change_state;
275 
276   gstbasesrc_class->get_caps = gst_ahc_src_getcaps;
277   gstbasesrc_class->set_caps = gst_ahc_src_setcaps;
278   gstbasesrc_class->fixate = gst_ahc_src_fixate;
279   gstbasesrc_class->start = gst_ahc_src_start;
280   gstbasesrc_class->stop = gst_ahc_src_stop;
281   gstbasesrc_class->unlock = gst_ahc_src_unlock;
282   gstbasesrc_class->unlock_stop = gst_ahc_src_unlock_stop;
283   gstbasesrc_class->query = gst_ahc_src_query;
284 
285   gstpushsrc_class->create = gst_ahc_src_create;
286 
287   gst_element_class_add_static_pad_template (element_class,
288       &gst_ahc_src_pad_template);
289 
290   /**
291    * GstAHCSrc:device:
292    *
293    * The Device ID of the camera to capture from
294    */
295   properties[PROP_DEVICE] = g_param_spec_string ("device",
296       "Device", "Device ID", DEFAULT_DEVICE,
297       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
298   g_object_class_install_property (gobject_class, PROP_DEVICE,
299       properties[PROP_DEVICE]);
300 
301   /**
302    * GstAHCSrc:device-name:
303    *
304    * A user-friendly name for the camera device
305    */
306   properties[PROP_DEVICE_NAME] = g_param_spec_string ("device-name",
307       "Device name", "Device name", NULL,
308       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
309   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
310       properties[PROP_DEVICE_NAME]);
311 
312   /**
313    * GstAHCSrc:device-orientation:
314    *
315    * The orientation of the currently set camera @device.
316    * The value is the angle that the camera image needs to be rotated clockwise
317    * so it shows correctly on the display in its natural orientation.
318    * It should be 0, 90, 180, or 270.
319    */
320   properties[PROP_DEVICE_ORIENTATION] = g_param_spec_int ("device-orientation",
321       "Device orientation", "The orientation of the camera image",
322       0, 360, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
323   g_object_class_install_property (gobject_class, PROP_DEVICE_ORIENTATION,
324       properties[PROP_DEVICE_ORIENTATION]);
325 
326   /**
327    * GstAHCSrc:device-facing:
328    *
329    * The direction that the currently select camera @device faces.
330    *
331    * A value of 0 means the camera is facing the opposite direction as the
332    * screen while a value of 1 means the camera is facing the same direction
333    * as the screen.
334    */
335   properties[PROP_DEVICE_FACING] = g_param_spec_enum ("device-facing",
336       "Device facing", "The direction that the camera faces",
337       GST_AHC_SRC_FACING_TYPE, CAMERA_FACING_BACK,
338       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
339   g_object_class_install_property (gobject_class, PROP_DEVICE_FACING,
340       properties[PROP_DEVICE_FACING]);
341 
342   /**
343    * GstAHCSrc:focal-length:
344    *
345    * Gets the focal length (in millimeter) of the camera.
346    */
347   properties[PROP_FOCAL_LENGTH] = g_param_spec_float ("focal-length",
348       "Focal length", "Gets the focal length (in millimeter) of the camera",
349       -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
350   g_object_class_install_property (gobject_class, PROP_FOCAL_LENGTH,
351       properties[PROP_FOCAL_LENGTH]);
352 
353   /**
354    * GstAHCSrc:horizontal-view-angle:
355    *
356    * Gets the horizontal angle of view in degrees.
357    */
358   properties[PROP_HORIZONTAL_VIEW_ANGLE] =
359       g_param_spec_float ("horizontal-view-angle", "Horizontal view angle",
360       "Gets the horizontal angle of view in degrees",
361       -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
362   g_object_class_install_property (gobject_class, PROP_HORIZONTAL_VIEW_ANGLE,
363       properties[PROP_HORIZONTAL_VIEW_ANGLE]);
364 
365   /**
366    * GstAHCSrc:vertical-view-angle:
367    *
368    * Gets the vertical angle of view in degrees.
369    */
370   properties[PROP_VERTICAL_VIEW_ANGLE] =
371       g_param_spec_float ("vertical-view-angle", "Vertical view angle",
372       "Gets the vertical angle of view in degrees",
373       -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
374   g_object_class_install_property (gobject_class, PROP_VERTICAL_VIEW_ANGLE,
375       properties[PROP_VERTICAL_VIEW_ANGLE]);
376 
377   /**
378    * GstAHCSrc:video-stabilization:
379    *
380    * Video stabilization reduces the shaking due to the motion of the camera.
381    */
382   properties[PROP_VIDEO_STABILIZATION] =
383       g_param_spec_boolean ("video-stabilization", "Video stabilization",
384       "Video stabilization reduces the shaking due to the motion of the camera",
385       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
386   g_object_class_install_property (gobject_class, PROP_VIDEO_STABILIZATION,
387       properties[PROP_VIDEO_STABILIZATION]);
388 
389   /**
390    * GstAHCSrc:smooth-zoom:
391    *
392    * If enabled, then smooth zooming will be used when the @zoom property is
393    * changed. In that case, the @zoom property can be queried to know the
394    * current zoom level while the smooth zoom is in progress.
395    */
396   properties[PROP_SMOOTH_ZOOM] = g_param_spec_boolean ("smooth-zoom",
397       "Smooth Zoom", "Use smooth zoom when available",
398       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
399   g_object_class_install_property (gobject_class, PROP_SMOOTH_ZOOM,
400       properties[PROP_SMOOTH_ZOOM]);
401 
402   /* Override GstPhotography properties */
403   g_object_class_override_property (gobject_class, PROP_WB_MODE,
404       GST_PHOTOGRAPHY_PROP_WB_MODE);
405   properties[PROP_WB_MODE] = g_object_class_find_property (gobject_class,
406       GST_PHOTOGRAPHY_PROP_WB_MODE);
407 
408   g_object_class_override_property (gobject_class, PROP_COLOUR_TONE,
409       GST_PHOTOGRAPHY_PROP_COLOR_TONE);
410   properties[PROP_COLOUR_TONE] = g_object_class_find_property (gobject_class,
411       GST_PHOTOGRAPHY_PROP_COLOR_TONE);
412 
413   g_object_class_override_property (gobject_class, PROP_SCENE_MODE,
414       GST_PHOTOGRAPHY_PROP_SCENE_MODE);
415   properties[PROP_SCENE_MODE] = g_object_class_find_property (gobject_class,
416       GST_PHOTOGRAPHY_PROP_SCENE_MODE);
417 
418   g_object_class_override_property (gobject_class, PROP_FLASH_MODE,
419       GST_PHOTOGRAPHY_PROP_FLASH_MODE);
420   properties[PROP_FLASH_MODE] = g_object_class_find_property (gobject_class,
421       GST_PHOTOGRAPHY_PROP_FLASH_MODE);
422 
423   g_object_class_override_property (gobject_class, PROP_NOISE_REDUCTION,
424       GST_PHOTOGRAPHY_PROP_NOISE_REDUCTION);
425   properties[PROP_NOISE_REDUCTION] =
426       g_object_class_find_property (gobject_class,
427       GST_PHOTOGRAPHY_PROP_NOISE_REDUCTION);
428 
429   g_object_class_override_property (gobject_class, PROP_CAPABILITIES,
430       GST_PHOTOGRAPHY_PROP_CAPABILITIES);
431   properties[PROP_CAPABILITIES] = g_object_class_find_property (gobject_class,
432       GST_PHOTOGRAPHY_PROP_CAPABILITIES);
433 
434   g_object_class_override_property (gobject_class, PROP_EV_COMP,
435       GST_PHOTOGRAPHY_PROP_EV_COMP);
436   properties[PROP_EV_COMP] = g_object_class_find_property (gobject_class,
437       GST_PHOTOGRAPHY_PROP_EV_COMP);
438 
439   g_object_class_override_property (gobject_class, PROP_ISO_SPEED,
440       GST_PHOTOGRAPHY_PROP_ISO_SPEED);
441   properties[PROP_ISO_SPEED] = g_object_class_find_property (gobject_class,
442       GST_PHOTOGRAPHY_PROP_ISO_SPEED);
443 
444   g_object_class_override_property (gobject_class, PROP_APERTURE,
445       GST_PHOTOGRAPHY_PROP_APERTURE);
446   properties[PROP_APERTURE] = g_object_class_find_property (gobject_class,
447       GST_PHOTOGRAPHY_PROP_APERTURE);
448 
449 #if 0
450   g_object_class_override_property (gobject_class, PROP_EXPOSURE_MODE,
451       GST_PHOTOGRAPHY_PROP_EXPOSURE_MODE);
452   properties[PROP_EXPOSURE] = g_object_class_find_property (gobject_class,
453       GST_PHOTOGRAPHY_PROP_EXPOSURE_MODE);
454 #endif
455 
456   g_object_class_override_property (gobject_class,
457       PROP_IMAGE_CAPTURE_SUPPORTED_CAPS,
458       GST_PHOTOGRAPHY_PROP_IMAGE_CAPTURE_SUPPORTED_CAPS);
459   properties[PROP_IMAGE_CAPTURE_SUPPORTED_CAPS] =
460       g_object_class_find_property (gobject_class,
461       GST_PHOTOGRAPHY_PROP_IMAGE_CAPTURE_SUPPORTED_CAPS);
462 
463   g_object_class_override_property (gobject_class,
464       PROP_IMAGE_PREVIEW_SUPPORTED_CAPS,
465       GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS);
466   properties[PROP_IMAGE_PREVIEW_SUPPORTED_CAPS] =
467       g_object_class_find_property (gobject_class,
468       GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS);
469 
470   g_object_class_override_property (gobject_class, PROP_FLICKER_MODE,
471       GST_PHOTOGRAPHY_PROP_FLICKER_MODE);
472   properties[PROP_FLICKER_MODE] = g_object_class_find_property (gobject_class,
473       GST_PHOTOGRAPHY_PROP_FLICKER_MODE);
474 
475   g_object_class_override_property (gobject_class, PROP_FOCUS_MODE,
476       GST_PHOTOGRAPHY_PROP_FOCUS_MODE);
477   properties[PROP_FOCUS_MODE] = g_object_class_find_property (gobject_class,
478       GST_PHOTOGRAPHY_PROP_FOCUS_MODE);
479 
480   g_object_class_override_property (gobject_class, PROP_ZOOM,
481       GST_PHOTOGRAPHY_PROP_ZOOM);
482   properties[PROP_ZOOM] = g_object_class_find_property (gobject_class,
483       GST_PHOTOGRAPHY_PROP_ZOOM);
484 
485   g_object_class_override_property (gobject_class, PROP_WHITE_POINT,
486       GST_PHOTOGRAPHY_PROP_WHITE_POINT);
487   properties[PROP_WHITE_POINT] = g_object_class_find_property (gobject_class,
488       GST_PHOTOGRAPHY_PROP_WHITE_POINT);
489 
490   g_object_class_override_property (gobject_class, PROP_MIN_EXPOSURE_TIME,
491       GST_PHOTOGRAPHY_PROP_MIN_EXPOSURE_TIME);
492   properties[PROP_MIN_EXPOSURE_TIME] =
493       g_object_class_find_property (gobject_class,
494       GST_PHOTOGRAPHY_PROP_MIN_EXPOSURE_TIME);
495 
496   g_object_class_override_property (gobject_class, PROP_MAX_EXPOSURE_TIME,
497       GST_PHOTOGRAPHY_PROP_MAX_EXPOSURE_TIME);
498   properties[PROP_MAX_EXPOSURE_TIME] =
499       g_object_class_find_property (gobject_class,
500       GST_PHOTOGRAPHY_PROP_MAX_EXPOSURE_TIME);
501 
502   g_object_class_override_property (gobject_class, PROP_LENS_FOCUS,
503       GST_PHOTOGRAPHY_PROP_LENS_FOCUS);
504   properties[PROP_LENS_FOCUS] = g_object_class_find_property (gobject_class,
505       GST_PHOTOGRAPHY_PROP_LENS_FOCUS);
506 
507   g_object_class_override_property (gobject_class, PROP_EXPOSURE_TIME,
508       GST_PHOTOGRAPHY_PROP_EXPOSURE_TIME);
509   properties[PROP_EXPOSURE_TIME] = g_object_class_find_property (gobject_class,
510       GST_PHOTOGRAPHY_PROP_EXPOSURE_TIME);
511 
512   g_object_class_override_property (gobject_class, PROP_COLOR_TEMPERATURE,
513       GST_PHOTOGRAPHY_PROP_COLOR_TEMPERATURE);
514   properties[PROP_COLOR_TEMPERATURE] =
515       g_object_class_find_property (gobject_class,
516       GST_PHOTOGRAPHY_PROP_COLOR_TEMPERATURE);
517 
518   g_object_class_override_property (gobject_class, PROP_ANALOG_GAIN,
519       GST_PHOTOGRAPHY_PROP_ANALOG_GAIN);
520   properties[PROP_ANALOG_GAIN] = g_object_class_find_property (gobject_class,
521       GST_PHOTOGRAPHY_PROP_ANALOG_GAIN);
522 
523   gst_element_class_set_static_metadata (element_class,
524       "Android Camera Source",
525       "Source/Video/Hardware",
526       "Reads frames from android.hardware.Camera class into buffers",
527       "Youness Alaoui <youness.alaoui@collabora.co.uk>");
528 
529   GST_DEBUG_CATEGORY_INIT (gst_ahc_src_debug, "ahcsrc", 0,
530       "android.hardware.Camera source element");
531 }
532 
533 static gboolean
_data_queue_check_full(GstDataQueue * queue,guint visible,guint bytes,guint64 time,gpointer checkdata)534 _data_queue_check_full (GstDataQueue * queue, guint visible,
535     guint bytes, guint64 time, gpointer checkdata)
536 {
537   return FALSE;
538 }
539 
540 static void
gst_ahc_src_init(GstAHCSrc * self)541 gst_ahc_src_init (GstAHCSrc * self)
542 {
543   gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
544   gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
545   gst_base_src_set_do_timestamp (GST_BASE_SRC (self), FALSE);
546 
547   self->camera = NULL;
548   self->texture = NULL;
549   self->data = NULL;
550   self->queue = gst_data_queue_new (_data_queue_check_full, NULL, NULL, NULL);
551   self->start = FALSE;
552   self->previous_ts = GST_CLOCK_TIME_NONE;
553 
554   g_mutex_init (&self->mutex);
555 }
556 
557 static void
gst_ahc_src_finalize(GObject * object)558 gst_ahc_src_finalize (GObject * object)
559 {
560   GstAHCSrc *self = GST_AHC_SRC (object);
561 
562   g_clear_object (&self->queue);
563   g_mutex_clear (&self->mutex);
564 
565   G_OBJECT_CLASS (parent_class)->finalize (object);
566 }
567 
568 static void
gst_ahc_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)569 gst_ahc_src_set_property (GObject * object, guint prop_id,
570     const GValue * value, GParamSpec * pspec)
571 {
572   GstAHCSrc *self = GST_AHC_SRC (object);
573 
574   GST_DEBUG_OBJECT (self, "set props %d", prop_id);
575 
576   switch (prop_id) {
577     case PROP_DEVICE:{
578       const gchar *dev = g_value_get_string (value);
579       gchar *endptr = NULL;
580       guint64 device;
581 
582       device = g_ascii_strtoll (dev, &endptr, 10);
583       if (endptr != dev && endptr[0] == 0 && device < G_MAXINT)
584         self->device = (gint) device;
585     }
586       break;
587     case PROP_VIDEO_STABILIZATION:
588       if (self->camera) {
589         GstAHCParameters *params;
590 
591         params = gst_ah_camera_get_parameters (self->camera);
592         if (params) {
593           gst_ahc_parameters_set_video_stabilization (params,
594               g_value_get_boolean (value));
595           gst_ah_camera_set_parameters (self->camera, params);
596           gst_ahc_parameters_free (params);
597         }
598       }
599       break;
600     case PROP_SMOOTH_ZOOM:
601       self->smooth_zoom = g_value_get_boolean (value);
602       break;
603     case PROP_WB_MODE:{
604       GstPhotographyWhiteBalanceMode wb = g_value_get_enum (value);
605 
606       gst_ahc_src_set_white_balance_mode (GST_PHOTOGRAPHY (self), wb);
607     }
608       break;
609     case PROP_COLOUR_TONE:{
610       GstPhotographyColorToneMode tone = g_value_get_enum (value);
611 
612       gst_ahc_src_set_colour_tone_mode (GST_PHOTOGRAPHY (self), tone);
613     }
614       break;
615     case PROP_SCENE_MODE:{
616       GstPhotographySceneMode scene = g_value_get_enum (value);
617 
618       gst_ahc_src_set_scene_mode (GST_PHOTOGRAPHY (self), scene);
619     }
620       break;
621     case PROP_FLASH_MODE:{
622       GstPhotographyFlashMode flash = g_value_get_enum (value);
623 
624       gst_ahc_src_set_flash_mode (GST_PHOTOGRAPHY (self), flash);
625     }
626       break;
627     case PROP_EV_COMP:{
628       gfloat ev = g_value_get_float (value);
629 
630       gst_ahc_src_set_ev_compensation (GST_PHOTOGRAPHY (self), ev);
631     }
632       break;
633     case PROP_FLICKER_MODE:{
634       GstPhotographyFlickerReductionMode flicker = g_value_get_enum (value);
635 
636       gst_ahc_src_set_flicker_mode (GST_PHOTOGRAPHY (self), flicker);
637     }
638       break;
639     case PROP_FOCUS_MODE:{
640       GstPhotographyFocusMode focus = g_value_get_enum (value);
641 
642       gst_ahc_src_set_focus_mode (GST_PHOTOGRAPHY (self), focus);
643     }
644       break;
645     case PROP_ZOOM:{
646       gfloat zoom = g_value_get_float (value);
647 
648       gst_ahc_src_set_zoom (GST_PHOTOGRAPHY (self), zoom);
649     }
650       break;
651     case PROP_NOISE_REDUCTION:
652     case PROP_ISO_SPEED:
653     case PROP_APERTURE:
654     case PROP_EXPOSURE_MODE:
655     case PROP_IMAGE_CAPTURE_SUPPORTED_CAPS:
656     case PROP_IMAGE_PREVIEW_SUPPORTED_CAPS:
657     case PROP_WHITE_POINT:
658     case PROP_MIN_EXPOSURE_TIME:
659     case PROP_MAX_EXPOSURE_TIME:
660     case PROP_LENS_FOCUS:
661     case PROP_EXPOSURE_TIME:
662     case PROP_COLOR_TEMPERATURE:
663     case PROP_ANALOG_GAIN:
664       break;
665     default:
666       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667       break;
668   }
669 }
670 
671 static void
gst_ahc_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)672 gst_ahc_src_get_property (GObject * object, guint prop_id,
673     GValue * value, GParamSpec * pspec)
674 {
675   GstAHCSrc *self = GST_AHC_SRC (object);
676   (void) self;
677 
678   switch (prop_id) {
679     case PROP_DEVICE:{
680       gchar *dev = g_strdup_printf ("%d", self->device);
681 
682       g_value_take_string (value, dev);
683     }
684       break;
685     case PROP_DEVICE_NAME:{
686       GstAHCCameraInfo info;
687       gchar *dev;
688 
689       if (gst_ah_camera_get_camera_info (self->device, &info))
690         dev = g_strdup_printf ("#%d %s", self->device,
691             info.facing == CameraInfo_CAMERA_FACING_BACK ? "Back" : "Front");
692       else
693         dev = g_strdup_printf ("#%d", self->device);
694 
695       g_value_take_string (value, dev);
696     }
697       break;
698     case PROP_DEVICE_FACING:{
699       GstAHCCameraInfo info;
700 
701       if (gst_ah_camera_get_camera_info (self->device, &info))
702         g_value_set_enum (value, info.facing == CameraInfo_CAMERA_FACING_BACK ?
703             CAMERA_FACING_BACK : CAMERA_FACING_FRONT);
704       else
705         g_value_set_enum (value, CAMERA_FACING_BACK);
706     }
707       break;
708     case PROP_DEVICE_ORIENTATION:{
709       GstAHCCameraInfo info;
710 
711       if (gst_ah_camera_get_camera_info (self->device, &info))
712         g_value_set_int (value, info.orientation);
713       else
714         g_value_set_int (value, 0);
715     }
716       break;
717     case PROP_FOCAL_LENGTH:
718       if (self->camera) {
719         GstAHCParameters *params;
720 
721         params = gst_ah_camera_get_parameters (self->camera);
722         if (params) {
723           g_value_set_float (value,
724               gst_ahc_parameters_get_focal_length (params));
725           gst_ahc_parameters_free (params);
726         }
727       }
728       break;
729     case PROP_HORIZONTAL_VIEW_ANGLE:
730       if (self->camera) {
731         GstAHCParameters *params;
732 
733         params = gst_ah_camera_get_parameters (self->camera);
734         if (params) {
735           g_value_set_float (value,
736               gst_ahc_parameters_get_horizontal_view_angle (params));
737           gst_ahc_parameters_free (params);
738         }
739       }
740       break;
741     case PROP_VERTICAL_VIEW_ANGLE:
742       if (self->camera) {
743         GstAHCParameters *params;
744 
745         params = gst_ah_camera_get_parameters (self->camera);
746         if (params) {
747           g_value_set_float (value,
748               gst_ahc_parameters_get_vertical_view_angle (params));
749           gst_ahc_parameters_free (params);
750         }
751       }
752       break;
753     case PROP_VIDEO_STABILIZATION:
754       if (self->camera) {
755         GstAHCParameters *params;
756 
757         params = gst_ah_camera_get_parameters (self->camera);
758         if (params) {
759           g_value_set_boolean (value,
760               gst_ahc_parameters_get_video_stabilization (params));
761           gst_ahc_parameters_free (params);
762         }
763       }
764       break;
765     case PROP_SMOOTH_ZOOM:
766       g_value_set_boolean (value, self->smooth_zoom);
767       break;
768     case PROP_WB_MODE:{
769       GstPhotographyWhiteBalanceMode wb;
770 
771       if (gst_ahc_src_get_white_balance_mode (GST_PHOTOGRAPHY (self), &wb))
772         g_value_set_enum (value, wb);
773     }
774       break;
775     case PROP_COLOUR_TONE:{
776       GstPhotographyColorToneMode tone;
777 
778       if (gst_ahc_src_get_colour_tone_mode (GST_PHOTOGRAPHY (self), &tone))
779         g_value_set_enum (value, tone);
780     }
781       break;
782     case PROP_SCENE_MODE:{
783       GstPhotographySceneMode scene;
784 
785       if (gst_ahc_src_get_scene_mode (GST_PHOTOGRAPHY (self), &scene))
786         g_value_set_enum (value, scene);
787     }
788       break;
789     case PROP_FLASH_MODE:{
790       GstPhotographyFlashMode flash;
791 
792       if (gst_ahc_src_get_flash_mode (GST_PHOTOGRAPHY (self), &flash))
793         g_value_set_enum (value, flash);
794     }
795       break;
796     case PROP_CAPABILITIES:{
797       GstPhotographyCaps caps;
798 
799       caps = gst_ahc_src_get_capabilities (GST_PHOTOGRAPHY (self));
800       g_value_set_ulong (value, caps);
801     }
802       break;
803     case PROP_EV_COMP:{
804       gfloat ev;
805 
806       if (gst_ahc_src_get_ev_compensation (GST_PHOTOGRAPHY (self), &ev))
807         g_value_set_float (value, ev);
808     }
809       break;
810     case PROP_FLICKER_MODE:{
811       GstPhotographyFlickerReductionMode flicker;
812 
813       if (gst_ahc_src_get_flicker_mode (GST_PHOTOGRAPHY (self), &flicker))
814         g_value_set_enum (value, flicker);
815     }
816       break;
817     case PROP_FOCUS_MODE:{
818       GstPhotographyFocusMode focus;
819 
820       if (gst_ahc_src_get_focus_mode (GST_PHOTOGRAPHY (self), &focus))
821         g_value_set_enum (value, focus);
822     }
823       break;
824     case PROP_ZOOM:{
825       gfloat zoom;
826 
827       if (gst_ahc_src_get_zoom (GST_PHOTOGRAPHY (self), &zoom))
828         g_value_set_float (value, zoom);
829     }
830       break;
831     case PROP_IMAGE_CAPTURE_SUPPORTED_CAPS:
832     case PROP_IMAGE_PREVIEW_SUPPORTED_CAPS:
833     case PROP_NOISE_REDUCTION:
834     case PROP_ISO_SPEED:
835     case PROP_APERTURE:
836     case PROP_EXPOSURE_MODE:
837     case PROP_WHITE_POINT:
838     case PROP_MIN_EXPOSURE_TIME:
839     case PROP_MAX_EXPOSURE_TIME:
840     case PROP_LENS_FOCUS:
841     case PROP_EXPOSURE_TIME:
842     case PROP_COLOR_TEMPERATURE:
843     case PROP_ANALOG_GAIN:
844       break;
845     default:
846       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
847       break;
848   }
849 }
850 
851 static gboolean
_antibanding_to_enum(const gchar * antibanding,GstPhotographyFlickerReductionMode * mode)852 _antibanding_to_enum (const gchar * antibanding,
853     GstPhotographyFlickerReductionMode * mode)
854 {
855   if (antibanding == Parameters_ANTIBANDING_AUTO)
856     *mode = GST_PHOTOGRAPHY_FLICKER_REDUCTION_AUTO;
857   else if (antibanding == Parameters_ANTIBANDING_50HZ)
858     *mode = GST_PHOTOGRAPHY_FLICKER_REDUCTION_50HZ;
859   else if (antibanding == Parameters_ANTIBANDING_60HZ)
860     *mode = GST_PHOTOGRAPHY_FLICKER_REDUCTION_60HZ;
861   else if (antibanding == Parameters_ANTIBANDING_OFF)
862     *mode = GST_PHOTOGRAPHY_FLICKER_REDUCTION_OFF;
863   else
864     return FALSE;
865 
866   return TRUE;
867 }
868 
869 static gboolean
_white_balance_to_enum(const gchar * white_balance,GstPhotographyWhiteBalanceMode * mode)870 _white_balance_to_enum (const gchar * white_balance,
871     GstPhotographyWhiteBalanceMode * mode)
872 {
873   if (white_balance == Parameters_WHITE_BALANCE_AUTO)
874     *mode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
875   else if (white_balance == Parameters_WHITE_BALANCE_INCANDESCENT)
876     *mode = GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN;
877   else if (white_balance == Parameters_WHITE_BALANCE_FLUORESCENT)
878     *mode = GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT;
879   else if (white_balance == Parameters_WHITE_BALANCE_WARM_FLUORESCENT)
880     *mode = GST_PHOTOGRAPHY_WB_MODE_WARM_FLUORESCENT;
881   else if (white_balance == Parameters_WHITE_BALANCE_DAYLIGHT)
882     *mode = GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT;
883   else if (white_balance == Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT)
884     *mode = GST_PHOTOGRAPHY_WB_MODE_CLOUDY;
885   else if (white_balance == Parameters_WHITE_BALANCE_TWILIGHT)
886     *mode = GST_PHOTOGRAPHY_WB_MODE_SUNSET;
887   else if (white_balance == Parameters_WHITE_BALANCE_SHADE)
888     *mode = GST_PHOTOGRAPHY_WB_MODE_SHADE;
889   else
890     return FALSE;
891 
892   return TRUE;
893 }
894 
895 static gboolean
_color_effects_to_enum(const gchar * color_effect,GstPhotographyColorToneMode * mode)896 _color_effects_to_enum (const gchar * color_effect,
897     GstPhotographyColorToneMode * mode)
898 {
899   if (color_effect == Parameters_EFFECT_NONE)
900     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL;
901   else if (color_effect == Parameters_EFFECT_MONO)
902     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_GRAYSCALE;
903   else if (color_effect == Parameters_EFFECT_NEGATIVE)
904     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_NEGATIVE;
905   else if (color_effect == Parameters_EFFECT_SOLARIZE)
906     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_SOLARIZE;
907   else if (color_effect == Parameters_EFFECT_SEPIA)
908     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_SEPIA;
909   else if (color_effect == Parameters_EFFECT_POSTERIZE)
910     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_POSTERIZE;
911   else if (color_effect == Parameters_EFFECT_WHITEBOARD)
912     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_WHITEBOARD;
913   else if (color_effect == Parameters_EFFECT_BLACKBOARD)
914     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_BLACKBOARD;
915   else if (color_effect == Parameters_EFFECT_AQUA)
916     *mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_AQUA;
917   else
918     return FALSE;
919 
920   return TRUE;
921 }
922 
923 static gboolean
_scene_modes_to_enum(const gchar * scene,GstPhotographySceneMode * mode)924 _scene_modes_to_enum (const gchar * scene, GstPhotographySceneMode * mode)
925 {
926   if (scene == Parameters_SCENE_MODE_AUTO)
927     *mode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
928   else if (scene == Parameters_SCENE_MODE_ACTION)
929     *mode = GST_PHOTOGRAPHY_SCENE_MODE_ACTION;
930   else if (scene == Parameters_SCENE_MODE_PORTRAIT)
931     *mode = GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT;
932   else if (scene == Parameters_SCENE_MODE_LANDSCAPE)
933     *mode = GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE;
934   else if (scene == Parameters_SCENE_MODE_NIGHT)
935     *mode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT;
936   else if (scene == Parameters_SCENE_MODE_NIGHT_PORTRAIT)
937     *mode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT_PORTRAIT;
938   else if (scene == Parameters_SCENE_MODE_THEATRE)
939     *mode = GST_PHOTOGRAPHY_SCENE_MODE_THEATRE;
940   else if (scene == Parameters_SCENE_MODE_BEACH)
941     *mode = GST_PHOTOGRAPHY_SCENE_MODE_BEACH;
942   else if (scene == Parameters_SCENE_MODE_SNOW)
943     *mode = GST_PHOTOGRAPHY_SCENE_MODE_SNOW;
944   else if (scene == Parameters_SCENE_MODE_SUNSET)
945     *mode = GST_PHOTOGRAPHY_SCENE_MODE_SUNSET;
946   else if (scene == Parameters_SCENE_MODE_STEADYPHOTO)
947     *mode = GST_PHOTOGRAPHY_SCENE_MODE_STEADY_PHOTO;
948   else if (scene == Parameters_SCENE_MODE_FIREWORKS)
949     *mode = GST_PHOTOGRAPHY_SCENE_MODE_FIREWORKS;
950   else if (scene == Parameters_SCENE_MODE_SPORTS)
951     *mode = GST_PHOTOGRAPHY_SCENE_MODE_SPORT;
952   else if (scene == Parameters_SCENE_MODE_PARTY)
953     *mode = GST_PHOTOGRAPHY_SCENE_MODE_PARTY;
954   else if (scene == Parameters_SCENE_MODE_CANDLELIGHT)
955     *mode = GST_PHOTOGRAPHY_SCENE_MODE_CANDLELIGHT;
956   else if (scene == Parameters_SCENE_MODE_BARCODE)
957     *mode = GST_PHOTOGRAPHY_SCENE_MODE_BARCODE;
958   else
959     return FALSE;
960 
961   return TRUE;
962 }
963 
964 static gboolean
_flash_modes_to_enum(const gchar * flash,GstPhotographyFlashMode * mode)965 _flash_modes_to_enum (const gchar * flash, GstPhotographyFlashMode * mode)
966 {
967   if (flash == Parameters_FLASH_MODE_OFF)
968     *mode = GST_PHOTOGRAPHY_FLASH_MODE_OFF;
969   else if (flash == Parameters_FLASH_MODE_AUTO)
970     *mode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO;
971   else if (flash == Parameters_FLASH_MODE_ON)
972     *mode = GST_PHOTOGRAPHY_FLASH_MODE_ON;
973   else if (flash == Parameters_FLASH_MODE_RED_EYE)
974     *mode = GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE;
975   else if (flash == Parameters_FLASH_MODE_TORCH)
976     *mode = GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN;
977   else
978     return FALSE;
979 
980   return TRUE;
981 }
982 
983 static gboolean
_focus_modes_to_enum(const gchar * focus,GstPhotographyFocusMode * mode)984 _focus_modes_to_enum (const gchar * focus, GstPhotographyFocusMode * mode)
985 {
986   if (focus == Parameters_FOCUS_MODE_AUTO)
987     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_AUTO;
988   else if (focus == Parameters_FOCUS_MODE_INFINITY)
989     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY;
990   else if (focus == Parameters_FOCUS_MODE_MACRO)
991     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_MACRO;
992   else if (focus == Parameters_FOCUS_MODE_FIXED)
993     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_HYPERFOCAL;
994   else if (focus == Parameters_FOCUS_MODE_EDOF)
995     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_EXTENDED;
996   else if (focus == Parameters_FOCUS_MODE_CONTINUOUS_VIDEO)
997     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_EXTENDED;
998   else if (focus == Parameters_FOCUS_MODE_CONTINUOUS_PICTURE)
999     *mode = GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL;
1000   else
1001     return FALSE;
1002 
1003   return TRUE;
1004 }
1005 
1006 static gboolean
gst_ahc_src_get_ev_compensation(GstPhotography * photo,gfloat * ev_comp)1007 gst_ahc_src_get_ev_compensation (GstPhotography * photo, gfloat * ev_comp)
1008 {
1009   GstAHCSrc *self = GST_AHC_SRC (photo);
1010   gboolean ret = FALSE;
1011 
1012   if (self->camera) {
1013     GstAHCParameters *params;
1014 
1015     params = gst_ah_camera_get_parameters (self->camera);
1016     if (params) {
1017       gint ev, min, max;
1018       gfloat step;
1019 
1020       ev = gst_ahc_parameters_get_exposure_compensation (params);
1021       min = gst_ahc_parameters_get_min_exposure_compensation (params);
1022       max = gst_ahc_parameters_get_max_exposure_compensation (params);
1023       step = gst_ahc_parameters_get_exposure_compensation_step (params);
1024 
1025       if (step != 0.0 && min != max && min <= ev && ev <= max) {
1026         if (ev_comp)
1027           *ev_comp = ev * step;
1028         ret = TRUE;
1029       }
1030       gst_ahc_parameters_free (params);
1031     }
1032   }
1033 
1034   return ret;
1035 }
1036 
1037 static gboolean
gst_ahc_src_get_white_balance_mode(GstPhotography * photo,GstPhotographyWhiteBalanceMode * wb_mode)1038 gst_ahc_src_get_white_balance_mode (GstPhotography * photo,
1039     GstPhotographyWhiteBalanceMode * wb_mode)
1040 {
1041   GstAHCSrc *self = GST_AHC_SRC (photo);
1042   gboolean ret = FALSE;
1043 
1044   if (self->camera) {
1045     GstAHCParameters *params;
1046 
1047     params = gst_ah_camera_get_parameters (self->camera);
1048     if (params) {
1049       const gchar *wb = gst_ahc_parameters_get_white_balance (params);
1050       GstPhotographyWhiteBalanceMode mode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
1051 
1052       if (_white_balance_to_enum (wb, &mode)) {
1053         ret = TRUE;
1054 
1055         if (wb_mode)
1056           *wb_mode = mode;
1057       }
1058 
1059       gst_ahc_parameters_free (params);
1060     }
1061   }
1062 
1063   return ret;
1064 }
1065 
1066 static gboolean
gst_ahc_src_get_colour_tone_mode(GstPhotography * photo,GstPhotographyColorToneMode * tone_mode)1067 gst_ahc_src_get_colour_tone_mode (GstPhotography * photo,
1068     GstPhotographyColorToneMode * tone_mode)
1069 {
1070   GstAHCSrc *self = GST_AHC_SRC (photo);
1071   gboolean ret = FALSE;
1072 
1073   if (self->camera) {
1074     GstAHCParameters *params;
1075 
1076     params = gst_ah_camera_get_parameters (self->camera);
1077     if (params) {
1078       const gchar *effect = gst_ahc_parameters_get_color_effect (params);
1079       GstPhotographyColorToneMode mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL;
1080 
1081       if (_color_effects_to_enum (effect, &mode)) {
1082         ret = TRUE;
1083 
1084         if (tone_mode)
1085           *tone_mode = mode;
1086       }
1087 
1088       gst_ahc_parameters_free (params);
1089     }
1090   }
1091 
1092   return ret;
1093 }
1094 
1095 static gboolean
gst_ahc_src_get_scene_mode(GstPhotography * photo,GstPhotographySceneMode * scene_mode)1096 gst_ahc_src_get_scene_mode (GstPhotography * photo,
1097     GstPhotographySceneMode * scene_mode)
1098 {
1099   GstAHCSrc *self = GST_AHC_SRC (photo);
1100   gboolean ret = FALSE;
1101 
1102   if (scene_mode && self->camera) {
1103     GstAHCParameters *params;
1104 
1105     params = gst_ah_camera_get_parameters (self->camera);
1106     if (params) {
1107       const gchar *scene = gst_ahc_parameters_get_scene_mode (params);
1108       GstPhotographySceneMode mode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
1109 
1110       if (_scene_modes_to_enum (scene, &mode)) {
1111         ret = TRUE;
1112 
1113         if (scene_mode)
1114           *scene_mode = mode;
1115       }
1116 
1117       gst_ahc_parameters_free (params);
1118     }
1119   }
1120 
1121   return ret;
1122 }
1123 
1124 static gboolean
gst_ahc_src_get_flash_mode(GstPhotography * photo,GstPhotographyFlashMode * flash_mode)1125 gst_ahc_src_get_flash_mode (GstPhotography * photo,
1126     GstPhotographyFlashMode * flash_mode)
1127 {
1128   GstAHCSrc *self = GST_AHC_SRC (photo);
1129   gboolean ret = FALSE;
1130 
1131   if (self->camera) {
1132     GstAHCParameters *params;
1133 
1134     params = gst_ah_camera_get_parameters (self->camera);
1135     if (params) {
1136       const gchar *flash = gst_ahc_parameters_get_flash_mode (params);
1137       GstPhotographyFlashMode mode = GST_PHOTOGRAPHY_FLASH_MODE_OFF;
1138 
1139       if (_flash_modes_to_enum (flash, &mode)) {
1140         ret = TRUE;
1141 
1142         if (flash_mode)
1143           *flash_mode = mode;
1144       }
1145 
1146       gst_ahc_parameters_free (params);
1147     }
1148   }
1149 
1150   return ret;
1151 }
1152 
1153 static gboolean
gst_ahc_src_get_zoom(GstPhotography * photo,gfloat * zoom)1154 gst_ahc_src_get_zoom (GstPhotography * photo, gfloat * zoom)
1155 {
1156   GstAHCSrc *self = GST_AHC_SRC (photo);
1157   gboolean ret = FALSE;
1158 
1159   if (self->camera) {
1160     GstAHCParameters *params;
1161 
1162     params = gst_ah_camera_get_parameters (self->camera);
1163     if (params) {
1164       GList *zoom_ratios = gst_ahc_parameters_get_zoom_ratios (params);
1165       gint zoom_idx = gst_ahc_parameters_get_zoom (params);
1166       gint max_zoom = gst_ahc_parameters_get_max_zoom (params);
1167 
1168       if (zoom_ratios && g_list_length (zoom_ratios) == (max_zoom + 1) &&
1169           zoom_idx >= 0 && zoom_idx < max_zoom) {
1170         gint zoom_value;
1171 
1172         zoom_value = GPOINTER_TO_INT (g_list_nth_data (zoom_ratios, zoom_idx));
1173         if (zoom)
1174           *zoom = (gfloat) zoom_value / 100.0;
1175 
1176         ret = TRUE;
1177       }
1178 
1179       gst_ahc_parameters_zoom_ratios_free (zoom_ratios);
1180       gst_ahc_parameters_free (params);
1181     }
1182   }
1183 
1184   return ret;
1185 }
1186 
1187 static gboolean
gst_ahc_src_get_flicker_mode(GstPhotography * photo,GstPhotographyFlickerReductionMode * flicker_mode)1188 gst_ahc_src_get_flicker_mode (GstPhotography * photo,
1189     GstPhotographyFlickerReductionMode * flicker_mode)
1190 {
1191   GstAHCSrc *self = GST_AHC_SRC (photo);
1192   gboolean ret = FALSE;
1193 
1194   if (self->camera) {
1195     GstAHCParameters *params;
1196 
1197     params = gst_ah_camera_get_parameters (self->camera);
1198     if (params) {
1199       const gchar *antibanding = gst_ahc_parameters_get_antibanding (params);
1200       GstPhotographyFlickerReductionMode mode =
1201           GST_PHOTOGRAPHY_FLICKER_REDUCTION_AUTO;
1202 
1203       if (_antibanding_to_enum (antibanding, &mode)) {
1204         ret = TRUE;
1205 
1206         if (flicker_mode)
1207           *flicker_mode = mode;
1208       }
1209 
1210       gst_ahc_parameters_free (params);
1211     }
1212   }
1213 
1214   return ret;
1215 }
1216 
1217 static gboolean
gst_ahc_src_get_focus_mode(GstPhotography * photo,GstPhotographyFocusMode * focus_mode)1218 gst_ahc_src_get_focus_mode (GstPhotography * photo,
1219     GstPhotographyFocusMode * focus_mode)
1220 {
1221   GstAHCSrc *self = GST_AHC_SRC (photo);
1222   gboolean ret = FALSE;
1223 
1224   if (self->camera) {
1225     GstAHCParameters *params;
1226 
1227     params = gst_ah_camera_get_parameters (self->camera);
1228     if (params) {
1229       const gchar *focus = gst_ahc_parameters_get_focus_mode (params);
1230       GstPhotographyFocusMode mode = GST_PHOTOGRAPHY_FOCUS_MODE_AUTO;
1231 
1232       if (_focus_modes_to_enum (focus, &mode)) {
1233         ret = TRUE;
1234 
1235         if (focus_mode)
1236           *focus_mode = mode;
1237       }
1238 
1239       gst_ahc_parameters_free (params);
1240     }
1241   }
1242 
1243   return ret;
1244 }
1245 
1246 
1247 static gboolean
gst_ahc_src_set_ev_compensation(GstPhotography * photo,gfloat ev_comp)1248 gst_ahc_src_set_ev_compensation (GstPhotography * photo, gfloat ev_comp)
1249 {
1250   GstAHCSrc *self = GST_AHC_SRC (photo);
1251   gboolean ret = FALSE;
1252 
1253   if (self->camera) {
1254     GstAHCParameters *params;
1255 
1256     params = gst_ah_camera_get_parameters (self->camera);
1257     if (params) {
1258       gint ev, min, max;
1259       gfloat step;
1260 
1261       ev = gst_ahc_parameters_get_exposure_compensation (params);
1262       min = gst_ahc_parameters_get_min_exposure_compensation (params);
1263       max = gst_ahc_parameters_get_max_exposure_compensation (params);
1264       step = gst_ahc_parameters_get_exposure_compensation_step (params);
1265       if (step != 0.0 && min != max &&
1266           (min * step) <= ev_comp && ev_comp <= (max * step)) {
1267         ev = ev_comp / step;
1268         if ((ev * step) == ev_comp) {
1269           gst_ahc_parameters_set_exposure_compensation (params, ev);
1270           ret = gst_ah_camera_set_parameters (self->camera, params);
1271         }
1272       }
1273     }
1274     gst_ahc_parameters_free (params);
1275   }
1276 
1277   return ret;
1278 }
1279 
1280 static gboolean
gst_ahc_src_set_white_balance_mode(GstPhotography * photo,GstPhotographyWhiteBalanceMode wb_mode)1281 gst_ahc_src_set_white_balance_mode (GstPhotography * photo,
1282     GstPhotographyWhiteBalanceMode wb_mode)
1283 {
1284   GstAHCSrc *self = GST_AHC_SRC (photo);
1285   gboolean ret = FALSE;
1286 
1287   if (self->camera) {
1288     GstAHCParameters *params;
1289 
1290     params = gst_ah_camera_get_parameters (self->camera);
1291     if (params) {
1292       const gchar *white_balance = NULL;
1293 
1294       switch (wb_mode) {
1295         case GST_PHOTOGRAPHY_WB_MODE_AUTO:
1296           white_balance = Parameters_WHITE_BALANCE_AUTO;
1297           break;
1298         case GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT:
1299           white_balance = Parameters_WHITE_BALANCE_DAYLIGHT;
1300           break;
1301         case GST_PHOTOGRAPHY_WB_MODE_CLOUDY:
1302           white_balance = Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT;
1303           break;
1304         case GST_PHOTOGRAPHY_WB_MODE_SUNSET:
1305           white_balance = Parameters_WHITE_BALANCE_TWILIGHT;
1306           break;
1307         case GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN:
1308           white_balance = Parameters_WHITE_BALANCE_INCANDESCENT;
1309           break;
1310         case GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT:
1311           white_balance = Parameters_WHITE_BALANCE_FLUORESCENT;
1312           break;
1313         case GST_PHOTOGRAPHY_WB_MODE_WARM_FLUORESCENT:
1314           white_balance = Parameters_WHITE_BALANCE_WARM_FLUORESCENT;
1315           break;
1316         case GST_PHOTOGRAPHY_WB_MODE_SHADE:
1317           white_balance = Parameters_WHITE_BALANCE_SHADE;
1318           break;
1319         default:
1320           white_balance = NULL;
1321           break;
1322       }
1323 
1324       if (white_balance) {
1325         gst_ahc_parameters_set_white_balance (params, white_balance);
1326         ret = gst_ah_camera_set_parameters (self->camera, params);
1327       }
1328       gst_ahc_parameters_free (params);
1329     }
1330   }
1331 
1332   return ret;
1333 }
1334 
1335 static gboolean
gst_ahc_src_set_colour_tone_mode(GstPhotography * photo,GstPhotographyColorToneMode tone_mode)1336 gst_ahc_src_set_colour_tone_mode (GstPhotography * photo,
1337     GstPhotographyColorToneMode tone_mode)
1338 {
1339   GstAHCSrc *self = GST_AHC_SRC (photo);
1340   gboolean ret = FALSE;
1341 
1342   if (self->camera) {
1343     GstAHCParameters *params;
1344 
1345     params = gst_ah_camera_get_parameters (self->camera);
1346     if (params) {
1347       const gchar *color_effect = NULL;
1348 
1349       switch (tone_mode) {
1350         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL:
1351           color_effect = Parameters_EFFECT_NONE;
1352           break;
1353         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_SEPIA:
1354           color_effect = Parameters_EFFECT_SEPIA;
1355           break;
1356         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_NEGATIVE:
1357           color_effect = Parameters_EFFECT_NEGATIVE;
1358           break;
1359         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_GRAYSCALE:
1360           color_effect = Parameters_EFFECT_MONO;
1361           break;
1362         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_SOLARIZE:
1363           color_effect = Parameters_EFFECT_SOLARIZE;
1364           break;
1365         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_POSTERIZE:
1366           color_effect = Parameters_EFFECT_POSTERIZE;
1367           break;
1368         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_WHITEBOARD:
1369           color_effect = Parameters_EFFECT_WHITEBOARD;
1370           break;
1371         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_BLACKBOARD:
1372           color_effect = Parameters_EFFECT_BLACKBOARD;
1373           break;
1374         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_AQUA:
1375           color_effect = Parameters_EFFECT_AQUA;
1376           break;
1377         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_NATURAL:
1378         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_VIVID:
1379         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_COLORSWAP:
1380         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_OUT_OF_FOCUS:
1381         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_SKY_BLUE:
1382         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_GRASS_GREEN:
1383         case GST_PHOTOGRAPHY_COLOR_TONE_MODE_SKIN_WHITEN:
1384         default:
1385           color_effect = NULL;
1386           break;
1387       }
1388 
1389       if (color_effect) {
1390         gst_ahc_parameters_set_color_effect (params, color_effect);
1391         ret = gst_ah_camera_set_parameters (self->camera, params);
1392       }
1393       gst_ahc_parameters_free (params);
1394     }
1395   }
1396 
1397   return ret;
1398 }
1399 
1400 static gboolean
gst_ahc_src_set_scene_mode(GstPhotography * photo,GstPhotographySceneMode scene_mode)1401 gst_ahc_src_set_scene_mode (GstPhotography * photo,
1402     GstPhotographySceneMode scene_mode)
1403 {
1404   GstAHCSrc *self = GST_AHC_SRC (photo);
1405   gboolean ret = FALSE;
1406 
1407   if (self->camera) {
1408     GstAHCParameters *params;
1409 
1410     params = gst_ah_camera_get_parameters (self->camera);
1411     if (params) {
1412       const gchar *scene = NULL;
1413 
1414       switch (scene_mode) {
1415         case GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT:
1416           scene = Parameters_SCENE_MODE_PORTRAIT;
1417           break;
1418         case GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE:
1419           scene = Parameters_SCENE_MODE_LANDSCAPE;
1420           break;
1421         case GST_PHOTOGRAPHY_SCENE_MODE_SPORT:
1422           scene = Parameters_SCENE_MODE_SPORTS;
1423           break;
1424         case GST_PHOTOGRAPHY_SCENE_MODE_NIGHT:
1425           scene = Parameters_SCENE_MODE_NIGHT;
1426           break;
1427         case GST_PHOTOGRAPHY_SCENE_MODE_AUTO:
1428           scene = Parameters_SCENE_MODE_AUTO;
1429           break;
1430         case GST_PHOTOGRAPHY_SCENE_MODE_ACTION:
1431           scene = Parameters_SCENE_MODE_ACTION;
1432           break;
1433         case GST_PHOTOGRAPHY_SCENE_MODE_NIGHT_PORTRAIT:
1434           scene = Parameters_SCENE_MODE_NIGHT_PORTRAIT;
1435           break;
1436         case GST_PHOTOGRAPHY_SCENE_MODE_THEATRE:
1437           scene = Parameters_SCENE_MODE_THEATRE;
1438           break;
1439         case GST_PHOTOGRAPHY_SCENE_MODE_BEACH:
1440           scene = Parameters_SCENE_MODE_BEACH;
1441           break;
1442         case GST_PHOTOGRAPHY_SCENE_MODE_SNOW:
1443           scene = Parameters_SCENE_MODE_SNOW;
1444           break;
1445         case GST_PHOTOGRAPHY_SCENE_MODE_SUNSET:
1446           scene = Parameters_SCENE_MODE_SUNSET;
1447           break;
1448         case GST_PHOTOGRAPHY_SCENE_MODE_STEADY_PHOTO:
1449           scene = Parameters_SCENE_MODE_STEADYPHOTO;
1450           break;
1451         case GST_PHOTOGRAPHY_SCENE_MODE_FIREWORKS:
1452           scene = Parameters_SCENE_MODE_FIREWORKS;
1453           break;
1454         case GST_PHOTOGRAPHY_SCENE_MODE_PARTY:
1455           scene = Parameters_SCENE_MODE_PARTY;
1456           break;
1457         case GST_PHOTOGRAPHY_SCENE_MODE_CANDLELIGHT:
1458           scene = Parameters_SCENE_MODE_CANDLELIGHT;
1459           break;
1460         case GST_PHOTOGRAPHY_SCENE_MODE_BARCODE:
1461           scene = Parameters_SCENE_MODE_BARCODE;
1462           break;
1463         case GST_PHOTOGRAPHY_SCENE_MODE_MANUAL:
1464         case GST_PHOTOGRAPHY_SCENE_MODE_CLOSEUP:
1465         default:
1466           scene = NULL;
1467           break;
1468       }
1469 
1470       if (scene) {
1471         gst_ahc_parameters_set_scene_mode (params, scene);
1472         ret = gst_ah_camera_set_parameters (self->camera, params);
1473       }
1474       gst_ahc_parameters_free (params);
1475     }
1476   }
1477 
1478   return ret;
1479 }
1480 
1481 static gboolean
gst_ahc_src_set_flash_mode(GstPhotography * photo,GstPhotographyFlashMode flash_mode)1482 gst_ahc_src_set_flash_mode (GstPhotography * photo,
1483     GstPhotographyFlashMode flash_mode)
1484 {
1485   GstAHCSrc *self = GST_AHC_SRC (photo);
1486   gboolean ret = FALSE;
1487 
1488   if (self->camera) {
1489     GstAHCParameters *params;
1490 
1491     params = gst_ah_camera_get_parameters (self->camera);
1492     if (params) {
1493       const gchar *flash = NULL;
1494 
1495       switch (flash_mode) {
1496         case GST_PHOTOGRAPHY_FLASH_MODE_AUTO:
1497           flash = Parameters_FLASH_MODE_AUTO;
1498           break;
1499         case GST_PHOTOGRAPHY_FLASH_MODE_OFF:
1500           flash = Parameters_FLASH_MODE_OFF;
1501           break;
1502         case GST_PHOTOGRAPHY_FLASH_MODE_ON:
1503           flash = Parameters_FLASH_MODE_ON;
1504           break;
1505         case GST_PHOTOGRAPHY_FLASH_MODE_FILL_IN:
1506           flash = Parameters_FLASH_MODE_TORCH;
1507           break;
1508         case GST_PHOTOGRAPHY_FLASH_MODE_RED_EYE:
1509           flash = Parameters_FLASH_MODE_RED_EYE;
1510           break;
1511         default:
1512           flash = NULL;
1513           break;
1514       }
1515 
1516       if (flash) {
1517         gst_ahc_parameters_set_flash_mode (params, flash);
1518         ret = gst_ah_camera_set_parameters (self->camera, params);
1519       }
1520       gst_ahc_parameters_free (params);
1521     }
1522   }
1523 
1524   return ret;
1525 }
1526 
1527 static gboolean
gst_ahc_src_set_zoom(GstPhotography * photo,gfloat zoom)1528 gst_ahc_src_set_zoom (GstPhotography * photo, gfloat zoom)
1529 {
1530   GstAHCSrc *self = GST_AHC_SRC (photo);
1531   gboolean ret = FALSE;
1532 
1533   if (self->camera) {
1534     GstAHCParameters *params;
1535 
1536     params = gst_ah_camera_get_parameters (self->camera);
1537     if (params) {
1538       GList *zoom_ratios = gst_ahc_parameters_get_zoom_ratios (params);
1539       gint max_zoom = gst_ahc_parameters_get_max_zoom (params);
1540       gint zoom_idx = -1;
1541 
1542       if (zoom_ratios && g_list_length (zoom_ratios) == (max_zoom + 1)) {
1543         gint i;
1544         gint value = zoom * 100;
1545 
1546         for (i = 0; i < max_zoom + 1; i++) {
1547           gint zoom_value = GPOINTER_TO_INT (g_list_nth_data (zoom_ratios, i));
1548 
1549           if (value == zoom_value)
1550             zoom_idx = i;
1551         }
1552       }
1553 
1554       if (zoom_idx != -1) {
1555         if (self->smooth_zoom &&
1556             gst_ahc_parameters_is_smooth_zoom_supported (params)) {
1557           // First, we need to cancel any previous smooth zoom operation
1558           gst_ah_camera_stop_smooth_zoom (self->camera);
1559           ret = gst_ah_camera_start_smooth_zoom (self->camera, zoom_idx);
1560         } else {
1561           gst_ahc_parameters_set_zoom (params, zoom_idx);
1562           ret = gst_ah_camera_set_parameters (self->camera, params);
1563         }
1564       }
1565 
1566       gst_ahc_parameters_zoom_ratios_free (zoom_ratios);
1567       gst_ahc_parameters_free (params);
1568     }
1569   }
1570 
1571   return ret;
1572 }
1573 
1574 static gboolean
gst_ahc_src_set_flicker_mode(GstPhotography * photo,GstPhotographyFlickerReductionMode flicker_mode)1575 gst_ahc_src_set_flicker_mode (GstPhotography * photo,
1576     GstPhotographyFlickerReductionMode flicker_mode)
1577 {
1578   GstAHCSrc *self = GST_AHC_SRC (photo);
1579   gboolean ret = FALSE;
1580 
1581   if (self->camera) {
1582     GstAHCParameters *params;
1583 
1584     params = gst_ah_camera_get_parameters (self->camera);
1585     if (params) {
1586       const gchar *antibanding = NULL;
1587 
1588       switch (flicker_mode) {
1589         case GST_PHOTOGRAPHY_FLICKER_REDUCTION_OFF:
1590           antibanding = Parameters_ANTIBANDING_OFF;
1591           break;
1592         case GST_PHOTOGRAPHY_FLICKER_REDUCTION_50HZ:
1593           antibanding = Parameters_ANTIBANDING_50HZ;
1594           break;
1595         case GST_PHOTOGRAPHY_FLICKER_REDUCTION_60HZ:
1596           antibanding = Parameters_ANTIBANDING_60HZ;
1597           break;
1598         case GST_PHOTOGRAPHY_FLICKER_REDUCTION_AUTO:
1599           antibanding = Parameters_ANTIBANDING_AUTO;
1600           break;
1601         default:
1602           antibanding = NULL;
1603           break;
1604       }
1605 
1606       if (antibanding) {
1607         gst_ahc_parameters_set_antibanding (params, antibanding);
1608         ret = gst_ah_camera_set_parameters (self->camera, params);
1609       }
1610       gst_ahc_parameters_free (params);
1611     }
1612   }
1613 
1614   return ret;
1615 }
1616 
1617 static gboolean
gst_ahc_src_set_focus_mode(GstPhotography * photo,GstPhotographyFocusMode focus_mode)1618 gst_ahc_src_set_focus_mode (GstPhotography * photo,
1619     GstPhotographyFocusMode focus_mode)
1620 {
1621   GstAHCSrc *self = GST_AHC_SRC (photo);
1622   gboolean ret = FALSE;
1623 
1624   if (self->camera) {
1625     GstAHCParameters *params;
1626 
1627     params = gst_ah_camera_get_parameters (self->camera);
1628     if (params) {
1629       const gchar *focus = NULL;
1630 
1631       switch (focus_mode) {
1632         case GST_PHOTOGRAPHY_FOCUS_MODE_AUTO:
1633           focus = Parameters_FOCUS_MODE_AUTO;
1634           break;
1635         case GST_PHOTOGRAPHY_FOCUS_MODE_MACRO:
1636           focus = Parameters_FOCUS_MODE_MACRO;
1637           break;
1638         case GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY:
1639           focus = Parameters_FOCUS_MODE_INFINITY;
1640           break;
1641         case GST_PHOTOGRAPHY_FOCUS_MODE_HYPERFOCAL:
1642           focus = Parameters_FOCUS_MODE_FIXED;
1643           break;
1644         case GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL:
1645           focus = Parameters_FOCUS_MODE_CONTINUOUS_PICTURE;
1646           break;
1647         case GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_EXTENDED:
1648           focus = Parameters_FOCUS_MODE_CONTINUOUS_VIDEO;
1649           break;
1650         case GST_PHOTOGRAPHY_FOCUS_MODE_EXTENDED:
1651           focus = Parameters_FOCUS_MODE_EDOF;
1652           break;
1653         case GST_PHOTOGRAPHY_FOCUS_MODE_PORTRAIT:
1654         default:
1655           focus = NULL;
1656           break;
1657       }
1658 
1659       if (focus) {
1660         gst_ahc_parameters_set_focus_mode (params, focus);
1661         ret = gst_ah_camera_set_parameters (self->camera, params);
1662       }
1663       gst_ahc_parameters_free (params);
1664     }
1665   }
1666 
1667   return ret;
1668 }
1669 
1670 static GstPhotographyCaps
gst_ahc_src_get_capabilities(GstPhotography * photo)1671 gst_ahc_src_get_capabilities (GstPhotography * photo)
1672 {
1673   GstAHCSrc *self = GST_AHC_SRC (photo);
1674 
1675   GstPhotographyCaps caps = GST_PHOTOGRAPHY_CAPS_EV_COMP |
1676       GST_PHOTOGRAPHY_CAPS_WB_MODE | GST_PHOTOGRAPHY_CAPS_TONE |
1677       GST_PHOTOGRAPHY_CAPS_SCENE | GST_PHOTOGRAPHY_CAPS_FLASH |
1678       GST_PHOTOGRAPHY_CAPS_FOCUS | GST_PHOTOGRAPHY_CAPS_ZOOM;
1679 
1680   if (self->camera) {
1681     GstAHCParameters *params;
1682 
1683     params = gst_ah_camera_get_parameters (self->camera);
1684     if (!gst_ahc_parameters_is_zoom_supported (params))
1685       caps &= ~GST_PHOTOGRAPHY_CAPS_ZOOM;
1686 
1687     gst_ahc_parameters_free (params);
1688   }
1689 
1690   return caps;
1691 }
1692 
1693 static void
gst_ahc_src_on_auto_focus(gboolean success,gpointer user_data)1694 gst_ahc_src_on_auto_focus (gboolean success, gpointer user_data)
1695 {
1696   GstAHCSrc *self = GST_AHC_SRC (user_data);
1697 
1698   GST_WARNING_OBJECT (self, "Auto focus completed : %d", success);
1699   gst_element_post_message (GST_ELEMENT (self),
1700       gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (self),
1701           gst_structure_new_empty (GST_PHOTOGRAPHY_AUTOFOCUS_DONE)));
1702 }
1703 
1704 static void
gst_ahc_src_set_autofocus(GstPhotography * photo,gboolean on)1705 gst_ahc_src_set_autofocus (GstPhotography * photo, gboolean on)
1706 {
1707   GstAHCSrc *self = GST_AHC_SRC (photo);
1708 
1709   if (self->camera) {
1710     if (on)
1711       gst_ah_camera_auto_focus (self->camera, gst_ahc_src_on_auto_focus, self);
1712     else
1713       gst_ah_camera_cancel_auto_focus (self->camera);
1714   }
1715 
1716 }
1717 
1718 static gint
_compare_formats(int f1,int f2)1719 _compare_formats (int f1, int f2)
1720 {
1721   if (f1 == f2)
1722     return 0;
1723   /* YV12 has priority */
1724   if (f1 == ImageFormat_YV12)
1725     return -1;
1726   if (f2 == ImageFormat_YV12)
1727     return 1;
1728   /* Then NV21 */
1729   if (f1 == ImageFormat_NV21)
1730     return -1;
1731   if (f2 == ImageFormat_NV21)
1732     return 1;
1733   /* Then we don't care */
1734   return f2 - f1;
1735 }
1736 
1737 static gint
_compare_sizes(GstAHCSize * s1,GstAHCSize * s2)1738 _compare_sizes (GstAHCSize * s1, GstAHCSize * s2)
1739 {
1740   return ((s2->width * s2->height) - (s1->width * s1->height));
1741 }
1742 
1743 
1744 static gint
_compare_ranges(int * r1,int * r2)1745 _compare_ranges (int *r1, int *r2)
1746 {
1747   if (r1[1] == r2[1])
1748     /* Smallest range */
1749     return (r1[1] - r1[0]) - (r2[1] - r2[0]);
1750   else
1751     /* Highest fps */
1752     return r2[1] - r1[1];
1753 }
1754 
1755 static GstCaps *
gst_ahc_src_getcaps(GstBaseSrc * src,GstCaps * filter)1756 gst_ahc_src_getcaps (GstBaseSrc * src, GstCaps * filter)
1757 {
1758   GstAHCSrc *self = GST_AHC_SRC (src);
1759 
1760   if (self->camera) {
1761     GstCaps *ret = gst_caps_new_empty ();
1762     GstAHCParameters *params;
1763 
1764     params = gst_ah_camera_get_parameters (self->camera);
1765     if (params) {
1766       GList *formats, *sizes, *ranges;
1767       GList *i, *j, *k;
1768       int previous_format = ImageFormat_UNKNOWN;
1769 
1770       formats = gst_ahc_parameters_get_supported_preview_formats (params);
1771       formats = g_list_sort (formats, (GCompareFunc) _compare_formats);
1772       sizes = gst_ahc_parameters_get_supported_preview_sizes (params);
1773       sizes = g_list_sort (sizes, (GCompareFunc) _compare_sizes);
1774       ranges = gst_ahc_parameters_get_supported_preview_fps_range (params);
1775       ranges = g_list_sort (ranges, (GCompareFunc) _compare_ranges);
1776       GST_DEBUG_OBJECT (self, "Supported preview formats:");
1777 
1778       for (i = formats; i; i = i->next) {
1779         int f = GPOINTER_TO_INT (i->data);
1780         gchar *format_string = NULL;
1781         GstStructure *format = NULL;
1782 
1783         /* Ignore duplicates */
1784         if (f == previous_format)
1785           continue;
1786 
1787         /* Can't use switch/case because the values are not constants */
1788         if (f == ImageFormat_NV16) {
1789           GST_DEBUG_OBJECT (self, "    NV16 (%d)", f);
1790           format_string = g_strdup ("NV16");
1791         } else if (f == ImageFormat_NV21) {
1792           GST_DEBUG_OBJECT (self, "    NV21 (%d)", f);
1793           format_string = g_strdup ("NV21");
1794         } else if (f == ImageFormat_RGB_565) {
1795           GstVideoFormat vformat;
1796           vformat = gst_video_format_from_masks (16, 16, G_LITTLE_ENDIAN,
1797               0xf800, 0x07e0, 0x001f, 0x0);
1798           GST_DEBUG_OBJECT (self, "    RGB565 (%d)", f);
1799           format_string = g_strdup (gst_video_format_to_string (vformat));
1800         } else if (f == ImageFormat_YUY2) {
1801           GST_DEBUG_OBJECT (self, "    YUY2 (%d)", f);
1802           format_string = g_strdup ("YUY2");
1803         } else if (f == ImageFormat_YV12) {
1804           GST_DEBUG_OBJECT (self, "    YV12 (%d)", f);
1805           format_string = g_strdup ("YV12");
1806         }
1807         previous_format = f;
1808 
1809         if (format_string) {
1810           format = gst_structure_new ("video/x-raw",
1811               "format", G_TYPE_STRING, format_string, NULL);
1812           g_free (format_string);
1813         }
1814 
1815         if (format) {
1816           for (j = sizes; j; j = j->next) {
1817             GstAHCSize *s = j->data;
1818             GstStructure *size;
1819 
1820             size = gst_structure_copy (format);
1821             gst_structure_set (size, "width", G_TYPE_INT, s->width,
1822                 "height", G_TYPE_INT, s->height,
1823                 "interlaced", G_TYPE_BOOLEAN, FALSE,
1824                 "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
1825 
1826             for (k = ranges; k; k = k->next) {
1827               int *range = k->data;
1828               GstStructure *s;
1829 
1830               s = gst_structure_copy (size);
1831               if (range[0] == range[1]) {
1832                 gst_structure_set (s, "framerate", GST_TYPE_FRACTION,
1833                     range[0], 1000, NULL);
1834               } else {
1835                 gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE,
1836                     range[0], 1000, range[1], 1000, NULL);
1837               }
1838               gst_caps_append_structure (ret, s);
1839             }
1840             gst_structure_free (size);
1841           }
1842           gst_structure_free (format);
1843         }
1844       }
1845       GST_DEBUG_OBJECT (self, "Supported preview sizes:");
1846       for (i = sizes; i; i = i->next) {
1847         GstAHCSize *s = i->data;
1848 
1849         GST_DEBUG_OBJECT (self, "    %dx%d", s->width, s->height);
1850       }
1851       GST_DEBUG_OBJECT (self, "Supported preview fps range:");
1852       for (i = ranges; i; i = i->next) {
1853         int *range = i->data;
1854 
1855         GST_DEBUG_OBJECT (self, "    [%d, %d]", range[0], range[1]);
1856       }
1857 
1858       gst_ahc_parameters_supported_preview_formats_free (formats);
1859       gst_ahc_parameters_supported_preview_sizes_free (sizes);
1860       gst_ahc_parameters_supported_preview_fps_range_free (ranges);
1861       gst_ahc_parameters_free (params);
1862     }
1863 
1864     return ret;
1865   } else {
1866     return NULL;
1867   }
1868 }
1869 
1870 static GstCaps *
gst_ahc_src_fixate(GstBaseSrc * src,GstCaps * caps)1871 gst_ahc_src_fixate (GstBaseSrc * src, GstCaps * caps)
1872 {
1873   GstAHCSrc *self = GST_AHC_SRC (src);
1874   GstStructure *s = gst_caps_get_structure (caps, 0);
1875 
1876   GST_DEBUG_OBJECT (self, "Fixating : %" GST_PTR_FORMAT, caps);
1877 
1878   caps = gst_caps_make_writable (caps);
1879 
1880   /* Width/height will be fixed already here, format will
1881    * be left for fixation by the default handler.
1882    * We only have to fixate framerate here, to the
1883    * highest possible framerate.
1884    */
1885   gst_structure_fixate_field_nearest_fraction (s, "framerate", G_MAXINT, 1);
1886 
1887   caps = GST_BASE_SRC_CLASS (parent_class)->fixate (src, caps);
1888 
1889   return caps;
1890 }
1891 
1892 static gboolean
gst_ahc_src_setcaps(GstBaseSrc * src,GstCaps * caps)1893 gst_ahc_src_setcaps (GstBaseSrc * src, GstCaps * caps)
1894 {
1895   GstAHCSrc *self = GST_AHC_SRC (src);
1896   gboolean ret = FALSE;
1897   GstAHCParameters *params = NULL;
1898 
1899   if (!self->camera) {
1900     GST_WARNING_OBJECT (self, "setcaps called without a camera available");
1901     goto end;
1902   }
1903 
1904   params = gst_ah_camera_get_parameters (self->camera);
1905   if (params) {
1906     GstStructure *s;
1907     const gchar *format_str = NULL;
1908     GstVideoFormat format;
1909     gint fmt;
1910     gint width, height, fps_n, fps_d, buffer_size;
1911     GList *ranges, *l;
1912     gint range_size = G_MAXINT;
1913 
1914     s = gst_caps_get_structure (caps, 0);
1915 
1916     format_str = gst_structure_get_string (s, "format");
1917     format = gst_video_format_from_string (format_str);
1918 
1919     gst_structure_get_int (s, "width", &width);
1920     gst_structure_get_int (s, "height", &height);
1921     gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
1922 
1923     fps_n *= 1000 / fps_d;
1924 
1925     /* Select the best range that contains our framerate.
1926      * We *must* set a range of those returned by the camera
1927      * according to the API docs and can't use a subset of any
1928      * of those ranges.
1929      * We chose the smallest range that contains the target
1930      * framerate.
1931      */
1932     self->fps_max = self->fps_min = 0;
1933     ranges = gst_ahc_parameters_get_supported_preview_fps_range (params);
1934     ranges = g_list_sort (ranges, (GCompareFunc) _compare_ranges);
1935     for (l = ranges; l; l = l->next) {
1936       int *range = l->data;
1937 
1938       if (fps_n >= range[0] && fps_n <= range[1] &&
1939           range_size > (range[1] - range[0])) {
1940         self->fps_min = range[0];
1941         self->fps_max = range[1];
1942         range_size = range[1] - range[0];
1943       }
1944     }
1945     gst_ahc_parameters_supported_preview_fps_range_free (ranges);
1946     if (self->fps_max == 0 || self->fps_min == 0) {
1947       GST_ERROR_OBJECT (self, "Couldn't find an applicable FPS range");
1948       goto end;
1949     }
1950 
1951     switch (format) {
1952       case GST_VIDEO_FORMAT_YV12:
1953         fmt = ImageFormat_YV12;
1954         break;
1955       case GST_VIDEO_FORMAT_NV21:
1956         fmt = ImageFormat_NV21;
1957         break;
1958       case GST_VIDEO_FORMAT_YUY2:
1959         fmt = ImageFormat_YUY2;
1960         break;
1961       case GST_VIDEO_FORMAT_RGB16:
1962         fmt = ImageFormat_RGB_565;
1963         break;
1964         /* GST_VIDEO_FORMAT_NV16 doesn't exist */
1965         //case GST_VIDEO_FORMAT_NV16:
1966         //fmt = ImageFormat_NV16;
1967         //break;
1968       default:
1969         fmt = ImageFormat_UNKNOWN;
1970         break;
1971     }
1972 
1973     if (fmt == ImageFormat_UNKNOWN) {
1974       GST_WARNING_OBJECT (self, "unsupported video format (%s)", format_str);
1975       goto end;
1976     }
1977 
1978     gst_ahc_parameters_set_preview_size (params, width, height);
1979     gst_ahc_parameters_set_preview_format (params, fmt);
1980     gst_ahc_parameters_set_preview_fps_range (params, self->fps_min,
1981         self->fps_max);
1982 
1983     GST_DEBUG_OBJECT (self, "Setting camera parameters : %d %dx%d @ [%f, %f]",
1984         fmt, width, height, self->fps_min / 1000.0, self->fps_max / 1000.0);
1985 
1986     if (!gst_ah_camera_set_parameters (self->camera, params)) {
1987       GST_WARNING_OBJECT (self, "Unable to set video parameters");
1988       goto end;
1989     }
1990 
1991     self->width = width;
1992     self->height = height;
1993     self->format = fmt;
1994     buffer_size = width * height *
1995         ((double) gst_ag_imageformat_get_bits_per_pixel (fmt) / 8);
1996 
1997     if (buffer_size > self->buffer_size) {
1998       JNIEnv *env = gst_amc_jni_get_env ();
1999       gint i;
2000 
2001       for (i = 0; i < NUM_CALLBACK_BUFFERS; i++) {
2002         jbyteArray array = (*env)->NewByteArray (env, buffer_size);
2003 
2004         if (array) {
2005           gst_ah_camera_add_callback_buffer (self->camera, array);
2006           (*env)->DeleteLocalRef (env, array);
2007         }
2008       }
2009     }
2010     self->buffer_size = buffer_size;
2011 
2012     GST_DEBUG_OBJECT (self, "setting buffer w:%d h:%d buffer_size: %d",
2013         self->width, self->height, self->buffer_size);
2014 
2015     ret = TRUE;
2016   }
2017 
2018 end:
2019   if (params)
2020     gst_ahc_parameters_free (params);
2021 
2022   if (ret && self->start) {
2023     GST_DEBUG_OBJECT (self, "Starting preview");
2024     ret = gst_ah_camera_start_preview (self->camera);
2025     if (ret) {
2026       /* Need to reset callbacks after every startPreview */
2027       gst_ah_camera_set_preview_callback_with_buffer (self->camera,
2028           gst_ahc_src_on_preview_frame, self);
2029       gst_ah_camera_set_error_callback (self->camera, gst_ahc_src_on_error,
2030           self);
2031       self->start = FALSE;
2032     }
2033   }
2034   return ret;
2035 }
2036 
2037 typedef struct
2038 {
2039   GstAHCSrc *self;
2040   jbyteArray array;
2041   jbyte *data;
2042 } FreeFuncBuffer;
2043 
2044 static void
gst_ahc_src_buffer_free_func(gpointer priv)2045 gst_ahc_src_buffer_free_func (gpointer priv)
2046 {
2047   FreeFuncBuffer *data = (FreeFuncBuffer *) priv;
2048   GstAHCSrc *self = data->self;
2049   JNIEnv *env = gst_amc_jni_get_env ();
2050 
2051   g_mutex_lock (&self->mutex);
2052 
2053   GST_DEBUG_OBJECT (self, "release %p->%p", data, data->array);
2054 
2055   (*env)->ReleaseByteArrayElements (env, data->array, data->data, JNI_ABORT);
2056   if (self->camera)
2057     gst_ah_camera_add_callback_buffer (self->camera, data->array);
2058 
2059   (*env)->DeleteGlobalRef (env, data->array);
2060 
2061   g_slice_free (FreeFuncBuffer, data);
2062 
2063   g_mutex_unlock (&self->mutex);
2064   gst_object_unref (self);
2065 }
2066 
2067 static void
_data_queue_item_free(GstDataQueueItem * item)2068 _data_queue_item_free (GstDataQueueItem * item)
2069 {
2070   GST_DEBUG ("release  %p", item->object);
2071 
2072   gst_buffer_unref (GST_BUFFER (item->object));
2073   g_slice_free (GstDataQueueItem, item);
2074 }
2075 
2076 static void
gst_ahc_src_on_preview_frame(jbyteArray array,gpointer user_data)2077 gst_ahc_src_on_preview_frame (jbyteArray array, gpointer user_data)
2078 {
2079   GstAHCSrc *self = GST_AHC_SRC (user_data);
2080   JNIEnv *env = gst_amc_jni_get_env ();
2081   GstBuffer *buffer;
2082   GstDataQueueItem *item = NULL;
2083   FreeFuncBuffer *malloc_data = NULL;
2084   GstClockTime timestamp = GST_CLOCK_TIME_NONE;
2085   GstClockTime duration = 0;
2086   GstClock *clock;
2087   gboolean queued = FALSE;
2088 
2089   g_mutex_lock (&self->mutex);
2090 
2091   if (array == NULL) {
2092     GST_DEBUG_OBJECT (self, "Size of array in queue is too small, dropping it");
2093     goto done;
2094   }
2095 
2096   if ((clock = GST_ELEMENT_CLOCK (self))) {
2097     GstClockTime base_time = GST_ELEMENT_CAST (self)->base_time;
2098     GstClockTime current_ts;
2099 
2100     gst_object_ref (clock);
2101     current_ts = gst_clock_get_time (clock) - base_time;
2102     gst_object_unref (clock);
2103     if (GST_CLOCK_TIME_IS_VALID (self->previous_ts)) {
2104       timestamp = self->previous_ts;
2105       duration = current_ts - self->previous_ts;
2106       self->previous_ts = current_ts;
2107     } else {
2108       /* Drop the first buffer */
2109       self->previous_ts = current_ts;
2110       gst_ah_camera_add_callback_buffer (self->camera, array);
2111       GST_DEBUG_OBJECT (self, "dropping the first buffer");
2112       goto done;
2113     }
2114   } else {
2115     GST_DEBUG_OBJECT (self, "element clock hasn't created yet.");
2116     gst_ah_camera_add_callback_buffer (self->camera, array);
2117     goto done;
2118   }
2119 
2120   GST_DEBUG_OBJECT (self, "Received data buffer %p", array);
2121 
2122   malloc_data = g_slice_new (FreeFuncBuffer);
2123   malloc_data->self = gst_object_ref (self);
2124   malloc_data->array = (*env)->NewGlobalRef (env, array);
2125   malloc_data->data = (*env)->GetByteArrayElements (env, array, NULL);
2126 
2127   buffer =
2128       gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, malloc_data->data,
2129       self->buffer_size, 0, self->buffer_size, malloc_data,
2130       gst_ahc_src_buffer_free_func);
2131   GST_BUFFER_DURATION (buffer) = duration;
2132   GST_BUFFER_PTS (buffer) = timestamp;
2133 
2134   GST_DEBUG_OBJECT (self, "creating wrapped buffer (size: %d)",
2135       self->buffer_size);
2136 
2137   item = g_slice_new (GstDataQueueItem);
2138   item->object = GST_MINI_OBJECT (buffer);
2139   item->size = gst_buffer_get_size (buffer);
2140   item->duration = GST_BUFFER_DURATION (buffer);
2141   item->visible = TRUE;
2142   item->destroy = (GDestroyNotify) _data_queue_item_free;
2143 
2144   GST_DEBUG_OBJECT (self, "wrapping jni array %p->%p %p->%p", item,
2145       item->object, malloc_data, malloc_data->array);
2146 
2147   queued = gst_data_queue_push (self->queue, item);
2148 
2149 done:
2150   g_mutex_unlock (&self->mutex);
2151 
2152   if (item && !queued) {
2153     GST_INFO_OBJECT (self, "could not add buffer to queue");
2154     /* Can't add buffer to queue. Must be flushing. */
2155     _data_queue_item_free (item);
2156   }
2157 }
2158 
2159 static void
gst_ahc_src_on_error(gint error,gpointer user_data)2160 gst_ahc_src_on_error (gint error, gpointer user_data)
2161 {
2162   GstAHCSrc *self = GST_AHC_SRC (user_data);
2163 
2164   GST_WARNING_OBJECT (self, "Received error code : %d", error);
2165 }
2166 
2167 static gboolean
gst_ahc_src_open(GstAHCSrc * self)2168 gst_ahc_src_open (GstAHCSrc * self)
2169 {
2170   GError *err = NULL;
2171 
2172   GST_DEBUG_OBJECT (self, "Opening camera");
2173 
2174   self->camera = gst_ah_camera_open (self->device);
2175 
2176   if (self->camera) {
2177     GST_DEBUG_OBJECT (self, "Opened camera");
2178 
2179     self->texture = gst_amc_surface_texture_new (&err);
2180     if (self->texture == NULL) {
2181       GST_ERROR_OBJECT (self,
2182           "Failed to create surface texture object: %s", err->message);
2183       g_clear_error (&err);
2184       goto failed_surfacetexutre;
2185     }
2186     gst_ah_camera_set_preview_texture (self->camera, self->texture);
2187     self->buffer_size = 0;
2188   } else {
2189     gint num_cams = gst_ah_camera_get_number_of_cameras ();
2190     if (num_cams > 0 && self->device < num_cams) {
2191       GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
2192           ("Unable to open device '%d'.", self->device), (NULL));
2193     } else if (num_cams > 0) {
2194       GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
2195           ("Device '%d' does not exist.", self->device), (NULL));
2196     } else {
2197       GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
2198           ("There are no cameras available on this device."), (NULL));
2199     }
2200   }
2201 
2202   return (self->camera != NULL);
2203 
2204 failed_surfacetexutre:
2205   gst_ah_camera_release (self->camera);
2206   gst_ah_camera_free (self->camera);
2207   self->camera = NULL;
2208 
2209   return FALSE;
2210 }
2211 
2212 static void
gst_ahc_src_close(GstAHCSrc * self)2213 gst_ahc_src_close (GstAHCSrc * self)
2214 {
2215   GError *err = NULL;
2216 
2217   if (self->camera) {
2218     gst_ah_camera_set_error_callback (self->camera, NULL, NULL);
2219     gst_ah_camera_set_preview_callback_with_buffer (self->camera, NULL, NULL);
2220     gst_ah_camera_release (self->camera);
2221     gst_ah_camera_free (self->camera);
2222   }
2223   self->camera = NULL;
2224 
2225   if (self->texture && !gst_amc_surface_texture_release (self->texture, &err)) {
2226     GST_ERROR_OBJECT (self,
2227         "Failed to release surface texture object: %s", err->message);
2228     g_clear_error (&err);
2229   }
2230 
2231   g_clear_object (&self->texture);
2232 }
2233 
2234 static GstStateChangeReturn
gst_ahc_src_change_state(GstElement * element,GstStateChange transition)2235 gst_ahc_src_change_state (GstElement * element, GstStateChange transition)
2236 {
2237   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2238   GstAHCSrc *self = GST_AHC_SRC (element);
2239 
2240   switch (transition) {
2241     case GST_STATE_CHANGE_NULL_TO_READY:
2242       if (!gst_ahc_src_open (self))
2243         return GST_STATE_CHANGE_FAILURE;
2244       break;
2245     default:
2246       break;
2247   }
2248 
2249   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2250 
2251   switch (transition) {
2252     case GST_STATE_CHANGE_READY_TO_NULL:
2253       gst_ahc_src_close (self);
2254       break;
2255     default:
2256       break;
2257   }
2258 
2259   return ret;
2260 }
2261 
2262 static gboolean
gst_ahc_src_start(GstBaseSrc * bsrc)2263 gst_ahc_src_start (GstBaseSrc * bsrc)
2264 {
2265   GstAHCSrc *self = GST_AHC_SRC (bsrc);
2266 
2267   GST_DEBUG_OBJECT (self, "Starting preview");
2268   if (self->camera) {
2269     self->previous_ts = GST_CLOCK_TIME_NONE;
2270     self->fps_min = self->fps_max = self->width = self->height = 0;
2271     self->format = ImageFormat_UNKNOWN;
2272     self->start = TRUE;
2273 
2274     return TRUE;
2275   } else {
2276     return FALSE;
2277   }
2278 }
2279 
2280 static gboolean
gst_ahc_src_stop(GstBaseSrc * bsrc)2281 gst_ahc_src_stop (GstBaseSrc * bsrc)
2282 {
2283   GstAHCSrc *self = GST_AHC_SRC (bsrc);
2284 
2285   GST_DEBUG_OBJECT (self, "Stopping preview");
2286   if (self->camera) {
2287     gst_data_queue_flush (self->queue);
2288     self->start = FALSE;
2289     gst_ah_camera_set_error_callback (self->camera, NULL, NULL);
2290     return gst_ah_camera_stop_preview (self->camera);
2291   }
2292   return TRUE;
2293 }
2294 
2295 static gboolean
gst_ahc_src_unlock(GstBaseSrc * bsrc)2296 gst_ahc_src_unlock (GstBaseSrc * bsrc)
2297 {
2298   GstAHCSrc *self = GST_AHC_SRC (bsrc);
2299 
2300   GST_DEBUG_OBJECT (self, "Unlocking create");
2301   gst_data_queue_set_flushing (self->queue, TRUE);
2302 
2303   return TRUE;
2304 }
2305 
2306 static gboolean
gst_ahc_src_unlock_stop(GstBaseSrc * bsrc)2307 gst_ahc_src_unlock_stop (GstBaseSrc * bsrc)
2308 {
2309   GstAHCSrc *self = GST_AHC_SRC (bsrc);
2310 
2311   GST_DEBUG_OBJECT (self, "Stopping unlock");
2312   gst_data_queue_set_flushing (self->queue, FALSE);
2313 
2314   return TRUE;
2315 }
2316 
2317 static GstFlowReturn
gst_ahc_src_create(GstPushSrc * src,GstBuffer ** buffer)2318 gst_ahc_src_create (GstPushSrc * src, GstBuffer ** buffer)
2319 {
2320   GstAHCSrc *self = GST_AHC_SRC (src);
2321   GstDataQueueItem *item;
2322 
2323   if (!gst_data_queue_pop (self->queue, &item)) {
2324     GST_INFO_OBJECT (self, "empty queue");
2325     return GST_FLOW_FLUSHING;
2326   }
2327 
2328   GST_DEBUG_OBJECT (self, "creating buffer %p->%p", item, item->object);
2329 
2330   *buffer = GST_BUFFER (item->object);
2331   g_slice_free (GstDataQueueItem, item);
2332 
2333   return GST_FLOW_OK;
2334 }
2335 
2336 static gboolean
gst_ahc_src_query(GstBaseSrc * bsrc,GstQuery * query)2337 gst_ahc_src_query (GstBaseSrc * bsrc, GstQuery * query)
2338 {
2339   GstAHCSrc *self = GST_AHC_SRC (bsrc);
2340 
2341   switch (GST_QUERY_TYPE (query)) {
2342     case GST_QUERY_LATENCY:{
2343       GstClockTime min;
2344 
2345       /* Cannot query latency before setcaps() */
2346       if (self->fps_min == 0)
2347         return FALSE;
2348 
2349       /* Allow of 1 frame latency base on the longer frame duration */
2350       gst_query_parse_latency (query, NULL, &min, NULL);
2351       min = gst_util_uint64_scale (GST_SECOND, 1000, self->fps_min);
2352       GST_DEBUG_OBJECT (self,
2353           "Reporting latency min: %" GST_TIME_FORMAT, GST_TIME_ARGS (min));
2354       gst_query_set_latency (query, TRUE, min, min);
2355 
2356       return TRUE;
2357       break;
2358     }
2359     default:
2360       return GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
2361       break;
2362   }
2363 
2364   g_assert_not_reached ();
2365 }
2366