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