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