docs: fix gtk-doc warnings
[platform/upstream/gstreamer.git] / sys / v4l2 / gstv4l2object.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  * gstv4l2object.c: base class for V4L2 elements
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Library General Public License as published
10  * by the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version. This library is distributed in the hope
12  * that it will be useful, but WITHOUT ANY WARRANTY; without even the
13  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  * PURPOSE.  See the GNU Library General Public License for more details.
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18  * USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30
31 #ifdef HAVE_GUDEV
32 #include <gudev/gudev.h>
33 #endif
34
35 #include "v4l2_calls.h"
36 #include "gstv4l2tuner.h"
37 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
38 #include "gstv4l2xoverlay.h"
39 #endif
40 #include "gstv4l2colorbalance.h"
41
42 #include "gst/gst-i18n-plugin.h"
43
44
45 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
46 #define GST_CAT_DEFAULT v4l2_debug
47
48
49 #define DEFAULT_PROP_DEVICE_NAME        NULL
50 #define DEFAULT_PROP_DEVICE_FD          -1
51 #define DEFAULT_PROP_FLAGS              0
52 #define DEFAULT_PROP_NORM               NULL
53 #define DEFAULT_PROP_CHANNEL            NULL
54 #define DEFAULT_PROP_FREQUENCY          0
55
56 enum
57 {
58   PROP_0,
59   V4L2_STD_OBJECT_PROPS,
60 };
61
62 const GList *
63 gst_v4l2_probe_get_properties (GstPropertyProbe * probe)
64 {
65   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
66   static GList *list = NULL;
67
68   /* well, not perfect, but better than no locking at all.
69    * In the worst case we leak a list node, so who cares? */
70   GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
71
72   if (!list) {
73     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
74   }
75
76   GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
77
78   return list;
79 }
80
81 static gboolean init = FALSE;
82 static GList *devices = NULL;
83
84 #ifdef HAVE_GUDEV
85 static gboolean
86 gst_v4l2_class_probe_devices_with_udev (GstElementClass * klass, gboolean check,
87     GList ** klass_devices)
88 {
89   GUdevClient *client;
90   GList *item;
91
92   if (!check) {
93     while (devices) {
94       gchar *device = devices->data;
95       devices = g_list_remove (devices, device);
96       g_free (device);
97     }
98
99     GST_INFO ("Enumerating video4linux devices from udev");
100     client = g_udev_client_new (NULL);
101     if (!client) {
102       GST_WARNING ("Failed to initialize gudev client");
103       goto finish;
104     }
105
106     item = g_udev_client_query_by_subsystem (client, "video4linux");
107     while (item) {
108       GUdevDevice *device = item->data;
109       gchar *devnode = g_strdup (g_udev_device_get_device_file (device));
110       gint api = g_udev_device_get_property_as_int (device, "ID_V4L_VERSION");
111       GST_INFO ("Found new device: %s, API: %d", devnode, api);
112       /* Append v4l2 devices only. If api is 0 probably v4l_id has
113          been stripped out of the current udev installation, append
114          anyway */
115       if (api == 0) {
116         GST_WARNING
117             ("Couldn't retrieve ID_V4L_VERSION, silly udev installation?");
118       }
119       if ((api == 2 || api == 0)) {
120         devices = g_list_append (devices, devnode);
121       } else {
122         g_free (devnode);
123       }
124       g_object_unref (device);
125       item = item->next;
126     }
127     g_list_free (item);
128     init = TRUE;
129   }
130
131 finish:
132   if (client) {
133     g_object_unref (client);
134   }
135
136   *klass_devices = devices;
137
138   return init;
139 }
140 #endif /* HAVE_GUDEV */
141
142 static gboolean
143 gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check,
144     GList ** klass_devices)
145 {
146   if (!check) {
147     const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL };
148     gint base, n, fd;
149
150     while (devices) {
151       gchar *device = devices->data;
152       devices = g_list_remove (devices, device);
153       g_free (device);
154     }
155
156     /*
157      * detect /dev entries
158      */
159     for (n = 0; n < 64; n++) {
160       for (base = 0; dev_base[base] != NULL; base++) {
161         struct stat s;
162         gchar *device = g_strdup_printf ("%s%d",
163             dev_base[base],
164             n);
165
166         /*
167          * does the /dev/ entry exist at all?
168          */
169         if (stat (device, &s) == 0) {
170           /*
171            * yes: is a device attached?
172            */
173           if (S_ISCHR (s.st_mode)) {
174
175             if ((fd = open (device, O_RDWR | O_NONBLOCK)) > 0 || errno == EBUSY) {
176               if (fd > 0)
177                 close (fd);
178
179               devices = g_list_append (devices, device);
180               break;
181             }
182           }
183         }
184         g_free (device);
185       }
186     }
187     init = TRUE;
188   }
189
190   *klass_devices = devices;
191
192   return init;
193 }
194
195 void
196 gst_v4l2_probe_probe_property (GstPropertyProbe * probe,
197     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
198 {
199   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
200
201   switch (prop_id) {
202     case PROP_DEVICE:
203 #ifdef HAVE_GUDEV
204       if (!gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices))
205         gst_v4l2_class_probe_devices (klass, FALSE, klass_devices);
206 #else /* !HAVE_GUDEV */
207       gst_v4l2_class_probe_devices (klass, FALSE, klass_devices);
208 #endif /* HAVE_GUDEV */
209       break;
210     default:
211       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
212       break;
213   }
214 }
215
216 gboolean
217 gst_v4l2_probe_needs_probe (GstPropertyProbe * probe,
218     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
219 {
220   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
221   gboolean ret = FALSE;
222
223   switch (prop_id) {
224     case PROP_DEVICE:
225 #ifdef HAVE_GUDEV
226       ret =
227           !gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices);
228 #else /* !HAVE_GUDEV */
229       ret = !gst_v4l2_class_probe_devices (klass, TRUE, klass_devices);
230 #endif /* HAVE_GUDEV */
231       break;
232     default:
233       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
234       break;
235   }
236   return ret;
237 }
238
239 static GValueArray *
240 gst_v4l2_class_list_devices (GstElementClass * klass, GList ** klass_devices)
241 {
242   GValueArray *array;
243   GValue value = { 0 };
244   GList *item;
245
246   if (!*klass_devices)
247     return NULL;
248
249   array = g_value_array_new (g_list_length (*klass_devices));
250   item = *klass_devices;
251   g_value_init (&value, G_TYPE_STRING);
252   while (item) {
253     gchar *device = item->data;
254
255     g_value_set_string (&value, device);
256     g_value_array_append (array, &value);
257
258     item = item->next;
259   }
260   g_value_unset (&value);
261
262   return array;
263 }
264
265 GValueArray *
266 gst_v4l2_probe_get_values (GstPropertyProbe * probe,
267     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
268 {
269   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
270   GValueArray *array = NULL;
271
272   switch (prop_id) {
273     case PROP_DEVICE:
274       array = gst_v4l2_class_list_devices (klass, klass_devices);
275       break;
276     default:
277       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
278       break;
279   }
280
281   return array;
282 }
283
284 #define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ())
285 GType
286 gst_v4l2_device_get_type (void)
287 {
288   static GType v4l2_device_type = 0;
289
290   if (v4l2_device_type == 0) {
291     static const GFlagsValue values[] = {
292       {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"},
293       {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
294       {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
295
296       {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
297       {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
298
299       {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
300       {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
301
302       {0, NULL, NULL}
303     };
304
305     v4l2_device_type =
306         g_flags_register_static ("GstV4l2DeviceTypeFlags", values);
307   }
308
309   return v4l2_device_type;
310 }
311
312 void
313 gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
314     const char *default_device)
315 {
316   g_object_class_install_property (gobject_class, PROP_DEVICE,
317       g_param_spec_string ("device", "Device", "Device location",
318           default_device, G_PARAM_READWRITE));
319   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
320       g_param_spec_string ("device-name", "Device name",
321           "Name of the device", DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE));
322   g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
323       g_param_spec_int ("device-fd", "File descriptor",
324           "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
325           G_PARAM_READABLE));
326   g_object_class_install_property (gobject_class, PROP_FLAGS,
327       g_param_spec_flags ("flags", "Flags", "Device type flags",
328           GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS, G_PARAM_READABLE));
329 }
330
331 GstV4l2Object *
332 gst_v4l2_object_new (GstElement * element,
333     enum v4l2_buf_type type,
334     char *default_device,
335     GstV4l2GetInOutFunction get_in_out_func,
336     GstV4l2SetInOutFunction set_in_out_func,
337     GstV4l2UpdateFpsFunction update_fps_func)
338 {
339   GstV4l2Object *v4l2object;
340
341   /*
342    * some default values
343    */
344   v4l2object = g_new0 (GstV4l2Object, 1);
345
346   v4l2object->type = type;
347   v4l2object->formats = NULL;
348
349   v4l2object->element = element;
350   v4l2object->get_in_out_func = get_in_out_func;
351   v4l2object->set_in_out_func = set_in_out_func;
352   v4l2object->update_fps_func = update_fps_func;
353
354   v4l2object->video_fd = -1;
355   v4l2object->poll = gst_poll_new (TRUE);
356   v4l2object->buffer = NULL;
357   v4l2object->videodev = g_strdup (default_device);
358
359   v4l2object->norms = NULL;
360   v4l2object->channels = NULL;
361   v4l2object->colors = NULL;
362
363   v4l2object->xwindow_id = 0;
364
365   return v4l2object;
366 }
367
368 static gboolean gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object);
369
370
371 void
372 gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
373 {
374   g_return_if_fail (v4l2object != NULL);
375
376   if (v4l2object->videodev)
377     g_free (v4l2object->videodev);
378
379   if (v4l2object->poll)
380     gst_poll_free (v4l2object->poll);
381
382   if (v4l2object->channel)
383     g_free (v4l2object->channel);
384
385   if (v4l2object->norm)
386     g_free (v4l2object->norm);
387
388   if (v4l2object->formats) {
389     gst_v4l2_object_clear_format_list (v4l2object);
390   }
391
392   g_free (v4l2object);
393 }
394
395
396 static gboolean
397 gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object)
398 {
399   g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
400   g_slist_free (v4l2object->formats);
401   v4l2object->formats = NULL;
402
403   return TRUE;
404 }
405
406
407 gboolean
408 gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
409     guint prop_id, const GValue * value, GParamSpec * pspec)
410 {
411   switch (prop_id) {
412     case PROP_DEVICE:
413       g_free (v4l2object->videodev);
414       v4l2object->videodev = g_value_dup_string (value);
415       break;
416 #if 0
417     case PROP_NORM:
418       if (GST_V4L2_IS_OPEN (v4l2object)) {
419         GstTuner *tuner = GST_TUNER (v4l2object->element);
420         GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner,
421             (gchar *) g_value_get_string (value));
422
423         if (norm) {
424           /* like gst_tuner_set_norm (tuner, norm)
425              without g_object_notify */
426           gst_v4l2_tuner_set_norm (v4l2object, norm);
427         }
428       } else {
429         g_free (v4l2object->norm);
430         v4l2object->norm = g_value_dup_string (value);
431       }
432       break;
433     case PROP_CHANNEL:
434       if (GST_V4L2_IS_OPEN (v4l2object)) {
435         GstTuner *tuner = GST_TUNER (v4l2object->element);
436         GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
437             (gchar *) g_value_get_string (value));
438
439         if (channel) {
440           /* like gst_tuner_set_channel (tuner, channel)
441              without g_object_notify */
442           gst_v4l2_tuner_set_channel (v4l2object, channel);
443         }
444       } else {
445         g_free (v4l2object->channel);
446         v4l2object->channel = g_value_dup_string (value);
447       }
448       break;
449     case PROP_FREQUENCY:
450       if (GST_V4L2_IS_OPEN (v4l2object)) {
451         GstTuner *tuner = GST_TUNER (v4l2object->element);
452         GstTunerChannel *channel = gst_tuner_get_channel (tuner);
453
454         if (channel &&
455             GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
456           /* like
457              gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value))
458              without g_object_notify */
459           gst_v4l2_tuner_set_frequency (v4l2object, channel,
460               g_value_get_ulong (value));
461         }
462       } else {
463         v4l2object->frequency = g_value_get_ulong (value);
464       }
465       break;
466 #endif
467     default:
468       return FALSE;
469       break;
470   }
471   return TRUE;
472 }
473
474
475 gboolean
476 gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
477     guint prop_id, GValue * value, GParamSpec * pspec)
478 {
479   switch (prop_id) {
480     case PROP_DEVICE:
481       g_value_set_string (value, v4l2object->videodev);
482       break;
483     case PROP_DEVICE_NAME:
484     {
485       const guchar *new = NULL;
486
487       if (GST_V4L2_IS_OPEN (v4l2object)) {
488         new = v4l2object->vcap.card;
489       } else if (gst_v4l2_open (v4l2object)) {
490         new = v4l2object->vcap.card;
491         gst_v4l2_close (v4l2object);
492       }
493       g_value_set_string (value, (gchar *) new);
494       break;
495     }
496     case PROP_DEVICE_FD:
497     {
498       if (GST_V4L2_IS_OPEN (v4l2object))
499         g_value_set_int (value, v4l2object->video_fd);
500       else
501         g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
502       break;
503     }
504     case PROP_FLAGS:
505     {
506       guint flags = 0;
507
508       if (GST_V4L2_IS_OPEN (v4l2object)) {
509         flags |= v4l2object->vcap.capabilities &
510             (V4L2_CAP_VIDEO_CAPTURE |
511             V4L2_CAP_VIDEO_OUTPUT |
512             V4L2_CAP_VIDEO_OVERLAY |
513             V4L2_CAP_VBI_CAPTURE |
514             V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
515       }
516       g_value_set_flags (value, flags);
517       break;
518     }
519     default:
520       return FALSE;
521       break;
522   }
523   return TRUE;
524 }
525
526 static void
527 gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
528 {
529   GstTunerNorm *norm = NULL;
530   GstTunerChannel *channel = NULL;
531   GstTuner *tuner;
532
533   if (!GST_IS_TUNER (v4l2object->element))
534     return;
535
536   tuner = GST_TUNER (v4l2object->element);
537
538   if (v4l2object->norm)
539     norm = gst_tuner_find_norm_by_name (tuner, v4l2object->norm);
540   if (norm) {
541     gst_tuner_set_norm (tuner, norm);
542   } else {
543     norm =
544         GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
545     if (norm) {
546       g_free (v4l2object->norm);
547       v4l2object->norm = g_strdup (norm->label);
548       gst_tuner_norm_changed (tuner, norm);
549     }
550   }
551
552   if (v4l2object->channel)
553     channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
554   if (channel) {
555     gst_tuner_set_channel (tuner, channel);
556   } else {
557     channel =
558         GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
559             (v4l2object->element)));
560     if (channel) {
561       g_free (v4l2object->channel);
562       v4l2object->channel = g_strdup (channel->label);
563       gst_tuner_channel_changed (tuner, channel);
564     }
565   }
566
567   if (channel
568       && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
569     if (v4l2object->frequency != 0) {
570       gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
571     } else {
572       v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
573       if (v4l2object->frequency == 0) {
574         /* guess */
575         gst_tuner_set_frequency (tuner, channel, 1000);
576       } else {
577       }
578     }
579   }
580 }
581
582 gboolean
583 gst_v4l2_object_start (GstV4l2Object * v4l2object)
584 {
585   if (gst_v4l2_open (v4l2object))
586     gst_v4l2_set_defaults (v4l2object);
587   else
588     return FALSE;
589
590 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
591   gst_v4l2_xoverlay_start (v4l2object);
592 #endif
593
594   return TRUE;
595 }
596
597 gboolean
598 gst_v4l2_object_stop (GstV4l2Object * v4l2object)
599 {
600 #if 0                           /* overlay is still not implemented #ifdef HAVE_XVIDEO */
601   gst_v4l2_xoverlay_stop (v4l2object);
602 #endif
603
604   if (!gst_v4l2_close (v4l2object))
605     return FALSE;
606
607   if (v4l2object->formats) {
608     gst_v4l2_object_clear_format_list (v4l2object);
609   }
610
611   return TRUE;
612 }
613
614
615 /*
616  * common format / caps utilities:
617  */
618 typedef struct
619 {
620   guint32 format;
621   gboolean dimensions;
622 } GstV4L2FormatDesc;
623
624 static const GstV4L2FormatDesc gst_v4l2_formats[] = {
625   /* from Linux 2.6.15 videodev2.h */
626   {V4L2_PIX_FMT_RGB332, TRUE},
627   {V4L2_PIX_FMT_RGB555, TRUE},
628   {V4L2_PIX_FMT_RGB565, TRUE},
629   {V4L2_PIX_FMT_RGB555X, TRUE},
630   {V4L2_PIX_FMT_RGB565X, TRUE},
631   {V4L2_PIX_FMT_BGR24, TRUE},
632   {V4L2_PIX_FMT_RGB24, TRUE},
633   {V4L2_PIX_FMT_BGR32, TRUE},
634   {V4L2_PIX_FMT_RGB32, TRUE},
635   {V4L2_PIX_FMT_GREY, TRUE},
636   {V4L2_PIX_FMT_YVU410, TRUE},
637   {V4L2_PIX_FMT_YVU420, TRUE},
638   {V4L2_PIX_FMT_YUYV, TRUE},
639   {V4L2_PIX_FMT_UYVY, TRUE},
640   {V4L2_PIX_FMT_YUV422P, TRUE},
641   {V4L2_PIX_FMT_YUV411P, TRUE},
642   {V4L2_PIX_FMT_Y41P, TRUE},
643
644   /* two planes -- one Y, one Cr + Cb interleaved  */
645   {V4L2_PIX_FMT_NV12, TRUE},
646   {V4L2_PIX_FMT_NV21, TRUE},
647
648   /*  The following formats are not defined in the V4L2 specification */
649   {V4L2_PIX_FMT_YUV410, TRUE},
650   {V4L2_PIX_FMT_YUV420, TRUE},
651   {V4L2_PIX_FMT_YYUV, TRUE},
652   {V4L2_PIX_FMT_HI240, TRUE},
653
654   /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
655 #ifdef V4L2_PIX_FMT_SBGGR8
656   {V4L2_PIX_FMT_SBGGR8, TRUE},
657 #endif
658
659   /* compressed formats */
660   {V4L2_PIX_FMT_MJPEG, TRUE},
661   {V4L2_PIX_FMT_JPEG, TRUE},
662   {V4L2_PIX_FMT_DV, TRUE},
663   {V4L2_PIX_FMT_MPEG, FALSE},
664
665   /*  Vendor-specific formats   */
666   {V4L2_PIX_FMT_WNVA, TRUE},
667
668 #ifdef V4L2_PIX_FMT_SN9C10X
669   {V4L2_PIX_FMT_SN9C10X, TRUE},
670 #endif
671 #ifdef V4L2_PIX_FMT_PWC1
672   {V4L2_PIX_FMT_PWC1, TRUE},
673 #endif
674 #ifdef V4L2_PIX_FMT_PWC2
675   {V4L2_PIX_FMT_PWC2, TRUE},
676 #endif
677 #ifdef V4L2_PIX_FMT_YVYU
678   {V4L2_PIX_FMT_YVYU, TRUE},
679 #endif
680 };
681
682 #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
683
684
685 static struct v4l2_fmtdesc *
686 gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object,
687     guint32 fourcc)
688 {
689   struct v4l2_fmtdesc *fmt;
690   GSList *walk;
691
692   if (fourcc == 0)
693     return NULL;
694
695   walk = gst_v4l2_object_get_format_list (v4l2object);
696   while (walk) {
697     fmt = (struct v4l2_fmtdesc *) walk->data;
698     if (fmt->pixelformat == fourcc)
699       return fmt;
700     /* special case for jpeg */
701     if ((fmt->pixelformat == V4L2_PIX_FMT_MJPEG && fourcc == V4L2_PIX_FMT_JPEG)
702         || (fmt->pixelformat == V4L2_PIX_FMT_JPEG
703             && fourcc == V4L2_PIX_FMT_MJPEG)) {
704       return fmt;
705     }
706     walk = g_slist_next (walk);
707   }
708
709   return NULL;
710 }
711
712
713
714 /* complete made up ranking, the values themselves are meaningless */
715 #define YUV_BASE_RANK     1000
716 #define JPEG_BASE_RANK     500
717 #define DV_BASE_RANK       200
718 #define RGB_BASE_RANK      100
719 #define YUV_ODD_BASE_RANK   50
720 #define RGB_ODD_BASE_RANK   25
721 #define BAYER_BASE_RANK     15
722 #define S910_BASE_RANK      10
723 #define GREY_BASE_RANK       5
724 #define PWC_BASE_RANK        1
725
726 /* This flag is already used by libv4l2 although
727  * it was added to the Linux kernel in 2.6.32
728  */
729 #ifndef V4L2_FMT_FLAG_EMULATED
730 #define V4L2_FMT_FLAG_EMULATED 0x0002
731 #endif
732
733 static gint
734 gst_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
735 {
736   guint32 fourcc = fmt->pixelformat;
737   gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
738   gint rank = 0;
739
740   switch (fourcc) {
741     case V4L2_PIX_FMT_MJPEG:
742       rank = JPEG_BASE_RANK;
743       break;
744     case V4L2_PIX_FMT_JPEG:
745       rank = JPEG_BASE_RANK + 1;
746       break;
747     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
748       rank = JPEG_BASE_RANK + 2;
749       break;
750
751     case V4L2_PIX_FMT_RGB332:
752     case V4L2_PIX_FMT_RGB555:
753     case V4L2_PIX_FMT_RGB555X:
754     case V4L2_PIX_FMT_RGB565:
755     case V4L2_PIX_FMT_RGB565X:
756       rank = RGB_ODD_BASE_RANK;
757       break;
758
759     case V4L2_PIX_FMT_RGB24:
760     case V4L2_PIX_FMT_BGR24:
761       rank = RGB_BASE_RANK - 1;
762       break;
763
764     case V4L2_PIX_FMT_RGB32:
765     case V4L2_PIX_FMT_BGR32:
766       rank = RGB_BASE_RANK;
767       break;
768
769     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
770       rank = GREY_BASE_RANK;
771       break;
772
773     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
774     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
775     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
776     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
777       rank = YUV_ODD_BASE_RANK;
778       break;
779
780     case V4L2_PIX_FMT_YVU410:  /* YVU9,  9 bits per pixel */
781       rank = YUV_BASE_RANK + 3;
782       break;
783     case V4L2_PIX_FMT_YUV410:  /* YUV9,  9 bits per pixel */
784       rank = YUV_BASE_RANK + 2;
785       break;
786     case V4L2_PIX_FMT_YUV420:  /* I420, 12 bits per pixel */
787       rank = YUV_BASE_RANK + 7;
788       break;
789     case V4L2_PIX_FMT_YUYV:    /* YUY2, 16 bits per pixel */
790       rank = YUV_BASE_RANK + 10;
791       break;
792     case V4L2_PIX_FMT_YVU420:  /* YV12, 12 bits per pixel */
793       rank = YUV_BASE_RANK + 6;
794       break;
795     case V4L2_PIX_FMT_UYVY:    /* UYVY, 16 bits per pixel */
796       rank = YUV_BASE_RANK + 9;
797       break;
798     case V4L2_PIX_FMT_Y41P:    /* Y41P, 12 bits per pixel */
799       rank = YUV_BASE_RANK + 5;
800       break;
801     case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
802       rank = YUV_BASE_RANK + 4;
803       break;
804     case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
805       rank = YUV_BASE_RANK + 8;
806       break;
807
808     case V4L2_PIX_FMT_DV:
809       rank = DV_BASE_RANK;
810       break;
811
812     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
813       rank = 0;
814       break;
815
816 #ifdef V4L2_PIX_FMT_SBGGR8
817     case V4L2_PIX_FMT_SBGGR8:
818       rank = BAYER_BASE_RANK;
819       break;
820 #endif
821
822 #ifdef V4L2_PIX_FMT_SN9C10X
823     case V4L2_PIX_FMT_SN9C10X:
824       rank = S910_BASE_RANK;
825       break;
826 #endif
827
828 #ifdef V4L2_PIX_FMT_PWC1
829     case V4L2_PIX_FMT_PWC1:
830       rank = PWC_BASE_RANK;
831       break;
832 #endif
833 #ifdef V4L2_PIX_FMT_PWC2
834     case V4L2_PIX_FMT_PWC2:
835       rank = PWC_BASE_RANK;
836       break;
837 #endif
838
839     default:
840       rank = 0;
841       break;
842   }
843
844   /* All ranks are below 1<<15 so a shift by 15
845    * will a) make all non-emulated formats larger
846    * than emulated and b) will not overflow
847    */
848   if (!emulated)
849     rank <<= 15;
850
851   return rank;
852 }
853
854
855
856 static gint
857 format_cmp_func (gconstpointer a, gconstpointer b)
858 {
859   const struct v4l2_fmtdesc *fa = a;
860   const struct v4l2_fmtdesc *fb = b;
861
862   if (fa->pixelformat == fb->pixelformat)
863     return 0;
864
865   return gst_v4l2_object_format_get_rank (fa) -
866       gst_v4l2_object_format_get_rank (fb);
867 }
868
869 /******************************************************
870  * gst_v4l2_object_fill_format_list():
871  *   create list of supported capture formats
872  * return value: TRUE on success, FALSE on error
873  ******************************************************/
874 static gboolean
875 gst_v4l2_object_fill_format_list (GstV4l2Object * v4l2object)
876 {
877   gint n;
878   struct v4l2_fmtdesc *format;
879
880   GST_DEBUG_OBJECT (v4l2object->element, "getting src format enumerations");
881
882   /* format enumeration */
883   for (n = 0;; n++) {
884     format = g_new0 (struct v4l2_fmtdesc, 1);
885
886     format->index = n;
887     format->type = v4l2object->type;
888
889     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
890       if (errno == EINVAL) {
891         g_free (format);
892         break;                  /* end of enumeration */
893       } else {
894         goto failed;
895       }
896     }
897
898     GST_LOG_OBJECT (v4l2object->element, "index:       %u", format->index);
899     GST_LOG_OBJECT (v4l2object->element, "type:        %d", format->type);
900     GST_LOG_OBJECT (v4l2object->element, "flags:       %08x", format->flags);
901     GST_LOG_OBJECT (v4l2object->element, "description: '%s'",
902         format->description);
903     GST_LOG_OBJECT (v4l2object->element, "pixelformat: %" GST_FOURCC_FORMAT,
904         GST_FOURCC_ARGS (format->pixelformat));
905
906     /* sort formats according to our preference;  we do this, because caps
907      * are probed in the order the formats are in the list, and the order of
908      * formats in the final probed caps matters for things like fixation */
909     v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
910         (GCompareFunc) format_cmp_func);
911   }
912
913   GST_DEBUG_OBJECT (v4l2object->element, "got %d format(s)", n);
914
915   return TRUE;
916
917   /* ERRORS */
918 failed:
919   {
920     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
921         (_("Failed to enumerate possible video formats device '%s' can work with"), v4l2object->videodev), ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)", n, v4l2object->videodev, errno, g_strerror (errno)));
922     g_free (format);
923     return FALSE;
924   }
925 }
926
927 /*
928  * Get the list of supported capture formats, a list of
929  * <code>struct v4l2_fmtdesc</code>.
930  */
931 GSList *
932 gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object)
933 {
934   if (!v4l2object->formats)
935     gst_v4l2_object_fill_format_list (v4l2object);
936   return v4l2object->formats;
937 }
938
939
940 GstStructure *
941 gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
942 {
943   GstStructure *structure = NULL;
944
945   switch (fourcc) {
946     case V4L2_PIX_FMT_MJPEG:   /* Motion-JPEG */
947     case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
948       structure = gst_structure_new ("image/jpeg", NULL);
949       break;
950     case V4L2_PIX_FMT_RGB332:
951     case V4L2_PIX_FMT_RGB555:
952     case V4L2_PIX_FMT_RGB555X:
953     case V4L2_PIX_FMT_RGB565:
954     case V4L2_PIX_FMT_RGB565X:
955     case V4L2_PIX_FMT_RGB24:
956     case V4L2_PIX_FMT_BGR24:
957     case V4L2_PIX_FMT_RGB32:
958     case V4L2_PIX_FMT_BGR32:{
959       guint depth = 0, bpp = 0;
960
961       gint endianness = 0;
962
963       guint32 r_mask = 0, b_mask = 0, g_mask = 0;
964
965       switch (fourcc) {
966         case V4L2_PIX_FMT_RGB332:
967           bpp = depth = 8;
968           endianness = G_BYTE_ORDER;    /* 'like, whatever' */
969           r_mask = 0xe0;
970           g_mask = 0x1c;
971           b_mask = 0x03;
972           break;
973         case V4L2_PIX_FMT_RGB555:
974         case V4L2_PIX_FMT_RGB555X:
975           bpp = 16;
976           depth = 15;
977           endianness =
978               fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
979           r_mask = 0x7c00;
980           g_mask = 0x03e0;
981           b_mask = 0x001f;
982           break;
983         case V4L2_PIX_FMT_RGB565:
984         case V4L2_PIX_FMT_RGB565X:
985           bpp = depth = 16;
986           endianness =
987               fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
988           r_mask = 0xf800;
989           g_mask = 0x07e0;
990           b_mask = 0x001f;
991           break;
992         case V4L2_PIX_FMT_RGB24:
993           bpp = depth = 24;
994           endianness = G_BIG_ENDIAN;
995           r_mask = 0xff0000;
996           g_mask = 0x00ff00;
997           b_mask = 0x0000ff;
998           break;
999         case V4L2_PIX_FMT_BGR24:
1000           bpp = depth = 24;
1001           endianness = G_BIG_ENDIAN;
1002           r_mask = 0x0000ff;
1003           g_mask = 0x00ff00;
1004           b_mask = 0xff0000;
1005           break;
1006         case V4L2_PIX_FMT_RGB32:
1007           bpp = depth = 32;
1008           endianness = G_BIG_ENDIAN;
1009           r_mask = 0xff000000;
1010           g_mask = 0x00ff0000;
1011           b_mask = 0x0000ff00;
1012           break;
1013         case V4L2_PIX_FMT_BGR32:
1014           bpp = depth = 32;
1015           endianness = G_BIG_ENDIAN;
1016           r_mask = 0x000000ff;
1017           g_mask = 0x0000ff00;
1018           b_mask = 0x00ff0000;
1019           break;
1020         default:
1021           g_assert_not_reached ();
1022           break;
1023       }
1024       structure = gst_structure_new ("video/x-raw-rgb",
1025           "bpp", G_TYPE_INT, bpp,
1026           "depth", G_TYPE_INT, depth,
1027           "red_mask", G_TYPE_INT, r_mask,
1028           "green_mask", G_TYPE_INT, g_mask,
1029           "blue_mask", G_TYPE_INT, b_mask,
1030           "endianness", G_TYPE_INT, endianness, NULL);
1031       break;
1032     }
1033     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
1034       structure = gst_structure_new ("video/x-raw-gray",
1035           "bpp", G_TYPE_INT, 8, NULL);
1036       break;
1037     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
1038     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
1039       /* FIXME: get correct fourccs here */
1040       break;
1041     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
1042     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
1043     case V4L2_PIX_FMT_YVU410:
1044     case V4L2_PIX_FMT_YUV410:
1045     case V4L2_PIX_FMT_YUV420:  /* I420/IYUV */
1046     case V4L2_PIX_FMT_YUYV:
1047     case V4L2_PIX_FMT_YVU420:
1048     case V4L2_PIX_FMT_UYVY:
1049     case V4L2_PIX_FMT_Y41P:
1050     case V4L2_PIX_FMT_YUV422P:
1051 #ifdef V4L2_PIX_FMT_YVYU
1052     case V4L2_PIX_FMT_YVYU:
1053 #endif
1054     case V4L2_PIX_FMT_YUV411P:{
1055       guint32 fcc = 0;
1056
1057       switch (fourcc) {
1058         case V4L2_PIX_FMT_NV12:
1059           fcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
1060           break;
1061         case V4L2_PIX_FMT_NV21:
1062           fcc = GST_MAKE_FOURCC ('N', 'V', '2', '1');
1063           break;
1064         case V4L2_PIX_FMT_YVU410:
1065           fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
1066           break;
1067         case V4L2_PIX_FMT_YUV410:
1068           fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
1069           break;
1070         case V4L2_PIX_FMT_YUV420:
1071           fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
1072           break;
1073         case V4L2_PIX_FMT_YUYV:
1074           fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
1075           break;
1076         case V4L2_PIX_FMT_YVU420:
1077           fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
1078           break;
1079         case V4L2_PIX_FMT_UYVY:
1080           fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
1081           break;
1082         case V4L2_PIX_FMT_Y41P:
1083           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
1084           break;
1085         case V4L2_PIX_FMT_YUV411P:
1086           fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
1087           break;
1088         case V4L2_PIX_FMT_YUV422P:
1089           fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
1090           break;
1091 #ifdef V4L2_PIX_FMT_YVYU
1092         case V4L2_PIX_FMT_YVYU:
1093           fcc = GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U');
1094           break;
1095 #endif
1096         default:
1097           g_assert_not_reached ();
1098           break;
1099       }
1100       structure = gst_structure_new ("video/x-raw-yuv",
1101           "format", GST_TYPE_FOURCC, fcc, NULL);
1102       break;
1103     }
1104     case V4L2_PIX_FMT_DV:
1105       structure =
1106           gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1107           NULL);
1108       break;
1109     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
1110       structure = gst_structure_new ("video/mpegts", NULL);
1111       break;
1112     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
1113       break;
1114 #ifdef V4L2_PIX_FMT_SBGGR8
1115     case V4L2_PIX_FMT_SBGGR8:
1116       structure = gst_structure_new ("video/x-raw-bayer", NULL);
1117       break;
1118 #endif
1119 #ifdef V4L2_PIX_FMT_SN9C10X
1120     case V4L2_PIX_FMT_SN9C10X:
1121       structure = gst_structure_new ("video/x-sonix", NULL);
1122       break;
1123 #endif
1124 #ifdef V4L2_PIX_FMT_PWC1
1125     case V4L2_PIX_FMT_PWC1:
1126       structure = gst_structure_new ("video/x-pwc1", NULL);
1127       break;
1128 #endif
1129 #ifdef V4L2_PIX_FMT_PWC2
1130     case V4L2_PIX_FMT_PWC2:
1131       structure = gst_structure_new ("video/x-pwc2", NULL);
1132       break;
1133 #endif
1134     default:
1135       GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
1136           fourcc, GST_FOURCC_ARGS (fourcc));
1137       break;
1138   }
1139
1140   return structure;
1141 }
1142
1143
1144
1145 GstCaps *
1146 gst_v4l2_object_get_all_caps (void)
1147 {
1148   static GstCaps *caps = NULL;
1149
1150   if (caps == NULL) {
1151     GstStructure *structure;
1152
1153     guint i;
1154
1155     caps = gst_caps_new_empty ();
1156     for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
1157       structure =
1158           gst_v4l2_object_v4l2fourcc_to_structure (gst_v4l2_formats[i].format);
1159       if (structure) {
1160         if (gst_v4l2_formats[i].dimensions) {
1161           gst_structure_set (structure,
1162               "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
1163               "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
1164               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL);
1165         }
1166         gst_caps_append_structure (caps, structure);
1167       }
1168     }
1169   }
1170
1171   return gst_caps_ref (caps);
1172 }
1173
1174
1175 /* collect data for the given caps
1176  * @caps: given input caps
1177  * @format: location for the v4l format
1178  * @w/@h: location for width and height
1179  * @fps_n/@fps_d: location for framerate
1180  * @size: location for expected size of the frame or 0 if unknown
1181  */
1182 gboolean
1183 gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
1184     struct v4l2_fmtdesc ** format, gint * w, gint * h, guint * fps_n,
1185     guint * fps_d, guint * size)
1186 {
1187   GstStructure *structure;
1188   const GValue *framerate;
1189   guint32 fourcc;
1190   const gchar *mimetype;
1191   guint outsize;
1192
1193   /* default unknown values */
1194   fourcc = 0;
1195   outsize = 0;
1196
1197   structure = gst_caps_get_structure (caps, 0);
1198
1199   mimetype = gst_structure_get_name (structure);
1200
1201   if (strcmp (mimetype, "video/mpegts") == 0) {
1202     fourcc = V4L2_PIX_FMT_MPEG;
1203     outsize = 8192;
1204     *fps_n = 0;
1205     *fps_d = 1;
1206     goto done;
1207   }
1208
1209   if (!gst_structure_get_int (structure, "width", w))
1210     return FALSE;
1211
1212   if (!gst_structure_get_int (structure, "height", h))
1213     return FALSE;
1214
1215   framerate = gst_structure_get_value (structure, "framerate");
1216   if (!framerate)
1217     return FALSE;
1218
1219   *fps_n = gst_value_get_fraction_numerator (framerate);
1220   *fps_d = gst_value_get_fraction_denominator (framerate);
1221
1222   if (!strcmp (mimetype, "video/x-raw-yuv")) {
1223     gst_structure_get_fourcc (structure, "format", &fourcc);
1224
1225     switch (fourcc) {
1226       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
1227       case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
1228         fourcc = V4L2_PIX_FMT_YUV420;
1229         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
1230         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
1231         break;
1232       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
1233         fourcc = V4L2_PIX_FMT_YUYV;
1234         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
1235         break;
1236       case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
1237         fourcc = V4L2_PIX_FMT_Y41P;
1238         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
1239         break;
1240       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
1241         fourcc = V4L2_PIX_FMT_UYVY;
1242         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
1243         break;
1244       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
1245         fourcc = V4L2_PIX_FMT_YVU420;
1246         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
1247         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
1248         break;
1249       case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
1250         fourcc = V4L2_PIX_FMT_YUV411P;
1251         outsize = GST_ROUND_UP_4 (*w) * *h;
1252         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h);
1253         break;
1254       case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
1255         fourcc = V4L2_PIX_FMT_YUV422P;
1256         outsize = GST_ROUND_UP_4 (*w) * *h;
1257         outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h);
1258         break;
1259       case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
1260         fourcc = V4L2_PIX_FMT_NV12;
1261         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
1262         outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
1263         break;
1264       case GST_MAKE_FOURCC ('N', 'V', '2', '1'):
1265         fourcc = V4L2_PIX_FMT_NV21;
1266         outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
1267         outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
1268         break;
1269 #ifdef V4L2_PIX_FMT_YVYU
1270       case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
1271         fourcc = V4L2_PIX_FMT_YVYU;
1272         outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
1273         break;
1274 #endif
1275     }
1276   } else if (!strcmp (mimetype, "video/x-raw-rgb")) {
1277     gint depth, endianness, r_mask;
1278
1279     gst_structure_get_int (structure, "depth", &depth);
1280     gst_structure_get_int (structure, "endianness", &endianness);
1281     gst_structure_get_int (structure, "red_mask", &r_mask);
1282
1283     switch (depth) {
1284       case 8:
1285         fourcc = V4L2_PIX_FMT_RGB332;
1286         break;
1287       case 15:
1288         fourcc = (endianness == G_LITTLE_ENDIAN) ?
1289             V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
1290         break;
1291       case 16:
1292         fourcc = (endianness == G_LITTLE_ENDIAN) ?
1293             V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
1294         break;
1295       case 24:
1296         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
1297         break;
1298       case 32:
1299         fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
1300         break;
1301     }
1302   } else if (strcmp (mimetype, "video/x-dv") == 0) {
1303     fourcc = V4L2_PIX_FMT_DV;
1304   } else if (strcmp (mimetype, "image/jpeg") == 0) {
1305     fourcc = V4L2_PIX_FMT_JPEG;
1306 #ifdef V4L2_PIX_FMT_SBGGR8
1307   } else if (strcmp (mimetype, "video/x-raw-bayer") == 0) {
1308     fourcc = V4L2_PIX_FMT_SBGGR8;
1309 #endif
1310 #ifdef V4L2_PIX_FMT_SN9C10X
1311   } else if (strcmp (mimetype, "video/x-sonix") == 0) {
1312     fourcc = V4L2_PIX_FMT_SN9C10X;
1313 #endif
1314 #ifdef V4L2_PIX_FMT_PWC1
1315   } else if (strcmp (mimetype, "video/x-pwc1") == 0) {
1316     fourcc = V4L2_PIX_FMT_PWC1;
1317 #endif
1318 #ifdef V4L2_PIX_FMT_PWC2
1319   } else if (strcmp (mimetype, "video/x-pwc2") == 0) {
1320     fourcc = V4L2_PIX_FMT_PWC2;
1321 #endif
1322   } else if (strcmp (mimetype, "video/x-raw-gray") == 0) {
1323     fourcc = V4L2_PIX_FMT_GREY;
1324   }
1325
1326   if (fourcc == 0)
1327     return FALSE;
1328
1329 done:
1330   *format = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
1331   *size = outsize;
1332
1333   return TRUE;
1334 }
1335
1336
1337
1338 /* The frame interval enumeration code first appeared in Linux 2.6.19. */
1339 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
1340 static GstStructure *
1341 gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
1342     guint32 pixelformat,
1343     guint32 width, guint32 height, const GstStructure * template)
1344 {
1345   gint fd = v4l2object->video_fd;
1346   struct v4l2_frmivalenum ival;
1347   guint32 num, denom;
1348   GstStructure *s;
1349   GValue rates = { 0, };
1350
1351   memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
1352   ival.index = 0;
1353   ival.pixel_format = pixelformat;
1354   ival.width = width;
1355   ival.height = height;
1356
1357   GST_LOG_OBJECT (v4l2object->element,
1358       "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
1359       GST_FOURCC_ARGS (pixelformat));
1360
1361   /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
1362    * fraction to get framerate */
1363   if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
1364     goto enum_frameintervals_failed;
1365
1366   if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
1367     GValue rate = { 0, };
1368
1369     g_value_init (&rates, GST_TYPE_LIST);
1370     g_value_init (&rate, GST_TYPE_FRACTION);
1371
1372     do {
1373       num = ival.discrete.numerator;
1374       denom = ival.discrete.denominator;
1375
1376       if (num > G_MAXINT || denom > G_MAXINT) {
1377         /* let us hope we don't get here... */
1378         num >>= 1;
1379         denom >>= 1;
1380       }
1381
1382       GST_LOG_OBJECT (v4l2object->element, "adding discrete framerate: %d/%d",
1383           denom, num);
1384
1385       /* swap to get the framerate */
1386       gst_value_set_fraction (&rate, denom, num);
1387       gst_value_list_append_value (&rates, &rate);
1388
1389       ival.index++;
1390     } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
1391   } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
1392     GValue min = { 0, };
1393     GValue step = { 0, };
1394     GValue max = { 0, };
1395     gboolean added = FALSE;
1396     guint32 minnum, mindenom;
1397     guint32 maxnum, maxdenom;
1398
1399     g_value_init (&rates, GST_TYPE_LIST);
1400
1401     g_value_init (&min, GST_TYPE_FRACTION);
1402     g_value_init (&step, GST_TYPE_FRACTION);
1403     g_value_init (&max, GST_TYPE_FRACTION);
1404
1405     /* get the min */
1406     minnum = ival.stepwise.min.numerator;
1407     mindenom = ival.stepwise.min.denominator;
1408     if (minnum > G_MAXINT || mindenom > G_MAXINT) {
1409       minnum >>= 1;
1410       mindenom >>= 1;
1411     }
1412     GST_LOG_OBJECT (v4l2object->element, "stepwise min frame interval: %d/%d",
1413         minnum, mindenom);
1414     gst_value_set_fraction (&min, minnum, mindenom);
1415
1416     /* get the max */
1417     maxnum = ival.stepwise.max.numerator;
1418     maxdenom = ival.stepwise.max.denominator;
1419     if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
1420       maxnum >>= 1;
1421       maxdenom >>= 1;
1422     }
1423
1424     GST_LOG_OBJECT (v4l2object->element, "stepwise max frame interval: %d/%d",
1425         maxnum, maxdenom);
1426     gst_value_set_fraction (&max, maxnum, maxdenom);
1427
1428     /* get the step */
1429     num = ival.stepwise.step.numerator;
1430     denom = ival.stepwise.step.denominator;
1431     if (num > G_MAXINT || denom > G_MAXINT) {
1432       num >>= 1;
1433       denom >>= 1;
1434     }
1435
1436     if (num == 0 || denom == 0) {
1437       /* in this case we have a wrong fraction or no step, set the step to max
1438        * so that we only add the min value in the loop below */
1439       num = maxnum;
1440       denom = maxdenom;
1441     }
1442
1443     /* since we only have gst_value_fraction_subtract and not add, negate the
1444      * numerator */
1445     GST_LOG_OBJECT (v4l2object->element, "stepwise step frame interval: %d/%d",
1446         num, denom);
1447     gst_value_set_fraction (&step, -num, denom);
1448
1449     while (gst_value_compare (&min, &max) <= 0) {
1450       GValue rate = { 0, };
1451
1452       num = gst_value_get_fraction_numerator (&min);
1453       denom = gst_value_get_fraction_denominator (&min);
1454       GST_LOG_OBJECT (v4l2object->element, "adding stepwise framerate: %d/%d",
1455           denom, num);
1456
1457       /* invert to get the framerate */
1458       g_value_init (&rate, GST_TYPE_FRACTION);
1459       gst_value_set_fraction (&rate, denom, num);
1460       gst_value_list_append_value (&rates, &rate);
1461       added = TRUE;
1462
1463       /* we're actually adding because step was negated above. This is because
1464        * there is no _add function... */
1465       if (!gst_value_fraction_subtract (&min, &min, &step)) {
1466         GST_WARNING_OBJECT (v4l2object->element, "could not step fraction!");
1467         break;
1468       }
1469     }
1470     if (!added) {
1471       /* no range was added, leave the default range from the template */
1472       GST_WARNING_OBJECT (v4l2object->element,
1473           "no range added, leaving default");
1474       g_value_unset (&rates);
1475     }
1476   } else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
1477     guint32 maxnum, maxdenom;
1478
1479     g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
1480
1481     num = ival.stepwise.min.numerator;
1482     denom = ival.stepwise.min.denominator;
1483     if (num > G_MAXINT || denom > G_MAXINT) {
1484       num >>= 1;
1485       denom >>= 1;
1486     }
1487
1488     maxnum = ival.stepwise.max.numerator;
1489     maxdenom = ival.stepwise.max.denominator;
1490     if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
1491       maxnum >>= 1;
1492       maxdenom >>= 1;
1493     }
1494
1495     GST_LOG_OBJECT (v4l2object->element,
1496         "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
1497         num);
1498
1499     gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
1500   } else {
1501     goto unknown_type;
1502   }
1503
1504 return_data:
1505   s = gst_structure_copy (template);
1506   gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
1507       "height", G_TYPE_INT, (gint) height, NULL);
1508
1509   if (G_IS_VALUE (&rates)) {
1510     /* only change the framerate on the template when we have a valid probed new
1511      * value */
1512     gst_structure_set_value (s, "framerate", &rates);
1513     g_value_unset (&rates);
1514   } else {
1515     gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1,
1516         NULL);
1517   }
1518   return s;
1519
1520   /* ERRORS */
1521 enum_frameintervals_failed:
1522   {
1523     GST_DEBUG_OBJECT (v4l2object->element,
1524         "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
1525         GST_FOURCC_ARGS (pixelformat), width, height);
1526     goto return_data;
1527   }
1528 unknown_type:
1529   {
1530     /* I don't see how this is actually an error, we ignore the format then */
1531     GST_WARNING_OBJECT (v4l2object->element,
1532         "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
1533         GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
1534     return NULL;
1535   }
1536 }
1537 #endif /* defined VIDIOC_ENUM_FRAMEINTERVALS */
1538
1539 #ifdef VIDIOC_ENUM_FRAMESIZES
1540 static gint
1541 sort_by_frame_size (GstStructure * s1, GstStructure * s2)
1542 {
1543   int w1, h1, w2, h2;
1544
1545   gst_structure_get_int (s1, "width", &w1);
1546   gst_structure_get_int (s1, "height", &h1);
1547   gst_structure_get_int (s2, "width", &w2);
1548   gst_structure_get_int (s2, "height", &h2);
1549
1550   /* I think it's safe to assume that this won't overflow for a while */
1551   return ((w2 * h2) - (w1 * h1));
1552 }
1553 #endif
1554
1555 static gboolean
1556 gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
1557     guint32 pixelformat, gint * width, gint * height);
1558
1559 GstCaps *
1560 gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
1561     guint32 pixelformat, const GstStructure * template)
1562 {
1563   GstCaps *ret = gst_caps_new_empty ();
1564   GstStructure *tmp;
1565
1566 #ifdef VIDIOC_ENUM_FRAMESIZES
1567   gint fd = v4l2object->video_fd;
1568   struct v4l2_frmsizeenum size;
1569   GList *results = NULL;
1570   guint32 w, h;
1571
1572   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
1573     return gst_caps_new_simple ("video/mpegts", NULL);
1574
1575   memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
1576   size.index = 0;
1577   size.pixel_format = pixelformat;
1578
1579   GST_DEBUG_OBJECT (v4l2object->element, "Enumerating frame sizes");
1580
1581   if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
1582     goto enum_framesizes_failed;
1583
1584   if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
1585     do {
1586       GST_LOG_OBJECT (v4l2object->element, "got discrete frame size %dx%d",
1587           size.discrete.width, size.discrete.height);
1588
1589       w = MIN (size.discrete.width, G_MAXINT);
1590       h = MIN (size.discrete.height, G_MAXINT);
1591
1592       if (w && h) {
1593         tmp =
1594             gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
1595             pixelformat, w, h, template);
1596
1597         if (tmp)
1598           results = g_list_prepend (results, tmp);
1599       }
1600
1601       size.index++;
1602     } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
1603     GST_DEBUG_OBJECT (v4l2object->element,
1604         "done iterating discrete frame sizes");
1605   } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
1606     GST_DEBUG_OBJECT (v4l2object->element, "we have stepwise frame sizes:");
1607     GST_DEBUG_OBJECT (v4l2object->element, "min width:   %d",
1608         size.stepwise.min_width);
1609     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
1610         size.stepwise.min_height);
1611     GST_DEBUG_OBJECT (v4l2object->element, "max width:   %d",
1612         size.stepwise.max_width);
1613     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
1614         size.stepwise.max_height);
1615     GST_DEBUG_OBJECT (v4l2object->element, "step width:  %d",
1616         size.stepwise.step_width);
1617     GST_DEBUG_OBJECT (v4l2object->element, "step height: %d",
1618         size.stepwise.step_height);
1619
1620     for (w = size.stepwise.min_width, h = size.stepwise.min_height;
1621         w < size.stepwise.max_width && h < size.stepwise.max_height;
1622         w += size.stepwise.step_width, h += size.stepwise.step_height) {
1623       if (w == 0 || h == 0)
1624         continue;
1625
1626       tmp =
1627           gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
1628           pixelformat, w, h, template);
1629
1630       if (tmp)
1631         results = g_list_prepend (results, tmp);
1632     }
1633     GST_DEBUG_OBJECT (v4l2object->element,
1634         "done iterating stepwise frame sizes");
1635   } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
1636     guint32 maxw, maxh;
1637
1638     GST_DEBUG_OBJECT (v4l2object->element, "we have continuous frame sizes:");
1639     GST_DEBUG_OBJECT (v4l2object->element, "min width:   %d",
1640         size.stepwise.min_width);
1641     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
1642         size.stepwise.min_height);
1643     GST_DEBUG_OBJECT (v4l2object->element, "max width:   %d",
1644         size.stepwise.max_width);
1645     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
1646         size.stepwise.max_height);
1647
1648     w = MAX (size.stepwise.min_width, 1);
1649     h = MAX (size.stepwise.min_height, 1);
1650     maxw = MIN (size.stepwise.max_width, G_MAXINT);
1651     maxh = MIN (size.stepwise.max_height, G_MAXINT);
1652
1653     tmp =
1654         gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
1655         w, h, template);
1656     if (tmp) {
1657       gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
1658           (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
1659           NULL);
1660
1661       /* no point using the results list here, since there's only one struct */
1662       gst_caps_append_structure (ret, tmp);
1663     }
1664   } else {
1665     goto unknown_type;
1666   }
1667
1668   /* we use an intermediary list to store and then sort the results of the
1669    * probing because we can't make any assumptions about the order in which
1670    * the driver will give us the sizes, but we want the final caps to contain
1671    * the results starting with the highest resolution and having the lowest
1672    * resolution last, since order in caps matters for things like fixation. */
1673   results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
1674   while (results != NULL) {
1675     gst_caps_append_structure (ret, GST_STRUCTURE (results->data));
1676     results = g_list_delete_link (results, results);
1677   }
1678
1679   if (gst_caps_is_empty (ret))
1680     goto enum_framesizes_no_results;
1681
1682   return ret;
1683
1684   /* ERRORS */
1685 enum_framesizes_failed:
1686   {
1687     /* I don't see how this is actually an error */
1688     GST_DEBUG_OBJECT (v4l2object->element,
1689         "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
1690         " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
1691     goto default_frame_sizes;
1692   }
1693 enum_framesizes_no_results:
1694   {
1695     /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
1696      * question doesn't actually support it yet */
1697     GST_DEBUG_OBJECT (v4l2object->element,
1698         "No results for pixelformat %" GST_FOURCC_FORMAT
1699         " enumerating frame sizes, trying fallback",
1700         GST_FOURCC_ARGS (pixelformat));
1701     goto default_frame_sizes;
1702   }
1703 unknown_type:
1704   {
1705     GST_WARNING_OBJECT (v4l2object->element,
1706         "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
1707         ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
1708     goto default_frame_sizes;
1709   }
1710 default_frame_sizes:
1711 #endif /* defined VIDIOC_ENUM_FRAMESIZES */
1712   {
1713     gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0;
1714
1715     /* This code is for Linux < 2.6.19 */
1716     min_w = min_h = 1;
1717     max_w = max_h = GST_V4L2_MAX_SIZE;
1718     if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
1719             &min_h)) {
1720       GST_WARNING_OBJECT (v4l2object->element,
1721           "Could not probe minimum capture size for pixelformat %"
1722           GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
1723     }
1724     if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
1725             &max_h)) {
1726       GST_WARNING_OBJECT (v4l2object->element,
1727           "Could not probe maximum capture size for pixelformat %"
1728           GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
1729     }
1730
1731     /* Since we can't get framerate directly, try to use the current norm */
1732     if (v4l2object->norm && v4l2object->norms) {
1733       GList *norms;
1734       GstTunerNorm *norm;
1735
1736       for (norms = v4l2object->norms; norms != NULL; norms = norms->next) {
1737         norm = (GstTunerNorm *) norms->data;
1738         if (!strcmp (norm->label, v4l2object->norm))
1739           break;
1740       }
1741       /* If it's possible, set framerate to that (discrete) value */
1742       if (norm) {
1743         fix_num = gst_value_get_fraction_numerator (&norm->framerate);
1744         fix_denom = gst_value_get_fraction_denominator (&norm->framerate);
1745       }
1746     }
1747
1748     tmp = gst_structure_copy (template);
1749     if (fix_num) {
1750       gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
1751           fix_denom, NULL);
1752     } else {
1753       /* if norm can't be used, copy the template framerate */
1754       gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
1755           100, 1, NULL);
1756     }
1757
1758     if (min_w == max_w)
1759       gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
1760     else
1761       gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
1762
1763     if (min_h == max_h)
1764       gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
1765     else
1766       gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
1767
1768     gst_caps_append_structure (ret, tmp);
1769
1770     return ret;
1771   }
1772 }
1773
1774 static gboolean
1775 gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
1776     guint32 pixelformat, gint * width, gint * height)
1777 {
1778   struct v4l2_format fmt;
1779   int fd;
1780   int r;
1781
1782   g_return_val_if_fail (width != NULL, FALSE);
1783   g_return_val_if_fail (height != NULL, FALSE);
1784
1785   GST_LOG_OBJECT (v4l2object->element,
1786       "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
1787       *width, *height, GST_FOURCC_ARGS (pixelformat));
1788
1789   fd = v4l2object->video_fd;
1790
1791   /* get size delimiters */
1792   memset (&fmt, 0, sizeof (fmt));
1793   fmt.type = v4l2object->type;
1794   fmt.fmt.pix.width = *width;
1795   fmt.fmt.pix.height = *height;
1796   fmt.fmt.pix.pixelformat = pixelformat;
1797   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
1798
1799   r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
1800   if (r < 0 && errno == EINVAL) {
1801     /* try again with progressive video */
1802     fmt.fmt.pix.width = *width;
1803     fmt.fmt.pix.height = *height;
1804     fmt.fmt.pix.pixelformat = pixelformat;
1805     fmt.fmt.pix.field = V4L2_FIELD_NONE;
1806     r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
1807   }
1808
1809   if (r < 0) {
1810     /* The driver might not implement TRY_FMT, in which case we will try
1811        S_FMT to probe */
1812     if (errno != ENOTTY)
1813       return FALSE;
1814
1815     /* Only try S_FMT if we're not actively capturing yet, which we shouldn't
1816        be, because we're still probing */
1817     if (GST_V4L2_IS_ACTIVE (v4l2object))
1818       return FALSE;
1819
1820     GST_LOG_OBJECT (v4l2object->element,
1821         "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT");
1822
1823     fmt.fmt.pix.width = *width;
1824     fmt.fmt.pix.height = *height;
1825
1826     r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
1827     if (r < 0 && errno == EINVAL) {
1828       /* try again with progressive video */
1829       fmt.fmt.pix.width = *width;
1830       fmt.fmt.pix.height = *height;
1831       fmt.fmt.pix.pixelformat = pixelformat;
1832       fmt.fmt.pix.field = V4L2_FIELD_NONE;
1833       r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
1834     }
1835
1836     if (r < 0)
1837       return FALSE;
1838   }
1839
1840   GST_LOG_OBJECT (v4l2object->element,
1841       "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
1842
1843   *width = fmt.fmt.pix.width;
1844   *height = fmt.fmt.pix.height;
1845
1846   return TRUE;
1847 }
1848
1849
1850 gboolean
1851 gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
1852     guint32 width, guint32 height)
1853 {
1854   gint fd = v4l2object->video_fd;
1855   struct v4l2_format format;
1856
1857   GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
1858       "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
1859
1860   GST_V4L2_CHECK_OPEN (v4l2object);
1861   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
1862
1863   memset (&format, 0x00, sizeof (struct v4l2_format));
1864   format.type = v4l2object->type;
1865
1866   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
1867     return TRUE;
1868
1869   if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0)
1870     goto get_fmt_failed;
1871
1872   format.type = v4l2object->type;
1873   format.fmt.pix.width = width;
1874   format.fmt.pix.height = height;
1875   format.fmt.pix.pixelformat = pixelformat;
1876   /* request whole frames; change when gstreamer supports interlaced video
1877    * (INTERLACED mode returns frames where the fields have already been
1878    *  combined, there are other modes for requesting fields individually) */
1879   format.fmt.pix.field = V4L2_FIELD_INTERLACED;
1880
1881   if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) {
1882     if (errno != EINVAL)
1883       goto set_fmt_failed;
1884
1885     GST_DEBUG_OBJECT (v4l2object->element, "trying again...");
1886
1887     /* try again with progressive video */
1888     format.fmt.pix.width = width;
1889     format.fmt.pix.height = height;
1890     format.fmt.pix.pixelformat = pixelformat;
1891     format.fmt.pix.field = V4L2_FIELD_NONE;
1892     if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0)
1893       goto set_fmt_failed;
1894   }
1895
1896   if (format.fmt.pix.width != width || format.fmt.pix.height != height)
1897     goto invalid_dimensions;
1898
1899   if (format.fmt.pix.pixelformat != pixelformat)
1900     goto invalid_pixelformat;
1901
1902   return TRUE;
1903
1904   /* ERRORS */
1905 get_fmt_failed:
1906   {
1907     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1908         (_("Device '%s' does not support video capture"),
1909             v4l2object->videodev),
1910         ("Call to G_FMT failed: (%s)", g_strerror (errno)));
1911     return FALSE;
1912   }
1913 set_fmt_failed:
1914   {
1915     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1916         (_("Device '%s' cannot capture at %dx%d"),
1917             v4l2object->videodev, width, height),
1918         ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
1919             GST_FOURCC_ARGS (pixelformat), width, height, g_strerror (errno)));
1920     return FALSE;
1921   }
1922 invalid_dimensions:
1923   {
1924     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1925         (_("Device '%s' cannot capture at %dx%d"),
1926             v4l2object->videodev, width, height),
1927         ("Tried to capture at %dx%d, but device returned size %dx%d",
1928             width, height, format.fmt.pix.width, format.fmt.pix.height));
1929     return FALSE;
1930   }
1931 invalid_pixelformat:
1932   {
1933     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1934         (_("Device '%s' cannot capture in the specified format"),
1935             v4l2object->videodev),
1936         ("Tried to capture in %" GST_FOURCC_FORMAT
1937             ", but device returned format" " %" GST_FOURCC_FORMAT,
1938             GST_FOURCC_ARGS (pixelformat),
1939             GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
1940     return FALSE;
1941   }
1942 }
1943
1944 gboolean
1945 gst_v4l2_object_start_streaming (GstV4l2Object * v4l2object)
1946 {
1947   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMON,
1948           &(v4l2object->type)) < 0) {
1949     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
1950         (_("Error starting streaming on device '%s'."), v4l2object->videodev),
1951         GST_ERROR_SYSTEM);
1952     return FALSE;
1953   }
1954   return TRUE;
1955 }
1956
1957 gboolean
1958 gst_v4l2_object_stop_streaming (GstV4l2Object * v4l2object)
1959 {
1960   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMOFF,
1961           &(v4l2object->type)) < 0) {
1962     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
1963         (_("Error stopping streaming on device '%s'."), v4l2object->videodev),
1964         GST_ERROR_SYSTEM);
1965     return FALSE;
1966   }
1967   return TRUE;
1968 }