Update and add documentation for platform specific plugins (sys).
[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  * v4l2src can be used to capture video from v4l2 devices, like webcams and tv
28  * cards.
29  *
30  * <refsect2>
31  * <title>Example launch lines</title>
32  * |[
33  * gst-launch v4l2src ! xvimagesink
34  * ]| This pipeline shows the video captured from /dev/video0 tv card and for
35  * webcams.
36  * |[
37  * gst-launch-0.10 v4l2src ! jpegdec ! xvimagesink
38  * ]| This pipeline shows the video captured from a webcam that delivers jpeg
39  * images.
40  * </refsect2>
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46
47 #include <string.h>
48 #include <sys/time.h>
49 #include "v4l2src_calls.h"
50 #include <unistd.h>
51
52 #include "gstv4l2colorbalance.h"
53 #include "gstv4l2tuner.h"
54 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
55 #include "gstv4l2xoverlay.h"
56 #endif
57 #include "gstv4l2vidorient.h"
58
59 static const GstElementDetails gst_v4l2src_details =
60 GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source",
61     "Source/Video",
62     "Reads raw frames from a video4linux2 (BT8x8) device",
63     "Ronald Bultje <rbultje@ronald.bitfreak.net>,"
64     " Edgard Lima <edgard.lima@indt.org.br>");
65
66 GST_DEBUG_CATEGORY (v4l2src_debug);
67 #define GST_CAT_DEFAULT v4l2src_debug
68
69 #define DEFAULT_PROP_ALWAYS_COPY        TRUE
70
71 enum
72 {
73   PROP_0,
74   V4L2_STD_OBJECT_PROPS,
75   PROP_QUEUE_SIZE,
76   PROP_ALWAYS_COPY
77 };
78
79 static const guint32 gst_v4l2_formats[] = {
80   /* from Linux 2.6.15 videodev2.h */
81   V4L2_PIX_FMT_RGB332,
82   V4L2_PIX_FMT_RGB555,
83   V4L2_PIX_FMT_RGB565,
84   V4L2_PIX_FMT_RGB555X,
85   V4L2_PIX_FMT_RGB565X,
86   V4L2_PIX_FMT_BGR24,
87   V4L2_PIX_FMT_RGB24,
88   V4L2_PIX_FMT_BGR32,
89   V4L2_PIX_FMT_RGB32,
90   V4L2_PIX_FMT_GREY,
91   V4L2_PIX_FMT_YVU410,
92   V4L2_PIX_FMT_YVU420,
93   V4L2_PIX_FMT_YUYV,
94   V4L2_PIX_FMT_UYVY,
95   V4L2_PIX_FMT_YUV422P,
96   V4L2_PIX_FMT_YUV411P,
97   V4L2_PIX_FMT_Y41P,
98
99   /* two planes -- one Y, one Cr + Cb interleaved  */
100   V4L2_PIX_FMT_NV12,
101   V4L2_PIX_FMT_NV21,
102
103   /*  The following formats are not defined in the V4L2 specification */
104   V4L2_PIX_FMT_YUV410,
105   V4L2_PIX_FMT_YUV420,
106   V4L2_PIX_FMT_YYUV,
107   V4L2_PIX_FMT_HI240,
108
109   /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
110 #ifdef V4L2_PIX_FMT_SBGGR8
111   V4L2_PIX_FMT_SBGGR8,
112 #endif
113
114   /* compressed formats */
115   V4L2_PIX_FMT_MJPEG,
116   V4L2_PIX_FMT_JPEG,
117   V4L2_PIX_FMT_DV,
118   V4L2_PIX_FMT_MPEG,
119
120   /*  Vendor-specific formats   */
121   V4L2_PIX_FMT_WNVA,
122
123 #ifdef V4L2_PIX_FMT_SN9C10X
124   V4L2_PIX_FMT_SN9C10X,
125 #endif
126 #ifdef V4L2_PIX_FMT_PWC1
127   V4L2_PIX_FMT_PWC1,
128 #endif
129 #ifdef V4L2_PIX_FMT_PWC2
130   V4L2_PIX_FMT_PWC2,
131 #endif
132 };
133
134 #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
135
136 GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
137 GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src);
138 GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src);
139 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
140 GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Src, gst_v4l2src);
141 #endif
142 GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src);
143
144 static gboolean
145 gst_v4l2src_iface_supported (GstImplementsInterface * iface, GType iface_type)
146 {
147   GstV4l2Object *v4l2object = GST_V4L2SRC (iface)->v4l2object;
148
149 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
150   g_assert (iface_type == GST_TYPE_TUNER ||
151       iface_type == GST_TYPE_X_OVERLAY ||
152       iface_type == GST_TYPE_COLOR_BALANCE ||
153       iface_type == GST_TYPE_VIDEO_ORIENTATION);
154 #else
155   g_assert (iface_type == GST_TYPE_TUNER ||
156       iface_type == GST_TYPE_COLOR_BALANCE ||
157       iface_type == GST_TYPE_VIDEO_ORIENTATION);
158 #endif
159
160   if (v4l2object->video_fd == -1)
161     return FALSE;
162
163 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
164   if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2object))
165     return FALSE;
166 #endif
167
168   return TRUE;
169 }
170
171 static void
172 gst_v4l2src_interface_init (GstImplementsInterfaceClass * klass)
173 {
174   /*
175    * default virtual functions 
176    */
177   klass->supported = gst_v4l2src_iface_supported;
178 }
179
180 void
181 gst_v4l2src_init_interfaces (GType type)
182 {
183   static const GInterfaceInfo v4l2iface_info = {
184     (GInterfaceInitFunc) gst_v4l2src_interface_init,
185     NULL,
186     NULL,
187   };
188   static const GInterfaceInfo v4l2_tuner_info = {
189     (GInterfaceInitFunc) gst_v4l2src_tuner_interface_init,
190     NULL,
191     NULL,
192   };
193 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
194   static const GInterfaceInfo v4l2_xoverlay_info = {
195     (GInterfaceInitFunc) gst_v4l2src_xoverlay_interface_init,
196     NULL,
197     NULL,
198   };
199 #endif
200   static const GInterfaceInfo v4l2_colorbalance_info = {
201     (GInterfaceInitFunc) gst_v4l2src_color_balance_interface_init,
202     NULL,
203     NULL,
204   };
205   static const GInterfaceInfo v4l2_videoorientation_info = {
206     (GInterfaceInitFunc) gst_v4l2src_video_orientation_interface_init,
207     NULL,
208     NULL,
209   };
210   static const GInterfaceInfo v4l2_propertyprobe_info = {
211     (GInterfaceInitFunc) gst_v4l2src_property_probe_interface_init,
212     NULL,
213     NULL,
214   };
215
216   g_type_add_interface_static (type,
217       GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info);
218   g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info);
219 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
220   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info);
221 #endif
222   g_type_add_interface_static (type,
223       GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info);
224   g_type_add_interface_static (type,
225       GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info);
226   g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
227       &v4l2_propertyprobe_info);
228 }
229
230 GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC,
231     gst_v4l2src_init_interfaces);
232
233 static void gst_v4l2src_dispose (GObject * object);
234
235 static void gst_v4l2src_finalize (GstV4l2Src * v4l2src);
236
237 /* basesrc methods */
238 static gboolean gst_v4l2src_start (GstBaseSrc * src);
239
240 static gboolean gst_v4l2src_stop (GstBaseSrc * src);
241
242 static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
243
244 static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
245
246 static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
247
248 static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
249
250 static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
251
252 static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc);
253
254 static void gst_v4l2src_set_property (GObject * object, guint prop_id,
255     const GValue * value, GParamSpec * pspec);
256 static void gst_v4l2src_get_property (GObject * object, guint prop_id,
257     GValue * value, GParamSpec * pspec);
258
259 static GstCaps *gst_v4l2src_get_all_caps (void);
260
261 static void
262 gst_v4l2src_base_init (gpointer g_class)
263 {
264   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
265
266   GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
267
268   gstv4l2src_class->v4l2_class_devices = NULL;
269
270   GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
271
272   gst_element_class_set_details (gstelement_class, &gst_v4l2src_details);
273
274   gst_element_class_add_pad_template
275       (gstelement_class,
276       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
277           gst_v4l2src_get_all_caps ()));
278 }
279
280 static void
281 gst_v4l2src_class_init (GstV4l2SrcClass * klass)
282 {
283   GObjectClass *gobject_class;
284
285   GstBaseSrcClass *basesrc_class;
286
287   GstPushSrcClass *pushsrc_class;
288
289   gobject_class = G_OBJECT_CLASS (klass);
290   basesrc_class = GST_BASE_SRC_CLASS (klass);
291   pushsrc_class = GST_PUSH_SRC_CLASS (klass);
292
293   gobject_class->dispose = gst_v4l2src_dispose;
294   gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2src_finalize;
295   gobject_class->set_property = gst_v4l2src_set_property;
296   gobject_class->get_property = gst_v4l2src_get_property;
297
298   gst_v4l2_object_install_properties_helper (gobject_class);
299   g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
300       g_param_spec_uint ("queue-size", "Queue size",
301           "Number of buffers to be enqueud in the driver",
302           GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, GST_V4L2_MIN_BUFFERS,
303           G_PARAM_READWRITE));
304   g_object_class_install_property (gobject_class, PROP_ALWAYS_COPY,
305       g_param_spec_boolean ("always-copy", "Always Copy",
306           "If the buffer will or not be used directly from mmap",
307           DEFAULT_PROP_ALWAYS_COPY, G_PARAM_READWRITE));
308
309   basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_get_caps);
310   basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_set_caps);
311   basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start);
312   basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);
313   basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query);
314   basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate);
315   basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate);
316
317   pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
318 }
319
320 static void
321 gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
322 {
323   /* fixme: give an update_fps_function */
324   v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
325       gst_v4l2_get_input, gst_v4l2_set_input, NULL);
326
327   /* number of buffers requested */
328   v4l2src->num_buffers = GST_V4L2_MIN_BUFFERS;
329
330   v4l2src->always_copy = DEFAULT_PROP_ALWAYS_COPY;
331
332   v4l2src->formats = NULL;
333
334   v4l2src->is_capturing = FALSE;
335
336   gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
337   gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
338
339   v4l2src->fps_d = 0;
340   v4l2src->fps_n = 0;
341 }
342
343
344 static void
345 gst_v4l2src_dispose (GObject * object)
346 {
347   GstV4l2Src *v4l2src = GST_V4L2SRC (object);
348
349   if (v4l2src->formats) {
350     gst_v4l2src_clear_format_list (v4l2src);
351   }
352
353   if (v4l2src->probed_caps) {
354     gst_caps_unref (v4l2src->probed_caps);
355   }
356
357
358   G_OBJECT_CLASS (parent_class)->dispose (object);
359 }
360
361
362 static void
363 gst_v4l2src_finalize (GstV4l2Src * v4l2src)
364 {
365   gst_v4l2_object_destroy (v4l2src->v4l2object);
366
367   G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2src));
368 }
369
370
371 static void
372 gst_v4l2src_set_property (GObject * object,
373     guint prop_id, const GValue * value, GParamSpec * pspec)
374 {
375   GstV4l2Src *v4l2src = GST_V4L2SRC (object);
376
377   if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
378           prop_id, value, pspec)) {
379     switch (prop_id) {
380       case PROP_QUEUE_SIZE:
381         v4l2src->num_buffers = g_value_get_uint (value);
382         break;
383       case PROP_ALWAYS_COPY:
384         v4l2src->always_copy = g_value_get_boolean (value);
385         break;
386       default:
387         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
388         break;
389     }
390   }
391 }
392
393
394 static void
395 gst_v4l2src_get_property (GObject * object,
396     guint prop_id, GValue * value, GParamSpec * pspec)
397 {
398   GstV4l2Src *v4l2src = GST_V4L2SRC (object);
399
400   if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
401           prop_id, value, pspec)) {
402     switch (prop_id) {
403       case PROP_QUEUE_SIZE:
404         g_value_set_uint (value, v4l2src->num_buffers);
405         break;
406       case PROP_ALWAYS_COPY:
407         g_value_set_boolean (value, v4l2src->always_copy);
408         break;
409       default:
410         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
411         break;
412     }
413   }
414 }
415
416
417 /* this function is a bit of a last resort */
418 static void
419 gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
420 {
421   GstStructure *structure;
422
423   gint i;
424
425   GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
426
427   for (i = 0; i < gst_caps_get_size (caps); ++i) {
428     const GValue *v;
429
430     structure = gst_caps_get_structure (caps, i);
431
432     /* FIXME such sizes? we usually fixate to something in the 320x200
433      * range... */
434     /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
435        and the maximum framerate resolution for that size */
436     gst_structure_fixate_field_nearest_int (structure, "width",
437         GST_V4L2_MAX_SIZE);
438     gst_structure_fixate_field_nearest_int (structure, "height",
439         GST_V4L2_MAX_SIZE);
440     gst_structure_fixate_field_nearest_fraction (structure, "framerate",
441         G_MAXINT, 1);
442
443     v = gst_structure_get_value (structure, "format");
444     if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
445       guint32 fourcc;
446
447       g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
448
449       fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
450       gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
451     }
452   }
453
454   GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
455 }
456
457
458 static gboolean
459 gst_v4l2src_negotiate (GstBaseSrc * basesrc)
460 {
461   GstCaps *thiscaps;
462
463   GstCaps *caps = NULL;
464
465   GstCaps *peercaps = NULL;
466
467   gboolean result = FALSE;
468
469   /* first see what is possible on our source pad */
470   thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
471   GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
472   /* nothing or anything is allowed, we're done */
473   if (thiscaps == NULL || gst_caps_is_any (thiscaps))
474     goto no_nego_needed;
475
476   /* get the peer caps */
477   peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
478   GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
479   if (peercaps && !gst_caps_is_any (peercaps)) {
480     GstCaps *icaps = NULL;
481     int i;
482
483     /* Prefer the first caps we are compatible with that the peer proposed */
484     for (i = 0; i < gst_caps_get_size (peercaps); i++) {
485       /* get intersection */
486       GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i);
487
488       GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps);
489
490       icaps = gst_caps_intersect (thiscaps, ipcaps);
491       gst_caps_unref (ipcaps);
492
493       if (!gst_caps_is_empty (icaps))
494         break;
495
496       gst_caps_unref (icaps);
497       icaps = NULL;
498     }
499
500     GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps);
501     if (icaps) {
502       /* If there are multiple intersections pick the one with the smallest
503        * resolution strictly bigger then the first peer caps */
504       if (gst_caps_get_size (icaps) > 1) {
505         GstStructure *s = gst_caps_get_structure (peercaps, 0);
506
507         int best = 0;
508
509         int twidth, theight;
510
511         int width = G_MAXINT, height = G_MAXINT;
512
513         if (gst_structure_get_int (s, "width", &twidth)
514             && gst_structure_get_int (s, "height", &theight)) {
515
516           /* Walk the structure backwards to get the first entry of the
517            * smallest resolution bigger (or equal to) the preferred resolution)
518            */
519           for (i = gst_caps_get_size (icaps) - 1; i >= 0; i--) {
520             GstStructure *is = gst_caps_get_structure (icaps, i);
521
522             int w, h;
523
524             if (gst_structure_get_int (is, "width", &w)
525                 && gst_structure_get_int (is, "height", &h)) {
526               if (w >= twidth && w <= width && h >= theight && h <= height) {
527                 width = w;
528                 height = h;
529                 best = i;
530               }
531             }
532           }
533         }
534
535         caps = gst_caps_copy_nth (icaps, best);
536         gst_caps_unref (icaps);
537       } else {
538         caps = icaps;
539       }
540     }
541     gst_caps_unref (thiscaps);
542     gst_caps_unref (peercaps);
543   } else {
544     /* no peer or peer have ANY caps, work with our own caps then */
545     caps = thiscaps;
546   }
547   if (caps) {
548     caps = gst_caps_make_writable (caps);
549     gst_caps_truncate (caps);
550
551     /* now fixate */
552     if (!gst_caps_is_empty (caps)) {
553       gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
554       GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
555
556       if (gst_caps_is_any (caps)) {
557         /* hmm, still anything, so element can do anything and
558          * nego is not needed */
559         result = TRUE;
560       } else if (gst_caps_is_fixed (caps)) {
561         /* yay, fixed caps, use those then */
562         gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
563         result = TRUE;
564       }
565     }
566     gst_caps_unref (caps);
567   }
568   return result;
569
570 no_nego_needed:
571   {
572     GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
573     if (thiscaps)
574       gst_caps_unref (thiscaps);
575     return TRUE;
576   }
577 }
578
579
580 static GstStructure *
581 gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc)
582 {
583   GstStructure *structure = NULL;
584
585   switch (fourcc) {
586     case V4L2_PIX_FMT_MJPEG:   /* Motion-JPEG */
587     case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
588       structure = gst_structure_new ("image/jpeg", NULL);
589       break;
590     case V4L2_PIX_FMT_RGB332:
591     case V4L2_PIX_FMT_RGB555:
592     case V4L2_PIX_FMT_RGB555X:
593     case V4L2_PIX_FMT_RGB565:
594     case V4L2_PIX_FMT_RGB565X:
595     case V4L2_PIX_FMT_RGB24:
596     case V4L2_PIX_FMT_BGR24:
597     case V4L2_PIX_FMT_RGB32:
598     case V4L2_PIX_FMT_BGR32:{
599       guint depth = 0, bpp = 0;
600
601       gint endianness = 0;
602
603       guint32 r_mask = 0, b_mask = 0, g_mask = 0;
604
605       switch (fourcc) {
606         case V4L2_PIX_FMT_RGB332:
607           bpp = depth = 8;
608           endianness = G_BYTE_ORDER;    /* 'like, whatever' */
609           r_mask = 0xe0;
610           g_mask = 0x1c;
611           b_mask = 0x03;
612           break;
613         case V4L2_PIX_FMT_RGB555:
614         case V4L2_PIX_FMT_RGB555X:
615           bpp = 16;
616           depth = 15;
617           endianness =
618               fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
619           r_mask = 0x7c00;
620           g_mask = 0x03e0;
621           b_mask = 0x001f;
622           break;
623         case V4L2_PIX_FMT_RGB565:
624         case V4L2_PIX_FMT_RGB565X:
625           bpp = depth = 16;
626           endianness =
627               fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
628           r_mask = 0xf800;
629           g_mask = 0x07e0;
630           b_mask = 0x001f;
631           break;
632         case V4L2_PIX_FMT_RGB24:
633           bpp = depth = 24;
634           endianness = G_BIG_ENDIAN;
635           r_mask = 0xff0000;
636           g_mask = 0x00ff00;
637           b_mask = 0x0000ff;
638           break;
639         case V4L2_PIX_FMT_BGR24:
640           bpp = depth = 24;
641           endianness = G_BIG_ENDIAN;
642           r_mask = 0x0000ff;
643           g_mask = 0x00ff00;
644           b_mask = 0xff0000;
645           break;
646         case V4L2_PIX_FMT_RGB32:
647           bpp = depth = 32;
648           endianness = G_BIG_ENDIAN;
649           r_mask = 0xff000000;
650           g_mask = 0x00ff0000;
651           b_mask = 0x0000ff00;
652           break;
653         case V4L2_PIX_FMT_BGR32:
654           bpp = depth = 32;
655           endianness = G_BIG_ENDIAN;
656           r_mask = 0x000000ff;
657           g_mask = 0x0000ff00;
658           b_mask = 0x00ff0000;
659           break;
660         default:
661           g_assert_not_reached ();
662           break;
663       }
664       structure = gst_structure_new ("video/x-raw-rgb",
665           "bpp", G_TYPE_INT, bpp,
666           "depth", G_TYPE_INT, depth,
667           "red_mask", G_TYPE_INT, r_mask,
668           "green_mask", G_TYPE_INT, g_mask,
669           "blue_mask", G_TYPE_INT, b_mask,
670           "endianness", G_TYPE_INT, endianness, NULL);
671       break;
672     }
673     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
674       structure = gst_structure_new ("video/x-raw-gray",
675           "bpp", G_TYPE_INT, 8, NULL);
676       break;
677     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
678     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
679       /* FIXME: get correct fourccs here */
680       break;
681     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
682     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
683     case V4L2_PIX_FMT_YVU410:
684     case V4L2_PIX_FMT_YUV410:
685     case V4L2_PIX_FMT_YUV420:  /* I420/IYUV */
686     case V4L2_PIX_FMT_YUYV:
687     case V4L2_PIX_FMT_YVU420:
688     case V4L2_PIX_FMT_UYVY:
689     case V4L2_PIX_FMT_Y41P:
690     case V4L2_PIX_FMT_YUV422P:
691     case V4L2_PIX_FMT_YUV411P:{
692       guint32 fcc = 0;
693
694       switch (fourcc) {
695         case V4L2_PIX_FMT_NV12:
696           fcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
697           break;
698         case V4L2_PIX_FMT_NV21:
699           fcc = GST_MAKE_FOURCC ('N', 'V', '2', '1');
700           break;
701         case V4L2_PIX_FMT_YVU410:
702           fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
703           break;
704         case V4L2_PIX_FMT_YUV410:
705           fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
706           break;
707         case V4L2_PIX_FMT_YUV420:
708           fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
709           break;
710         case V4L2_PIX_FMT_YUYV:
711           fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
712           break;
713         case V4L2_PIX_FMT_YVU420:
714           fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
715           break;
716         case V4L2_PIX_FMT_UYVY:
717           fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
718           break;
719         case V4L2_PIX_FMT_Y41P:
720           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
721           break;
722         case V4L2_PIX_FMT_YUV411P:
723           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
724           break;
725         case V4L2_PIX_FMT_YUV422P:
726           fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
727           break;
728         default:
729           g_assert_not_reached ();
730           break;
731       }
732       structure = gst_structure_new ("video/x-raw-yuv",
733           "format", GST_TYPE_FOURCC, fcc, NULL);
734       break;
735     }
736     case V4L2_PIX_FMT_DV:
737       structure =
738           gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
739           NULL);
740       break;
741     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
742       /* someone figure out the MPEG format used... */
743       break;
744     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
745       break;
746 #ifdef V4L2_PIX_FMT_SBGGR8
747     case V4L2_PIX_FMT_SBGGR8:
748       structure = gst_structure_new ("video/x-raw-bayer", NULL);
749       break;
750 #endif
751 #ifdef V4L2_PIX_FMT_SN9C10X
752     case V4L2_PIX_FMT_SN9C10X:
753       structure = gst_structure_new ("video/x-sonix", NULL);
754       break;
755 #endif
756 #ifdef V4L2_PIX_FMT_PWC1
757     case V4L2_PIX_FMT_PWC1:
758       structure = gst_structure_new ("video/x-pwc1", NULL);
759       break;
760 #endif
761 #ifdef V4L2_PIX_FMT_PWC2
762     case V4L2_PIX_FMT_PWC2:
763       structure = gst_structure_new ("video/x-pwc2", NULL);
764       break;
765 #endif
766     default:
767       GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
768           fourcc, GST_FOURCC_ARGS (fourcc));
769       break;
770   }
771
772   return structure;
773 }
774
775 static struct v4l2_fmtdesc *
776 gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
777 {
778   struct v4l2_fmtdesc *fmt;
779
780   GSList *walk;
781
782   if (fourcc == 0)
783     return NULL;
784
785   walk = v4l2src->formats;
786   while (walk) {
787     fmt = (struct v4l2_fmtdesc *) walk->data;
788     if (fmt->pixelformat == fourcc)
789       return fmt;
790     /* special case for jpeg */
791     if ((fmt->pixelformat == V4L2_PIX_FMT_MJPEG && fourcc == V4L2_PIX_FMT_JPEG)
792         || (fmt->pixelformat == V4L2_PIX_FMT_JPEG
793             && fourcc == V4L2_PIX_FMT_MJPEG)) {
794       return fmt;
795     }
796     walk = g_slist_next (walk);
797   }
798
799   return NULL;
800 }
801
802 static GstCaps *
803 gst_v4l2src_get_all_caps (void)
804 {
805   static GstCaps *caps = NULL;
806
807   if (caps == NULL) {
808     GstStructure *structure;
809
810     guint i;
811
812     caps = gst_caps_new_empty ();
813     for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
814       structure = gst_v4l2src_v4l2fourcc_to_structure (gst_v4l2_formats[i]);
815       if (structure) {
816         gst_structure_set (structure,
817             "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
818             "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
819             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL);
820         gst_caps_append_structure (caps, structure);
821       }
822     }
823   }
824
825   return caps;
826 }
827
828 static GstCaps *
829 gst_v4l2src_get_caps (GstBaseSrc * src)
830 {
831   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
832
833   GstCaps *ret;
834
835   GSList *walk;
836
837   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
838     /* FIXME: copy? */
839     return
840         gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
841             (v4l2src)));
842   }
843
844   if (v4l2src->probed_caps)
845     return gst_caps_ref (v4l2src->probed_caps);
846
847   if (!v4l2src->formats)
848     gst_v4l2src_fill_format_list (v4l2src);
849
850   ret = gst_caps_new_empty ();
851
852   for (walk = v4l2src->formats; walk; walk = walk->next) {
853     struct v4l2_fmtdesc *format;
854
855     GstStructure *template;
856
857     format = (struct v4l2_fmtdesc *) walk->data;
858
859     template = gst_v4l2src_v4l2fourcc_to_structure (format->pixelformat);
860
861     if (template) {
862       GstCaps *tmp;
863
864       tmp = gst_v4l2src_probe_caps_for_format (v4l2src, format->pixelformat,
865           template);
866       if (tmp)
867         gst_caps_append (ret, tmp);
868
869       gst_structure_free (template);
870     } else {
871       GST_DEBUG_OBJECT (v4l2src, "unknown format %u", format->pixelformat);
872     }
873   }
874
875   v4l2src->probed_caps = gst_caps_ref (ret);
876
877   GST_INFO_OBJECT (v4l2src, "probed caps: %" GST_PTR_FORMAT, ret);
878
879   return ret;
880 }
881
882 /* collect data for the given caps
883  * @caps: given input caps
884  * @format: location for the v4l format
885  * @w/@h: location for width and height
886  * @fps_n/@fps_d: location for framerate
887  * @size: location for expected size of the frame or 0 if unknown
888  */
889 static gboolean
890 gst_v4l2_get_caps_info (GstV4l2Src * v4l2src, GstCaps * caps,
891     struct v4l2_fmtdesc **format, gint * w, gint * h, guint * fps_n,
892     guint * fps_d, guint * size)
893 {
894   GstStructure *structure;
895
896   const GValue *framerate;
897
898   guint32 fourcc;
899
900   const gchar *mimetype;
901
902   guint outsize;
903
904   /* default unknown values */
905   fourcc = 0;
906   outsize = 0;
907
908   structure = gst_caps_get_structure (caps, 0);
909
910   if (!gst_structure_get_int (structure, "width", w))
911     return FALSE;
912
913   if (!gst_structure_get_int (structure, "height", h))
914     return FALSE;
915
916   framerate = gst_structure_get_value (structure, "framerate");
917   if (!framerate)
918     return FALSE;
919
920   *fps_n = gst_value_get_fraction_numerator (framerate);
921   *fps_d = gst_value_get_fraction_denominator (framerate);
922
923   mimetype = gst_structure_get_name (structure);
924
925   if (!strcmp (mimetype, "video/x-raw-yuv")) {
926     gst_structure_get_fourcc (structure, "format", &fourcc);
927
928     switch (fourcc) {
929       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
930       case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
931         fourcc = V4L2_PIX_FMT_YUV420;
932         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
933         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
934         break;
935       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
936         fourcc = V4L2_PIX_FMT_YUYV;
937         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
938         break;
939       case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
940         fourcc = V4L2_PIX_FMT_Y41P;
941         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
942         break;
943       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
944         fourcc = V4L2_PIX_FMT_UYVY;
945         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
946         break;
947       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
948         fourcc = V4L2_PIX_FMT_YVU420;
949         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
950         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
951         break;
952       case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
953         fourcc = V4L2_PIX_FMT_YUV411P;
954         outsize = GST_ROUND_UP_4 (*w) * *h;
955         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h);
956         break;
957       case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
958         fourcc = V4L2_PIX_FMT_YUV422P;
959         outsize = GST_ROUND_UP_4 (*w) * *h;
960         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h);
961         break;
962       case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
963         fourcc = V4L2_PIX_FMT_NV12;
964         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
965         outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
966         break;
967       case GST_MAKE_FOURCC ('N', 'V', '2', '1'):
968         fourcc = V4L2_PIX_FMT_NV21;
969         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
970         outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
971         break;
972     }
973   } else if (!strcmp (mimetype, "video/x-raw-rgb")) {
974     gint depth, endianness, r_mask;
975
976     gst_structure_get_int (structure, "depth", &depth);
977     gst_structure_get_int (structure, "endianness", &endianness);
978     gst_structure_get_int (structure, "red_mask", &r_mask);
979
980     switch (depth) {
981       case 8:
982         fourcc = V4L2_PIX_FMT_RGB332;
983         break;
984       case 15:
985         fourcc = (endianness == G_LITTLE_ENDIAN) ?
986             V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
987         break;
988       case 16:
989         fourcc = (endianness == G_LITTLE_ENDIAN) ?
990             V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
991         break;
992       case 24:
993         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
994         break;
995       case 32:
996         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
997         break;
998     }
999   } else if (strcmp (mimetype, "video/x-dv") == 0) {
1000     fourcc = V4L2_PIX_FMT_DV;
1001   } else if (strcmp (mimetype, "image/jpeg") == 0) {
1002     fourcc = V4L2_PIX_FMT_JPEG;
1003 #ifdef V4L2_PIX_FMT_SBGGR8
1004   } else if (strcmp (mimetype, "video/x-raw-bayer") == 0) {
1005     fourcc = V4L2_PIX_FMT_SBGGR8;
1006 #endif
1007 #ifdef V4L2_PIX_FMT_SN9C10X
1008   } else if (strcmp (mimetype, "video/x-sonix") == 0) {
1009     fourcc = V4L2_PIX_FMT_SN9C10X;
1010 #endif
1011 #ifdef V4L2_PIX_FMT_PWC1
1012   } else if (strcmp (mimetype, "video/x-pwc1") == 0) {
1013     fourcc = V4L2_PIX_FMT_PWC1;
1014 #endif
1015 #ifdef V4L2_PIX_FMT_PWC2
1016   } else if (strcmp (mimetype, "video/x-pwc2") == 0) {
1017     fourcc = V4L2_PIX_FMT_PWC2;
1018 #endif
1019   } else if (strcmp (mimetype, "video/x-raw-gray") == 0) {
1020     fourcc = V4L2_PIX_FMT_GREY;
1021   }
1022
1023   if (fourcc == 0)
1024     return FALSE;
1025
1026   *format = gst_v4l2src_get_format_from_fourcc (v4l2src, fourcc);
1027   *size = outsize;
1028
1029   return TRUE;
1030 }
1031
1032 static gboolean
1033 gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
1034 {
1035   GstV4l2Src *v4l2src;
1036
1037   gint w = 0, h = 0;
1038
1039   struct v4l2_fmtdesc *format;
1040
1041   guint fps_n, fps_d;
1042
1043   guint size;
1044
1045   v4l2src = GST_V4L2SRC (src);
1046
1047   /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
1048   if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
1049     return FALSE;
1050
1051   /* make sure we stop capturing and dealloc buffers */
1052   if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
1053     /* both will throw an element-error on failure */
1054     if (!gst_v4l2src_capture_stop (v4l2src))
1055       return FALSE;
1056     if (!gst_v4l2src_capture_deinit (v4l2src))
1057       return FALSE;
1058   }
1059
1060   /* we want our own v4l2 type of fourcc codes */
1061   if (!gst_v4l2_get_caps_info (v4l2src, caps, &format, &w, &h, &fps_n, &fps_d,
1062           &size)) {
1063     GST_DEBUG_OBJECT (v4l2src,
1064         "can't get capture format from caps %" GST_PTR_FORMAT, caps);
1065     return FALSE;
1066   }
1067
1068   GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d at %d/%d fps, "
1069       "format %s", w, h, fps_n, fps_d, format->description);
1070
1071   if (!gst_v4l2src_set_capture (v4l2src, format->pixelformat, w, h, fps_n,
1072           fps_d))
1073     /* error already posted */
1074     return FALSE;
1075
1076   if (!gst_v4l2src_capture_init (v4l2src, caps))
1077     return FALSE;
1078
1079   if (!gst_v4l2src_capture_start (v4l2src))
1080     return FALSE;
1081
1082   /* now store the expected output size */
1083   v4l2src->frame_byte_size = size;
1084
1085   return TRUE;
1086 }
1087
1088 static gboolean
1089 gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
1090 {
1091   GstV4l2Src *src;
1092
1093   gboolean res = FALSE;
1094
1095   src = GST_V4L2SRC (bsrc);
1096
1097   switch (GST_QUERY_TYPE (query)) {
1098     case GST_QUERY_LATENCY:{
1099       GstClockTime min_latency, max_latency;
1100
1101       /* device must be open */
1102       if (!GST_V4L2_IS_OPEN (src->v4l2object)) {
1103         GST_WARNING_OBJECT (src,
1104             "Can't give latency since device isn't open !");
1105         goto done;
1106       }
1107
1108       /* we must have a framerate */
1109       if (src->fps_n <= 0 || src->fps_d <= 0) {
1110         GST_WARNING_OBJECT (src,
1111             "Can't give latency since framerate isn't fixated !");
1112         goto done;
1113       }
1114
1115       /* min latency is the time to capture one frame */
1116       min_latency =
1117           gst_util_uint64_scale_int (GST_SECOND, src->fps_d, src->fps_n);
1118
1119       /* max latency is total duration of the frame buffer */
1120       max_latency = src->num_buffers * min_latency;
1121
1122       GST_DEBUG_OBJECT (bsrc,
1123           "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1124           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
1125
1126       /* we are always live, the min latency is 1 frame and the max latency is
1127        * the complete buffer of frames. */
1128       gst_query_set_latency (query, TRUE, min_latency, max_latency);
1129
1130       res = TRUE;
1131       break;
1132     }
1133     default:
1134       res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
1135       break;
1136   }
1137
1138 done:
1139
1140   return res;
1141 }
1142
1143 /* start and stop are not symmetric -- start will open the device, but not start
1144  * capture. it's setcaps that will start capture, which is called via basesrc's
1145  * negotiate method. stop will both stop capture and close the device.
1146  */
1147 static gboolean
1148 gst_v4l2src_start (GstBaseSrc * src)
1149 {
1150   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
1151
1152   /* open the device */
1153   if (!gst_v4l2_object_start (v4l2src->v4l2object))
1154     return FALSE;
1155
1156   v4l2src->offset = 0;
1157
1158   return TRUE;
1159 }
1160
1161 static gboolean
1162 gst_v4l2src_stop (GstBaseSrc * src)
1163 {
1164   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
1165
1166   if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)
1167       && !gst_v4l2src_capture_stop (v4l2src))
1168     return FALSE;
1169
1170   if (v4l2src->v4l2object->buffer != NULL) {
1171     if (!gst_v4l2src_capture_deinit (v4l2src))
1172       return FALSE;
1173   }
1174
1175   /* close the device */
1176   if (!gst_v4l2_object_stop (v4l2src->v4l2object))
1177     return FALSE;
1178
1179   v4l2src->fps_d = 0;
1180   v4l2src->fps_n = 0;
1181
1182   return TRUE;
1183 }
1184
1185 static GstFlowReturn
1186 gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
1187 {
1188   gint amount;
1189
1190   gint buffersize;
1191
1192   buffersize = v4l2src->frame_byte_size;
1193
1194   *buf = gst_buffer_new_and_alloc (buffersize);
1195
1196   do {
1197     amount =
1198         v4l2_read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
1199         buffersize);
1200     if (amount == buffersize) {
1201       break;
1202     } else if (amount == -1) {
1203       if (errno == EAGAIN || errno == EINTR) {
1204         continue;
1205       } else
1206         goto read_error;
1207     } else {
1208       /* short reads can happen if a signal interrupts the read */
1209       continue;
1210     }
1211   } while (TRUE);
1212
1213   GST_BUFFER_OFFSET (*buf) = v4l2src->offset++;
1214   GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset;
1215   /* timestamps, LOCK to get clock and base time. */
1216   {
1217     GstClock *clock;
1218
1219     GstClockTime timestamp;
1220
1221     GST_OBJECT_LOCK (v4l2src);
1222     if ((clock = GST_ELEMENT_CLOCK (v4l2src))) {
1223       /* we have a clock, get base time and ref clock */
1224       timestamp = GST_ELEMENT (v4l2src)->base_time;
1225       gst_object_ref (clock);
1226     } else {
1227       /* no clock, can't set timestamps */
1228       timestamp = GST_CLOCK_TIME_NONE;
1229     }
1230     GST_OBJECT_UNLOCK (v4l2src);
1231
1232     if (clock) {
1233       GstClockTime latency;
1234
1235       /* the time now is the time of the clock minus the base time */
1236       timestamp = gst_clock_get_time (clock) - timestamp;
1237       gst_object_unref (clock);
1238
1239       latency =
1240           gst_util_uint64_scale_int (GST_SECOND, v4l2src->fps_d,
1241           v4l2src->fps_n);
1242
1243       if (timestamp > latency)
1244         timestamp -= latency;
1245       else
1246         timestamp = 0;
1247     }
1248
1249     /* FIXME: use the timestamp from the buffer itself! */
1250     GST_BUFFER_TIMESTAMP (*buf) = timestamp;
1251   }
1252
1253   return GST_FLOW_OK;
1254
1255   /* ERRORS */
1256 read_error:
1257   {
1258     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
1259         (_("Error reading %d bytes from device '%s'."),
1260             buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
1261     gst_buffer_unref (*buf);
1262     return GST_FLOW_ERROR;
1263   }
1264 }
1265
1266 static GstFlowReturn
1267 gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
1268 {
1269   GstBuffer *temp;
1270
1271   GstFlowReturn ret;
1272
1273   guint size;
1274
1275   guint count;
1276
1277   count = 0;
1278
1279 again:
1280   ret = gst_v4l2src_grab_frame (v4l2src, &temp);
1281   if (ret != GST_FLOW_OK)
1282     goto done;
1283
1284   if (v4l2src->frame_byte_size > 0) {
1285     size = GST_BUFFER_SIZE (temp);
1286
1287     /* if size does not match what we expected, try again */
1288     if (size != v4l2src->frame_byte_size) {
1289       GST_ELEMENT_WARNING (v4l2src, RESOURCE, READ,
1290           (_("Got unexpected frame size of %u instead of %u."),
1291               size, v4l2src->frame_byte_size), (NULL));
1292       gst_buffer_unref (temp);
1293       if (count++ > 50)
1294         goto size_error;
1295
1296       goto again;
1297     }
1298   }
1299
1300   *buf = temp;
1301 done:
1302   return ret;
1303
1304   /* ERRORS */
1305 size_error:
1306   {
1307     GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
1308         (_("Error reading %d bytes on device '%s'."),
1309             v4l2src->frame_byte_size, v4l2src->v4l2object->videodev), (NULL));
1310     return GST_FLOW_ERROR;
1311   }
1312 }
1313
1314 static GstFlowReturn
1315 gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
1316 {
1317   GstV4l2Src *v4l2src = GST_V4L2SRC (src);
1318
1319   GstFlowReturn ret;
1320
1321   if (v4l2src->use_mmap) {
1322     ret = gst_v4l2src_get_mmap (v4l2src, buf);
1323   } else {
1324     ret = gst_v4l2src_get_read (v4l2src, buf);
1325   }
1326   return ret;
1327 }