camera: implement camerabin2's renegotiate event
[gstreamer-omap:gst-openmax.git] / omx / gstomx_camera.c
1 /* GStreamer
2  *
3  * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/
4  * Copyright (C) 2011 Collabora Ltda
5  *  @author: Luciana Fujii Pontello <luciana.fujii@collabora.co.uk>
6  *
7  * Description: OMX Camera element
8  *  Created on: Aug 31, 2009
9  *      Author: Rob Clark <rob@ti.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation
14  * version 2.1 of the License.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25
26 #include "gstomx_camera_parameters.h"
27 #include "gstomx_camera.h"
28 #include "gstomx.h"
29
30 #include <gst/video/video.h>
31 #include <gst/interfaces/photography.h>
32 #include <gst/interfaces/photography-enumtypes.h>
33 #include <gst/interfaces/colorbalance.h>
34
35 #ifdef USE_OMXTICORE
36 #  include <OMX_TI_IVCommon.h>
37 #  include <OMX_TI_Index.h>
38 #endif
39
40 #include <stdint.h>
41 #include <fcntl.h>
42 #include <sys/ioctl.h>
43 #include <linux/timer-32k.h>
44 #include <OMX_CoreExt.h>
45 #include <OMX_IndexExt.h>
46
47 /**
48  * SECTION:element-omx_camerasrc
49  *
50  * omx_camerasrc can be used to capture video and/or still frames from OMX
51  * camera.  It can also be used as a filter to provide access to the camera's
52  * memory-to-memory mode.
53  * <p>
54  * In total, the omx_camerasrc element exposes one optional input port, "sink",
55  * one mandatory src pad, "src", and two optional src pads, "imgsrc" and
56  * "vidsrc".  If "imgsrc" and/or "vidsrc" are linked, then viewfinder buffers
57  * are pushed on the "src" pad.
58  * <p>
59  * In all modes, preview buffers are pushed on the "src" pad.  In video capture
60  * mode, the same buffer is pushed on the "vidsrc" pad.  In image capture mode,
61  * a separate full resolution image (either raw or jpg encoded) is pushed on
62  * the "imgsrc" pad.
63  * <p>
64  * The camera pad_alloc()s buffers from the "src" pad, in order to allocate
65  * memory from the video driver.  The "vidsrc" caps are slaved to the "src"
66  * caps.  Although this should be considered an implementation detail.
67  * <p>
68  * TODO: for legacy mode support, as a replacement for v4l2src, can we push
69  * buffers of the requested resolution on the "src" pad?  Can we configure the
70  * OMX component for arbitrary resolution on the preview port, or do we need
71  * to dynamically map the "src" pad to different ports depending on the config?
72  * The OMX camera supports only video resolutions on the preview and video
73  * ports, but supports higher resolution stills on the image port.
74  *
75  * <refsect2>
76  * <title>Example launch lines</title>
77  * |[
78  * gst-launch omx_camera vstab=1 mode=2 vnf=1 name=cam cam.src ! queue ! v4l2sink \
79  * cam.vidsrc ! "video/x-raw-yuv, format=(fourcc)UYVY, width=720, height=480, framerate=30/1" ! \
80  * queue ! omx_h264enc matroskamux name=mux ! filesink location=capture.mkv ! \
81  * alsasrc ! "audio/x-raw-int,rate=48000,channels=1, width=16, depth=16, endianness=1234" ! \
82  * queue ! omx_aacenc bitrate=64000 profile=2 ! "audio/mpeg,mpegversion=4,rate=48000,channels=1" ! \
83  * mux. cam.imgsrc ! "image/jpeg, width=720, height=480" ! filesink name=capture.jpg
84  * ]|
85  * </refsect2>
86  */
87
88 static void create_ports (GstOmxCamera *self);
89
90 static const GstElementDetails element_details =
91 GST_ELEMENT_DETAILS ("Video OMX Camera Source",
92     "Source/Video",
93     "Reads frames from a OMX Camera Component",
94     "Rob Clark <rob@ti.com>");
95
96 static gboolean
97 gst_omx_camera_interface_supported (GstImplementsInterface * iface,
98     GType type)
99 {
100     g_assert (type == GST_TYPE_PHOTOGRAPHY || type == GST_TYPE_COLOR_BALANCE);
101     return TRUE;
102 }
103
104 static void gst_omx_camera_photography_init (GstPhotographyInterface *iface);
105 static void gst_omx_camera_colorbalance_init (GstColorBalanceClass *iface);
106
107 static void
108 gst_omx_camera_interface_init (GstImplementsInterfaceClass * klass)
109 {
110     klass->supported = gst_omx_camera_interface_supported;
111 }
112
113
114 static void
115 _do_init (GType omx_camera_type)
116 {
117     static const GInterfaceInfo iface_info = {
118         (GInterfaceInitFunc) gst_omx_camera_interface_init,
119         NULL,
120         NULL,
121     };
122     static const GInterfaceInfo photography_info = {
123         (GInterfaceInitFunc) gst_omx_camera_photography_init,
124         NULL,
125         NULL,
126     };
127
128     static const GInterfaceInfo colorbalance_info = {
129       (GInterfaceInitFunc) gst_omx_camera_colorbalance_init,
130       NULL,
131       NULL,
132     };
133
134     g_type_add_interface_static (omx_camera_type,
135             GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
136     g_type_add_interface_static (omx_camera_type, GST_TYPE_PHOTOGRAPHY,
137             &photography_info);
138     g_type_add_interface_static (omx_camera_type, GST_TYPE_COLOR_BALANCE,
139             &colorbalance_info);
140 }
141
142 GSTOMX_BOILERPLATE_FULL (GstOmxCamera, gst_omx_camera, GstOmxBaseSrc,
143         GST_OMX_BASE_SRC_TYPE, _do_init);
144
145 const GList *
146 gst_omx_camera_colorbalance_list_channels (GstColorBalance *balance)
147 {
148     GstOmxCamera *self = GST_OMX_CAMERA (balance);
149
150     g_return_val_if_fail (self != NULL, NULL);
151     return self->channels;
152 }
153
154 static gint
155 gst_omx_camera_colorbalance_get_value (GstColorBalance *balance,
156                                        GstColorBalanceChannel *channel)
157 {
158     GstOmxCamera *self = GST_OMX_CAMERA (balance);
159     gint value = 0;
160
161     g_return_val_if_fail (self != NULL, 0);
162
163     if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS"))
164         gst_omx_camera_get_brightness (self, &value);
165     else if (!g_ascii_strcasecmp (channel->label, "SATURATION"))
166         gst_omx_camera_get_saturation (self, &value);
167     else if (!g_ascii_strcasecmp (channel->label, "SHARPNESS"))
168         gst_omx_camera_get_sharpness (self, &value);
169     else if (!g_ascii_strcasecmp (channel->label, "CONTRAST"))
170         gst_omx_camera_get_contrast (self, &value);
171     return value;
172 }
173
174 static void
175 gst_omx_camera_colorbalance_set_value (GstColorBalance *balance,
176                                        GstColorBalanceChannel *channel,
177                                        gint value)
178 {
179     GstOmxCamera *self = GST_OMX_CAMERA (balance);
180
181     g_return_if_fail (self != NULL);
182
183     if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS"))
184         gst_omx_camera_set_brightness (self, value);
185     else if (!g_ascii_strcasecmp (channel->label, "SATURATION"))
186         gst_omx_camera_set_saturation (self, value);
187     else if (!g_ascii_strcasecmp (channel->label, "SHARPNESS"))
188         gst_omx_camera_set_sharpness (self, value);
189     else if (!g_ascii_strcasecmp (channel->label, "CONTRAST"))
190         gst_omx_camera_set_contrast (self, value);
191 }
192
193 static void gst_omx_camera_colorbalance_init (GstColorBalanceClass *iface)
194 {
195   iface->list_channels = gst_omx_camera_colorbalance_list_channels;
196   iface->get_value = gst_omx_camera_colorbalance_get_value;
197   iface->set_value = gst_omx_camera_colorbalance_set_value;
198 }
199
200 static void gst_omx_camera_photography_init (GstPhotographyInterface *iface)
201 {
202   iface->get_ev_compensation = gst_omx_camera_photography_get_ev_compensation;
203   iface->get_iso_speed = gst_omx_camera_photography_get_iso_speed;
204   iface->get_white_balance_mode = gst_omx_camera_photography_get_white_balance_mode;
205   iface->get_scene_mode = gst_omx_camera_photography_get_scene_mode;
206   iface->get_zoom = gst_omx_camera_photography_get_zoom;
207   iface->get_flicker_mode = gst_omx_camera_photography_get_flicker_mode;
208
209   iface->set_ev_compensation = gst_omx_camera_photography_set_ev_compensation;
210   iface->set_iso_speed = gst_omx_camera_photography_set_iso_speed;
211   iface->set_white_balance_mode = gst_omx_camera_photography_set_white_balance_mode;
212   iface->set_scene_mode = gst_omx_camera_photography_set_scene_mode;
213   iface->set_zoom = gst_omx_camera_photography_set_zoom;
214   iface->set_flicker_mode = gst_omx_camera_photography_set_flicker_mode;
215   iface->set_autofocus = gst_omx_camera_photography_set_autofocus;
216   iface->get_capabilities = gst_omx_camera_photography_get_capabilities;
217 }
218
219
220 #define USE_GSTOMXCAM_IMGSRCPAD
221 #define USE_GSTOMXCAM_VIDSRCPAD
222 #define USE_GSTOMXCAM_THUMBSRCPAD
223 //#define USE_GSTOMXCAM_IN_PORT
224
225
226 /*
227  * Caps:
228  */
229
230
231 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
232         GST_PAD_SRC,
233         GST_PAD_ALWAYS,
234         GST_STATIC_CAPS (
235                 "video/x-raw-rgb-strided, bpp=16, depth=16, red_mask=63488, "
236                 "green_mask=2016, blue_mask=31, endianness=1234, "
237                 "rowstride=(int)[1,max], width=(int)[1,max], height=(int)[1,max], "
238                 "framerate=(fraction)[0,max]; "
239                 GST_VIDEO_CAPS_YUV_STRIDED (GSTOMX_ALL_FORMATS, "[ 0, max ]"))
240     );
241
242 static GstStaticPadTemplate imgsrc_template = GST_STATIC_PAD_TEMPLATE ("imgsrc",
243         GST_PAD_SRC,
244         GST_PAD_ALWAYS,
245         /* Note: imgsrc pad supports JPEG format, Bayer, as well as
246            non-strided YUV. */
247         GST_STATIC_CAPS (
248                 "image/jpeg, width=(int)[1,max], height=(int)[1,max]; "
249                 "video/x-raw-bayer, width=(int)[1,max], height=(int)[1,max]; "
250                 GST_VIDEO_CAPS_YUV (GSTOMX_ALL_FORMATS))
251     );
252
253 static GstStaticPadTemplate vidsrc_template = GST_STATIC_PAD_TEMPLATE ("vidsrc",
254         GST_PAD_SRC,
255         GST_PAD_ALWAYS,
256         GST_STATIC_CAPS (
257                 "video/x-raw-rgb-strided, bpp=16, depth=16, red_mask=63488, "
258                 "green_mask=2016, blue_mask=31, endianness=1234, "
259                 "rowstride=(int)[1,max], width=(int)[1,max], height=(int)[1,max], "
260                 "framerate=(fraction)[0,max]; "
261                 GST_VIDEO_CAPS_YUV_STRIDED (GSTOMX_ALL_FORMATS, "[ 0, max ]"))
262     );
263
264 static GstStaticPadTemplate thumbsrc_template = GST_STATIC_PAD_TEMPLATE ("thumbsrc",
265         GST_PAD_SRC,
266         GST_PAD_REQUEST,
267         GST_STATIC_CAPS (
268                 "video/x-raw-bayer, width=(int)[1,max], height=(int)[1,max]; "
269                 GST_VIDEO_CAPS_RGB "; "
270                 GST_VIDEO_CAPS_RGB_16 "; "
271                 GST_VIDEO_CAPS_YUV (GSTOMX_ALL_FORMATS))
272     );
273
274 #ifdef USE_GSTOMXCAM_IN_PORT
275 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
276         GST_PAD_SINK,
277         GST_PAD_ALWAYS,
278         GST_STATIC_CAPS ("???")
279     );
280 #endif
281
282 static void
283 set_allocate_buffer_size (GstOmxCamera *self)
284 {
285     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
286     OMX_PARAM_PORTDEFINITIONTYPE param;
287     GOmxPort *port, *ports[] = { omx_base->out_port, self->img_port };
288     guint32 buffer_size = 0;
289     gint i;
290
291     for (i = 0; i < G_N_ELEMENTS (ports); i++) {
292       port = ports[i];
293       if (!port->omx_allocate)
294         continue;
295       G_OMX_PORT_GET_DEFINITION (port, &param);
296       buffer_size = MAX (buffer_size, param.nBufferSize);
297     }
298     
299     for (i = 0; i < G_N_ELEMENTS (ports); i++) {
300       port = ports[i];
301       if (!port->omx_allocate)
302         continue;
303       param.nBufferSize = buffer_size;
304       G_OMX_PORT_SET_DEFINITION (port, &param);
305     }
306 }
307
308 static gboolean
309 src_setcaps (GstPad *pad, GstCaps *caps)
310 {
311     GstOmxCamera *self = GST_OMX_CAMERA (GST_PAD_PARENT (pad));
312     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
313
314     GstVideoFormat format;
315     gint width, height, rowstride;
316     gint framerate_num, framerate_denom;
317     const GValue *framerate = NULL;
318     OMX_ERRORTYPE err;
319
320     if (!self)
321     {
322         GST_DEBUG_OBJECT (pad, "pad has no parent (yet?)");
323         return TRUE;  // ???
324     }
325
326     GST_INFO_OBJECT (omx_base, "setcaps (src/vidsrc): %" GST_PTR_FORMAT, caps);
327
328     g_return_val_if_fail (caps, FALSE);
329     g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
330
331     if (gst_video_format_parse_caps_strided (caps,
332             &format, &width, &height, &rowstride))
333     {
334         /* Output port configuration: */
335         OMX_PARAM_PORTDEFINITIONTYPE param;
336         gboolean configure_port = FALSE;
337
338         G_OMX_PORT_GET_DEFINITION (omx_base->out_port, &param);
339
340         if ((param.format.video.nFrameWidth != width) ||
341            (param.format.video.nFrameHeight != height) ||
342            (param.format.video.nStride != rowstride))
343         {
344             param.format.video.nFrameWidth  = width;
345             param.format.video.nFrameHeight = height;
346             param.format.video.nStride      = self->rowstride = rowstride;
347             configure_port = TRUE;
348         }
349
350         param.nBufferSize = gst_video_format_get_size_strided (format, width, height, rowstride);
351
352         /* special hack to work around OMX camera bug:
353          */
354         if (param.format.video.eColorFormat != g_omx_gstvformat_to_colorformat (format))
355         {
356             if (g_omx_gstvformat_to_colorformat (format) == OMX_COLOR_FormatYUV420PackedSemiPlanar)
357             {
358                 if (param.format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar)
359                 {
360                     param.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
361                     configure_port = TRUE;
362                 }
363             }
364             else
365             {
366                 param.format.video.eColorFormat = g_omx_gstvformat_to_colorformat (format);
367                 configure_port = TRUE;
368             }
369         }
370
371         framerate = gst_structure_get_value (
372                 gst_caps_get_structure (caps, 0), "framerate");
373
374         if (framerate)
375         {
376             guint32 xFramerate;
377             framerate_num = gst_value_get_fraction_numerator (framerate);
378             framerate_denom = gst_value_get_fraction_denominator (framerate);
379
380             xFramerate = (framerate_num << 16) / framerate_denom;
381
382             if (param.format.video.xFramerate != xFramerate)
383             {
384                 param.format.video.xFramerate = xFramerate;
385                 configure_port = TRUE;
386             }
387          }
388
389         /* At the moment we are only using preview port and not vid_port
390          * From omx camera desing document we are missing
391          * SetParam CommonSensormode -> bOneShot = FALSE ?
392          */
393
394         if (configure_port)
395         {
396             gboolean port_enabled = FALSE;
397
398             if (omx_base->out_port->enabled && (omx_base->gomx->omx_state != OMX_StateLoaded))
399             {
400                 g_omx_port_disable (omx_base->out_port);
401                 port_enabled = TRUE;
402             }
403
404             err = G_OMX_PORT_SET_DEFINITION (omx_base->out_port, &param);
405             if (err != OMX_ErrorNone)
406                 return FALSE;
407
408             if (port_enabled)
409                 g_omx_port_enable (omx_base->out_port);
410         }
411
412         GST_INFO_OBJECT (omx_base, " Rowstride=%d, Width=%d, Height=%d, Color=%d, Buffersize=%d, framerate=%d",
413             param.format.video.nStride, param.format.video.nFrameWidth, param.format.video.nFrameHeight, param.format.video.eColorFormat, param.nBufferSize,param.format.video.xFramerate );
414
415 #ifdef USE_OMXTICORE
416         self->img_regioncenter_x = (param.format.video.nFrameWidth / 2);
417         self->img_regioncenter_y = (param.format.video.nFrameHeight / 2);
418 #endif
419
420         if  (!gst_pad_set_caps (GST_BASE_SRC (self)->srcpad, caps))
421             return FALSE;
422
423         GST_INFO_OBJECT (omx_base, " exit setcaps src: %");
424     }
425
426     return TRUE;
427 }
428
429 static void
430 src_fixatecaps (GstPad *pad, GstCaps *caps)
431 {
432     GstStructure *structure;
433     const GValue *value;
434     gint width;
435
436     structure = gst_caps_get_structure (caps, 0);
437
438     gst_structure_fixate_field_nearest_int (structure, "width", 864);
439     gst_structure_fixate_field_nearest_int (structure, "height", 480);
440     gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
441
442     value = gst_structure_get_value (structure, "rowstride");
443     if (value == NULL || G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
444         gst_structure_get_int (structure, "width", &width);
445         gst_caps_set_simple (caps, "rowstride",
446             G_TYPE_INT, 4096, NULL);
447     }
448 }
449
450 static gboolean
451 imgsrc_setcaps (GstPad *pad, GstCaps *caps)
452 {
453     GstOmxCamera *self = GST_OMX_CAMERA (GST_PAD_PARENT (pad));
454     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
455
456     GstVideoFormat format;
457     gint width, height, rowstride;
458     GstStructure *s;
459
460     GST_INFO_OBJECT (omx_base, "setcaps (imgsrc): %" GST_PTR_FORMAT, caps);
461
462     g_return_val_if_fail (caps, FALSE);
463     g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
464
465     if (gst_video_format_parse_caps_strided (caps,
466             &format, &width, &height, &rowstride))
467     {
468         /* Output port configuration for YUV: */
469         OMX_PARAM_PORTDEFINITIONTYPE param;
470
471         GST_DEBUG_OBJECT (self, "set raw format");
472
473         G_OMX_PORT_GET_DEFINITION (self->img_port, &param);
474
475         param.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
476         param.format.image.eColorFormat = g_omx_gstvformat_to_colorformat (format);
477         param.format.image.nFrameWidth  = width;
478         param.format.image.nFrameHeight = height;
479         param.format.image.nStride      = rowstride;
480
481         /* special hack to work around OMX camera bug:
482          */
483         if (param.format.video.eColorFormat == OMX_COLOR_FormatYUV420PackedSemiPlanar)
484             param.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
485
486         G_OMX_PORT_SET_DEFINITION (self->img_port, &param);
487     }
488     else if (gst_structure_has_name (s=gst_caps_get_structure (caps, 0), "image/jpeg"))
489     {
490         /* Output port configuration for JPEG: */
491         OMX_PARAM_PORTDEFINITIONTYPE param;
492
493         GST_DEBUG_OBJECT (self, "set JPEG format");
494
495         G_OMX_PORT_GET_DEFINITION (self->img_port, &param);
496
497         gst_structure_get_int (s, "width", &width);
498         gst_structure_get_int (s, "height", &height);
499
500         param.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY;
501         param.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
502         param.format.image.nFrameWidth  = width;
503         param.format.image.nFrameHeight = height;
504         param.format.image.nStride      = 0;
505
506         GST_INFO_OBJECT (self, "Rowstride=%d, Width=%d, Height=%d, Buffersize=%d, num-buffer=%d",
507             param.format.image.nStride, param.format.image.nFrameWidth, param.format.image.nFrameHeight, param.nBufferSize, param.nBufferCountActual);
508
509         G_OMX_PORT_SET_DEFINITION (self->img_port, &param);
510     }
511     else if (gst_structure_has_name (s=gst_caps_get_structure (caps, 0),
512                      "video/x-raw-bayer"))
513     {
514         /* Output port configuration for Bayer: */
515         OMX_PARAM_PORTDEFINITIONTYPE param;
516
517         GST_DEBUG_OBJECT (self, "set Raw-Bayer format");
518
519         G_OMX_PORT_GET_DEFINITION (self->img_port, &param);
520
521         gst_structure_get_int (s, "width", &width);
522         gst_structure_get_int (s, "height", &height);
523
524         param.format.image.eColorFormat = OMX_COLOR_FormatRawBayer10bit;
525         param.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
526         param.format.image.nFrameWidth  = width;
527         param.format.image.nFrameHeight = height;
528         param.format.image.nStride      = width * 2;
529
530         GST_INFO_OBJECT (self, "Rowstride=%d, Width=%d, Height=%d, "
531             "Buffersize=%d, num-buffer=%d", param.format.image.nStride,
532             param.format.image.nFrameWidth, param.format.image.nFrameHeight,
533             param.nBufferSize, param.nBufferCountActual);
534
535         G_OMX_PORT_SET_DEFINITION (self->img_port, &param);
536     }
537
538     return TRUE;
539 }
540
541 static void
542 imgsrc_fixatecaps (GstPad *pad, GstCaps *caps)
543 {
544     GstStructure *structure;
545
546     structure = gst_caps_get_structure (caps, 0);
547
548     gst_structure_fixate_field_nearest_int (structure, "width", 864);
549     gst_structure_fixate_field_nearest_int (structure, "height", 480);
550 }
551
552 static gboolean
553 imgsrc_event (GstPad * pad, GstEvent * event)
554 {
555     GstOmxCamera *self = GST_OMX_CAMERA (gst_pad_get_parent (pad));
556     gboolean res = FALSE;
557
558     switch (GST_EVENT_TYPE (event)) {
559       case GST_EVENT_CUSTOM_BOTH:
560       {
561         const GstStructure *s;
562         GstCaps *caps;
563
564         s = gst_event_get_structure (event);
565         if (strcmp (gst_structure_get_name (s), "renegotiate"))
566           break;
567
568         caps = gst_pad_peer_get_caps (pad);
569         if (!gst_caps_is_fixed (caps)) {
570           caps = gst_caps_make_writable (caps);
571           gst_pad_fixate_caps (pad, caps);
572         }
573         GST_INFO_OBJECT (self, "renegotiating image caps %"GST_PTR_FORMAT, caps);
574         res = gst_pad_set_caps (pad, caps);
575         GST_INFO_OBJECT (self, "negotiation result: %d", res);
576         gst_caps_unref (caps);
577
578         break;
579       }
580       default:
581         break;
582     }
583
584     gst_object_unref (self);
585     return res;
586 }
587
588 static gboolean
589 thumbsrc_setcaps (GstPad *pad, GstCaps *caps)
590 {
591     GstOmxCamera *self = GST_OMX_CAMERA (GST_PAD_PARENT (pad));
592     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
593
594     GstVideoFormat format;
595     gint width, height;
596     GstStructure *s;
597
598     GST_INFO_OBJECT (omx_base, "setcaps (thumbsrc): %" GST_PTR_FORMAT, caps);
599
600     g_return_val_if_fail (caps, FALSE);
601     g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
602
603     if (gst_video_format_parse_caps (caps, &format, &width, &height))
604     {
605         /* Output port configuration for RAW: */
606         OMX_PARAM_PORTDEFINITIONTYPE param;
607
608         GST_DEBUG_OBJECT (self, "set YUV/RGB raw format");
609
610         G_OMX_PORT_GET_DEFINITION (self->vid_port, &param);
611
612         param.format.image.eCompressionFormat = OMX_VIDEO_CodingUnused;
613         param.format.image.eColorFormat = g_omx_gstvformat_to_colorformat (format);
614         param.format.image.nFrameWidth  = width;
615         param.format.image.nFrameHeight = height;
616
617         /* special hack to work around OMX camera bug:
618          */
619         if (param.format.video.eColorFormat == OMX_COLOR_FormatYUV420PackedSemiPlanar)
620             param.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
621
622         G_OMX_PORT_SET_DEFINITION (self->vid_port, &param);
623     }
624     else if (gst_structure_has_name (s=gst_caps_get_structure (caps, 0),
625                      "video/x-raw-bayer"))
626     {
627         /* Output port configuration for Bayer: */
628         OMX_PARAM_PORTDEFINITIONTYPE param;
629
630         GST_DEBUG_OBJECT (self, "set Raw-Bayer format");
631
632         G_OMX_PORT_GET_DEFINITION (self->vid_port, &param);
633
634         gst_structure_get_int (s, "width", &width);
635         gst_structure_get_int (s, "height", &height);
636
637         param.format.image.eColorFormat = OMX_COLOR_FormatRawBayer10bit;
638         param.format.image.eCompressionFormat = OMX_VIDEO_CodingUnused;
639         param.format.image.nFrameWidth  = width;
640         param.format.image.nFrameHeight = height;
641
642         GST_INFO_OBJECT (self, "Width=%d, Height=%d, Buffersize=%d, num-buffer=%d",
643             param.format.image.nFrameWidth, param.format.image.nFrameHeight,
644             param.nBufferSize, param.nBufferCountActual);
645
646         G_OMX_PORT_SET_DEFINITION (self->vid_port, &param);
647     }
648
649     return TRUE;
650 }
651
652 static gboolean
653 src_query (GstPad *pad, GstQuery *query)
654 {
655     GstOmxCamera *self = GST_OMX_CAMERA (GST_PAD_PARENT (pad));
656     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
657     gboolean ret = FALSE;
658
659     GST_DEBUG_OBJECT (self, "Begin");
660
661     switch (GST_QUERY_TYPE (query))
662     {
663         case GST_QUERY_BUFFERS:
664         {
665             const GstCaps *caps;
666             OMX_ERRORTYPE err;
667             OMX_PARAM_PORTDEFINITIONTYPE param;
668
669             _G_OMX_INIT_PARAM (&param);
670
671             gst_query_parse_buffers_caps (query, &caps);
672
673             /* ensure the caps we are querying are the current ones, otherwise
674              * results are meaningless..
675              *
676              * @todo should we save and restore current caps??
677              */
678 #if 0
679             /* FIXME: why is this needed? it breaks renegotiation happening inside
680              * camerabin2 */
681             src_setcaps (pad, (GstCaps *)caps);
682 #endif
683
684             param.nPortIndex = omx_base->out_port->port_index;
685             err = OMX_GetParameter (omx_base->gomx->omx_handle,
686                     OMX_IndexParamPortDefinition, &param);
687             g_assert (err == OMX_ErrorNone);
688
689             GST_DEBUG_OBJECT (self, "Actual buffers: %d", param.nBufferCountActual);
690
691             gst_query_set_buffers_count (query, param.nBufferCountActual);
692
693 #ifdef USE_OMXTICORE
694             {
695                 OMX_CONFIG_RECTTYPE rect;
696                 _G_OMX_INIT_PARAM (&rect);
697
698                 rect.nPortIndex = omx_base->out_port->port_index;
699                 err = OMX_GetParameter (omx_base->gomx->omx_handle,
700                         OMX_TI_IndexParam2DBufferAllocDimension, &rect);
701                 if (err == OMX_ErrorNone)
702                 {
703                     GST_DEBUG_OBJECT (self, "Min dimensions: %dx%d",
704                             rect.nWidth, rect.nHeight);
705
706                     gst_query_set_buffers_dimensions (query,
707                             rect.nWidth, rect.nHeight);
708                 }
709             }
710 #endif
711
712             ret = TRUE;
713             break;
714         }
715
716         case GST_QUERY_LATENCY:
717         {
718             GstClockTime min, max;
719
720             /* FIXME this is hardcoded for now but we should try to do better */
721             min = 0;
722             max = GST_CLOCK_TIME_NONE;
723             gst_query_set_latency (query, TRUE, min, max);
724
725             ret = TRUE;
726             break;
727         }
728
729         default:
730             ret = GST_BASE_SRC_CLASS (parent_class)->query (GST_BASE_SRC (self), query);
731     }
732
733     GST_DEBUG_OBJECT (self, "End -> %d", ret);
734
735     return ret;
736 }
737
738 /* note.. maybe this should be moved somewhere common... GstOmxBaseVideoDec has
739  * almost same logic..
740  */
741 static void
742 settings_changed (GstElement *self, GstPad *pad)
743 {
744     GstCaps *new_caps;
745
746     if (!gst_pad_is_linked (pad))
747     {
748         GST_DEBUG_OBJECT (self, "%"GST_PTR_FORMAT": pad is not linked", pad);
749         return;
750     }
751
752     new_caps = gst_caps_intersect (gst_pad_get_caps (pad),
753            gst_pad_peer_get_caps (pad));
754
755     if (!gst_caps_is_fixed (new_caps))
756     {
757         gst_caps_do_simplify (new_caps);
758
759         if (gst_caps_is_subset (GST_PAD_CAPS(pad), new_caps))
760         {
761             gst_caps_replace (&new_caps, GST_PAD_CAPS(pad));
762         }
763
764         GST_INFO_OBJECT (self, "%"GST_PTR_FORMAT": pre-fixated caps: %" GST_PTR_FORMAT, pad, new_caps);
765         gst_pad_fixate_caps (pad, new_caps);
766     }
767
768     GST_INFO_OBJECT (self, "%"GST_PTR_FORMAT": caps are: %" GST_PTR_FORMAT, pad, new_caps);
769     GST_INFO_OBJECT (self, "%"GST_PTR_FORMAT": old caps are: %" GST_PTR_FORMAT, pad, GST_PAD_CAPS (pad));
770
771     gst_pad_set_caps (pad, new_caps);
772     gst_caps_unref (new_caps);
773 }
774
775 static void
776 settings_changed_cb (GOmxCore *core)
777 {
778     GstOmxCamera *self = core->object;
779
780     GST_DEBUG_OBJECT (self, "settings changed");
781
782     settings_changed (GST_ELEMENT (self), GST_BASE_SRC (self)->srcpad);
783
784 #ifdef USE_GSTOMXCAM_VIDSRCPAD
785     settings_changed (GST_ELEMENT (self), self->vidsrcpad);
786 #endif
787 #ifdef USE_GSTOMXCAM_IMGSRCPAD
788     settings_changed (GST_ELEMENT (self), self->imgsrcpad);
789 #endif
790 #ifdef USE_GSTOMXCAM_THUMBSRCPAD
791     settings_changed (GST_ELEMENT (self), self->thumbsrcpad);
792 #endif
793 }
794
795 static void
796 autofocus_cb (GstOmxCamera *self)
797 {
798     guint32 autofocus_cb_time;
799
800     GstStructure *structure = gst_structure_new ("omx_camera",
801             "auto-focus", G_TYPE_BOOLEAN, TRUE, NULL);
802
803     GstMessage *message = gst_message_new_element (GST_OBJECT (self),
804             structure);
805
806     gst_element_post_message (GST_ELEMENT (self), message);
807
808     autofocus_cb_time = omap_32k_readraw ();
809     GST_CAT_INFO_OBJECT (gstomx_ppm, GST_OBJECT (self), "%d Autofocus locked",
810                          autofocus_cb_time);
811 }
812
813 static void
814 index_settings_changed_cb (GOmxCore *core, gint data1, gint data2)
815 {
816     GstOmxCamera *self = core->object;
817
818     if (data2 == OMX_IndexConfigCommonFocusStatus)
819         autofocus_cb (self);
820 }
821
822 static void
823 setup_ports (GstOmxBaseSrc *base_src)
824 {
825     GstOmxCamera *self = GST_OMX_CAMERA (base_src);
826     OMX_PARAM_PORTDEFINITIONTYPE param;
827
828 #ifdef USE_GSTOMXCAM_THUMBSRCPAD
829     G_OMX_PORT_GET_DEFINITION (self->vid_port, &param);
830     g_omx_port_setup (self->vid_port, &param);
831 #endif
832
833 #ifdef USE_GSTOMXCAM_IMGSRCPAD
834     G_OMX_PORT_GET_DEFINITION (self->img_port, &param);
835     g_omx_port_setup (self->img_port, &param);
836 #endif
837
838 #ifdef USE_GSTOMXCAM_IN_PORT
839     G_OMX_PORT_GET_DEFINITION (self->in_port, &param);
840     g_omx_port_setup (self->in_port, &param);
841 #endif
842
843 /*   Not supported yet
844     self->vid_port->share_buffer = TRUE;
845     self->img_port->share_buffer = TRUE;
846 */
847 #ifdef USE_GSTOMXCAM_IMGSRCPAD
848     self->img_port->omx_allocate = TRUE;
849     self->img_port->share_buffer = FALSE;
850 #endif
851
852 #ifdef USE_GSTOMXCAM_THUMBSRCPAD
853     self->vid_port->omx_allocate = TRUE;
854     self->vid_port->share_buffer = FALSE;
855 #endif
856 }
857
858
859 static GstClockTime
860 get_timestamp (GstOmxCamera *self)
861 {
862     GstClock *clock;
863     GstClockTime timestamp;
864
865     /* timestamps, LOCK to get clock and base time. */
866     GST_OBJECT_LOCK (self);
867     if ((clock = GST_ELEMENT_CLOCK (self))) {
868       /* we have a clock, get base time and ref clock */
869       timestamp = GST_ELEMENT (self)->base_time;
870       gst_object_ref (clock);
871     } else {
872       /* no clock, can't set timestamps */
873       timestamp = GST_CLOCK_TIME_NONE;
874     }
875     GST_OBJECT_UNLOCK (self);
876
877     if (clock) {
878       /* the time now is the time of the clock minus the base time */
879       /* Hack: Need to subtract the extra lag that is causing problems to AV sync */
880       timestamp = gst_clock_get_time (clock) - timestamp;
881       gst_object_unref (clock);
882
883       /* if we have a framerate adjust timestamp for frame latency */
884 #if 0
885       if (self->fps_n > 0 && self->fps_d > 0)
886       {
887         GstClockTime latency;
888
889         latency = gst_util_uint64_scale_int (GST_SECOND, self->fps_d, self->fps_n);
890
891         if (timestamp > latency)
892           timestamp -= latency;
893         else
894           timestamp = 0;
895       }
896 #endif
897     }
898
899     return timestamp;
900 }
901
902 #ifdef USE_GSTOMXCAM_IMGSRCPAD
903 /** This function configure the camera component on capturing/no capturing mode **/
904 static void
905 set_capture (GstOmxCamera *self, gboolean capture_mode)
906 {
907     OMX_CONFIG_BOOLEANTYPE param;
908     GOmxCore *gomx;
909     OMX_ERRORTYPE err;
910     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
911
912     gomx = (GOmxCore *) omx_base->gomx;
913
914     _G_OMX_INIT_PARAM (&param);
915
916     param.bEnabled = (capture_mode == TRUE) ? OMX_TRUE : OMX_FALSE;
917
918     err = G_OMX_CORE_SET_CONFIG (gomx, OMX_IndexConfigCapturing, &param);
919     g_warn_if_fail (err == OMX_ErrorNone);
920
921     GST_DEBUG_OBJECT (self, "Capture = %d", param.bEnabled);
922 }
923 #endif
924
925
926 static void
927 start_ports (GstOmxCamera *self)
928 {
929     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
930
931     if (config[self->mode] & PORT_PREVIEW)
932     {
933         GST_DEBUG_OBJECT (self, "enable preview port");
934         g_omx_port_enable (omx_base->out_port);
935     }
936
937 #ifdef USE_GSTOMXCAM_THUMBSRCPAD
938     if (config[self->mode] & PORT_VIDEO)
939     {
940         GST_DEBUG_OBJECT (self, "enable video port");
941         g_omx_port_enable (self->vid_port);
942     }
943 #endif
944
945 #ifdef USE_GSTOMXCAM_IMGSRCPAD
946     if (config[self->mode] & PORT_IMAGE)
947     {
948         guint32 capture_start_time;
949
950         GST_DEBUG_OBJECT (self, "enable image port");
951
952         /* WORKAROUND: Image capture set only in LOADED state */
953         /* set_camera_operating_mode (self); */
954         g_omx_port_enable (self->img_port);
955
956         GST_DEBUG_OBJECT (self, "image port set_capture set to  %d", TRUE);
957
958         capture_start_time = omap_32k_readraw();
959         GST_CAT_INFO_OBJECT (gstomx_ppm, self, "%d Start Image Capture",
960                              capture_start_time);
961
962         set_capture (self, TRUE);
963     }
964 #endif
965 }
966
967
968 static void
969 stop_ports (GstOmxCamera *self)
970 {
971
972     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
973     if (config[self->mode] & PORT_PREVIEW)
974     {
975         GST_DEBUG_OBJECT (self, "disable preview port");
976         g_omx_port_disable (omx_base->out_port);
977     }
978
979 #ifdef USE_GSTOMXCAM_THUMBSRCPAD
980     if (config[self->mode] & PORT_VIDEO)
981     {
982         GST_DEBUG_OBJECT (self, "disable video port");
983         g_omx_port_disable (self->vid_port);
984     }
985 #endif
986
987 #ifdef USE_GSTOMXCAM_IMGSRCPAD
988     if (config[self->mode] & PORT_IMAGE)
989     {
990         GST_DEBUG_OBJECT (self, "disable image port");
991         g_omx_port_disable (self->img_port);
992         set_capture (self, FALSE);
993     }
994 #endif
995 }
996
997 #define CALC_RELATIVE(mult, image_size, chunk_size) ((mult * chunk_size) / image_size)
998
999
1000 /*
1001  * GstBaseSrc Methods:
1002  */
1003 static gboolean
1004 stop (GstBaseSrc *gst_base)
1005 {
1006     gboolean res;
1007     GstOmxCamera *self = GST_OMX_CAMERA (gst_base);
1008
1009     res = GST_BASE_SRC_CLASS (parent_class)->stop (gst_base);
1010
1011     self->next_mode = self->mode;
1012     self->mode = -1;
1013     create_ports (self);
1014
1015     return TRUE;
1016 }
1017
1018 static GstFlowReturn
1019 create (GstBaseSrc *gst_base,
1020         guint64 offset,
1021         guint length,
1022         GstBuffer **ret_buf)
1023 {
1024     GstOmxCamera *self = GST_OMX_CAMERA (gst_base);
1025     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
1026     GstBuffer *preview_buf = NULL;
1027     GstBuffer *vid_buf = NULL;
1028     GstBuffer *img_buf = NULL;
1029     GstBuffer *thumb_buf = NULL;
1030     GstFlowReturn ret = GST_FLOW_NOT_NEGOTIATED;
1031     GstClockTime timestamp;
1032     GstEvent *vstab_evt = NULL;
1033     gboolean pending_eos;
1034     guint n_offset = 0;
1035     static guint cont;
1036
1037     pending_eos = g_atomic_int_compare_and_exchange (&self->pending_eos, TRUE, FALSE);
1038
1039     GST_DEBUG_OBJECT (self, "begin, mode=%d, pending_eos=%d", self->mode, pending_eos);
1040
1041     GST_LOG_OBJECT (self, "state: %d", omx_base->gomx->omx_state);
1042
1043     if (self->mode != self->next_mode)
1044     {
1045         if (self->mode != -1) {
1046             stop_ports (self);
1047             g_omx_core_stop (omx_base->gomx);
1048             g_omx_core_unload (omx_base->gomx);
1049         }
1050
1051         set_camera_operating_mode (self);
1052         gst_omx_base_src_setup_ports (omx_base);
1053         set_allocate_buffer_size (self);
1054         g_omx_core_prepare (omx_base->gomx);
1055         self->mode = self->next_mode;
1056         start_ports (self);
1057
1058         /* @todo for now just capture one image... later let the user config
1059          * this to the number of desired burst mode images
1060          */
1061         if (self->mode == MODE_IMAGE)
1062             self->img_count = 1;
1063         if (self->mode == MODE_IMAGE_HS)
1064             self->img_count = self->img_port->num_buffers;
1065     }
1066
1067     if (config[self->mode] & PORT_PREVIEW)
1068     {
1069         ret = gst_omx_base_src_create_from_port (omx_base,
1070                 omx_base->out_port, &preview_buf);
1071         n_offset = omx_base->out_port->n_offset;
1072         if (ret != GST_FLOW_OK)
1073             goto fail;
1074         if (self->mode == MODE_VIDEO)
1075         {
1076             vid_buf = gst_buffer_ref (preview_buf);
1077         }
1078     }
1079
1080     if (config[self->mode] & PORT_VIDEO)
1081     {
1082         ret = gst_omx_base_src_create_from_port (omx_base,
1083                 self->vid_port, &thumb_buf);
1084         n_offset = self->vid_port->n_offset;
1085         if (ret != GST_FLOW_OK)
1086             goto fail;
1087     }
1088
1089     if (config[self->mode] & PORT_IMAGE)
1090     {
1091         ret = gst_omx_base_src_create_from_port (omx_base,
1092                 self->img_port, &img_buf);
1093         if (ret != GST_FLOW_OK)
1094             goto fail;
1095
1096         if (--self->img_count == 0)
1097         {
1098             self->next_mode = MODE_PREVIEW;
1099             GST_DEBUG_OBJECT (self, "image port set_capture set to %d", FALSE);
1100             set_capture (self, FALSE);
1101         }
1102         GST_DEBUG_OBJECT (self, "### img_count = %d ###", self->img_count);
1103     }
1104
1105     timestamp = get_timestamp (self);
1106     cont ++;
1107     GST_DEBUG_OBJECT (self, "******** preview buffers cont = %d", cont);
1108     GST_BUFFER_TIMESTAMP (preview_buf) = timestamp;
1109
1110     *ret_buf = preview_buf;
1111
1112     if (n_offset)
1113     {
1114         vstab_evt = gst_event_new_crop (n_offset / self->rowstride, /* top */
1115                 n_offset % self->rowstride, /* left */
1116                 -1, -1); /* width/height: we can just give invalid for now */
1117         gst_pad_push_event (GST_BASE_SRC (self)->srcpad,
1118                 gst_event_ref (vstab_evt));
1119     }
1120
1121     if (vid_buf)
1122     {
1123         GST_DEBUG_OBJECT (self, "pushing vid_buf");
1124         GST_BUFFER_TIMESTAMP (vid_buf) = timestamp;
1125         if (vstab_evt)
1126             gst_pad_push_event (self->vidsrcpad, gst_event_ref (vstab_evt));
1127         gst_buffer_set_caps (vid_buf, GST_PAD_CAPS (gst_base->srcpad));
1128         gst_pad_push (self->vidsrcpad, vid_buf);
1129         if (G_UNLIKELY (pending_eos))
1130             gst_pad_push_event (self->vidsrcpad, gst_event_new_eos ());
1131     }
1132
1133     if (img_buf)
1134     {
1135         GST_DEBUG_OBJECT (self, "pushing img_buf");
1136         GST_BUFFER_TIMESTAMP (img_buf) = timestamp;
1137         gst_pad_push (self->imgsrcpad, img_buf);
1138         if (G_UNLIKELY (pending_eos))
1139             gst_pad_push_event (self->imgsrcpad, gst_event_new_eos ());
1140     }
1141
1142     if (thumb_buf)
1143     {
1144         GST_DEBUG_OBJECT (self, "pushing thumb_buf");
1145         GST_BUFFER_TIMESTAMP (thumb_buf) = timestamp;
1146         gst_pad_push (self->thumbsrcpad, thumb_buf);
1147         if (G_UNLIKELY (pending_eos))
1148             gst_pad_push_event (self->thumbsrcpad, gst_event_new_eos ());
1149     }
1150
1151     if (vstab_evt)
1152     {
1153         gst_event_unref (vstab_evt);
1154     }
1155
1156     if (G_UNLIKELY (pending_eos))
1157     {
1158          /* now send eos event, which was previously deferred, to parent
1159           * class this will trigger basesrc's eos logic.  Unfortunately we
1160           * can't call parent->send_event() directly from here to pass along
1161           * the eos, which would be a more obvious approach, because that
1162           * would deadlock when it tries to acquire live-lock.. but live-
1163           * lock is already held when calling create().
1164           */
1165           return GST_FLOW_UNEXPECTED;
1166     }
1167
1168     GST_DEBUG_OBJECT (self, "end, ret=%d", ret);
1169
1170     return GST_FLOW_OK;
1171
1172 fail:
1173     if (preview_buf) gst_buffer_unref (preview_buf);
1174     if (vid_buf)     gst_buffer_unref (vid_buf);
1175     if (img_buf)     gst_buffer_unref (img_buf);
1176     if (thumb_buf)   gst_buffer_unref (thumb_buf);
1177
1178     return ret;
1179 }
1180
1181 static gboolean
1182 send_event (GstElement * element, GstEvent * event)
1183 {
1184     GstOmxCamera *self = GST_OMX_CAMERA (element);
1185
1186     GST_DEBUG_OBJECT (self, "received %s event", GST_EVENT_TYPE_NAME (event));
1187
1188     switch (GST_EVENT_TYPE (event))
1189     {
1190         case GST_EVENT_EOS:
1191             /* note: we don't pass the eos event on to basesrc until
1192              * we have a chance to handle it ourselves..
1193              */
1194             g_atomic_int_set (&self->pending_eos, TRUE);
1195             gst_event_unref (event);
1196             return TRUE;
1197         default:
1198             return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1199     }
1200 }
1201
1202
1203 /*
1204  * Initialization:
1205  */
1206
1207 static void
1208 type_base_init (gpointer g_class)
1209 {
1210     GstElementClass *element_class;
1211
1212     element_class = GST_ELEMENT_CLASS (g_class);
1213
1214     gst_element_class_set_details (element_class, &element_details);
1215
1216     gst_element_class_add_pad_template (element_class,
1217         gst_static_pad_template_get (&src_template));
1218
1219     gst_element_class_add_pad_template (element_class,
1220         gst_static_pad_template_get (&vidsrc_template));
1221
1222     gst_element_class_add_pad_template (element_class,
1223         gst_static_pad_template_get (&imgsrc_template));
1224
1225     gst_element_class_add_pad_template (element_class,
1226         gst_static_pad_template_get (&thumbsrc_template));
1227
1228 #if 0
1229     gst_element_class_add_pad_template (element_class,
1230         gst_static_pad_template_get (&sink_template));
1231 #endif
1232 }
1233
1234 static void
1235 type_class_init (gpointer g_class,
1236                  gpointer class_data)
1237 {
1238     GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
1239     GstElementClass *gst_element_class = GST_ELEMENT_CLASS (g_class);
1240     GstBaseSrcClass *gst_base_src_class = GST_BASE_SRC_CLASS (g_class);
1241     GstOmxBaseSrcClass *omx_base_class = GST_OMX_BASE_SRC_CLASS (g_class);
1242
1243     omx_base_class->out_port_index = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW;
1244
1245     /* GstBaseSrc methods: */
1246     gst_base_src_class->create = GST_DEBUG_FUNCPTR (create);
1247     gst_base_src_class->stop = GST_DEBUG_FUNCPTR (stop);
1248
1249     /* GstElement methods: */
1250     gst_element_class->send_event = GST_DEBUG_FUNCPTR (send_event);
1251
1252     /* GObject methods: */
1253     gobject_class->set_property = GST_DEBUG_FUNCPTR (set_property);
1254     gobject_class->get_property = GST_DEBUG_FUNCPTR (get_property);
1255
1256     /* install properties: */
1257     install_camera_properties (gobject_class);
1258
1259 }
1260
1261
1262 void check_settings (GOmxPort *port, GstPad *pad);
1263
1264
1265 /**
1266  * overrides the default buffer allocation for img_port to allow
1267  * pad_alloc'ing from the imgsrcpad
1268  */
1269 static GstBuffer *
1270 img_buffer_alloc (GOmxPort *port, gint len)
1271 {
1272     GstOmxCamera *self = port->core->object;
1273     GstBuffer *buf;
1274     GstFlowReturn ret;
1275
1276     GST_DEBUG_OBJECT (self, "img_buffer_alloc begin");
1277     check_settings (self->img_port, self->imgsrcpad);
1278
1279     ret = gst_pad_alloc_buffer_and_set_caps (
1280             self->imgsrcpad, GST_BUFFER_OFFSET_NONE,
1281             len, GST_PAD_CAPS (self->imgsrcpad), &buf);
1282
1283     if (ret == GST_FLOW_OK) return buf;
1284
1285     return NULL;
1286 }
1287
1288
1289 /**
1290  * overrides the default buffer allocation for thumb_port to allow
1291  * pad_alloc'ing from the thumbsrcpad
1292  */
1293 static GstBuffer *
1294 thumb_buffer_alloc (GOmxPort *port, gint len)
1295 {
1296     GstOmxCamera *self = port->core->object;
1297     GstBuffer *buf;
1298     GstFlowReturn ret;
1299
1300     GST_DEBUG_OBJECT (self, "thumb_buffer_alloc begin");
1301     check_settings (self->vid_port, self->thumbsrcpad);
1302
1303     ret = gst_pad_alloc_buffer_and_set_caps (
1304             self->thumbsrcpad, GST_BUFFER_OFFSET_NONE,
1305             len, GST_PAD_CAPS (self->thumbsrcpad), &buf);
1306
1307     if (ret == GST_FLOW_OK) return buf;
1308
1309     return NULL;
1310 }
1311
1312
1313 static void
1314 type_instance_init (GTypeInstance *instance,
1315                     gpointer g_class)
1316 {
1317     GstOmxCamera   *self     = GST_OMX_CAMERA (instance);
1318     GstOmxBaseSrc  *omx_base = GST_OMX_BASE_SRC (self);
1319     GstBaseSrc     *basesrc  = GST_BASE_SRC (self);
1320     GstPadTemplate *pad_template;
1321     GstColorBalanceChannel *channel;
1322     const gchar *channels[3] = { "SATURATION",
1323       "CONTRAST", "SHARPNESS"
1324     };
1325     gint i;
1326
1327     GST_DEBUG_OBJECT (omx_base, "begin");
1328
1329     self->mode = -1;
1330     self->next_mode = MODE_PREVIEW;
1331
1332     omx_base->setup_ports = setup_ports;
1333
1334     omx_base->gomx->settings_changed_cb = settings_changed_cb;
1335     omx_base->gomx->index_settings_changed_cb = index_settings_changed_cb;
1336
1337     omx_base->gomx->use_timestamps = TRUE;
1338
1339     create_ports (self);
1340
1341     gst_base_src_set_live (basesrc, TRUE);
1342
1343     /* setup src pad (already created by basesrc): */
1344
1345     gst_pad_set_setcaps_function (basesrc->srcpad,
1346             GST_DEBUG_FUNCPTR (src_setcaps));
1347     gst_pad_set_fixatecaps_function (basesrc->srcpad,
1348             GST_DEBUG_FUNCPTR (src_fixatecaps));
1349
1350     /* create/setup vidsrc pad: */
1351     pad_template = gst_element_class_get_pad_template (
1352             GST_ELEMENT_CLASS (g_class), "vidsrc");
1353     g_return_if_fail (pad_template != NULL);
1354
1355     GST_DEBUG_OBJECT (basesrc, "creating vidsrc pad");
1356     self->vidsrcpad = gst_pad_new_from_template (pad_template, "vidsrc");
1357     gst_element_add_pad (GST_ELEMENT_CAST (self), self->vidsrcpad);
1358
1359     /* create/setup imgsrc pad: */
1360     pad_template = gst_element_class_get_pad_template (
1361             GST_ELEMENT_CLASS (g_class), "imgsrc");
1362     g_return_if_fail (pad_template != NULL);
1363
1364     GST_DEBUG_OBJECT (basesrc, "creating imgsrc pad");
1365     self->imgsrcpad = gst_pad_new_from_template (pad_template, "imgsrc");
1366     gst_element_add_pad (GST_ELEMENT_CAST (self), self->imgsrcpad);
1367     gst_pad_set_setcaps_function (self->imgsrcpad,
1368             GST_DEBUG_FUNCPTR (imgsrc_setcaps));
1369     gst_pad_set_fixatecaps_function (self->imgsrcpad,
1370             GST_DEBUG_FUNCPTR (imgsrc_fixatecaps));
1371     gst_pad_set_event_function (self->imgsrcpad,
1372             GST_DEBUG_FUNCPTR (imgsrc_event));
1373
1374     /* create/setup thumbsrc pad: */
1375     pad_template = gst_element_class_get_pad_template (
1376             GST_ELEMENT_CLASS (g_class), "thumbsrc");
1377     g_return_if_fail (pad_template != NULL);
1378
1379     GST_DEBUG_OBJECT (basesrc, "creating thumbsrc pad");
1380     self->thumbsrcpad = gst_pad_new_from_template (pad_template, "thumbsrc");
1381     gst_element_add_pad (GST_ELEMENT_CAST (self), self->thumbsrcpad);
1382     gst_pad_set_setcaps_function (self->thumbsrcpad,
1383             GST_DEBUG_FUNCPTR (thumbsrc_setcaps));
1384
1385     gst_pad_set_query_function (basesrc->srcpad,
1386             GST_DEBUG_FUNCPTR (src_query));
1387     gst_pad_set_query_function (self->vidsrcpad,
1388             GST_DEBUG_FUNCPTR (src_query));
1389
1390     /* set colorbalance channels*/
1391
1392 #if 0
1393     self->contrast = DEFAULT_PROP_CONTRAST;
1394     self->brightness = DEFAULT_PROP_BRIGHTNESS;
1395     self->hue = DEFAULT_PROP_HUE;
1396     self->saturation = DEFAULT_PROP_SATURATION;
1397 #endif
1398
1399     g_assert (self->channels == NULL);
1400     for (i = 0; i < G_N_ELEMENTS (channels); i++) {
1401
1402       channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
1403       channel->label = g_strdup (channels[i]);
1404       channel->min_value = -100;
1405       channel->max_value = 100;
1406
1407       self->channels = g_list_append (self->channels, channel);
1408     }
1409
1410     channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
1411     channel->label = g_strdup ("BRIGHTNESS");
1412     channel->min_value = 0;
1413     channel->max_value = 100;
1414     self->channels = g_list_append (self->channels, channel);
1415
1416     GST_DEBUG_OBJECT (omx_base, "end");
1417 }
1418
1419 static void
1420 create_ports (GstOmxCamera *self)
1421 {
1422     GstOmxBaseSrc *omx_base = GST_OMX_BASE_SRC (self);
1423
1424     self->vid_port = g_omx_core_get_port (omx_base->gomx, "vid",
1425             OMX_CAMERA_PORT_VIDEO_OUT_VIDEO);
1426     self->img_port = g_omx_core_get_port (omx_base->gomx, "img",
1427             OMX_CAMERA_PORT_IMAGE_OUT_IMAGE);
1428     self->in_port = g_omx_core_get_port (omx_base->gomx, "in",
1429             OMX_CAMERA_PORT_OTHER_IN);
1430     self->in_vid_port = g_omx_core_get_port (omx_base->gomx, "in_vid",
1431             OMX_CAMERA_PORT_VIDEO_IN_VIDEO);
1432     self->msr_port = g_omx_core_get_port (omx_base->gomx, "msr",
1433             OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT);
1434
1435     self->img_port->buffer_alloc = img_buffer_alloc;
1436     self->vid_port->buffer_alloc = thumb_buffer_alloc;
1437
1438     g_object_set (self, "allocate-buffers", FALSE, NULL);
1439 #if 0
1440     self->in_port = g_omx_core_get_port (omx_base->gomx, "in"
1441             OMX_CAMERA_PORT_VIDEO_IN_VIDEO);
1442 #endif
1443
1444
1445
1446 #if 0
1447     /* disable all ports to begin with: */
1448     g_omx_port_disable (self->in_port);
1449 #endif
1450     g_omx_port_disable (omx_base->out_port);
1451     g_omx_port_disable (self->vid_port);
1452     g_omx_port_disable (self->img_port);
1453     g_omx_port_disable (self->in_port);
1454     g_omx_port_disable (self->in_vid_port);
1455     g_omx_port_disable (self->msr_port);
1456
1457     GST_DEBUG_OBJECT (omx_base, "end");
1458 }