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