sys/v4l2/: More FIXME comments and messaging changes.
[platform/upstream/gstreamer.git] / sys / v4l2 / gstv4l2src.c
1 /* GStreamer
2  *
3  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4  *               2006 Edgard Lima <edgard.lima@indt.org.br>
5  *
6  * gstv4l2src.c: Video4Linux2 source element
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:element-v4l2src
26  *
27  * <refsect2>
28  * v4l2src can be used to capture video from v4l2 devices, like webcams and tv cards.
29  * <title>Example launch line</title>
30  * <para>
31  * <programlisting>
32  * gst-launch v4l2src ! xvimagesink
33  * </programlisting>
34  * This pipeline shows the video captured from /dev/video0 tv card and for
35  * webcams.
36  * </para>
37  * </refsect2>
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include <string.h>
45 #include <sys/time.h>
46 #include "v4l2src_calls.h"
47 #include <unistd.h>
48
49 #include "gstv4l2colorbalance.h"
50 #include "gstv4l2tuner.h"
51 #include "gstv4l2xoverlay.h"
52 #include "gstv4l2vidorient.h"
53
54 static const GstElementDetails gst_v4l2src_details =
55 GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source",
56     "Source/Video",
57     "Reads raw frames from a video4linux2 (BT8x8) device",
58     "Ronald Bultje <rbultje@ronald.bitfreak.net>,"
59     " Edgard Lima <edgard.lima@indt.org.br>");
60
61 GST_DEBUG_CATEGORY (v4l2src_debug);
62 #define GST_CAT_DEFAULT v4l2src_debug
63
64 enum
65 {
66   PROP_0,
67   V4L2_STD_OBJECT_PROPS,
68   PROP_QUEUE_SIZE
69 };
70
71 static const guint32 gst_v4l2_formats[] = {
72   /* from Linux 2.6.15 videodev2.h */
73   V4L2_PIX_FMT_RGB332,
74   V4L2_PIX_FMT_RGB555,
75   V4L2_PIX_FMT_RGB565,
76   V4L2_PIX_FMT_RGB555X,
77   V4L2_PIX_FMT_RGB565X,
78   V4L2_PIX_FMT_BGR24,
79   V4L2_PIX_FMT_RGB24,
80   V4L2_PIX_FMT_BGR32,
81   V4L2_PIX_FMT_RGB32,
82   V4L2_PIX_FMT_GREY,
83   V4L2_PIX_FMT_YVU410,
84   V4L2_PIX_FMT_YVU420,
85   V4L2_PIX_FMT_YUYV,
86   V4L2_PIX_FMT_UYVY,
87   V4L2_PIX_FMT_YUV422P,
88   V4L2_PIX_FMT_YUV411P,
89   V4L2_PIX_FMT_Y41P,
90
91   /* two planes -- one Y, one Cr + Cb interleaved  */
92   V4L2_PIX_FMT_NV12,
93   V4L2_PIX_FMT_NV21,
94
95   /*  The following formats are not defined in the V4L2 specification */
96   V4L2_PIX_FMT_YUV410,
97   V4L2_PIX_FMT_YUV420,
98   V4L2_PIX_FMT_YYUV,
99   V4L2_PIX_FMT_HI240,
100
101   /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
102 #ifdef V4L2_PIX_FMT_SBGGR8
103   V4L2_PIX_FMT_SBGGR8,
104 #endif
105
106   /* compressed formats */
107   V4L2_PIX_FMT_MJPEG,
108   V4L2_PIX_FMT_JPEG,
109   V4L2_PIX_FMT_DV,
110   V4L2_PIX_FMT_MPEG,
111
112   /*  Vendor-specific formats   */
113   V4L2_PIX_FMT_WNVA,
114
115 #ifdef V4L2_PIX_FMT_SN9C10X
116   V4L2_PIX_FMT_SN9C10X,
117 #endif
118 #ifdef V4L2_PIX_FMT_PWC1
119   V4L2_PIX_FMT_PWC1,
120 #endif
121 #ifdef V4L2_PIX_FMT_PWC2
122   V4L2_PIX_FMT_PWC2,
123 #endif
124 };
125
126 #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
127
128 GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
129 GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src);
130 GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src);
131 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
132 GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Src, gst_v4l2src);
133 #endif
134 GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src);
135
136 static gboolean
137 gst_v4l2src_iface_supported (GstImplementsInterface * iface, GType iface_type)
138 {
139   GstV4l2Object *v4l2object = GST_V4L2SRC (iface)->v4l2object;
140
141 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
142   g_assert (iface_type == GST_TYPE_TUNER ||
143       iface_type == GST_TYPE_X_OVERLAY ||
144       iface_type == GST_TYPE_COLOR_BALANCE ||
145       iface_type == GST_TYPE_VIDEO_ORIENTATION);
146 #else
147   g_assert (iface_type == GST_TYPE_TUNER ||
148       iface_type == GST_TYPE_COLOR_BALANCE ||
149       iface_type == GST_TYPE_VIDEO_ORIENTATION);
150 #endif
151
152   if (v4l2object->video_fd == -1)
153     return FALSE;
154
155 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
156   if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2object))
157     return FALSE;
158 #endif
159
160   return TRUE;
161 }
162
163 static void
164 gst_v4l2src_interface_init (GstImplementsInterfaceClass * klass)
165 {
166   /*
167    * default virtual functions 
168    */
169   klass->supported = gst_v4l2src_iface_supported;
170 }
171
172 void
173 gst_v4l2src_init_interfaces (GType type)
174 {
175   static const GInterfaceInfo v4l2iface_info = {
176     (GInterfaceInitFunc) gst_v4l2src_interface_init,
177     NULL,
178     NULL,
179   };
180   static const GInterfaceInfo v4l2_tuner_info = {
181     (GInterfaceInitFunc) gst_v4l2src_tuner_interface_init,
182     NULL,
183     NULL,
184   };
185 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
186   static const GInterfaceInfo v4l2_xoverlay_info = {
187     (GInterfaceInitFunc) gst_v4l2src_xoverlay_interface_init,
188     NULL,
189     NULL,
190   };
191 #endif
192   static const GInterfaceInfo v4l2_colorbalance_info = {
193     (GInterfaceInitFunc) gst_v4l2src_color_balance_interface_init,
194     NULL,
195     NULL,
196   };
197   static const GInterfaceInfo v4l2_videoorientation_info = {
198     (GInterfaceInitFunc) gst_v4l2src_video_orientation_interface_init,
199     NULL,
200     NULL,
201   };
202   static const GInterfaceInfo v4l2_propertyprobe_info = {
203     (GInterfaceInitFunc) gst_v4l2src_property_probe_interface_init,
204     NULL,
205     NULL,
206   };
207
208   g_type_add_interface_static (type,
209       GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info);
210   g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info);
211 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
212   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info);
213 #endif
214   g_type_add_interface_static (type,
215       GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info);
216   g_type_add_interface_static (type,
217       GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info);
218   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
219       &v4l2_propertyprobe_info);
220 }
221
222 GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC,
223     gst_v4l2src_init_interfaces);
224
225 static void gst_v4l2src_dispose (GObject * object);
226
227 /* basesrc methods */
228 static gboolean gst_v4l2src_start (GstBaseSrc * src);
229 static gboolean gst_v4l2src_stop (GstBaseSrc * src);
230 static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
231 static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
232 static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
233
234 static void gst_v4l2src_fixate (GstPad * pad, GstCaps * caps);
235
236 static void gst_v4l2src_set_property (GObject * object, guint prop_id,
237     const GValue * value, GParamSpec * pspec);
238 static void gst_v4l2src_get_property (GObject * object, guint prop_id,
239     GValue * value, GParamSpec * pspec);
240
241 static GstCaps *gst_v4l2src_get_all_caps (void);
242
243 static void
244 gst_v4l2src_base_init (gpointer g_class)
245 {
246   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
247   GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
248
249   gstv4l2src_class->v4l2_class_devices = NULL;
250
251   GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
252
253   gst_element_class_set_details (gstelement_class, &gst_v4l2src_details);
254
255   gst_element_class_add_pad_template
256       (gstelement_class,
257       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
258           gst_v4l2src_get_all_caps ()));
259 }
260
261 static void
262 gst_v4l2src_class_init (GstV4l2SrcClass * klass)
263 {
264   GObjectClass *gobject_class;
265   GstBaseSrcClass *basesrc_class;
266   GstPushSrcClass *pushsrc_class;
267
268   gobject_class = G_OBJECT_CLASS (klass);
269   basesrc_class = GST_BASE_SRC_CLASS (klass);
270   pushsrc_class = GST_PUSH_SRC_CLASS (klass);
271
272   gobject_class->dispose = gst_v4l2src_dispose;
273   gobject_class->set_property = gst_v4l2src_set_property;
274   gobject_class->get_property = gst_v4l2src_get_property;
275
276   gst_v4l2_object_install_properties_helper (gobject_class);
277   g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
278       g_param_spec_uint ("queue-size", "Queue size",
279           "Number of buffers to be enqueud in the driver",
280           GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, GST_V4L2_MIN_BUFFERS,
281           G_PARAM_READWRITE));
282
283   basesrc_class->get_caps = gst_v4l2src_get_caps;
284   basesrc_class->set_caps = gst_v4l2src_set_caps;
285   basesrc_class->start = gst_v4l2src_start;
286   basesrc_class->stop = gst_v4l2src_stop;
287
288   pushsrc_class->create = gst_v4l2src_create;
289 }
290
291 static void
292 gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
293 {
294   v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
295       gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps);
296
297   /* number of buffers requested */
298   v4l2src->breq.count = 0;
299
300   v4l2src->formats = NULL;
301
302   /* fps */
303   v4l2src->fps_n = 0;
304   v4l2src->fps_d = 1;
305
306   v4l2src->is_capturing = FALSE;
307
308   gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (v4l2src),
309       gst_v4l2src_fixate);
310
311   gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
312   gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
313 }
314
315
316 static void
317 gst_v4l2src_dispose (GObject * object)
318 {
319   GstV4l2Src *v4l2src = GST_V4L2SRC (object);
320
321   if (v4l2src->formats) {
322     gst_v4l2src_clear_format_list (v4l2src);
323   }
324
325   G_OBJECT_CLASS (parent_class)->dispose (object);
326 }
327
328
329 static void
330 gst_v4l2src_set_property (GObject * object,
331     guint prop_id, const GValue * value, GParamSpec * pspec)
332 {
333   GstV4l2Src *v4l2src;
334
335   g_return_if_fail (GST_IS_V4L2SRC (object));
336   v4l2src = GST_V4L2SRC (object);
337
338   if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
339           prop_id, value, pspec)) {
340     switch (prop_id) {
341       case PROP_QUEUE_SIZE:
342         v4l2src->breq.count = g_value_get_uint (value);
343         break;
344       default:
345         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346         break;
347     }
348   }
349 }
350
351
352 static void
353 gst_v4l2src_get_property (GObject * object,
354     guint prop_id, GValue * value, GParamSpec * pspec)
355 {
356   GstV4l2Src *v4l2src;
357
358   g_return_if_fail (GST_IS_V4L2SRC (object));
359   v4l2src = GST_V4L2SRC (object);
360
361   if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
362           prop_id, value, pspec)) {
363     switch (prop_id) {
364       case PROP_QUEUE_SIZE:
365         g_value_set_uint (value, v4l2src->breq.count);
366         break;
367       default:
368         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
369         break;
370     }
371   }
372 }
373
374
375 /* this function is a bit of a last resort */
376 static void
377 gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
378 {
379   GstStructure *structure;
380   gint i;
381   G_GNUC_UNUSED gchar *caps_str;
382
383   caps_str = gst_caps_to_string (caps);
384   GST_DEBUG_OBJECT (GST_PAD_PARENT (pad), "fixating caps %s", caps_str);
385   g_free (caps_str);
386
387   for (i = 0; i < gst_caps_get_size (caps); ++i) {
388     structure = gst_caps_get_structure (caps, i);
389     const GValue *v;
390
391     /* FIXME such sizes? we usually fixate to something in the 320x200
392      * range... */
393     /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
394        and framarate closer to 15/2 that is common in web-cams */
395     gst_structure_fixate_field_nearest_int (structure, "width",
396         GST_V4L2_MAX_SIZE);
397     gst_structure_fixate_field_nearest_int (structure, "height",
398         GST_V4L2_MAX_SIZE);
399     gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
400
401     v = gst_structure_get_value (structure, "format");
402     if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
403       guint32 fourcc;
404
405       g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
406
407       fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
408       gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
409     }
410   }
411 }
412
413 static GstStructure *
414 gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc)
415 {
416   GstStructure *structure = NULL;
417
418   /* FIXME: new FourCCs
419      camera: ZC0301 PC Camera
420      driver: zc0301
421      BA81, S910, PWC1, PWC2
422
423      camera:
424      driver:
425    */
426
427   switch (fourcc) {
428     case V4L2_PIX_FMT_MJPEG:   /* Motion-JPEG */
429     case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
430       structure = gst_structure_new ("image/jpeg", NULL);
431       break;
432     case V4L2_PIX_FMT_RGB332:
433     case V4L2_PIX_FMT_RGB555:
434     case V4L2_PIX_FMT_RGB555X:
435     case V4L2_PIX_FMT_RGB565:
436     case V4L2_PIX_FMT_RGB565X:
437     case V4L2_PIX_FMT_RGB24:
438     case V4L2_PIX_FMT_BGR24:
439     case V4L2_PIX_FMT_RGB32:
440     case V4L2_PIX_FMT_BGR32:{
441       guint depth = 0, bpp = 0;
442       gint endianness = 0;
443       guint32 r_mask = 0, b_mask = 0, g_mask = 0;
444
445       switch (fourcc) {
446         case V4L2_PIX_FMT_RGB332:
447           bpp = depth = 8;
448           endianness = G_BYTE_ORDER;    /* 'like, whatever' */
449           r_mask = 0xe0;
450           g_mask = 0x1c;
451           b_mask = 0x03;
452           break;
453         case V4L2_PIX_FMT_RGB555:
454         case V4L2_PIX_FMT_RGB555X:
455           bpp = 16;
456           depth = 15;
457           endianness =
458               fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
459           r_mask = 0x7c00;
460           g_mask = 0x03e0;
461           b_mask = 0x001f;
462           break;
463         case V4L2_PIX_FMT_RGB565:
464         case V4L2_PIX_FMT_RGB565X:
465           bpp = depth = 16;
466           endianness =
467               fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
468           r_mask = 0xf800;
469           g_mask = 0x07e0;
470           b_mask = 0x001f;
471           break;
472         case V4L2_PIX_FMT_RGB24:
473           bpp = depth = 24;
474           endianness = G_BIG_ENDIAN;
475           r_mask = 0xff0000;
476           g_mask = 0x00ff00;
477           b_mask = 0x0000ff;
478           break;
479         case V4L2_PIX_FMT_BGR24:
480           bpp = depth = 24;
481           endianness = G_BIG_ENDIAN;
482           r_mask = 0x0000ff;
483           g_mask = 0x00ff00;
484           b_mask = 0xff0000;
485           break;
486         case V4L2_PIX_FMT_RGB32:
487           bpp = depth = 32;
488           endianness = G_BIG_ENDIAN;
489           r_mask = 0xff000000;
490           g_mask = 0x00ff0000;
491           b_mask = 0x0000ff00;
492           break;
493         case V4L2_PIX_FMT_BGR32:
494           bpp = depth = 32;
495           endianness = G_BIG_ENDIAN;
496           r_mask = 0x000000ff;
497           g_mask = 0x0000ff00;
498           b_mask = 0x00ff0000;
499           break;
500         default:
501           g_assert_not_reached ();
502           break;
503       }
504       structure = gst_structure_new ("video/x-raw-rgb",
505           "bpp", G_TYPE_INT, bpp,
506           "depth", G_TYPE_INT, depth,
507           "red_mask", G_TYPE_INT, r_mask,
508           "green_mask", G_TYPE_INT, g_mask,
509           "blue_mask", G_TYPE_INT, b_mask,
510           "endianness", G_TYPE_INT, endianness, NULL);
511       break;
512     }
513     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
514     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
515     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
516     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
517     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
518       /* FIXME: get correct fourccs here */
519       break;
520     case V4L2_PIX_FMT_YVU410:
521     case V4L2_PIX_FMT_YUV410:
522     case V4L2_PIX_FMT_YUV420:  /* I420/IYUV */
523     case V4L2_PIX_FMT_YUYV:
524     case V4L2_PIX_FMT_YVU420:
525     case V4L2_PIX_FMT_UYVY:
526     case V4L2_PIX_FMT_Y41P:
527     case V4L2_PIX_FMT_YUV422P:
528     case V4L2_PIX_FMT_YUV411P:{
529       guint32 fcc = 0;
530
531       switch (fourcc) {
532         case V4L2_PIX_FMT_YVU410:
533           fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
534           break;
535         case V4L2_PIX_FMT_YUV410:
536           fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
537           break;
538         case V4L2_PIX_FMT_YUV420:
539           fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
540           break;
541         case V4L2_PIX_FMT_YUYV:
542           fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
543           break;
544         case V4L2_PIX_FMT_YVU420:
545           fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
546           break;
547         case V4L2_PIX_FMT_UYVY:
548           fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
549           break;
550         case V4L2_PIX_FMT_Y41P:
551           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
552           break;
553         case V4L2_PIX_FMT_YUV411P:
554           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
555           break;
556         case V4L2_PIX_FMT_YUV422P:
557           fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
558           break;
559         default:
560           g_assert_not_reached ();
561           break;
562       }
563       structure = gst_structure_new ("video/x-raw-yuv",
564           "format", GST_TYPE_FOURCC, fcc, NULL);
565       break;
566     }
567     case V4L2_PIX_FMT_DV:
568       structure =
569           gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
570           NULL);
571       break;
572     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
573       /* someone figure out the MPEG format used... */
574       break;
575     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
576       break;
577     default:
578       GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
579           fourcc, GST_FOURCC_ARGS (fourcc));
580       break;
581   }
582
583   return structure;
584 }
585
586 static guint32
587 gst_v4l2_fourcc_from_structure (GstStructure * structure)
588 {
589   guint32 fourcc = 0;
590   const gchar *mimetype = gst_structure_get_name (structure);
591
592   if (!strcmp (mimetype, "video/x-raw-yuv")) {
593     gst_structure_get_fourcc (structure, "format", &fourcc);
594
595     switch (fourcc) {
596       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
597       case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
598         fourcc = V4L2_PIX_FMT_YUV420;
599         break;
600       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
601         fourcc = V4L2_PIX_FMT_YUYV;
602         break;
603       case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
604         fourcc = V4L2_PIX_FMT_Y41P;
605         break;
606       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
607         fourcc = V4L2_PIX_FMT_UYVY;
608         break;
609       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
610         fourcc = V4L2_PIX_FMT_YVU420;
611         break;
612       case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
613         fourcc = V4L2_PIX_FMT_YUV411P;
614         break;
615       case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
616         fourcc = V4L2_PIX_FMT_YUV422P;
617         break;
618     }
619   } else if (!strcmp (mimetype, "video/x-raw-rgb")) {
620     gint depth, endianness, r_mask;
621
622     gst_structure_get_int (structure, "depth", &depth);
623     gst_structure_get_int (structure, "endianness", &endianness);
624     gst_structure_get_int (structure, "red_mask", &r_mask);
625
626     switch (depth) {
627       case 8:
628         fourcc = V4L2_PIX_FMT_RGB332;
629         break;
630       case 15:
631         fourcc = (endianness == G_LITTLE_ENDIAN) ?
632             V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
633         break;
634       case 16:
635         fourcc = (endianness == G_LITTLE_ENDIAN) ?
636             V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
637         break;
638       case 24:
639         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
640         break;
641       case 32:
642         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
643         break;
644     }
645   } else if (strcmp (mimetype, "video/x-dv") == 0) {
646     fourcc = V4L2_PIX_FMT_DV;
647   } else if (strcmp (mimetype, "image/jpeg") == 0) {
648     fourcc = V4L2_PIX_FMT_JPEG;
649   }
650
651   return fourcc;
652 }
653
654 static struct v4l2_fmtdesc *
655 gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
656 {
657   struct v4l2_fmtdesc *fmt;
658   GSList *walk;
659
660   if (fourcc == 0)
661     return NULL;
662
663   walk = v4l2src->formats;
664   while (walk) {
665     fmt = (struct v4l2_fmtdesc *) walk->data;
666     if (fmt->pixelformat == fourcc)
667       return fmt;
668     /* special case for jpeg */
669     if ((fmt->pixelformat == V4L2_PIX_FMT_MJPEG && fourcc == V4L2_PIX_FMT_JPEG)
670         || (fmt->pixelformat == V4L2_PIX_FMT_JPEG
671             && fourcc == V4L2_PIX_FMT_MJPEG)) {
672       return fmt;
673     }
674     walk = g_slist_next (walk);
675   }
676
677   return NULL;
678 }
679
680 static struct v4l2_fmtdesc *
681 gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src * v4l2src, GstStructure * structure)
682 {
683   return gst_v4l2src_get_format_from_fourcc (v4l2src,
684       gst_v4l2_fourcc_from_structure (structure));
685 }
686
687 static GstCaps *
688 gst_v4l2src_get_all_caps (void)
689 {
690   static GstCaps *caps = NULL;
691
692   if (caps == NULL) {
693     GstStructure *structure;
694     guint i;
695
696     caps = gst_caps_new_empty ();
697     for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
698       structure = gst_v4l2src_v4l2fourcc_to_caps (gst_v4l2_formats[i]);
699       if (structure) {
700         gst_structure_set (structure,
701             "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
702             "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
703             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL);
704         gst_caps_append_structure (caps, structure);
705       }
706     }
707   }
708
709   return caps;
710 }
711
712 static GstCaps *
713 gst_v4l2src_get_caps (GstBaseSrc * src)
714 {
715   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
716   GstCaps *caps;
717   struct v4l2_fmtdesc *format;
718   int min_w, max_w, min_h, max_h;
719   GSList *walk;
720   GstStructure *structure;
721   guint fps_n, fps_d;
722
723   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
724     return
725         gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
726             (v4l2src)));
727   }
728
729   if (!v4l2src->formats)
730     gst_v4l2src_fill_format_list (v4l2src);
731
732   /* build our own capslist */
733   caps = gst_caps_new_empty ();
734   walk = v4l2src->formats;
735   if (!gst_v4l2src_get_fps (v4l2src, &fps_n, &fps_d)) {
736     GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown.");
737     fps_n = 0;
738     fps_d = 1;
739   }
740   while (walk) {
741     format = (struct v4l2_fmtdesc *) walk->data;
742     walk = g_slist_next (walk);
743
744     /* get size delimiters */
745     if (!gst_v4l2src_get_size_limits (v4l2src, format,
746             &min_w, &max_w, &min_h, &max_h)) {
747       continue;
748     }
749     /* template, FIXME, why limit if the device reported correct results? */
750     /* we are doing it right now to avoid unexpected results */
751     min_w = CLAMP (min_w, 1, GST_V4L2_MAX_SIZE);
752     min_h = CLAMP (min_h, 1, GST_V4L2_MAX_SIZE);
753     max_w = CLAMP (max_w, min_w, GST_V4L2_MAX_SIZE);
754     max_h = CLAMP (max_h, min_h, GST_V4L2_MAX_SIZE);
755
756     /* add to list */
757     structure = gst_v4l2src_v4l2fourcc_to_caps (format->pixelformat);
758
759     if (structure) {
760       gst_structure_set (structure,
761           "width", GST_TYPE_INT_RANGE, min_w, max_w,
762           "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
763
764       /* FIXME, why random range? */
765       /* AFAIK: in v4l2 standard we still don't have a good way to enum
766          for a range. Currently it is on discussion on v4l2 forum.
767          Currently, something more smart could be done for tvcard devices.
768          The maximum value could be determined by 'v4l2_standard.frameperiod'
769          and minimum also to the same if V4L2_CAP_TIMEPERFRAME is not set. */
770       /* another approach for web-cams would be to try to set a very
771          high(100/1) and low(1/1) FPSs and get the values returned */
772       gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
773           0, 1, 100, 1, NULL);
774
775       gst_caps_append_structure (caps, structure);
776     }
777   }
778   GST_DEBUG_OBJECT (v4l2src, "returning caps: %" GST_PTR_FORMAT, caps);
779
780   return caps;
781 }
782
783 static gboolean
784 gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
785 {
786   GstV4l2Src *v4l2src;
787   gint w = 0, h = 0;
788   GstStructure *structure;
789   struct v4l2_fmtdesc *format;
790   const GValue *framerate;
791   guint fps_n, fps_d;
792
793   v4l2src = GST_V4L2SRC (src);
794
795   /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
796   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
797     return FALSE;
798
799   /* make sure we stop capturing and dealloc buffers */
800   if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
801     /* both will throw an element-error on failure */
802     if (!gst_v4l2src_capture_stop (v4l2src))
803       return FALSE;
804     if (!gst_v4l2src_capture_deinit (v4l2src))
805       return FALSE;
806   }
807
808   structure = gst_caps_get_structure (caps, 0);
809
810   /* we want our own v4l2 type of fourcc codes */
811   if (!(format = gst_v4l2_caps_to_v4l2fourcc (v4l2src, structure))) {
812     GST_DEBUG_OBJECT (v4l2src, "can't get capture format from caps %"
813         GST_PTR_FORMAT, caps);
814     return FALSE;
815   }
816
817   gst_structure_get_int (structure, "width", &w);
818   gst_structure_get_int (structure, "height", &h);
819   framerate = gst_structure_get_value (structure, "framerate");
820
821   GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d, format %s",
822       w, h, format->description);
823
824   if (framerate) {
825     fps_n = gst_value_get_fraction_numerator (framerate);
826     fps_d = gst_value_get_fraction_denominator (framerate);
827   } else {
828     fps_n = 0;
829     fps_d = 1;
830   }
831
832   if (!gst_v4l2src_set_capture (v4l2src, format, &w, &h, &fps_n, &fps_d)) {
833     GST_WARNING_OBJECT (v4l2src, "could not set_capture %dx%d, format %s",
834         w, h, format->description);
835     return FALSE;
836   }
837
838   if (fps_n) {
839     gst_structure_set (structure,
840         "width", G_TYPE_INT, w,
841         "height", G_TYPE_INT, h,
842         "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
843   } else {
844     gst_structure_set (structure,
845         "width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL);
846   }
847
848   if (!gst_v4l2src_capture_init (v4l2src))
849     return FALSE;
850
851   if (!gst_v4l2src_capture_start (v4l2src))
852     return FALSE;
853
854   if (v4l2src->fps_n != fps_n || v4l2src->fps_d != fps_d) {
855     GST_WARNING_OBJECT (v4l2src,
856         "framerate changed after start capturing from %u/%u to %u/%u", fps_n,
857         fps_d, v4l2src->fps_n, v4l2src->fps_d);
858     if (fps_n) {
859       gst_structure_set (structure,
860           "width", G_TYPE_INT, w,
861           "height", G_TYPE_INT, h,
862           "framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
863     }
864   }
865   return TRUE;
866 }
867
868 /* start and stop are not symmetric -- start will open the device, but not start
869  * capture. it's setcaps that will start capture, which is called via basesrc's
870  * negotiate method. stop will both stop capture and close the device.
871  */
872 static gboolean
873 gst_v4l2src_start (GstBaseSrc * src)
874 {
875   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
876
877   if (!gst_v4l2_object_start (v4l2src->v4l2object))
878     return FALSE;
879
880   v4l2src->offset = 0;
881
882   return TRUE;
883 }
884
885 static gboolean
886 gst_v4l2src_stop (GstBaseSrc * src)
887 {
888   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
889
890   if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)
891       && !gst_v4l2src_capture_stop (v4l2src))
892     return FALSE;
893
894   if (v4l2src->v4l2object->buffer != NULL) {
895     if (!gst_v4l2src_capture_deinit (v4l2src))
896       return FALSE;
897   }
898
899   if (!gst_v4l2_object_stop (v4l2src->v4l2object))
900     return FALSE;
901
902   return TRUE;
903 }
904
905 static GstFlowReturn
906 gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
907 {
908   gint amount;
909   gint buffersize;
910
911   buffersize = v4l2src->format.fmt.pix.sizeimage;
912
913   do {
914     *buf = gst_v4l2src_buffer_new (v4l2src, buffersize, NULL, NULL);
915
916     amount =
917         read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
918         buffersize);
919     if (amount == buffersize) {
920       break;
921     } else if (amount == -1) {
922       if (errno == EAGAIN || errno == EINTR) {
923         continue;
924       } else
925         goto read_error;
926     } else
927       goto short_read;
928   } while (TRUE);
929
930   return GST_FLOW_OK;
931
932   /* ERRORS */
933 read_error:
934   {
935     GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
936         (_("Error read()ing %d bytes on device '%s'."),
937             buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
938     gst_buffer_unref (*buf);
939     return GST_FLOW_ERROR;
940   }
941 short_read:
942   {
943     GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
944         (_("Error reading from device '%s'"),
945             v4l2src->v4l2object->videodev),
946         ("Error read()ing a buffer on device %s: got only %d bytes instead of expected %d.",
947             v4l2src->v4l2object->videodev, amount, buffersize));
948     gst_buffer_unref (*buf);
949     return GST_FLOW_ERROR;
950   }
951 }
952
953 static GstFlowReturn
954 gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
955 {
956   gint i, num;
957
958   /* grab a frame from the device, post an error */
959   num = gst_v4l2src_grab_frame (v4l2src);
960   if (num == -1)
961     goto grab_failed;
962
963   i = v4l2src->format.fmt.pix.sizeimage;
964
965   /* check if this is the last buffer in the queue. If so do a memcpy to put it back asap
966      to avoid framedrops and deadlocks because of stupid elements */
967   if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
968     GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
969
970     *buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
971     memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i);
972
973     /* posts an error message if something went wrong */
974     if (!gst_v4l2src_queue_frame (v4l2src, num))
975       goto queue_failed;
976   } else {
977     GST_LOG_OBJECT (v4l2src, "using mmap'd buffer");
978     *buf =
979         gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start,
980         &v4l2src->pool->buffers[num]);
981
982     /* no need to be careful here, both are > 0, because the element uses them */
983     g_atomic_int_inc (&v4l2src->pool->buffers[num].refcount);
984     g_atomic_int_inc (&v4l2src->pool->refcount);
985   }
986   return GST_FLOW_OK;
987
988   /* ERRORS */
989 grab_failed:
990   {
991     GST_DEBUG_OBJECT (v4l2src, "failed to grab a frame");
992     return GST_FLOW_ERROR;
993   }
994 queue_failed:
995   {
996     GST_DEBUG_OBJECT (v4l2src, "failed to queue frame");
997     gst_buffer_unref (*buf);
998     return GST_FLOW_ERROR;
999   }
1000 }
1001
1002 static GstFlowReturn
1003 gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
1004 {
1005   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
1006   GstFlowReturn ret;
1007
1008   if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
1009     ret = gst_v4l2src_get_mmap (v4l2src, buf);
1010   } else {
1011     ret = gst_v4l2src_get_read (v4l2src, buf);
1012   }
1013   return ret;
1014 }