Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / sys / v4l / gstv4lsrc.c
1 /* GStreamer
2  *
3  * gstv4lsrc.c: BT8x8/V4L source element
4  *
5  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <sys/time.h>
29 #include "v4lsrc_calls.h"
30 #include <sys/ioctl.h>
31
32
33 GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug);
34 #define GST_CAT_DEFAULT v4lsrc_debug
35
36
37 enum
38 {
39   PROP_0,
40   PROP_AUTOPROBE,
41   PROP_AUTOPROBE_FPS,
42   PROP_COPY_MODE,
43   PROP_TIMESTAMP_OFFSET
44 };
45
46
47 GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT);
48
49 static GstStaticPadTemplate v4l_src_template = GST_STATIC_PAD_TEMPLATE ("src",
50     GST_PAD_SRC,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS ("ANY")
53     );
54
55 /* basesrc methods */
56 static gboolean gst_v4lsrc_start (GstBaseSrc * src);
57 static gboolean gst_v4lsrc_stop (GstBaseSrc * src);
58 static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps);
59 static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src);
60 static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out);
61 static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query);
62 static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps);
63
64 static void gst_v4lsrc_set_property (GObject * object,
65     guint prop_id, const GValue * value, GParamSpec * pspec);
66 static void gst_v4lsrc_get_property (GObject * object,
67     guint prop_id, GValue * value, GParamSpec * pspec);
68
69
70 static void
71 gst_v4lsrc_base_init (gpointer g_class)
72 {
73   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
74
75   gst_element_class_set_details_simple (gstelement_class,
76       "Video (video4linux/raw) Source", "Source/Video",
77       "Reads raw frames from a video4linux device",
78       "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
79
80   gst_element_class_add_pad_template (gstelement_class,
81       gst_static_pad_template_get (&v4l_src_template));
82 }
83
84 static void
85 gst_v4lsrc_class_init (GstV4lSrcClass * klass)
86 {
87   GObjectClass *gobject_class;
88   GstBaseSrcClass *basesrc_class;
89   GstPushSrcClass *pushsrc_class;
90
91   gobject_class = (GObjectClass *) klass;
92   basesrc_class = (GstBaseSrcClass *) klass;
93   pushsrc_class = (GstPushSrcClass *) klass;
94
95   gobject_class->set_property = gst_v4lsrc_set_property;
96   gobject_class->get_property = gst_v4lsrc_get_property;
97
98   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE,
99       g_param_spec_boolean ("autoprobe", "Autoprobe",
100           "Whether the device should be probed for all possible features",
101           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS,
103       g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS",
104           "Whether the device should be probed for framerates",
105           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
106   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE,
107       g_param_spec_boolean ("copy-mode", "Copy mode",
108           "Whether to send out copies of buffers, or direct pointers to the mmap region",
109           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110   g_object_class_install_property (G_OBJECT_CLASS (klass),
111       PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
112           "Timestamp offset",
113           "A time offset subtracted from timestamps set on buffers (in ns)",
114           G_MININT64, G_MAXINT64, 0,
115           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
116
117   GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element");
118
119   basesrc_class->get_caps = gst_v4lsrc_get_caps;
120   basesrc_class->set_caps = gst_v4lsrc_set_caps;
121   basesrc_class->start = gst_v4lsrc_start;
122   basesrc_class->stop = gst_v4lsrc_stop;
123   basesrc_class->fixate = gst_v4lsrc_fixate;
124   basesrc_class->query = gst_v4lsrc_query;
125
126   pushsrc_class->create = gst_v4lsrc_create;
127 }
128
129 static void
130 gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass)
131 {
132   v4lsrc->buffer_size = 0;
133
134   /* no colorspaces */
135   v4lsrc->colorspaces = NULL;
136
137   v4lsrc->is_capturing = FALSE;
138   v4lsrc->autoprobe = TRUE;
139   v4lsrc->autoprobe_fps = TRUE;
140   v4lsrc->copy_mode = TRUE;
141
142   v4lsrc->timestamp_offset = 0;
143
144   v4lsrc->fps_list = NULL;
145
146   gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME);
147   gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE);
148 }
149
150 static void
151 gst_v4lsrc_set_property (GObject * object,
152     guint prop_id, const GValue * value, GParamSpec * pspec)
153 {
154   GstV4lSrc *v4lsrc = GST_V4LSRC (object);
155
156   switch (prop_id) {
157     case PROP_AUTOPROBE:
158       g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
159       v4lsrc->autoprobe = g_value_get_boolean (value);
160       break;
161     case PROP_AUTOPROBE_FPS:
162       g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
163       v4lsrc->autoprobe_fps = g_value_get_boolean (value);
164       break;
165     case PROP_COPY_MODE:
166       v4lsrc->copy_mode = g_value_get_boolean (value);
167       break;
168     case PROP_TIMESTAMP_OFFSET:
169       v4lsrc->timestamp_offset = g_value_get_int64 (value);
170       break;
171     default:
172       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173       break;
174   }
175 }
176
177
178 static void
179 gst_v4lsrc_get_property (GObject * object,
180     guint prop_id, GValue * value, GParamSpec * pspec)
181 {
182   GstV4lSrc *v4lsrc = GST_V4LSRC (object);
183
184   switch (prop_id) {
185     case PROP_AUTOPROBE:
186       g_value_set_boolean (value, v4lsrc->autoprobe);
187       break;
188     case PROP_AUTOPROBE_FPS:
189       g_value_set_boolean (value, v4lsrc->autoprobe_fps);
190       break;
191     case PROP_COPY_MODE:
192       g_value_set_boolean (value, v4lsrc->copy_mode);
193       break;
194     case PROP_TIMESTAMP_OFFSET:
195       g_value_set_int64 (value, v4lsrc->timestamp_offset);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199       break;
200   }
201 }
202
203 /* this function is a bit of a last resort */
204 static void
205 gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps)
206 {
207   GstStructure *structure;
208   int i;
209   int targetwidth, targetheight;
210   GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc);
211   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
212   struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
213
214   if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
215     GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d",
216         vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight);
217     targetwidth = vcap->minwidth;
218     targetheight = vcap->minheight;
219     /* if we can get the current vwin settings, we use those to fixate */
220     if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc)))
221       GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities");
222     else {
223       targetwidth = vwin->width;
224       targetheight = vwin->height;
225     }
226   } else {
227     GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing");
228     targetwidth = 320;
229     targetheight = 200;
230   }
231
232   GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight);
233
234   for (i = 0; i < gst_caps_get_size (caps); ++i) {
235     const GValue *v;
236
237     structure = gst_caps_get_structure (caps, i);
238     gst_structure_fixate_field_nearest_int (structure, "width", targetwidth);
239     gst_structure_fixate_field_nearest_int (structure, "height", targetheight);
240     gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
241
242     v = gst_structure_get_value (structure, "format");
243     if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
244       guint32 fourcc;
245
246       g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
247
248       fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
249       gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
250     }
251   }
252 }
253
254 static gint all_palettes[] = {
255   VIDEO_PALETTE_YUV422,
256   VIDEO_PALETTE_YUV420P,
257   VIDEO_PALETTE_UYVY,
258   VIDEO_PALETTE_YUV411P,
259   VIDEO_PALETTE_YUV422P,
260   VIDEO_PALETTE_YUV410P,
261   VIDEO_PALETTE_YUV411,
262   VIDEO_PALETTE_RGB555,
263   VIDEO_PALETTE_RGB565,
264   VIDEO_PALETTE_RGB24,
265   VIDEO_PALETTE_RGB32,
266   -1
267 };
268
269 static GstCaps *
270 gst_v4lsrc_palette_to_caps (int palette)
271 {
272   guint32 fourcc;
273   GstCaps *caps;
274
275   switch (palette) {
276     case VIDEO_PALETTE_YUV422:
277     case VIDEO_PALETTE_YUYV:
278       fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
279       break;
280     case VIDEO_PALETTE_YUV420P:
281       fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
282       break;
283     case VIDEO_PALETTE_UYVY:
284       fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
285       break;
286     case VIDEO_PALETTE_YUV411P:
287       fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
288       break;
289     case VIDEO_PALETTE_YUV411:
290       fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
291       break;
292     case VIDEO_PALETTE_YUV422P:
293       fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
294       break;
295     case VIDEO_PALETTE_YUV410P:
296       fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
297       break;
298     case VIDEO_PALETTE_RGB555:
299     case VIDEO_PALETTE_RGB565:
300     case VIDEO_PALETTE_RGB24:
301     case VIDEO_PALETTE_RGB32:
302       fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
303       break;
304     default:
305       return NULL;
306   }
307
308   if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) {
309     switch (palette) {
310       case VIDEO_PALETTE_RGB555:
311         caps = gst_caps_from_string ("video/x-raw-rgb, "
312             "bpp = (int) 16, "
313             "depth = (int) 15, "
314             "endianness = (int) BYTE_ORDER, "
315             "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f");
316         break;
317       case VIDEO_PALETTE_RGB565:
318         caps = gst_caps_from_string ("video/x-raw-rgb, "
319             "bpp = (int) 16, "
320             "depth = (int) 16, "
321             "endianness = (int) BYTE_ORDER, "
322             "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f");
323         break;
324       case VIDEO_PALETTE_RGB24:
325         caps = gst_caps_from_string ("video/x-raw-rgb, "
326             "bpp = (int) 24, "
327             "depth = (int) 24, "
328             "endianness = (int) BIG_ENDIAN, "
329             "red_mask = 0xFF0000, "
330             "green_mask = 0x00FF00, " "blue_mask = 0x0000FF");
331         break;
332       case VIDEO_PALETTE_RGB32:
333         caps = gst_caps_from_string ("video/x-raw-rgb, "
334             "bpp = (int) 32, "
335             "depth = (int) 24, "
336             "endianness = (int) BIG_ENDIAN, "
337             "red_mask = 0xFF000000, "
338             "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00");
339         break;
340       default:
341         g_assert_not_reached ();
342         return NULL;
343     }
344   } else {
345     caps = gst_caps_new_simple ("video/x-raw-yuv",
346         "format", GST_TYPE_FOURCC, fourcc, NULL);
347   }
348
349   return caps;
350 }
351
352 static GstCaps *
353 gst_v4lsrc_get_any_caps (void)
354 {
355   gint i;
356   GstCaps *caps = gst_caps_new_empty (), *one;
357
358   for (i = 0; all_palettes[i] != -1; i++) {
359     one = gst_v4lsrc_palette_to_caps (all_palettes[i]);
360     gst_caps_append (caps, one);
361   }
362
363   return caps;
364 }
365
366 static GstCaps *
367 gst_v4lsrc_get_caps (GstBaseSrc * src)
368 {
369   GstCaps *list;
370   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
371   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
372   gint width = GST_V4LELEMENT (src)->vcap.minwidth;
373   gint height = GST_V4LELEMENT (src)->vcap.minheight;
374   gint i;
375   gint fps_n, fps_d;
376   GList *item;
377
378   if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
379     return gst_v4lsrc_get_any_caps ();
380   }
381
382   if (!v4lsrc->autoprobe) {
383     /* FIXME: query current caps and return those, with _any appended */
384     return gst_v4lsrc_get_any_caps ();
385   }
386
387   if (!v4lsrc->colorspaces) {
388     GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes");
389     for (i = 0; all_palettes[i] != -1; i++) {
390       /* try palette out */
391       if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i]))
392         continue;
393       GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list",
394           all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i]));
395       v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces,
396           GINT_TO_POINTER (all_palettes[i]));
397     }
398     GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported",
399         g_list_length (v4lsrc->colorspaces));
400     if (v4lsrc->autoprobe_fps) {
401       GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates");
402       v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc);
403     }
404   }
405
406
407   if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) {
408     fps_n = 0;
409     fps_d = 1;
410   }
411
412   list = gst_caps_new_empty ();
413   for (item = v4lsrc->colorspaces; item != NULL; item = item->next) {
414     GstCaps *one;
415
416     one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data));
417     if (!one) {
418       GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n",
419           GPOINTER_TO_INT (item->data));
420       continue;
421     }
422
423     GST_DEBUG_OBJECT (v4lsrc,
424         "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d",
425         vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight,
426         fps_n, fps_d, GPOINTER_TO_INT (item->data));
427
428     if (vcap->minwidth < vcap->maxwidth) {
429       gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
430           vcap->maxwidth, NULL);
431     } else {
432       gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL);
433     }
434     if (vcap->minheight < vcap->maxheight) {
435       gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight,
436           vcap->maxheight, NULL);
437     } else {
438       gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL);
439     }
440
441     if (v4lsrc->autoprobe_fps) {
442       GstStructure *structure = gst_caps_get_structure (one, 0);
443
444       if (v4lsrc->fps_list) {
445         gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
446       } else {
447         gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
448             fps_n, fps_d, NULL);
449       }
450     } else {
451       gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE,
452           1, 1, 100, 1, NULL);
453     }
454
455     GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one);
456     gst_caps_append (list, one);
457   }
458
459   return list;
460 }
461
462 static gboolean
463 gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps)
464 {
465   GstV4lSrc *v4lsrc;
466   guint32 fourcc;
467   gint bpp, depth, w, h, palette = -1;
468   const GValue *new_fps;
469   gint cur_fps_n, cur_fps_d;
470   GstStructure *structure;
471   struct video_window *vwin;
472
473   v4lsrc = GST_V4LSRC (src);
474   vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
475
476   /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
477   if (!GST_V4L_IS_OPEN (v4lsrc))
478     return FALSE;
479
480   /* make sure we stop capturing and dealloc buffers */
481   if (GST_V4L_IS_ACTIVE (v4lsrc)) {
482     if (!gst_v4lsrc_capture_stop (v4lsrc))
483       return FALSE;
484     if (!gst_v4lsrc_capture_deinit (v4lsrc))
485       return FALSE;
486   }
487
488   /* it's fixed, one struct */
489   structure = gst_caps_get_structure (caps, 0);
490
491   if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0)
492     gst_structure_get_fourcc (structure, "format", &fourcc);
493   else
494     fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
495
496   gst_structure_get_int (structure, "width", &w);
497   gst_structure_get_int (structure, "height", &h);
498   new_fps = gst_structure_get_value (structure, "framerate");
499
500   /* set framerate if it's not already correct */
501   if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d))
502     return FALSE;
503
504   if (new_fps) {
505     GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h,
506         gst_value_get_fraction_numerator (new_fps),
507         gst_value_get_fraction_denominator (new_fps));
508
509     if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n ||
510         gst_value_get_fraction_denominator (new_fps) != cur_fps_d) {
511       int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) /
512           (gst_value_get_fraction_denominator (new_fps) * 15);
513
514       GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index);
515       /* set bits 16 to 21 to 0 */
516       vwin->flags &= (0x3F00 - 1);
517       /* set bits 16 to 21 to the index */
518       vwin->flags |= fps_index << 16;
519       if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
520         return FALSE;
521       }
522     }
523   }
524
525   switch (fourcc) {
526     case GST_MAKE_FOURCC ('I', '4', '2', '0'):
527       palette = VIDEO_PALETTE_YUV420P;
528       v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5;
529       break;
530     case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
531       palette = VIDEO_PALETTE_YUV422;
532       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
533       break;
534     case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
535       palette = VIDEO_PALETTE_UYVY;
536       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
537       break;
538     case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
539       palette = VIDEO_PALETTE_YUV411P;
540       v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
541       break;
542     case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
543       palette = VIDEO_PALETTE_YUV411;
544       v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
545       break;
546     case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
547       palette = VIDEO_PALETTE_YUV410P;
548       v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125;
549       break;
550     case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
551       palette = VIDEO_PALETTE_YUV422P;
552       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
553       break;
554     case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
555       gst_structure_get_int (structure, "depth", &depth);
556       switch (depth) {
557         case 15:
558           palette = VIDEO_PALETTE_RGB555;
559           v4lsrc->buffer_size = w * h * 2;
560           break;
561         case 16:
562           palette = VIDEO_PALETTE_RGB565;
563           v4lsrc->buffer_size = w * h * 2;
564           break;
565         case 24:
566           gst_structure_get_int (structure, "bpp", &bpp);
567           switch (bpp) {
568             case 24:
569               palette = VIDEO_PALETTE_RGB24;
570               v4lsrc->buffer_size = w * h * 3;
571               break;
572             case 32:
573               palette = VIDEO_PALETTE_RGB32;
574               v4lsrc->buffer_size = w * h * 4;
575               break;
576             default:
577               break;
578           }
579           break;
580         default:
581           break;
582       }
583       break;
584     default:
585       break;
586   }
587
588   if (palette == -1) {
589     GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT
590         " is -1, refusing link", GST_FOURCC_ARGS (fourcc));
591     return FALSE;
592   }
593
594   GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d",
595       w, h, palette);
596   /* this only fills in v4lsrc->mmap values */
597   if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
598     GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d",
599         w, h, palette);
600     return FALSE;
601   }
602
603   /* first try the negotiated settings using try_capture */
604   if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
605     GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette,
606         w, h);
607     return FALSE;
608   }
609
610   if (!gst_v4lsrc_capture_init (v4lsrc))
611     return FALSE;
612
613   if (!gst_v4lsrc_capture_start (v4lsrc))
614     return FALSE;
615
616   return TRUE;
617 }
618
619 static gboolean
620 gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query)
621 {
622   GstV4lSrc *v4lsrc;
623   gboolean res = FALSE;
624
625   v4lsrc = GST_V4LSRC (bsrc);
626
627   switch (GST_QUERY_TYPE (query)) {
628     case GST_QUERY_LATENCY:
629     {
630       GstClockTime min_latency, max_latency;
631       gint fps_n, fps_d;
632
633       /* device must be open */
634       if (!GST_V4L_IS_OPEN (v4lsrc))
635         goto done;
636
637       /* we must have a framerate */
638       if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)))
639         goto done;
640
641       /* min latency is the time to capture one frame */
642       min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
643
644       /* max latency is total duration of the frame buffer */
645       max_latency = v4lsrc->mbuf.frames * min_latency;
646
647       GST_DEBUG_OBJECT (bsrc,
648           "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
649           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
650
651       /* we are always live, the min latency is 1 frame and the max latency is
652        * the complete buffer of frames. */
653       gst_query_set_latency (query, TRUE, min_latency, max_latency);
654
655       res = TRUE;
656       break;
657     }
658     default:
659       res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
660       break;
661   }
662 done:
663   return res;
664 }
665
666 /* start and stop are not symmetric -- start will open the device, but not start
667    capture. it's setcaps that will start capture, which is called via basesrc's
668    negotiate method. stop will both stop capture and close the device.
669  */
670 static gboolean
671 gst_v4lsrc_start (GstBaseSrc * src)
672 {
673   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
674
675   v4lsrc->offset = 0;
676
677   return TRUE;
678 }
679
680 static gboolean
681 gst_v4lsrc_stop (GstBaseSrc * src)
682 {
683   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
684
685   if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc))
686     return FALSE;
687
688   if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) {
689     if (!gst_v4lsrc_capture_deinit (v4lsrc))
690       return FALSE;
691   }
692
693   g_list_free (v4lsrc->colorspaces);
694   v4lsrc->colorspaces = NULL;
695
696   if (v4lsrc->fps_list) {
697     g_value_unset (v4lsrc->fps_list);
698     g_free (v4lsrc->fps_list);
699     v4lsrc->fps_list = NULL;
700   }
701
702   return TRUE;
703 }
704
705 static GstFlowReturn
706 gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf)
707 {
708   GstV4lSrc *v4lsrc;
709   gint num;
710
711   v4lsrc = GST_V4LSRC (src);
712
713   /* grab a frame from the device */
714   if (!gst_v4lsrc_grab_frame (v4lsrc, &num))
715     return GST_FLOW_ERROR;
716
717   *buf = gst_v4lsrc_buffer_new (v4lsrc, num);
718
719   if (v4lsrc->copy_mode) {
720     GstBuffer *copy = gst_buffer_copy (*buf);
721
722     gst_buffer_unref (*buf);
723     *buf = copy;
724   }
725
726   return GST_FLOW_OK;
727 }