v4l2object: Don't enforce dimension field on encoded formats
[platform/upstream/gst-plugins-good.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
18  * USA.
19  */
20
21 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
22  * with newer GLib versions (>= 2.31.0) */
23 #define GLIB_DISABLE_DEPRECATION_WARNINGS
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <string.h>
34
35 #ifdef HAVE_GUDEV
36 #include <gudev/gudev.h>
37 #endif
38
39 #include "v4l2_calls.h"
40 #include "gstv4l2tuner.h"
41 #ifdef HAVE_XVIDEO
42 #include "gstv4l2videooverlay.h"
43 #endif
44 #include "gstv4l2colorbalance.h"
45
46 #include "gst/gst-i18n-plugin.h"
47
48 #include <gst/video/video.h>
49
50 /* videodev2.h is not versioned and we can't easily check for the presence
51  * of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
52  * was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */
53 #ifndef V4L2_CAP_VIDEO_OUTPUT_OVERLAY
54 #define V4L2_FIELD_INTERLACED_TB 8
55 #define V4L2_FIELD_INTERLACED_BT 9
56 #endif
57
58 #ifndef V4L2_PIX_FMT_NV12M
59 #define V4L2_PIX_FMT_NV12M GST_MAKE_FOURCC ('N', 'M', '1', '2')
60 #endif
61 #ifndef V4L2_PIX_FMT_NV21M
62 #define V4L2_PIX_FMT_NV21M GST_MAKE_FOURCC ('N', 'M', '2', '1')
63 #endif
64 #ifndef V4L2_PIX_FMT_MPEG1
65 #define V4L2_PIX_FMT_MPEG1 GST_MAKE_FOURCC ('M', 'P', 'G', '1')
66 #endif
67 #ifndef V4L2_PIX_FMT_MPEG2
68 #define V4L2_PIX_FMT_MPEG2 GST_MAKE_FOURCC ('M', 'P', 'G', '2')
69 #endif
70 #ifndef V4L2_PIX_FMT_MPEG4
71 #define V4L2_PIX_FMT_MPEG4 GST_MAKE_FOURCC ('M', 'P', 'G', '4')
72 #endif
73
74 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
75 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
76 #define GST_CAT_DEFAULT v4l2_debug
77
78 #define DEFAULT_PROP_DEVICE_NAME        NULL
79 #define DEFAULT_PROP_DEVICE_FD          -1
80 #define DEFAULT_PROP_FLAGS              0
81 #define DEFAULT_PROP_TV_NORM            0
82 #define DEFAULT_PROP_CHANNEL            NULL
83 #define DEFAULT_PROP_FREQUENCY          0
84 #define DEFAULT_PROP_IO_MODE            GST_V4L2_IO_AUTO
85
86 #define ENCODED_BUFFER_SIZE             (1 * 1024 * 1024)
87
88 enum
89 {
90   PROP_0,
91   V4L2_STD_OBJECT_PROPS,
92 };
93
94 static GSList *gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object);
95
96 #if 0
97 G_LOCK_DEFINE_STATIC (probe_lock);
98
99 const GList *
100 gst_v4l2_probe_get_properties (GstPropertyProbe * probe)
101 {
102   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
103   static GList *list = NULL;
104
105   G_LOCK (probe_lock);
106
107   if (!list) {
108     list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
109   }
110
111   G_UNLOCK (probe_lock);
112
113   return list;
114 }
115
116 static gboolean init = FALSE;
117 static GList *devices = NULL;
118
119 #ifdef HAVE_GUDEV
120 static gboolean
121 gst_v4l2_class_probe_devices_with_udev (GstElementClass * klass, gboolean check,
122     GList ** klass_devices)
123 {
124   GUdevClient *client = NULL;
125   GList *item;
126
127   if (!check) {
128     while (devices) {
129       gchar *device = devices->data;
130       devices = g_list_remove (devices, device);
131       g_free (device);
132     }
133
134     GST_INFO ("Enumerating video4linux devices from udev");
135     client = g_udev_client_new (NULL);
136     if (!client) {
137       GST_WARNING ("Failed to initialize gudev client");
138       goto finish;
139     }
140
141     item = g_udev_client_query_by_subsystem (client, "video4linux");
142     while (item) {
143       GUdevDevice *device = item->data;
144       gchar *devnode = g_strdup (g_udev_device_get_device_file (device));
145       gint api = g_udev_device_get_property_as_int (device, "ID_V4L_VERSION");
146       GST_INFO ("Found new device: %s, API: %d", devnode, api);
147       /* Append v4l2 devices only. If api is 0 probably v4l_id has
148          been stripped out of the current udev installation, append
149          anyway */
150       if (api == 0) {
151         GST_WARNING
152             ("Couldn't retrieve ID_V4L_VERSION, silly udev installation?");
153       }
154       if ((api == 2 || api == 0)) {
155         devices = g_list_append (devices, devnode);
156       } else {
157         g_free (devnode);
158       }
159       g_object_unref (device);
160       item = item->next;
161     }
162     g_list_free (item);
163     init = TRUE;
164   }
165
166 finish:
167   if (client) {
168     g_object_unref (client);
169   }
170
171   *klass_devices = devices;
172
173   return init;
174 }
175 #endif /* HAVE_GUDEV */
176
177 static gboolean
178 gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check,
179     GList ** klass_devices)
180 {
181   if (!check) {
182     const gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL };
183     gint base, n, fd;
184
185     while (devices) {
186       gchar *device = devices->data;
187       devices = g_list_remove (devices, device);
188       g_free (device);
189     }
190
191     /*
192      * detect /dev entries
193      */
194     for (n = 0; n < 64; n++) {
195       for (base = 0; dev_base[base] != NULL; base++) {
196         struct stat s;
197         gchar *device = g_strdup_printf ("%s%d",
198             dev_base[base],
199             n);
200
201         /*
202          * does the /dev/ entry exist at all?
203          */
204         if (stat (device, &s) == 0) {
205           /*
206            * yes: is a device attached?
207            */
208           if (S_ISCHR (s.st_mode)) {
209
210             if ((fd = open (device, O_RDWR | O_NONBLOCK)) > 0 || errno == EBUSY) {
211               if (fd > 0)
212                 close (fd);
213
214               devices = g_list_append (devices, device);
215               break;
216             }
217           }
218         }
219         g_free (device);
220       }
221     }
222     init = TRUE;
223   }
224
225   *klass_devices = devices;
226
227   return init;
228 }
229
230 void
231 gst_v4l2_probe_probe_property (GstPropertyProbe * probe,
232     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
233 {
234   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
235
236   switch (prop_id) {
237     case PROP_DEVICE:
238 #ifdef HAVE_GUDEV
239       if (!gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices))
240         gst_v4l2_class_probe_devices (klass, FALSE, klass_devices);
241 #else /* !HAVE_GUDEV */
242       gst_v4l2_class_probe_devices (klass, FALSE, klass_devices);
243 #endif /* HAVE_GUDEV */
244       break;
245     default:
246       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
247       break;
248   }
249 }
250
251 gboolean
252 gst_v4l2_probe_needs_probe (GstPropertyProbe * probe,
253     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
254 {
255   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
256   gboolean ret = FALSE;
257
258   switch (prop_id) {
259     case PROP_DEVICE:
260 #ifdef HAVE_GUDEV
261       ret =
262           !gst_v4l2_class_probe_devices_with_udev (klass, FALSE, klass_devices);
263 #else /* !HAVE_GUDEV */
264       ret = !gst_v4l2_class_probe_devices (klass, TRUE, klass_devices);
265 #endif /* HAVE_GUDEV */
266       break;
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
269       break;
270   }
271   return ret;
272 }
273
274 static GValueArray *
275 gst_v4l2_class_list_devices (GstElementClass * klass, GList ** klass_devices)
276 {
277   GValueArray *array;
278   GValue value = { 0 };
279   GList *item;
280
281   if (!*klass_devices)
282     return NULL;
283
284   array = g_value_array_new (g_list_length (*klass_devices));
285   item = *klass_devices;
286   g_value_init (&value, G_TYPE_STRING);
287   while (item) {
288     gchar *device = item->data;
289
290     g_value_set_string (&value, device);
291     g_value_array_append (array, &value);
292
293     item = item->next;
294   }
295   g_value_unset (&value);
296
297   return array;
298 }
299
300 GValueArray *
301 gst_v4l2_probe_get_values (GstPropertyProbe * probe,
302     guint prop_id, const GParamSpec * pspec, GList ** klass_devices)
303 {
304   GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe);
305   GValueArray *array = NULL;
306
307   switch (prop_id) {
308     case PROP_DEVICE:
309       array = gst_v4l2_class_list_devices (klass, klass_devices);
310       break;
311     default:
312       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
313       break;
314   }
315
316   return array;
317 }
318 #endif
319
320 #define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ())
321 static GType
322 gst_v4l2_device_get_type (void)
323 {
324   static GType v4l2_device_type = 0;
325
326   if (v4l2_device_type == 0) {
327     static const GFlagsValue values[] = {
328       {V4L2_CAP_VIDEO_CAPTURE, "Device supports video capture", "capture"},
329       {V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
330       {V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
331
332       {V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
333       {V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
334
335       {V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
336       {V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
337
338       {0, NULL, NULL}
339     };
340
341     v4l2_device_type =
342         g_flags_register_static ("GstV4l2DeviceTypeFlags", values);
343   }
344
345   return v4l2_device_type;
346 }
347
348 #define GST_TYPE_V4L2_TV_NORM (gst_v4l2_tv_norm_get_type ())
349 static GType
350 gst_v4l2_tv_norm_get_type (void)
351 {
352   static GType v4l2_tv_norm = 0;
353
354   if (!v4l2_tv_norm) {
355     static const GEnumValue tv_norms[] = {
356       {0, "none", "none"},
357
358       {V4L2_STD_NTSC, "NTSC", "NTSC"},
359       {V4L2_STD_NTSC_M, "NTSC-M", "NTSC-M"},
360       {V4L2_STD_NTSC_M_JP, "NTSC-M-JP", "NTSC-M-JP"},
361       {V4L2_STD_NTSC_M_KR, "NTSC-M-KR", "NTSC-M-KR"},
362       {V4L2_STD_NTSC_443, "NTSC-443", "NTSC-443"},
363
364       {V4L2_STD_PAL, "PAL", "PAL"},
365       {V4L2_STD_PAL_BG, "PAL-BG", "PAL-BG"},
366       {V4L2_STD_PAL_B, "PAL-B", "PAL-B"},
367       {V4L2_STD_PAL_B1, "PAL-B1", "PAL-B1"},
368       {V4L2_STD_PAL_G, "PAL-G", "PAL-G"},
369       {V4L2_STD_PAL_H, "PAL-H", "PAL-H"},
370       {V4L2_STD_PAL_I, "PAL-I", "PAL-I"},
371       {V4L2_STD_PAL_DK, "PAL-DK", "PAL-DK"},
372       {V4L2_STD_PAL_D, "PAL-D", "PAL-D"},
373       {V4L2_STD_PAL_D1, "PAL-D1", "PAL-D1"},
374       {V4L2_STD_PAL_K, "PAL-K", "PAL-K"},
375       {V4L2_STD_PAL_M, "PAL-M", "PAL-M"},
376       {V4L2_STD_PAL_N, "PAL-N", "PAL-N"},
377       {V4L2_STD_PAL_Nc, "PAL-Nc", "PAL-Nc"},
378       {V4L2_STD_PAL_60, "PAL-60", "PAL-60"},
379
380       {V4L2_STD_SECAM, "SECAM", "SECAM"},
381       {V4L2_STD_SECAM_B, "SECAM-B", "SECAM-B"},
382       {V4L2_STD_SECAM_G, "SECAM-G", "SECAM-G"},
383       {V4L2_STD_SECAM_H, "SECAM-H", "SECAM-H"},
384       {V4L2_STD_SECAM_DK, "SECAM-DK", "SECAM-DK"},
385       {V4L2_STD_SECAM_D, "SECAM-D", "SECAM-D"},
386       {V4L2_STD_SECAM_K, "SECAM-K", "SECAM-K"},
387       {V4L2_STD_SECAM_K1, "SECAM-K1", "SECAM-K1"},
388       {V4L2_STD_SECAM_L, "SECAM-L", "SECAM-L"},
389       {V4L2_STD_SECAM_LC, "SECAM-Lc", "SECAM-Lc"},
390
391       {0, NULL, NULL}
392     };
393
394     v4l2_tv_norm = g_enum_register_static ("V4L2_TV_norms", tv_norms);
395   }
396
397   return v4l2_tv_norm;
398 }
399
400 GType
401 gst_v4l2_io_mode_get_type (void)
402 {
403   static GType v4l2_io_mode = 0;
404
405   if (!v4l2_io_mode) {
406     static const GEnumValue io_modes[] = {
407       {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
408       {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
409       {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
410       {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
411       {GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
412
413       {0, NULL, NULL}
414     };
415     v4l2_io_mode = g_enum_register_static ("GstV4l2IOMode", io_modes);
416   }
417   return v4l2_io_mode;
418 }
419
420 void
421 gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
422     const char *default_device)
423 {
424   g_object_class_install_property (gobject_class, PROP_DEVICE,
425       g_param_spec_string ("device", "Device", "Device location",
426           default_device, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
427   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
428       g_param_spec_string ("device-name", "Device name",
429           "Name of the device", DEFAULT_PROP_DEVICE_NAME,
430           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
431   g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
432       g_param_spec_int ("device-fd", "File descriptor",
433           "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
434           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
435   g_object_class_install_property (gobject_class, PROP_FLAGS,
436       g_param_spec_flags ("flags", "Flags", "Device type flags",
437           GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS,
438           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
439
440   /**
441    * GstV4l2Src:brightness:
442    *
443    * Picture brightness, or more precisely, the black level
444    */
445   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
446       g_param_spec_int ("brightness", "Brightness",
447           "Picture brightness, or more precisely, the black level", G_MININT,
448           G_MAXINT, 0,
449           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
450   /**
451    * GstV4l2Src:contrast:
452    *
453    * Picture contrast or luma gain
454    */
455   g_object_class_install_property (gobject_class, PROP_CONTRAST,
456       g_param_spec_int ("contrast", "Contrast",
457           "Picture contrast or luma gain", G_MININT,
458           G_MAXINT, 0,
459           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
460   /**
461    * GstV4l2Src:saturation:
462    *
463    * Picture color saturation or chroma gain
464    */
465   g_object_class_install_property (gobject_class, PROP_SATURATION,
466       g_param_spec_int ("saturation", "Saturation",
467           "Picture color saturation or chroma gain", G_MININT,
468           G_MAXINT, 0,
469           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
470   /**
471    * GstV4l2Src:hue:
472    *
473    * Hue or color balance
474    */
475   g_object_class_install_property (gobject_class, PROP_HUE,
476       g_param_spec_int ("hue", "Hue",
477           "Hue or color balance", G_MININT,
478           G_MAXINT, 0,
479           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
480
481   /**
482    * GstV4l2Src:norm:
483    *
484    * TV norm
485    */
486   g_object_class_install_property (gobject_class, PROP_TV_NORM,
487       g_param_spec_enum ("norm", "TV norm",
488           "video standard",
489           GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM,
490           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
491
492   /**
493    * GstV4l2Src:io-mode:
494    *
495    * IO Mode
496    */
497   g_object_class_install_property (gobject_class, PROP_IO_MODE,
498       g_param_spec_enum ("io-mode", "IO mode",
499           "I/O mode",
500           GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
501           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
502
503   /**
504    * GstV4l2Src:extra-controls:
505    *
506    * Additional v4l2 controls for the device. The controls are identified
507    * by the control name (lowercase with '_' for any non-alphanumeric
508    * characters).
509    *
510    * Since: 1.2
511    */
512   g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
513       g_param_spec_boxed ("extra-controls", "Extra Controls",
514           "Extra v4l2 controls (CIDs) for the device",
515           GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
516
517   /**
518    * GstV4l2Src:pixel-aspect-ratio:
519    *
520    * The pixel aspect ratio of the device. This overwrites the pixel aspect
521    * ratio queried from the device.
522    *
523    * Since: 1.2
524    */
525   g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
526       g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio",
527           "Overwrite the pixel aspect ratio of the device", "1/1",
528           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
529
530   /**
531    * GstV4l2Src:force-aspect-ratio:
532    *
533    * When enabled, the pixel aspect ratio queried from the device or set
534    * with the pixel-aspect-ratio property will be enforced.
535    *
536    * Since: 1.2
537    */
538   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
539       g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio",
540           "When enabled, the pixel aspect ratio will be enforced", TRUE,
541           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
542
543 }
544
545 GstV4l2Object *
546 gst_v4l2_object_new (GstElement * element,
547     enum v4l2_buf_type type,
548     const char *default_device,
549     GstV4l2GetInOutFunction get_in_out_func,
550     GstV4l2SetInOutFunction set_in_out_func,
551     GstV4l2UpdateFpsFunction update_fps_func)
552 {
553   GstV4l2Object *v4l2object;
554
555   /*
556    * some default values
557    */
558   v4l2object = g_new0 (GstV4l2Object, 1);
559
560   v4l2object->type = type;
561   v4l2object->formats = NULL;
562
563   v4l2object->element = element;
564   v4l2object->get_in_out_func = get_in_out_func;
565   v4l2object->set_in_out_func = set_in_out_func;
566   v4l2object->update_fps_func = update_fps_func;
567
568   v4l2object->video_fd = -1;
569   v4l2object->poll = gst_poll_new (TRUE);
570   v4l2object->active = FALSE;
571   v4l2object->videodev = g_strdup (default_device);
572
573   v4l2object->norms = NULL;
574   v4l2object->channels = NULL;
575   v4l2object->colors = NULL;
576
577   v4l2object->xwindow_id = 0;
578
579   v4l2object->keep_aspect = TRUE;
580
581   v4l2object->n_v4l2_planes = 0;
582
583   /*
584    * this boolean only applies in v4l2-MPLANE mode.
585    * TRUE: means it prefers to use several v4l2 (non contiguous)
586    * planes. For example if the device supports NV12 and NV12M
587    * both in MPLANE mode, then it will prefer NV12M
588    * FALSE: means it prefers to use one v4l2 plane (which contains
589    * all gst planes as if it was working in non-v4l2-MPLANE mode.
590    * For example if the device supports NV12 and NV12M
591    * both in MPLANE mode, then it will prefer NV12
592    *
593    * this boolean is also used to manage the case where the
594    * device only supports the mode MPLANE and at the same time it
595    * does not support both NV12 and NV12M. So in this case we first
596    * try to use the prefered config, and at least try the other case
597    * if it fails. For example in MPLANE mode if it has NV12 and not
598    * NV21M then even if you set prefered_non_contiguous to TRUE it will
599    * try NV21 as well.
600    */
601   v4l2object->prefered_non_contiguous = TRUE;
602
603   v4l2object->no_initial_format = FALSE;
604
605   return v4l2object;
606 }
607
608 static gboolean gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object);
609
610
611 void
612 gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
613 {
614   g_return_if_fail (v4l2object != NULL);
615
616   if (v4l2object->videodev)
617     g_free (v4l2object->videodev);
618
619   if (v4l2object->poll)
620     gst_poll_free (v4l2object->poll);
621
622   if (v4l2object->channel)
623     g_free (v4l2object->channel);
624
625   if (v4l2object->formats) {
626     gst_v4l2_object_clear_format_list (v4l2object);
627   }
628
629   if (v4l2object->probed_caps) {
630     gst_caps_unref (v4l2object->probed_caps);
631   }
632
633   g_free (v4l2object);
634 }
635
636
637 static gboolean
638 gst_v4l2_object_clear_format_list (GstV4l2Object * v4l2object)
639 {
640   g_slist_foreach (v4l2object->formats, (GFunc) g_free, NULL);
641   g_slist_free (v4l2object->formats);
642   v4l2object->formats = NULL;
643
644   return TRUE;
645 }
646
647 static gint
648 gst_v4l2_object_prop_to_cid (guint prop_id)
649 {
650   gint cid = -1;
651
652   switch (prop_id) {
653     case PROP_BRIGHTNESS:
654       cid = V4L2_CID_BRIGHTNESS;
655       break;
656     case PROP_CONTRAST:
657       cid = V4L2_CID_CONTRAST;
658       break;
659     case PROP_SATURATION:
660       cid = V4L2_CID_SATURATION;
661       break;
662     case PROP_HUE:
663       cid = V4L2_CID_HUE;
664       break;
665     default:
666       GST_WARNING ("unmapped property id: %d", prop_id);
667   }
668   return cid;
669 }
670
671
672 gboolean
673 gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
674     guint prop_id, const GValue * value, GParamSpec * pspec)
675 {
676   switch (prop_id) {
677     case PROP_DEVICE:
678       g_free (v4l2object->videodev);
679       v4l2object->videodev = g_value_dup_string (value);
680       break;
681     case PROP_BRIGHTNESS:
682     case PROP_CONTRAST:
683     case PROP_SATURATION:
684     case PROP_HUE:
685     {
686       gint cid = gst_v4l2_object_prop_to_cid (prop_id);
687
688       if (cid != -1) {
689         if (GST_V4L2_IS_OPEN (v4l2object)) {
690           gst_v4l2_set_attribute (v4l2object, cid, g_value_get_int (value));
691         }
692       }
693       return TRUE;
694     }
695       break;
696     case PROP_TV_NORM:
697       v4l2object->tv_norm = g_value_get_enum (value);
698       break;
699 #if 0
700     case PROP_CHANNEL:
701       if (GST_V4L2_IS_OPEN (v4l2object)) {
702         GstTuner *tuner = GST_TUNER (v4l2object->element);
703         GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
704             (gchar *) g_value_get_string (value));
705
706         if (channel) {
707           /* like gst_tuner_set_channel (tuner, channel)
708              without g_object_notify */
709           gst_v4l2_tuner_set_channel (v4l2object, channel);
710         }
711       } else {
712         g_free (v4l2object->channel);
713         v4l2object->channel = g_value_dup_string (value);
714       }
715       break;
716     case PROP_FREQUENCY:
717       if (GST_V4L2_IS_OPEN (v4l2object)) {
718         GstTuner *tuner = GST_TUNER (v4l2object->element);
719         GstTunerChannel *channel = gst_tuner_get_channel (tuner);
720
721         if (channel &&
722             GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
723           /* like
724              gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value))
725              without g_object_notify */
726           gst_v4l2_tuner_set_frequency (v4l2object, channel,
727               g_value_get_ulong (value));
728         }
729       } else {
730         v4l2object->frequency = g_value_get_ulong (value);
731       }
732       break;
733 #endif
734     case PROP_IO_MODE:
735       v4l2object->req_mode = g_value_get_enum (value);
736       break;
737     case PROP_EXTRA_CONTROLS:{
738       const GstStructure *s = gst_value_get_structure (value);
739
740       if (v4l2object->extra_controls)
741         gst_structure_free (v4l2object->extra_controls);
742
743       v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
744       if (GST_V4L2_IS_OPEN (v4l2object))
745         gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
746       break;
747     }
748     case PROP_PIXEL_ASPECT_RATIO:
749       g_free (v4l2object->par);
750       v4l2object->par = g_new0 (GValue, 1);
751       g_value_init (v4l2object->par, GST_TYPE_FRACTION);
752       if (!g_value_transform (value, v4l2object->par)) {
753         g_warning ("Could not transform string to aspect ratio");
754         gst_value_set_fraction (v4l2object->par, 1, 1);
755       }
756       GST_DEBUG_OBJECT (v4l2object->element, "set PAR to %d/%d",
757           gst_value_get_fraction_numerator (v4l2object->par),
758           gst_value_get_fraction_denominator (v4l2object->par));
759       break;
760     case PROP_FORCE_ASPECT_RATIO:
761       v4l2object->keep_aspect = g_value_get_boolean (value);
762       break;
763     default:
764       return FALSE;
765       break;
766   }
767   return TRUE;
768 }
769
770
771 gboolean
772 gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
773     guint prop_id, GValue * value, GParamSpec * pspec)
774 {
775   switch (prop_id) {
776     case PROP_DEVICE:
777       g_value_set_string (value, v4l2object->videodev);
778       break;
779     case PROP_DEVICE_NAME:
780     {
781       const guchar *new = NULL;
782
783       if (GST_V4L2_IS_OPEN (v4l2object)) {
784         new = v4l2object->vcap.card;
785       } else if (gst_v4l2_open (v4l2object)) {
786         new = v4l2object->vcap.card;
787         gst_v4l2_close (v4l2object);
788       }
789       g_value_set_string (value, (gchar *) new);
790       break;
791     }
792     case PROP_DEVICE_FD:
793     {
794       if (GST_V4L2_IS_OPEN (v4l2object))
795         g_value_set_int (value, v4l2object->video_fd);
796       else
797         g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
798       break;
799     }
800     case PROP_FLAGS:
801     {
802       guint flags = 0;
803
804       if (GST_V4L2_IS_OPEN (v4l2object)) {
805         flags |= v4l2object->vcap.capabilities &
806             (V4L2_CAP_VIDEO_CAPTURE |
807             V4L2_CAP_VIDEO_OUTPUT |
808             V4L2_CAP_VIDEO_OVERLAY |
809             V4L2_CAP_VBI_CAPTURE |
810             V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
811
812         if (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
813           flags |= V4L2_CAP_VIDEO_CAPTURE;
814
815         if (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
816           flags |= V4L2_CAP_VIDEO_OUTPUT;
817       }
818       g_value_set_flags (value, flags);
819       break;
820     }
821     case PROP_BRIGHTNESS:
822     case PROP_CONTRAST:
823     case PROP_SATURATION:
824     case PROP_HUE:
825     {
826       gint cid = gst_v4l2_object_prop_to_cid (prop_id);
827
828       if (cid != -1) {
829         if (GST_V4L2_IS_OPEN (v4l2object)) {
830           gint v;
831           if (gst_v4l2_get_attribute (v4l2object, cid, &v)) {
832             g_value_set_int (value, v);
833           }
834         }
835       }
836       return TRUE;
837     }
838       break;
839     case PROP_TV_NORM:
840       g_value_set_enum (value, v4l2object->tv_norm);
841       break;
842     case PROP_IO_MODE:
843       g_value_set_enum (value, v4l2object->req_mode);
844       break;
845     case PROP_EXTRA_CONTROLS:
846       gst_value_set_structure (value, v4l2object->extra_controls);
847       break;
848     case PROP_PIXEL_ASPECT_RATIO:
849       if (v4l2object->par)
850         g_value_transform (v4l2object->par, value);
851       break;
852     case PROP_FORCE_ASPECT_RATIO:
853       g_value_set_boolean (value, v4l2object->keep_aspect);
854       break;
855     default:
856       return FALSE;
857       break;
858   }
859   return TRUE;
860 }
861
862 static void
863 gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
864 {
865   GstTunerNorm *norm = NULL;
866   GstTunerChannel *channel = NULL;
867   GstTuner *tuner;
868
869   if (!GST_IS_TUNER (v4l2object->element))
870     return;
871
872   tuner = GST_TUNER (v4l2object->element);
873
874   if (v4l2object->tv_norm)
875     norm = gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm);
876   GST_DEBUG_OBJECT (v4l2object->element, "tv_norm=0x%" G_GINT64_MODIFIER "x, "
877       "norm=%p", (guint64) v4l2object->tv_norm, norm);
878   if (norm) {
879     gst_tuner_set_norm (tuner, norm);
880   } else {
881     norm =
882         GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
883     if (norm) {
884       v4l2object->tv_norm =
885           gst_v4l2_tuner_get_std_id_by_norm (v4l2object, norm);
886       gst_tuner_norm_changed (tuner, norm);
887     }
888   }
889
890   if (v4l2object->channel)
891     channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
892   if (channel) {
893     gst_tuner_set_channel (tuner, channel);
894   } else {
895     channel =
896         GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER
897             (v4l2object->element)));
898     if (channel) {
899       g_free (v4l2object->channel);
900       v4l2object->channel = g_strdup (channel->label);
901       gst_tuner_channel_changed (tuner, channel);
902     }
903   }
904
905   if (channel
906       && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
907     if (v4l2object->frequency != 0) {
908       gst_tuner_set_frequency (tuner, channel, v4l2object->frequency);
909     } else {
910       v4l2object->frequency = gst_tuner_get_frequency (tuner, channel);
911       if (v4l2object->frequency == 0) {
912         /* guess */
913         gst_tuner_set_frequency (tuner, channel, 1000);
914       } else {
915       }
916     }
917   }
918 }
919
920 gboolean
921 gst_v4l2_object_open (GstV4l2Object * v4l2object)
922 {
923   if (gst_v4l2_open (v4l2object))
924     gst_v4l2_set_defaults (v4l2object);
925   else
926     return FALSE;
927
928 #ifdef HAVE_XVIDEO
929   gst_v4l2_video_overlay_start (v4l2object);
930 #endif
931
932   return TRUE;
933 }
934
935 gboolean
936 gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other)
937 {
938   gboolean ret;
939
940   ret = gst_v4l2_dup (v4l2object, other);
941
942 #ifdef HAVE_XVIDEO
943   gst_v4l2_video_overlay_start (v4l2object);
944 #endif
945
946   return ret;
947 }
948
949 gboolean
950 gst_v4l2_object_close (GstV4l2Object * v4l2object)
951 {
952 #ifdef HAVE_XVIDEO
953   gst_v4l2_video_overlay_stop (v4l2object);
954 #endif
955
956   if (!gst_v4l2_close (v4l2object))
957     return FALSE;
958
959   gst_caps_replace (&v4l2object->probed_caps, NULL);
960
961   if (v4l2object->formats) {
962     gst_v4l2_object_clear_format_list (v4l2object);
963   }
964
965   return TRUE;
966 }
967
968
969 /*
970  * common format / caps utilities:
971  */
972 typedef enum
973 {
974   GST_V4L2_RAW = 1 << 0,
975   GST_V4L2_CODEC = 1 << 1,
976   GST_V4L2_TRANSPORT = 1 << 2,
977   GST_V4L2_ALL = 0xffff
978 } GstV4L2FormatFlags;
979
980 typedef struct
981 {
982   guint32 format;
983   gboolean dimensions;
984   GstV4L2FormatFlags flags;
985 } GstV4L2FormatDesc;
986
987 static const GstV4L2FormatDesc gst_v4l2_formats[] = {
988   /* from Linux 2.6.15 videodev2.h */
989   {V4L2_PIX_FMT_RGB332, TRUE, GST_V4L2_RAW},
990   {V4L2_PIX_FMT_RGB555, TRUE, GST_V4L2_RAW},
991   {V4L2_PIX_FMT_RGB565, TRUE, GST_V4L2_RAW},
992   {V4L2_PIX_FMT_RGB555X, TRUE, GST_V4L2_RAW},
993   {V4L2_PIX_FMT_RGB565X, TRUE, GST_V4L2_RAW},
994   {V4L2_PIX_FMT_BGR24, TRUE, GST_V4L2_RAW},
995   {V4L2_PIX_FMT_RGB24, TRUE, GST_V4L2_RAW},
996   {V4L2_PIX_FMT_BGR32, TRUE, GST_V4L2_RAW},
997   {V4L2_PIX_FMT_RGB32, TRUE, GST_V4L2_RAW},
998   {V4L2_PIX_FMT_GREY, TRUE, GST_V4L2_RAW},
999   {V4L2_PIX_FMT_YVU410, TRUE, GST_V4L2_RAW},
1000   {V4L2_PIX_FMT_YVU420, TRUE, GST_V4L2_RAW},
1001   {V4L2_PIX_FMT_YUYV, TRUE, GST_V4L2_RAW},
1002   {V4L2_PIX_FMT_UYVY, TRUE, GST_V4L2_RAW},
1003   {V4L2_PIX_FMT_YUV422P, TRUE, GST_V4L2_RAW},
1004   {V4L2_PIX_FMT_YUV411P, TRUE, GST_V4L2_RAW},
1005   {V4L2_PIX_FMT_Y41P, TRUE, GST_V4L2_RAW},
1006
1007   /* two planes -- one Y, one Cr + Cb interleaved  */
1008   {V4L2_PIX_FMT_NV12, TRUE, GST_V4L2_RAW},
1009   {V4L2_PIX_FMT_NV12M, TRUE, GST_V4L2_RAW},
1010   {V4L2_PIX_FMT_NV21, TRUE, GST_V4L2_RAW},
1011   {V4L2_PIX_FMT_NV21M, TRUE, GST_V4L2_RAW},
1012
1013   /*  The following formats are not defined in the V4L2 specification */
1014   {V4L2_PIX_FMT_YUV410, TRUE, GST_V4L2_RAW},
1015   {V4L2_PIX_FMT_YUV420, TRUE, GST_V4L2_RAW},
1016   {V4L2_PIX_FMT_YYUV, TRUE, GST_V4L2_RAW},
1017   {V4L2_PIX_FMT_HI240, TRUE, GST_V4L2_RAW},
1018
1019   /* see http://www.siliconimaging.com/RGB%20Bayer.htm */
1020 #ifdef V4L2_PIX_FMT_SBGGR8
1021   {V4L2_PIX_FMT_SBGGR8, TRUE, GST_V4L2_CODEC},
1022 #endif
1023
1024   /* compressed formats */
1025   {V4L2_PIX_FMT_MJPEG, FALSE, GST_V4L2_CODEC},
1026   {V4L2_PIX_FMT_JPEG, FALSE, GST_V4L2_CODEC},
1027 #ifdef V4L2_PIX_FMT_PJPG
1028   {V4L2_PIX_FMT_PJPG, FALSE, GST_V4L2_CODEC},
1029 #endif
1030   {V4L2_PIX_FMT_DV, FALSE, GST_V4L2_TRANSPORT},
1031   {V4L2_PIX_FMT_MPEG, FALSE, GST_V4L2_TRANSPORT},
1032   {V4L2_PIX_FMT_MPEG1, FALSE, GST_V4L2_CODEC},
1033   {V4L2_PIX_FMT_MPEG2, FALSE, GST_V4L2_CODEC},
1034   {V4L2_PIX_FMT_MPEG4, FALSE, GST_V4L2_CODEC},
1035
1036 #ifdef V4L2_PIX_FMT_H263
1037   {V4L2_PIX_FMT_H263, FALSE, GST_V4L2_CODEC},
1038 #endif
1039 #ifdef V4L2_PIX_FMT_H264
1040   {V4L2_PIX_FMT_H264, FALSE, GST_V4L2_CODEC},
1041 #endif
1042 #ifdef V4L2_PIX_FMT_VP8
1043   {V4L2_PIX_FMT_VP8, FALSE, GST_V4L2_CODEC},
1044 #endif
1045
1046   /*  Vendor-specific formats   */
1047   {V4L2_PIX_FMT_WNVA, TRUE, GST_V4L2_CODEC},
1048
1049 #ifdef V4L2_PIX_FMT_SN9C10X
1050   {V4L2_PIX_FMT_SN9C10X, TRUE, GST_V4L2_CODEC},
1051 #endif
1052 #ifdef V4L2_PIX_FMT_PWC1
1053   {V4L2_PIX_FMT_PWC1, TRUE, GST_V4L2_CODEC},
1054 #endif
1055 #ifdef V4L2_PIX_FMT_PWC2
1056   {V4L2_PIX_FMT_PWC2, TRUE, GST_V4L2_CODEC},
1057 #endif
1058 #ifdef V4L2_PIX_FMT_YVYU
1059   {V4L2_PIX_FMT_YVYU, TRUE, GST_V4L2_RAW},
1060 #endif
1061 };
1062
1063 #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
1064
1065
1066 static struct v4l2_fmtdesc *
1067 gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object,
1068     guint32 fourcc)
1069 {
1070   struct v4l2_fmtdesc *fmt;
1071   GSList *walk;
1072
1073   if (fourcc == 0)
1074     return NULL;
1075
1076   walk = gst_v4l2_object_get_format_list (v4l2object);
1077   while (walk) {
1078     fmt = (struct v4l2_fmtdesc *) walk->data;
1079     if (fmt->pixelformat == fourcc)
1080       return fmt;
1081     /* special case for jpeg */
1082     if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
1083         fmt->pixelformat == V4L2_PIX_FMT_JPEG
1084 #ifdef V4L2_PIX_FMT_PJPG
1085         || fmt->pixelformat == V4L2_PIX_FMT_PJPG
1086 #endif
1087         ) {
1088       if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG
1089 #ifdef V4L2_PIX_FMT_PJPG
1090           || fourcc == V4L2_PIX_FMT_PJPG
1091 #endif
1092           ) {
1093         return fmt;
1094       }
1095     }
1096     walk = g_slist_next (walk);
1097   }
1098
1099   return NULL;
1100 }
1101
1102
1103
1104 /* complete made up ranking, the values themselves are meaningless */
1105 /* These ranks MUST be X such that X<<15 fits on a signed int - see
1106    the comment at the end of gst_v4l2_object_format_get_rank. */
1107 #define YUV_BASE_RANK     1000
1108 #define JPEG_BASE_RANK     500
1109 #define DV_BASE_RANK       200
1110 #define RGB_BASE_RANK      100
1111 #define YUV_ODD_BASE_RANK   50
1112 #define RGB_ODD_BASE_RANK   25
1113 #define BAYER_BASE_RANK     15
1114 #define S910_BASE_RANK      10
1115 #define GREY_BASE_RANK       5
1116 #define PWC_BASE_RANK        1
1117
1118 /* This flag is already used by libv4l2 although
1119  * it was added to the Linux kernel in 2.6.32
1120  */
1121 #ifndef V4L2_FMT_FLAG_EMULATED
1122 #define V4L2_FMT_FLAG_EMULATED 0x0002
1123 #endif
1124
1125 static gint
1126 gst_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt)
1127 {
1128   guint32 fourcc = fmt->pixelformat;
1129   gboolean emulated = ((fmt->flags & V4L2_FMT_FLAG_EMULATED) != 0);
1130   gint rank = 0;
1131
1132   switch (fourcc) {
1133     case V4L2_PIX_FMT_MJPEG:
1134 #ifdef V4L2_PIX_FMT_PJPG
1135     case V4L2_PIX_FMT_PJPG:
1136       rank = JPEG_BASE_RANK;
1137       break;
1138 #endif
1139     case V4L2_PIX_FMT_JPEG:
1140       rank = JPEG_BASE_RANK + 1;
1141       break;
1142     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
1143       rank = JPEG_BASE_RANK + 2;
1144       break;
1145
1146     case V4L2_PIX_FMT_RGB332:
1147     case V4L2_PIX_FMT_RGB555:
1148     case V4L2_PIX_FMT_RGB555X:
1149     case V4L2_PIX_FMT_RGB565:
1150     case V4L2_PIX_FMT_RGB565X:
1151       rank = RGB_ODD_BASE_RANK;
1152       break;
1153
1154     case V4L2_PIX_FMT_RGB24:
1155     case V4L2_PIX_FMT_BGR24:
1156       rank = RGB_BASE_RANK - 1;
1157       break;
1158
1159     case V4L2_PIX_FMT_RGB32:
1160     case V4L2_PIX_FMT_BGR32:
1161       rank = RGB_BASE_RANK;
1162       break;
1163
1164     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
1165       rank = GREY_BASE_RANK;
1166       break;
1167
1168     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
1169     case V4L2_PIX_FMT_NV12M:   /* Same as NV12      */
1170     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
1171     case V4L2_PIX_FMT_NV21M:   /* Same as NV21      */
1172     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
1173     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
1174       rank = YUV_ODD_BASE_RANK;
1175       break;
1176
1177     case V4L2_PIX_FMT_YVU410:  /* YVU9,  9 bits per pixel */
1178       rank = YUV_BASE_RANK + 3;
1179       break;
1180     case V4L2_PIX_FMT_YUV410:  /* YUV9,  9 bits per pixel */
1181       rank = YUV_BASE_RANK + 2;
1182       break;
1183     case V4L2_PIX_FMT_YUV420:  /* I420, 12 bits per pixel */
1184       rank = YUV_BASE_RANK + 7;
1185       break;
1186     case V4L2_PIX_FMT_YUYV:    /* YUY2, 16 bits per pixel */
1187       rank = YUV_BASE_RANK + 10;
1188       break;
1189     case V4L2_PIX_FMT_YVU420:  /* YV12, 12 bits per pixel */
1190       rank = YUV_BASE_RANK + 6;
1191       break;
1192     case V4L2_PIX_FMT_UYVY:    /* UYVY, 16 bits per pixel */
1193       rank = YUV_BASE_RANK + 9;
1194       break;
1195     case V4L2_PIX_FMT_Y41P:    /* Y41P, 12 bits per pixel */
1196       rank = YUV_BASE_RANK + 5;
1197       break;
1198     case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */
1199       rank = YUV_BASE_RANK + 4;
1200       break;
1201     case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */
1202       rank = YUV_BASE_RANK + 8;
1203       break;
1204
1205     case V4L2_PIX_FMT_DV:
1206       rank = DV_BASE_RANK;
1207       break;
1208
1209     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
1210       rank = 0;
1211       break;
1212
1213 #ifdef V4L2_PIX_FMT_SBGGR8
1214     case V4L2_PIX_FMT_SBGGR8:
1215       rank = BAYER_BASE_RANK;
1216       break;
1217 #endif
1218
1219 #ifdef V4L2_PIX_FMT_SN9C10X
1220     case V4L2_PIX_FMT_SN9C10X:
1221       rank = S910_BASE_RANK;
1222       break;
1223 #endif
1224
1225 #ifdef V4L2_PIX_FMT_PWC1
1226     case V4L2_PIX_FMT_PWC1:
1227       rank = PWC_BASE_RANK;
1228       break;
1229 #endif
1230 #ifdef V4L2_PIX_FMT_PWC2
1231     case V4L2_PIX_FMT_PWC2:
1232       rank = PWC_BASE_RANK;
1233       break;
1234 #endif
1235
1236     default:
1237       rank = 0;
1238       break;
1239   }
1240
1241   /* All ranks are below 1<<15 so a shift by 15
1242    * will a) make all non-emulated formats larger
1243    * than emulated and b) will not overflow
1244    */
1245   if (!emulated)
1246     rank <<= 15;
1247
1248   return rank;
1249 }
1250
1251
1252
1253 static gint
1254 format_cmp_func (gconstpointer a, gconstpointer b)
1255 {
1256   const struct v4l2_fmtdesc *fa = a;
1257   const struct v4l2_fmtdesc *fb = b;
1258
1259   if (fa->pixelformat == fb->pixelformat)
1260     return 0;
1261
1262   return gst_v4l2_object_format_get_rank (fb) -
1263       gst_v4l2_object_format_get_rank (fa);
1264 }
1265
1266 /******************************************************
1267  * gst_v4l2_object_fill_format_list():
1268  *   create list of supported capture formats
1269  * return value: TRUE on success, FALSE on error
1270  ******************************************************/
1271 static gboolean
1272 gst_v4l2_object_fill_format_list (GstV4l2Object * v4l2object,
1273     enum v4l2_buf_type type)
1274 {
1275   gint n;
1276   struct v4l2_fmtdesc *format;
1277
1278   GST_DEBUG_OBJECT (v4l2object->element, "getting src format enumerations");
1279
1280   /* format enumeration */
1281   for (n = 0;; n++) {
1282     format = g_new0 (struct v4l2_fmtdesc, 1);
1283
1284     format->index = n;
1285     format->type = type;
1286
1287     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
1288       if (errno == EINVAL) {
1289         g_free (format);
1290         break;                  /* end of enumeration */
1291       } else {
1292         goto failed;
1293       }
1294     }
1295
1296     GST_LOG_OBJECT (v4l2object->element, "index:       %u", format->index);
1297     GST_LOG_OBJECT (v4l2object->element, "type:        %d", format->type);
1298     GST_LOG_OBJECT (v4l2object->element, "flags:       %08x", format->flags);
1299     GST_LOG_OBJECT (v4l2object->element, "description: '%s'",
1300         format->description);
1301     GST_LOG_OBJECT (v4l2object->element, "pixelformat: %" GST_FOURCC_FORMAT,
1302         GST_FOURCC_ARGS (format->pixelformat));
1303
1304     /* sort formats according to our preference;  we do this, because caps
1305      * are probed in the order the formats are in the list, and the order of
1306      * formats in the final probed caps matters for things like fixation */
1307     v4l2object->formats = g_slist_insert_sorted (v4l2object->formats, format,
1308         (GCompareFunc) format_cmp_func);
1309   }
1310
1311 #ifndef GST_DISABLE_GST_DEBUG
1312   {
1313     GSList *l;
1314
1315     GST_INFO_OBJECT (v4l2object->element, "got %d format(s):", n);
1316     for (l = v4l2object->formats; l != NULL; l = l->next) {
1317       format = l->data;
1318
1319       GST_INFO_OBJECT (v4l2object->element,
1320           "  %" GST_FOURCC_FORMAT "%s", GST_FOURCC_ARGS (format->pixelformat),
1321           ((format->flags & V4L2_FMT_FLAG_EMULATED)) ? " (emulated)" : "");
1322     }
1323   }
1324 #endif
1325
1326   return TRUE;
1327
1328   /* ERRORS */
1329 failed:
1330   {
1331     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
1332         (_("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)));
1333     g_free (format);
1334     return FALSE;
1335   }
1336 }
1337
1338 /*
1339   * Get the list of supported capture formats, a list of
1340   * <code>struct v4l2_fmtdesc</code>.
1341   */
1342 static GSList *
1343 gst_v4l2_object_get_format_list (GstV4l2Object * v4l2object)
1344 {
1345   if (!v4l2object->formats) {
1346
1347     /* check usual way */
1348     gst_v4l2_object_fill_format_list (v4l2object, v4l2object->type);
1349
1350     /* if our driver supports multi-planar
1351      * and if formats are still empty then we can workaround driver bug
1352      * by also looking up formats as if our device was not supporting
1353      * multiplanar */
1354     if (!v4l2object->formats) {
1355       switch (v4l2object->type) {
1356         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1357           gst_v4l2_object_fill_format_list (v4l2object,
1358               V4L2_BUF_TYPE_VIDEO_CAPTURE);
1359           break;
1360
1361         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1362           gst_v4l2_object_fill_format_list (v4l2object,
1363               V4L2_BUF_TYPE_VIDEO_OUTPUT);
1364           break;
1365
1366         default:
1367           break;
1368       }
1369     }
1370   }
1371   return v4l2object->formats;
1372 }
1373
1374 static GstVideoFormat
1375 gst_v4l2_object_v4l2fourcc_to_video_format (guint32 fourcc)
1376 {
1377   GstVideoFormat format;
1378
1379   switch (fourcc) {
1380     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
1381       format = GST_VIDEO_FORMAT_GRAY8;
1382       break;
1383     case V4L2_PIX_FMT_RGB555:
1384       format = GST_VIDEO_FORMAT_RGB15;
1385       break;
1386     case V4L2_PIX_FMT_RGB565:
1387       format = GST_VIDEO_FORMAT_RGB16;
1388       break;
1389     case V4L2_PIX_FMT_RGB24:
1390       format = GST_VIDEO_FORMAT_RGB;
1391       break;
1392     case V4L2_PIX_FMT_BGR24:
1393       format = GST_VIDEO_FORMAT_BGR;
1394       break;
1395     case V4L2_PIX_FMT_RGB32:
1396       format = GST_VIDEO_FORMAT_RGBx;
1397       break;
1398     case V4L2_PIX_FMT_BGR32:
1399       format = GST_VIDEO_FORMAT_BGRx;
1400       break;
1401     case V4L2_PIX_FMT_NV12:
1402     case V4L2_PIX_FMT_NV12M:
1403       format = GST_VIDEO_FORMAT_NV12;
1404       break;
1405     case V4L2_PIX_FMT_NV21:
1406     case V4L2_PIX_FMT_NV21M:
1407       format = GST_VIDEO_FORMAT_NV21;
1408       break;
1409     case V4L2_PIX_FMT_YVU410:
1410       format = GST_VIDEO_FORMAT_YVU9;
1411       break;
1412     case V4L2_PIX_FMT_YUV410:
1413       format = GST_VIDEO_FORMAT_YUV9;
1414       break;
1415     case V4L2_PIX_FMT_YUV420:
1416       format = GST_VIDEO_FORMAT_I420;
1417       break;
1418     case V4L2_PIX_FMT_YUYV:
1419       format = GST_VIDEO_FORMAT_YUY2;
1420       break;
1421     case V4L2_PIX_FMT_YVU420:
1422       format = GST_VIDEO_FORMAT_YV12;
1423       break;
1424     case V4L2_PIX_FMT_UYVY:
1425       format = GST_VIDEO_FORMAT_UYVY;
1426       break;
1427 #if 0
1428     case V4L2_PIX_FMT_Y41P:
1429       format = GST_VIDEO_FORMAT_Y41P;
1430       break;
1431 #endif
1432     case V4L2_PIX_FMT_YUV411P:
1433       format = GST_VIDEO_FORMAT_Y41B;
1434       break;
1435     case V4L2_PIX_FMT_YUV422P:
1436       format = GST_VIDEO_FORMAT_Y42B;
1437       break;
1438 #ifdef V4L2_PIX_FMT_YVYU
1439     case V4L2_PIX_FMT_YVYU:
1440       format = GST_VIDEO_FORMAT_YVYU;
1441       break;
1442 #endif
1443     default:
1444       format = GST_VIDEO_FORMAT_UNKNOWN;
1445       g_assert_not_reached ();
1446       break;
1447   }
1448
1449   return format;
1450 }
1451
1452 static GstStructure *
1453 gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
1454 {
1455   GstStructure *structure = NULL;
1456
1457   switch (fourcc) {
1458     case V4L2_PIX_FMT_MJPEG:   /* Motion-JPEG */
1459 #ifdef V4L2_PIX_FMT_PJPG
1460     case V4L2_PIX_FMT_PJPG:    /* Progressive-JPEG */
1461 #endif
1462     case V4L2_PIX_FMT_JPEG:    /* JFIF JPEG */
1463       structure = gst_structure_new_empty ("image/jpeg");
1464       break;
1465     case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */
1466     case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */
1467       /* FIXME: get correct fourccs here */
1468       break;
1469     case V4L2_PIX_FMT_MPEG1:
1470       structure = gst_structure_new ("video/mpeg",
1471           "mpegversion", G_TYPE_INT, 2, NULL);
1472       break;
1473     case V4L2_PIX_FMT_MPEG2:
1474       structure = gst_structure_new ("video/mpeg",
1475           "mpegversion", G_TYPE_INT, 2, NULL);
1476       break;
1477     case V4L2_PIX_FMT_MPEG4:
1478       structure = gst_structure_new ("video/mpeg",
1479           "mpegversion", G_TYPE_INT, 4, "systemstream",
1480           G_TYPE_BOOLEAN, FALSE, NULL);
1481       break;
1482 #ifdef V4L2_PIX_FMT_H263
1483     case V4L2_PIX_FMT_H263:
1484       structure = gst_structure_new ("video/x-h263",
1485           "variant", G_TYPE_STRING, "itu", NULL);
1486       break;
1487 #endif
1488 #ifdef V4L2_PIX_FMT_H264
1489     case V4L2_PIX_FMT_H264:    /* H.264 */
1490       structure = gst_structure_new ("video/x-h264",
1491           "stream-format", G_TYPE_STRING, "byte-stream", "alignment",
1492           G_TYPE_STRING, "au", NULL);
1493       break;
1494 #endif
1495 #ifdef V4L2_PIX_FMT_VP8
1496     case V4L2_PIX_FMT_VP8:
1497       structure = gst_structure_new_empty ("video/x-vp8");
1498       break;
1499 #endif
1500     case V4L2_PIX_FMT_RGB332:
1501     case V4L2_PIX_FMT_RGB555X:
1502     case V4L2_PIX_FMT_RGB565X:
1503       /* FIXME: get correct fourccs here */
1504       break;
1505     case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */
1506     case V4L2_PIX_FMT_RGB555:
1507     case V4L2_PIX_FMT_RGB565:
1508     case V4L2_PIX_FMT_RGB24:
1509     case V4L2_PIX_FMT_BGR24:
1510     case V4L2_PIX_FMT_RGB32:
1511     case V4L2_PIX_FMT_BGR32:
1512     case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */
1513     case V4L2_PIX_FMT_NV12M:
1514     case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */
1515     case V4L2_PIX_FMT_NV21M:
1516     case V4L2_PIX_FMT_YVU410:
1517     case V4L2_PIX_FMT_YUV410:
1518     case V4L2_PIX_FMT_YUV420:  /* I420/IYUV */
1519     case V4L2_PIX_FMT_YUYV:
1520     case V4L2_PIX_FMT_YVU420:
1521     case V4L2_PIX_FMT_UYVY:
1522 #if 0
1523     case V4L2_PIX_FMT_Y41P:
1524 #endif
1525     case V4L2_PIX_FMT_YUV422P:
1526 #ifdef V4L2_PIX_FMT_YVYU
1527     case V4L2_PIX_FMT_YVYU:
1528 #endif
1529     case V4L2_PIX_FMT_YUV411P:{
1530       GstVideoFormat format;
1531       format = gst_v4l2_object_v4l2fourcc_to_video_format (fourcc);
1532       if (format != GST_VIDEO_FORMAT_UNKNOWN)
1533         structure = gst_structure_new ("video/x-raw",
1534             "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
1535       break;
1536     }
1537     case V4L2_PIX_FMT_DV:
1538       structure =
1539           gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
1540           NULL);
1541       break;
1542     case V4L2_PIX_FMT_MPEG:    /* MPEG          */
1543       structure = gst_structure_new_empty ("video/mpegts");
1544       break;
1545     case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */
1546       break;
1547 #ifdef V4L2_PIX_FMT_SBGGR8
1548     case V4L2_PIX_FMT_SBGGR8:
1549       structure = gst_structure_new_empty ("video/x-bayer");
1550       break;
1551 #endif
1552 #ifdef V4L2_PIX_FMT_SN9C10X
1553     case V4L2_PIX_FMT_SN9C10X:
1554       structure = gst_structure_new_empty ("video/x-sonix");
1555       break;
1556 #endif
1557 #ifdef V4L2_PIX_FMT_PWC1
1558     case V4L2_PIX_FMT_PWC1:
1559       structure = gst_structure_new_empty ("video/x-pwc1");
1560       break;
1561 #endif
1562 #ifdef V4L2_PIX_FMT_PWC2
1563     case V4L2_PIX_FMT_PWC2:
1564       structure = gst_structure_new_empty ("video/x-pwc2");
1565       break;
1566 #endif
1567     default:
1568       GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
1569           fourcc, GST_FOURCC_ARGS (fourcc));
1570       break;
1571   }
1572
1573   return structure;
1574 }
1575
1576
1577 static GstCaps *
1578 gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags)
1579 {
1580   GstStructure *structure;
1581   GstCaps *caps;
1582   guint i;
1583
1584   caps = gst_caps_new_empty ();
1585   for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
1586
1587     if ((gst_v4l2_formats[i].flags & flags) == 0)
1588       continue;
1589
1590     structure =
1591         gst_v4l2_object_v4l2fourcc_to_structure (gst_v4l2_formats[i].format);
1592     if (structure) {
1593       if (gst_v4l2_formats[i].dimensions) {
1594         gst_structure_set (structure,
1595             "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
1596             "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
1597             "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL);
1598       }
1599       gst_caps_append_structure (caps, structure);
1600     }
1601   }
1602
1603   return gst_caps_simplify (caps);
1604 }
1605
1606 GstCaps *
1607 gst_v4l2_object_get_all_caps (void)
1608 {
1609   static GstCaps *caps = NULL;
1610
1611   if (caps == NULL)
1612     caps = gst_v4l2_object_get_caps_helper (GST_V4L2_ALL);
1613
1614   return gst_caps_ref (caps);
1615 }
1616
1617 GstCaps *
1618 gst_v4l2_object_get_raw_caps (void)
1619 {
1620   static GstCaps *caps = NULL;
1621
1622   if (caps == NULL)
1623     caps = gst_v4l2_object_get_caps_helper (GST_V4L2_RAW);
1624
1625   return gst_caps_ref (caps);
1626 }
1627
1628 GstCaps *
1629 gst_v4l2_object_get_codec_caps (void)
1630 {
1631   static GstCaps *caps = NULL;
1632
1633   if (caps == NULL)
1634     caps = gst_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
1635
1636   return gst_caps_ref (caps);
1637 }
1638
1639 /* gst_v4l2_object_choose_fourcc:
1640  * @obj a #GstV4l2Object
1641  * @fourcc_splane The format type in single plane representation
1642  * @fourcc_mplane The format type in multi-plane representation
1643  * @fourcc Set to the first format to try
1644  * @fourcc_alt The alternative format to use, or zero if mplane is not
1645  * supported. Note that if alternate is used, the prefered_non_contiguous
1646  * setting need to be inversed.
1647  *
1648  * Certain format can be stored into multi-planar buffer type with two
1649  * representation. As an example, NV12, which has two planes, can be stored
1650  * into 1 plane of multi-planar buffer sturcture, or two. This function will
1651  * choose the right format to use base on the object settings.
1652  */
1653 static void
1654 gst_v4l2_object_choose_fourcc (GstV4l2Object * obj, guint32 fourcc_splane,
1655     guint32 fourcc_mplane, guint32 * fourcc, guint32 * fourcc_alt)
1656 {
1657   if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
1658     if (obj->prefered_non_contiguous) {
1659       *fourcc = fourcc_mplane;
1660       *fourcc_alt = fourcc_splane;
1661     } else {
1662       *fourcc = fourcc_splane;
1663       *fourcc_alt = fourcc_mplane;
1664     }
1665   } else {
1666     *fourcc = fourcc_splane;
1667     *fourcc_alt = 0;
1668   }
1669 }
1670
1671 /* collect data for the given caps
1672  * @caps: given input caps
1673  * @format: location for the v4l format
1674  * @w/@h: location for width and height
1675  * @fps_n/@fps_d: location for framerate
1676  * @size: location for expected size of the frame or 0 if unknown
1677  */
1678 static gboolean
1679 gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
1680     struct v4l2_fmtdesc **format, GstVideoInfo * info)
1681 {
1682   GstStructure *structure;
1683   guint32 fourcc, fourcc_alt = 0;
1684   const gchar *mimetype;
1685   struct v4l2_fmtdesc *fmt;
1686
1687   /* default unknown values */
1688   fourcc = 0;
1689
1690   structure = gst_caps_get_structure (caps, 0);
1691
1692   mimetype = gst_structure_get_name (structure);
1693
1694   if (!gst_video_info_from_caps (info, caps))
1695     goto invalid_format;
1696
1697   if (g_str_equal (mimetype, "video/x-raw")) {
1698     switch (GST_VIDEO_INFO_FORMAT (info)) {
1699       case GST_VIDEO_FORMAT_I420:
1700         fourcc = V4L2_PIX_FMT_YUV420;
1701         break;
1702       case GST_VIDEO_FORMAT_YUY2:
1703         fourcc = V4L2_PIX_FMT_YUYV;
1704         break;
1705 #if 0
1706       case GST_VIDEO_FORMAT_Y41P:
1707         fourcc = V4L2_PIX_FMT_Y41P;
1708         break;
1709 #endif
1710       case GST_VIDEO_FORMAT_UYVY:
1711         fourcc = V4L2_PIX_FMT_UYVY;
1712         break;
1713       case GST_VIDEO_FORMAT_YV12:
1714         fourcc = V4L2_PIX_FMT_YVU420;
1715         break;
1716       case GST_VIDEO_FORMAT_Y41B:
1717         fourcc = V4L2_PIX_FMT_YUV411P;
1718         break;
1719       case GST_VIDEO_FORMAT_Y42B:
1720         fourcc = V4L2_PIX_FMT_YUV422P;
1721         break;
1722       case GST_VIDEO_FORMAT_NV12:
1723         gst_v4l2_object_choose_fourcc (v4l2object, V4L2_PIX_FMT_NV12,
1724             V4L2_PIX_FMT_NV12M, &fourcc, &fourcc_alt);
1725         break;
1726       case GST_VIDEO_FORMAT_NV21:
1727         gst_v4l2_object_choose_fourcc (v4l2object, V4L2_PIX_FMT_NV21,
1728             V4L2_PIX_FMT_NV21M, &fourcc, &fourcc_alt);
1729         break;
1730 #ifdef V4L2_PIX_FMT_YVYU
1731       case GST_VIDEO_FORMAT_YVYU:
1732         fourcc = V4L2_PIX_FMT_YVYU;
1733         break;
1734 #endif
1735       case GST_VIDEO_FORMAT_RGB15:
1736         fourcc = V4L2_PIX_FMT_RGB555;
1737         break;
1738       case GST_VIDEO_FORMAT_RGB16:
1739         fourcc = V4L2_PIX_FMT_RGB565;
1740         break;
1741       case GST_VIDEO_FORMAT_RGB:
1742         fourcc = V4L2_PIX_FMT_RGB24;
1743         break;
1744       case GST_VIDEO_FORMAT_BGR:
1745         fourcc = V4L2_PIX_FMT_BGR24;
1746         break;
1747       case GST_VIDEO_FORMAT_RGBx:
1748       case GST_VIDEO_FORMAT_RGBA:
1749         fourcc = V4L2_PIX_FMT_RGB32;
1750         break;
1751       case GST_VIDEO_FORMAT_BGRx:
1752       case GST_VIDEO_FORMAT_BGRA:
1753         fourcc = V4L2_PIX_FMT_BGR32;
1754         break;
1755       case GST_VIDEO_FORMAT_GRAY8:
1756         fourcc = V4L2_PIX_FMT_GREY;
1757       default:
1758         break;
1759     }
1760   } else {
1761     if (g_str_equal (mimetype, "video/mpegts")) {
1762       fourcc = V4L2_PIX_FMT_MPEG;
1763     } else if (g_str_equal (mimetype, "video/x-dv")) {
1764       fourcc = V4L2_PIX_FMT_DV;
1765     } else if (g_str_equal (mimetype, "image/jpeg")) {
1766       fourcc = V4L2_PIX_FMT_JPEG;
1767     } else if (g_str_equal (mimetype, "video/mpeg")) {
1768       gint version;
1769       if (gst_structure_get_int (structure, "mpegversion", &version)) {
1770         switch (version) {
1771           case 1:
1772             fourcc = V4L2_PIX_FMT_MPEG1;
1773             break;
1774           case 2:
1775             fourcc = V4L2_PIX_FMT_MPEG2;
1776             break;
1777           case 4:
1778             fourcc = V4L2_PIX_FMT_MPEG4;
1779             break;
1780           default:
1781             break;
1782         }
1783       }
1784 #ifdef V4L2_PIX_FMT_H263
1785     } else if (g_str_equal (mimetype, "video/x-h263")) {
1786       fourcc = V4L2_PIX_FMT_H263;
1787 #endif
1788 #ifdef V4L2_PIX_FMT_H264
1789     } else if (g_str_equal (mimetype, "video/x-h264")) {
1790       fourcc = V4L2_PIX_FMT_H264;
1791 #endif
1792 #ifdef V4L2_PIX_FMT_VP8
1793     } else if (g_str_equal (mimetype, "video/x-vp8")) {
1794       fourcc = V4L2_PIX_FMT_VP8;
1795 #endif
1796 #ifdef V4L2_PIX_FMT_SBGGR8
1797     } else if (g_str_equal (mimetype, "video/x-bayer")) {
1798       fourcc = V4L2_PIX_FMT_SBGGR8;
1799 #endif
1800 #ifdef V4L2_PIX_FMT_SN9C10X
1801     } else if (g_str_equal (mimetype, "video/x-sonix")) {
1802       fourcc = V4L2_PIX_FMT_SN9C10X;
1803 #endif
1804 #ifdef V4L2_PIX_FMT_PWC1
1805     } else if (g_str_equal (mimetype, "video/x-pwc1")) {
1806       fourcc = V4L2_PIX_FMT_PWC1;
1807 #endif
1808 #ifdef V4L2_PIX_FMT_PWC2
1809     } else if (g_str_equal (mimetype, "video/x-pwc2")) {
1810       fourcc = V4L2_PIX_FMT_PWC2;
1811     }
1812 #endif
1813   }
1814
1815   if (fourcc == 0)
1816     goto unhandled_format;
1817
1818   fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
1819
1820   if (fmt == NULL && fourcc_alt != 0) {
1821     GST_DEBUG_OBJECT (v4l2object, "No support for %" GST_FOURCC_FORMAT
1822         " trying %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc),
1823         GST_FOURCC_ARGS (fourcc_alt));
1824     v4l2object->prefered_non_contiguous = !v4l2object->prefered_non_contiguous;
1825     fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc_alt);
1826   }
1827
1828   if (fmt == NULL)
1829     goto unsupported_format;
1830
1831   *format = fmt;
1832
1833   return TRUE;
1834
1835   /* ERRORS */
1836 invalid_format:
1837   {
1838     GST_DEBUG_OBJECT (v4l2object, "invalid format");
1839     return FALSE;
1840   }
1841 unhandled_format:
1842   {
1843     GST_DEBUG_OBJECT (v4l2object, "unhandled format");
1844     return FALSE;
1845   }
1846 unsupported_format:
1847   {
1848     GST_DEBUG_OBJECT (v4l2object, "unsupported format");
1849     return FALSE;
1850   }
1851 }
1852
1853 static gboolean
1854 gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
1855     guint32 pixelformat, gint * width, gint * height, gboolean * interlaced);
1856
1857 static void
1858 gst_v4l2_object_add_aspect_ratio (GstV4l2Object * v4l2object, GstStructure * s)
1859 {
1860   struct v4l2_cropcap cropcap;
1861   int num = 1, den = 1;
1862
1863   if (!v4l2object->keep_aspect)
1864     return;
1865
1866   if (v4l2object->par) {
1867     num = gst_value_get_fraction_numerator (v4l2object->par);
1868     den = gst_value_get_fraction_denominator (v4l2object->par);
1869     goto done;
1870   }
1871
1872   memset (&cropcap, 0, sizeof (cropcap));
1873
1874   cropcap.type = v4l2object->type;
1875   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0)
1876     goto cropcap_failed;
1877
1878   num = cropcap.pixelaspect.numerator;
1879   den = cropcap.pixelaspect.denominator;
1880
1881 done:
1882   gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, num, den,
1883       NULL);
1884   return;
1885
1886 cropcap_failed:
1887   if (errno != ENOTTY)
1888     GST_WARNING_OBJECT (v4l2object->element,
1889         "Failed to probe pixel aspect ratio with VIDIOC_CROPCAP: %s",
1890         g_strerror (errno));
1891   goto done;
1892 }
1893
1894
1895 /* The frame interval enumeration code first appeared in Linux 2.6.19. */
1896 #ifdef VIDIOC_ENUM_FRAMEINTERVALS
1897 static GstStructure *
1898 gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
1899     guint32 pixelformat,
1900     guint32 width, guint32 height, const GstStructure * template)
1901 {
1902   gint fd = v4l2object->video_fd;
1903   struct v4l2_frmivalenum ival;
1904   guint32 num, denom;
1905   GstStructure *s;
1906   GValue rates = { 0, };
1907   gboolean interlaced;
1908   gint int_width = width;
1909   gint int_height = height;
1910
1911   if (v4l2object->never_interlaced) {
1912     interlaced = FALSE;
1913   } else {
1914     /* Interlaced detection using VIDIOC_TRY/S_FMT */
1915     if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat,
1916             &int_width, &int_height, &interlaced))
1917       return NULL;
1918   }
1919
1920   memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
1921   ival.index = 0;
1922   ival.pixel_format = pixelformat;
1923   ival.width = width;
1924   ival.height = height;
1925
1926   GST_LOG_OBJECT (v4l2object->element,
1927       "get frame interval for %ux%u, %" GST_FOURCC_FORMAT, width, height,
1928       GST_FOURCC_ARGS (pixelformat));
1929
1930   /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
1931    * fraction to get framerate */
1932   if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
1933     goto enum_frameintervals_failed;
1934
1935   if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
1936     GValue rate = { 0, };
1937
1938     g_value_init (&rates, GST_TYPE_LIST);
1939     g_value_init (&rate, GST_TYPE_FRACTION);
1940
1941     do {
1942       num = ival.discrete.numerator;
1943       denom = ival.discrete.denominator;
1944
1945       if (num > G_MAXINT || denom > G_MAXINT) {
1946         /* let us hope we don't get here... */
1947         num >>= 1;
1948         denom >>= 1;
1949       }
1950
1951       GST_LOG_OBJECT (v4l2object->element, "adding discrete framerate: %d/%d",
1952           denom, num);
1953
1954       /* swap to get the framerate */
1955       gst_value_set_fraction (&rate, denom, num);
1956       gst_value_list_append_value (&rates, &rate);
1957
1958       ival.index++;
1959     } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
1960   } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
1961     GValue min = { 0, };
1962     GValue step = { 0, };
1963     GValue max = { 0, };
1964     gboolean added = FALSE;
1965     guint32 minnum, mindenom;
1966     guint32 maxnum, maxdenom;
1967
1968     g_value_init (&rates, GST_TYPE_LIST);
1969
1970     g_value_init (&min, GST_TYPE_FRACTION);
1971     g_value_init (&step, GST_TYPE_FRACTION);
1972     g_value_init (&max, GST_TYPE_FRACTION);
1973
1974     /* get the min */
1975     minnum = ival.stepwise.min.numerator;
1976     mindenom = ival.stepwise.min.denominator;
1977     if (minnum > G_MAXINT || mindenom > G_MAXINT) {
1978       minnum >>= 1;
1979       mindenom >>= 1;
1980     }
1981     GST_LOG_OBJECT (v4l2object->element, "stepwise min frame interval: %d/%d",
1982         minnum, mindenom);
1983     gst_value_set_fraction (&min, minnum, mindenom);
1984
1985     /* get the max */
1986     maxnum = ival.stepwise.max.numerator;
1987     maxdenom = ival.stepwise.max.denominator;
1988     if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
1989       maxnum >>= 1;
1990       maxdenom >>= 1;
1991     }
1992
1993     GST_LOG_OBJECT (v4l2object->element, "stepwise max frame interval: %d/%d",
1994         maxnum, maxdenom);
1995     gst_value_set_fraction (&max, maxnum, maxdenom);
1996
1997     /* get the step */
1998     num = ival.stepwise.step.numerator;
1999     denom = ival.stepwise.step.denominator;
2000     if (num > G_MAXINT || denom > G_MAXINT) {
2001       num >>= 1;
2002       denom >>= 1;
2003     }
2004
2005     if (num == 0 || denom == 0) {
2006       /* in this case we have a wrong fraction or no step, set the step to max
2007        * so that we only add the min value in the loop below */
2008       num = maxnum;
2009       denom = maxdenom;
2010     }
2011
2012     /* since we only have gst_value_fraction_subtract and not add, negate the
2013      * numerator */
2014     GST_LOG_OBJECT (v4l2object->element, "stepwise step frame interval: %d/%d",
2015         num, denom);
2016     gst_value_set_fraction (&step, -num, denom);
2017
2018     while (gst_value_compare (&min, &max) != GST_VALUE_GREATER_THAN) {
2019       GValue rate = { 0, };
2020
2021       num = gst_value_get_fraction_numerator (&min);
2022       denom = gst_value_get_fraction_denominator (&min);
2023       GST_LOG_OBJECT (v4l2object->element, "adding stepwise framerate: %d/%d",
2024           denom, num);
2025
2026       /* invert to get the framerate */
2027       g_value_init (&rate, GST_TYPE_FRACTION);
2028       gst_value_set_fraction (&rate, denom, num);
2029       gst_value_list_append_value (&rates, &rate);
2030       added = TRUE;
2031
2032       /* we're actually adding because step was negated above. This is because
2033        * there is no _add function... */
2034       if (!gst_value_fraction_subtract (&min, &min, &step)) {
2035         GST_WARNING_OBJECT (v4l2object->element, "could not step fraction!");
2036         break;
2037       }
2038     }
2039     if (!added) {
2040       /* no range was added, leave the default range from the template */
2041       GST_WARNING_OBJECT (v4l2object->element,
2042           "no range added, leaving default");
2043       g_value_unset (&rates);
2044     }
2045   } else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
2046     guint32 maxnum, maxdenom;
2047
2048     g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
2049
2050     num = ival.stepwise.min.numerator;
2051     denom = ival.stepwise.min.denominator;
2052     if (num > G_MAXINT || denom > G_MAXINT) {
2053       num >>= 1;
2054       denom >>= 1;
2055     }
2056
2057     maxnum = ival.stepwise.max.numerator;
2058     maxdenom = ival.stepwise.max.denominator;
2059     if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
2060       maxnum >>= 1;
2061       maxdenom >>= 1;
2062     }
2063
2064     GST_LOG_OBJECT (v4l2object->element,
2065         "continuous frame interval %d/%d to %d/%d", maxdenom, maxnum, denom,
2066         num);
2067
2068     gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
2069   } else {
2070     goto unknown_type;
2071   }
2072
2073 return_data:
2074   s = gst_structure_copy (template);
2075   gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
2076       "height", G_TYPE_INT, (gint) height, NULL);
2077   gst_v4l2_object_add_aspect_ratio (v4l2object, s);
2078   if (g_str_equal (gst_structure_get_name (s), "video/x-raw"))
2079     gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
2080         (interlaced ? "mixed" : "progressive"), NULL);
2081
2082   if (G_IS_VALUE (&rates)) {
2083     /* only change the framerate on the template when we have a valid probed new
2084      * value */
2085     gst_structure_set_value (s, "framerate", &rates);
2086     g_value_unset (&rates);
2087   } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2088       v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
2089     gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1,
2090         NULL);
2091   }
2092   return s;
2093
2094   /* ERRORS */
2095 enum_frameintervals_failed:
2096   {
2097     GST_DEBUG_OBJECT (v4l2object->element,
2098         "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
2099         GST_FOURCC_ARGS (pixelformat), width, height);
2100     goto return_data;
2101   }
2102 unknown_type:
2103   {
2104     /* I don't see how this is actually an error, we ignore the format then */
2105     GST_WARNING_OBJECT (v4l2object->element,
2106         "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
2107         GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
2108     return NULL;
2109   }
2110 }
2111 #endif /* defined VIDIOC_ENUM_FRAMEINTERVALS */
2112
2113 #ifdef VIDIOC_ENUM_FRAMESIZES
2114 static gint
2115 sort_by_frame_size (GstStructure * s1, GstStructure * s2)
2116 {
2117   int w1, h1, w2, h2;
2118
2119   gst_structure_get_int (s1, "width", &w1);
2120   gst_structure_get_int (s1, "height", &h1);
2121   gst_structure_get_int (s2, "width", &w2);
2122   gst_structure_get_int (s2, "height", &h2);
2123
2124   /* I think it's safe to assume that this won't overflow for a while */
2125   return ((w2 * h2) - (w1 * h1));
2126 }
2127 #endif
2128
2129 static GstCaps *
2130 gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
2131     guint32 pixelformat, const GstStructure * template)
2132 {
2133   GstCaps *ret = gst_caps_new_empty ();
2134   GstStructure *tmp;
2135
2136 #ifdef VIDIOC_ENUM_FRAMESIZES
2137   gint fd = v4l2object->video_fd;
2138   struct v4l2_frmsizeenum size;
2139   GList *results = NULL;
2140   guint32 w, h;
2141
2142   if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
2143     return gst_caps_new_empty_simple ("video/mpegts");
2144
2145   memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
2146   size.index = 0;
2147   size.pixel_format = pixelformat;
2148
2149   GST_DEBUG_OBJECT (v4l2object->element,
2150       "Enumerating frame sizes for %" GST_FOURCC_FORMAT,
2151       GST_FOURCC_ARGS (pixelformat));
2152
2153   if (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
2154     goto enum_framesizes_failed;
2155
2156   if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
2157     do {
2158       GST_LOG_OBJECT (v4l2object->element, "got discrete frame size %dx%d",
2159           size.discrete.width, size.discrete.height);
2160
2161       w = MIN (size.discrete.width, G_MAXINT);
2162       h = MIN (size.discrete.height, G_MAXINT);
2163
2164       if (w && h) {
2165         tmp =
2166             gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2167             pixelformat, w, h, template);
2168
2169         if (tmp)
2170           results = g_list_prepend (results, tmp);
2171       }
2172
2173       size.index++;
2174     } while (v4l2_ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
2175     GST_DEBUG_OBJECT (v4l2object->element,
2176         "done iterating discrete frame sizes");
2177   } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
2178     GST_DEBUG_OBJECT (v4l2object->element, "we have stepwise frame sizes:");
2179     GST_DEBUG_OBJECT (v4l2object->element, "min width:   %d",
2180         size.stepwise.min_width);
2181     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
2182         size.stepwise.min_height);
2183     GST_DEBUG_OBJECT (v4l2object->element, "max width:   %d",
2184         size.stepwise.max_width);
2185     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
2186         size.stepwise.max_height);
2187     GST_DEBUG_OBJECT (v4l2object->element, "step width:  %d",
2188         size.stepwise.step_width);
2189     GST_DEBUG_OBJECT (v4l2object->element, "step height: %d",
2190         size.stepwise.step_height);
2191
2192     for (w = size.stepwise.min_width, h = size.stepwise.min_height;
2193         w <= size.stepwise.max_width && h <= size.stepwise.max_height;
2194         w += size.stepwise.step_width, h += size.stepwise.step_height) {
2195       if (w == 0 || h == 0)
2196         continue;
2197
2198       tmp =
2199           gst_v4l2_object_probe_caps_for_format_and_size (v4l2object,
2200           pixelformat, w, h, template);
2201
2202       if (tmp)
2203         results = g_list_prepend (results, tmp);
2204     }
2205     GST_DEBUG_OBJECT (v4l2object->element,
2206         "done iterating stepwise frame sizes");
2207   } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
2208     guint32 maxw, maxh;
2209
2210     GST_DEBUG_OBJECT (v4l2object->element, "we have continuous frame sizes:");
2211     GST_DEBUG_OBJECT (v4l2object->element, "min width:   %d",
2212         size.stepwise.min_width);
2213     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
2214         size.stepwise.min_height);
2215     GST_DEBUG_OBJECT (v4l2object->element, "max width:   %d",
2216         size.stepwise.max_width);
2217     GST_DEBUG_OBJECT (v4l2object->element, "min height:  %d",
2218         size.stepwise.max_height);
2219
2220     w = MAX (size.stepwise.min_width, 1);
2221     h = MAX (size.stepwise.min_height, 1);
2222     maxw = MIN (size.stepwise.max_width, G_MAXINT);
2223     maxh = MIN (size.stepwise.max_height, G_MAXINT);
2224
2225     tmp =
2226         gst_v4l2_object_probe_caps_for_format_and_size (v4l2object, pixelformat,
2227         w, h, template);
2228     if (tmp) {
2229       gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, (gint) w,
2230           (gint) maxw, "height", GST_TYPE_INT_RANGE, (gint) h, (gint) maxh,
2231           NULL);
2232
2233       /* no point using the results list here, since there's only one struct */
2234       gst_caps_append_structure (ret, tmp);
2235     }
2236   } else {
2237     goto unknown_type;
2238   }
2239
2240   /* we use an intermediary list to store and then sort the results of the
2241    * probing because we can't make any assumptions about the order in which
2242    * the driver will give us the sizes, but we want the final caps to contain
2243    * the results starting with the highest resolution and having the lowest
2244    * resolution last, since order in caps matters for things like fixation. */
2245   results = g_list_sort (results, (GCompareFunc) sort_by_frame_size);
2246   while (results != NULL) {
2247     gst_caps_append_structure (ret, GST_STRUCTURE (results->data));
2248     results = g_list_delete_link (results, results);
2249   }
2250
2251   if (gst_caps_is_empty (ret))
2252     goto enum_framesizes_no_results;
2253
2254   return ret;
2255
2256   /* ERRORS */
2257 enum_framesizes_failed:
2258   {
2259     /* I don't see how this is actually an error */
2260     GST_DEBUG_OBJECT (v4l2object->element,
2261         "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
2262         " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
2263     goto default_frame_sizes;
2264   }
2265 enum_framesizes_no_results:
2266   {
2267     /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
2268      * question doesn't actually support it yet */
2269     GST_DEBUG_OBJECT (v4l2object->element,
2270         "No results for pixelformat %" GST_FOURCC_FORMAT
2271         " enumerating frame sizes, trying fallback",
2272         GST_FOURCC_ARGS (pixelformat));
2273     goto default_frame_sizes;
2274   }
2275 unknown_type:
2276   {
2277     GST_WARNING_OBJECT (v4l2object->element,
2278         "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
2279         ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
2280     goto default_frame_sizes;
2281   }
2282 default_frame_sizes:
2283 #endif /* defined VIDIOC_ENUM_FRAMESIZES */
2284   {
2285     gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0;
2286     gboolean interlaced;
2287
2288     /* This code is for Linux < 2.6.19 */
2289     min_w = min_h = 1;
2290     max_w = max_h = GST_V4L2_MAX_SIZE;
2291     if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
2292             &min_h, &interlaced)) {
2293       GST_WARNING_OBJECT (v4l2object->element,
2294           "Could not probe minimum capture size for pixelformat %"
2295           GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
2296     }
2297     if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
2298             &max_h, &interlaced)) {
2299       GST_WARNING_OBJECT (v4l2object->element,
2300           "Could not probe maximum capture size for pixelformat %"
2301           GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
2302     }
2303
2304     /* Since we can't get framerate directly, try to use the current norm */
2305     if (v4l2object->tv_norm && v4l2object->norms) {
2306       GList *norms;
2307       GstTunerNorm *norm = NULL;
2308       GstTunerNorm *current =
2309           gst_v4l2_tuner_get_norm_by_std_id (v4l2object, v4l2object->tv_norm);
2310
2311       for (norms = v4l2object->norms; norms != NULL; norms = norms->next) {
2312         norm = (GstTunerNorm *) norms->data;
2313         if (!strcmp (norm->label, current->label))
2314           break;
2315       }
2316       /* If it's possible, set framerate to that (discrete) value */
2317       if (norm) {
2318         fix_num = gst_value_get_fraction_numerator (&norm->framerate);
2319         fix_denom = gst_value_get_fraction_denominator (&norm->framerate);
2320       }
2321     }
2322
2323     tmp = gst_structure_copy (template);
2324     if (fix_num) {
2325       gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION, fix_num,
2326           fix_denom, NULL);
2327     } else if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
2328         v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
2329       /* if norm can't be used, copy the template framerate */
2330       gst_structure_set (tmp, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
2331           100, 1, NULL);
2332     }
2333
2334     if (min_w == max_w)
2335       gst_structure_set (tmp, "width", G_TYPE_INT, max_w, NULL);
2336     else
2337       gst_structure_set (tmp, "width", GST_TYPE_INT_RANGE, min_w, max_w, NULL);
2338
2339     if (min_h == max_h)
2340       gst_structure_set (tmp, "height", G_TYPE_INT, max_h, NULL);
2341     else
2342       gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
2343
2344     if (g_str_equal (gst_structure_get_name (tmp), "video/x-raw"))
2345       gst_structure_set (tmp, "interlace-mode", G_TYPE_STRING,
2346           (interlaced ? "mixed" : "progressive"), NULL);
2347     gst_v4l2_object_add_aspect_ratio (v4l2object, tmp);
2348
2349     gst_caps_append_structure (ret, tmp);
2350
2351     return ret;
2352   }
2353 }
2354
2355 static gboolean
2356 gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
2357     guint32 pixelformat, gint * width, gint * height, gboolean * interlaced)
2358 {
2359   struct v4l2_format fmt, prevfmt;
2360   int fd;
2361   int r;
2362   int prevfmt_valid = FALSE;
2363   gboolean ret = FALSE;
2364
2365   g_return_val_if_fail (width != NULL, FALSE);
2366   g_return_val_if_fail (height != NULL, FALSE);
2367
2368   GST_LOG_OBJECT (v4l2object->element,
2369       "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
2370       *width, *height, GST_FOURCC_ARGS (pixelformat));
2371
2372   fd = v4l2object->video_fd;
2373
2374   memset (&fmt, 0, sizeof (struct v4l2_format));
2375   memset (&prevfmt, 0, sizeof (struct v4l2_format));
2376
2377   /* Some drivers are buggy and will modify the currently set format
2378      when processing VIDIOC_TRY_FMT, so we remember what is set at the
2379      minute, and will reset it when done. */
2380   if (!v4l2object->no_initial_format) {
2381     prevfmt.type = v4l2object->type;
2382     prevfmt_valid = (v4l2_ioctl (fd, VIDIOC_G_FMT, &prevfmt) >= 0);
2383   }
2384
2385   /* get size delimiters */
2386   memset (&fmt, 0, sizeof (fmt));
2387   fmt.type = v4l2object->type;
2388   fmt.fmt.pix.width = *width;
2389   fmt.fmt.pix.height = *height;
2390   fmt.fmt.pix.pixelformat = pixelformat;
2391   fmt.fmt.pix.field = V4L2_FIELD_NONE;
2392
2393   r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
2394   if (r < 0 && errno == EINVAL) {
2395     /* try again with interlaced video */
2396     fmt.fmt.pix.width = *width;
2397     fmt.fmt.pix.height = *height;
2398     fmt.fmt.pix.pixelformat = pixelformat;
2399     fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
2400     r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
2401   }
2402
2403   if (r < 0) {
2404     /* The driver might not implement TRY_FMT, in which case we will try
2405        S_FMT to probe */
2406     if (errno != ENOTTY)
2407       goto error;
2408
2409     /* Only try S_FMT if we're not actively capturing yet, which we shouldn't
2410        be, because we're still probing */
2411     if (GST_V4L2_IS_ACTIVE (v4l2object))
2412       goto error;
2413
2414     GST_LOG_OBJECT (v4l2object->element,
2415         "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT");
2416
2417     fmt.fmt.pix.width = *width;
2418     fmt.fmt.pix.height = *height;
2419
2420     r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
2421     if (r < 0 && errno == EINVAL) {
2422       /* try again with progressive video */
2423       fmt.fmt.pix.width = *width;
2424       fmt.fmt.pix.height = *height;
2425       fmt.fmt.pix.pixelformat = pixelformat;
2426       fmt.fmt.pix.field = V4L2_FIELD_NONE;
2427       r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
2428     }
2429
2430     if (r < 0)
2431       goto error;
2432   }
2433
2434   GST_LOG_OBJECT (v4l2object->element,
2435       "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
2436
2437   *width = fmt.fmt.pix.width;
2438   *height = fmt.fmt.pix.height;
2439
2440   switch (fmt.fmt.pix.field) {
2441     case V4L2_FIELD_ANY:
2442     case V4L2_FIELD_NONE:
2443       *interlaced = FALSE;
2444       break;
2445     case V4L2_FIELD_INTERLACED:
2446     case V4L2_FIELD_INTERLACED_TB:
2447     case V4L2_FIELD_INTERLACED_BT:
2448       *interlaced = TRUE;
2449       break;
2450     default:
2451       GST_WARNING_OBJECT (v4l2object->element,
2452           "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u",
2453           GST_FOURCC_ARGS (pixelformat), *width, *height);
2454       goto error;
2455   }
2456
2457   ret = TRUE;
2458
2459 error:
2460   if (!ret) {
2461     GST_WARNING_OBJECT (v4l2object->element,
2462         "Unable to try format: %s", g_strerror (errno));
2463   }
2464   if (prevfmt_valid)
2465     if (v4l2_ioctl (fd, VIDIOC_S_FMT, &prevfmt) < 0) {
2466       GST_WARNING_OBJECT (v4l2object->element,
2467           "Unable to restore format after trying format: %s",
2468           g_strerror (errno));
2469     }
2470
2471   return ret;
2472 }
2473
2474 static gboolean
2475 gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
2476 {
2477   GstV4l2IOMode mode;
2478
2479   GST_DEBUG_OBJECT (v4l2object->element, "initializing the capture system");
2480
2481   GST_V4L2_CHECK_OPEN (v4l2object);
2482   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
2483
2484   /* find transport */
2485   mode = v4l2object->req_mode;
2486
2487   if (v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
2488     if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
2489       mode = GST_V4L2_IO_RW;
2490   } else if (v4l2object->req_mode == GST_V4L2_IO_RW)
2491     goto method_not_supported;
2492
2493   if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
2494     if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
2495       mode = GST_V4L2_IO_MMAP;
2496   } else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
2497     goto method_not_supported;
2498
2499   /* if still no transport selected, error out */
2500   if (mode == GST_V4L2_IO_AUTO)
2501     goto no_supported_capture_method;
2502
2503   GST_INFO_OBJECT (v4l2object->element, "accessing buffers via mode %d", mode);
2504   v4l2object->mode = mode;
2505
2506   /* Map the buffers */
2507   GST_LOG_OBJECT (v4l2object->element, "initiating buffer pool");
2508
2509   if (!(v4l2object->pool = gst_v4l2_buffer_pool_new (v4l2object, caps)))
2510     goto buffer_pool_new_failed;
2511
2512   GST_V4L2_SET_ACTIVE (v4l2object);
2513
2514   return TRUE;
2515
2516   /* ERRORS */
2517 buffer_pool_new_failed:
2518   {
2519     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
2520         (_("Could not map buffers from device '%s'"),
2521             v4l2object->videodev),
2522         ("Failed to create buffer pool: %s", g_strerror (errno)));
2523     return FALSE;
2524   }
2525 method_not_supported:
2526   {
2527     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
2528         (_("The driver of device '%s' does not support the IO method %d"),
2529             v4l2object->videodev, mode), (NULL));
2530     return FALSE;
2531   }
2532 no_supported_capture_method:
2533   {
2534     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
2535         (_("The driver of device '%s' does not support any known IO "
2536                 "method."), v4l2object->videodev), (NULL));
2537     return FALSE;
2538   }
2539 }
2540
2541 static void
2542 gst_v4l2_object_save_format (GstV4l2Object * v4l2object,
2543     struct v4l2_fmtdesc *fmtdesc, struct v4l2_format *format,
2544     GstVideoInfo * info)
2545 {
2546   const GstVideoFormatInfo *finfo = info->finfo;
2547   gint i;
2548
2549   if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) {
2550     /* figure out the frame layout */
2551     v4l2object->n_v4l2_planes = MAX (1, format->fmt.pix_mp.num_planes);
2552     v4l2object->sizeimage = 0;
2553     for (i = 0; i < format->fmt.pix_mp.num_planes; i++) {
2554       v4l2object->bytesperline[i] =
2555           format->fmt.pix_mp.plane_fmt[i].bytesperline;
2556       v4l2object->sizeimage += format->fmt.pix_mp.plane_fmt[i].sizeimage;
2557     }
2558   } else {
2559     /* only one plane in non-MPLANE mode */
2560     v4l2object->n_v4l2_planes = 1;
2561
2562     /* figure out the frame layout */
2563     for (i = 0; i < finfo->n_planes; i++) {
2564       guint stride = format->fmt.pix.bytesperline;
2565
2566       switch (finfo->format) {
2567         case GST_VIDEO_FORMAT_NV12:
2568         case GST_VIDEO_FORMAT_NV21:
2569         case GST_VIDEO_FORMAT_NV16:
2570         case GST_VIDEO_FORMAT_NV24:
2571           v4l2object->bytesperline[i] = (i == 0 ? 1 : 2) *
2572               GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, stride);
2573           break;
2574         default:
2575           v4l2object->bytesperline[i] =
2576               GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, i, stride);
2577           break;
2578       }
2579
2580       GST_DEBUG_OBJECT (v4l2object->element,
2581           "Extrapolated stride for plane %d from %d to %d", i, stride,
2582           v4l2object->bytesperline[i]);
2583     }
2584
2585     v4l2object->sizeimage = format->fmt.pix.sizeimage;
2586   }
2587
2588   GST_DEBUG_OBJECT (v4l2object->element, "Got sizeimage %u",
2589       v4l2object->sizeimage);
2590
2591   v4l2object->info = *info;
2592   v4l2object->fmtdesc = fmtdesc;
2593
2594   /* if we have a framerate pre-calculate duration */
2595   if (info->fps_n > 0 && info->fps_d > 0) {
2596     v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, info->fps_d,
2597         info->fps_n);
2598   } else {
2599     v4l2object->duration = GST_CLOCK_TIME_NONE;
2600   }
2601 }
2602
2603 gboolean
2604 gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
2605 {
2606   gint fd = v4l2object->video_fd;
2607   struct v4l2_format format;
2608   struct v4l2_streamparm streamparm;
2609   enum v4l2_field field;
2610   guint32 pixelformat;
2611   struct v4l2_fmtdesc *fmtdesc;
2612   GstVideoInfo info;
2613   gint width, height, fps_n, fps_d;
2614   gint i = 0;
2615
2616   GST_V4L2_CHECK_OPEN (v4l2object);
2617   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
2618
2619   if (!gst_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
2620     goto invalid_caps;
2621
2622   pixelformat = fmtdesc->pixelformat;
2623   width = GST_VIDEO_INFO_WIDTH (&info);
2624   height = GST_VIDEO_INFO_HEIGHT (&info);
2625   fps_n = GST_VIDEO_INFO_FPS_N (&info);
2626   fps_d = GST_VIDEO_INFO_FPS_D (&info);
2627
2628   /* get bytesperline for each plane */
2629   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++)
2630     v4l2object->bytesperline[i] = GST_VIDEO_INFO_PLANE_STRIDE (&info, i);
2631
2632   if (GST_VIDEO_INFO_IS_INTERLACED (&info)) {
2633     GST_DEBUG_OBJECT (v4l2object->element, "interlaced video");
2634     /* ideally we would differentiate between types of interlaced video
2635      * but there is not sufficient information in the caps..
2636      */
2637     field = V4L2_FIELD_INTERLACED;
2638   } else {
2639     GST_DEBUG_OBJECT (v4l2object->element, "progressive video");
2640     field = V4L2_FIELD_NONE;
2641   }
2642
2643   GST_DEBUG_OBJECT (v4l2object->element, "Desired format %dx%d, format "
2644       "%" GST_FOURCC_FORMAT " stride: %d", width, height,
2645       GST_FOURCC_ARGS (pixelformat), v4l2object->bytesperline[0]);
2646
2647   /* MPEG-TS source cameras don't get their format set for some reason.
2648    * It looks wrong and we weren't able to track down the reason for that code
2649    * so it is disabled until someone who has an mpeg-ts camera complains...
2650    */
2651 #if 0
2652   /* Only unconditionally accept mpegts for sources */
2653   if ((v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
2654       (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')))
2655     goto done;
2656 #endif
2657
2658   memset (&format, 0x00, sizeof (struct v4l2_format));
2659   format.type = v4l2object->type;
2660
2661   if (!v4l2object->no_initial_format) {
2662     if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0)
2663       goto get_fmt_failed;
2664   }
2665
2666   if (V4L2_TYPE_IS_MULTIPLANAR (v4l2object->type)) {
2667     GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
2668         "%" GST_FOURCC_FORMAT " colorspace %d, nb planes %d",
2669         format.fmt.pix_mp.width, format.fmt.pix_mp.height,
2670         GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
2671         format.fmt.pix_mp.colorspace, format.fmt.pix_mp.num_planes);
2672
2673     if (format.type != v4l2object->type ||
2674         format.fmt.pix_mp.width != width ||
2675         format.fmt.pix_mp.height != height ||
2676         format.fmt.pix_mp.pixelformat != pixelformat ||
2677         format.fmt.pix_mp.field != field) {
2678       /* even in v4l2 multiplanar mode we can work in contiguous mode
2679        * if the device supports it */
2680       gint n_v4l_planes = GST_VIDEO_INFO_N_PLANES (&info);
2681
2682       /* if encoded format (GST_VIDEO_INFO_N_PLANES return 0)
2683        * or if contiguous is prefered */
2684       if (!n_v4l_planes || !v4l2object->prefered_non_contiguous)
2685         n_v4l_planes = 1;
2686
2687       /* something different, set the format */
2688       GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
2689           "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
2690
2691       format.type = v4l2object->type;
2692       format.fmt.pix_mp.pixelformat = pixelformat;
2693       format.fmt.pix_mp.width = width;
2694       format.fmt.pix_mp.height = height;
2695       format.fmt.pix_mp.field = field;
2696       format.fmt.pix_mp.num_planes = n_v4l_planes;
2697       /* try to ask our prefered stride but it's not a failure
2698        * if not accepted */
2699       for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
2700         format.fmt.pix_mp.plane_fmt[i].bytesperline =
2701             v4l2object->bytesperline[i];
2702
2703       if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) {
2704         format.fmt.pix_mp.plane_fmt[0].sizeimage = ENCODED_BUFFER_SIZE;
2705       }
2706
2707       if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0)
2708         goto set_fmt_failed;
2709
2710       GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
2711           "%" GST_FOURCC_FORMAT ", nb planes %d", format.fmt.pix.width,
2712           format.fmt.pix_mp.height,
2713           GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
2714           format.fmt.pix_mp.num_planes);
2715
2716 #ifndef GST_DISABLE_GST_DEBUG
2717       for (i = 0; i < format.fmt.pix_mp.num_planes; i++)
2718         GST_DEBUG_OBJECT (v4l2object->element, "  stride %d",
2719             format.fmt.pix_mp.plane_fmt[i].bytesperline);
2720 #endif
2721
2722       if (format.fmt.pix_mp.pixelformat != pixelformat)
2723         goto invalid_pixelformat;
2724
2725       /* we set the dimensions just in case but don't validate them afterwards
2726        * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
2727        * in ASF mode for example. */
2728       if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED) {
2729         if (format.fmt.pix_mp.width != width
2730             || format.fmt.pix_mp.height != height)
2731           goto invalid_dimensions;
2732       }
2733
2734       if (format.fmt.pix_mp.num_planes != n_v4l_planes)
2735         goto invalid_planes;
2736     }
2737
2738     /* figure out the frame layout */
2739     v4l2object->n_v4l2_planes = format.fmt.pix_mp.num_planes;
2740     v4l2object->sizeimage = 0;
2741     for (i = 0; i < format.fmt.pix_mp.num_planes; i++) {
2742       v4l2object->bytesperline[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline;
2743       v4l2object->sizeimage += format.fmt.pix_mp.plane_fmt[i].sizeimage;
2744     }
2745   } else {
2746     GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
2747         "%" GST_FOURCC_FORMAT " bytesperline %d, colorspace %d",
2748         format.fmt.pix.width, format.fmt.pix.height,
2749         GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
2750         format.fmt.pix.bytesperline, format.fmt.pix.colorspace);
2751
2752     if (format.type != v4l2object->type ||
2753         format.fmt.pix.width != width ||
2754         format.fmt.pix.height != height ||
2755         format.fmt.pix.pixelformat != pixelformat ||
2756         format.fmt.pix.field != field) {
2757       /* something different, set the format */
2758       GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
2759           "%" GST_FOURCC_FORMAT " bytesperline %d", width, height,
2760           GST_FOURCC_ARGS (pixelformat), v4l2object->bytesperline[0]);
2761
2762       format.type = v4l2object->type;
2763       format.fmt.pix.width = width;
2764       format.fmt.pix.height = height;
2765       format.fmt.pix.pixelformat = pixelformat;
2766       format.fmt.pix.field = field;
2767       /* try to ask our prefered stride */
2768       format.fmt.pix.bytesperline = v4l2object->bytesperline[0];
2769
2770       if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ENCODED) {
2771         format.fmt.pix.sizeimage = ENCODED_BUFFER_SIZE;
2772       }
2773
2774       if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0)
2775         goto set_fmt_failed;
2776
2777       GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
2778           "%" GST_FOURCC_FORMAT " stride %d", format.fmt.pix.width,
2779           format.fmt.pix.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
2780           format.fmt.pix.bytesperline);
2781
2782       /* we set the dimensions just in case but don't validate them afterwards
2783        * For some codecs the dimensions are *not* in the bitstream, IIRC VC1
2784        * in ASF mode for example. */
2785       if (info.finfo->format != GST_VIDEO_FORMAT_ENCODED) {
2786         if (format.fmt.pix.width != width || format.fmt.pix.height != height)
2787           goto invalid_dimensions;
2788       }
2789
2790       if (format.fmt.pix.pixelformat != pixelformat)
2791         goto invalid_pixelformat;
2792     }
2793   }
2794
2795   /* Is there a reason we require the caller to always specify a framerate? */
2796   GST_DEBUG_OBJECT (v4l2object->element, "Desired framerate: %u/%u", fps_n,
2797       fps_d);
2798
2799   memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
2800   streamparm.type = v4l2object->type;
2801
2802   if (v4l2_ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
2803     goto get_parm_failed;
2804
2805   GST_VIDEO_INFO_FPS_N (&info) =
2806       streamparm.parm.capture.timeperframe.denominator;
2807   GST_VIDEO_INFO_FPS_D (&info) = streamparm.parm.capture.timeperframe.numerator;
2808
2809   if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
2810       || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
2811     GST_DEBUG_OBJECT (v4l2object->element, "Got framerate: %u/%u",
2812         streamparm.parm.capture.timeperframe.denominator,
2813         streamparm.parm.capture.timeperframe.numerator);
2814
2815     /* We used to skip frame rate setup if the camera was already setup
2816      * with the requested frame rate. This breaks some cameras though,
2817      * causing them to not output data (several models of Thinkpad cameras
2818      * have this problem at least).
2819      * So, don't skip. */
2820     GST_LOG_OBJECT (v4l2object->element, "Setting framerate to %u/%u", fps_n,
2821         fps_d);
2822     /* We want to change the frame rate, so check whether we can. Some cheap USB
2823      * cameras don't have the capability */
2824     if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
2825       GST_DEBUG_OBJECT (v4l2object->element,
2826           "Not setting framerate (not supported)");
2827       goto done;
2828     }
2829
2830     /* Note: V4L2 wants the frame interval, we have the frame rate */
2831     streamparm.parm.capture.timeperframe.numerator = fps_d;
2832     streamparm.parm.capture.timeperframe.denominator = fps_n;
2833
2834     /* some cheap USB cam's won't accept any change */
2835     if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
2836       goto set_parm_failed;
2837
2838     /* get new values */
2839     fps_d = streamparm.parm.capture.timeperframe.numerator;
2840     fps_n = streamparm.parm.capture.timeperframe.denominator;
2841
2842     GST_INFO_OBJECT (v4l2object->element, "Set framerate to %u/%u", fps_n,
2843         fps_d);
2844
2845     GST_VIDEO_INFO_FPS_N (&info) = fps_n;
2846     GST_VIDEO_INFO_FPS_D (&info) = fps_d;
2847   }
2848
2849 done:
2850   gst_v4l2_object_save_format (v4l2object, fmtdesc, &format, &info);
2851
2852   /* now configure ther pools */
2853   if (!gst_v4l2_object_setup_pool (v4l2object, caps))
2854     goto pool_failed;
2855
2856   return TRUE;
2857
2858   /* ERRORS */
2859 invalid_caps:
2860   {
2861     GST_DEBUG_OBJECT (v4l2object->element, "can't parse caps %" GST_PTR_FORMAT,
2862         caps);
2863     return FALSE;
2864   }
2865 get_fmt_failed:
2866   {
2867     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2868         (_("Device '%s' does not support video capture"),
2869             v4l2object->videodev),
2870         ("Call to G_FMT failed: (%s)", g_strerror (errno)));
2871     return FALSE;
2872   }
2873 set_fmt_failed:
2874   {
2875     if (errno == EBUSY) {
2876       GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, BUSY,
2877           (_("Device '%s' is busy"), v4l2object->videodev),
2878           ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
2879               GST_FOURCC_ARGS (pixelformat), width, height,
2880               g_strerror (errno)));
2881     } else {
2882       GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2883           (_("Device '%s' cannot capture at %dx%d"),
2884               v4l2object->videodev, width, height),
2885           ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
2886               GST_FOURCC_ARGS (pixelformat), width, height,
2887               g_strerror (errno)));
2888     }
2889     return FALSE;
2890   }
2891 invalid_dimensions:
2892   {
2893     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2894         (_("Device '%s' cannot capture at %dx%d"),
2895             v4l2object->videodev, width, height),
2896         ("Tried to capture at %dx%d, but device returned size %dx%d",
2897             width, height, format.fmt.pix.width, format.fmt.pix.height));
2898     return FALSE;
2899   }
2900 invalid_pixelformat:
2901   {
2902     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2903         (_("Device '%s' cannot capture in the specified format"),
2904             v4l2object->videodev),
2905         ("Tried to capture in %" GST_FOURCC_FORMAT
2906             ", but device returned format" " %" GST_FOURCC_FORMAT,
2907             GST_FOURCC_ARGS (pixelformat),
2908             GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
2909     return FALSE;
2910   }
2911 invalid_planes:
2912   {
2913     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2914         (_("Device '%s' does support non-contiguous planes"),
2915             v4l2object->videodev),
2916         ("Device wants %d planes", format.fmt.pix_mp.num_planes));
2917     return FALSE;
2918   }
2919 get_parm_failed:
2920   {
2921     /* it's possible that this call is not supported */
2922     if (errno != EINVAL && errno != ENOTTY) {
2923       GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
2924           (_("Could not get parameters on device '%s'"),
2925               v4l2object->videodev), GST_ERROR_SYSTEM);
2926     }
2927     goto done;
2928   }
2929 set_parm_failed:
2930   {
2931     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
2932         (_("Video device did not accept new frame rate setting.")),
2933         GST_ERROR_SYSTEM);
2934     goto done;
2935   }
2936 pool_failed:
2937   {
2938     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
2939         (_("Video device could not create buffer pool.")), GST_ERROR_SYSTEM);
2940     return FALSE;
2941   }
2942 }
2943
2944 /**
2945  * gst_v4l2_object_setup_format:
2946  * @v4l2object the object
2947  * @info a GstVideoInfo to be filled
2948  * @align a GstVideoAlignment to be filled
2949  *
2950  * Setup the format base on the currently configured format. This is useful in
2951  * decoder or encoder elements where the output format is dictated by the
2952  * input.
2953  *
2954  * Returns: %TRUE on success, %FALSE on failure.
2955  */
2956 gboolean
2957 gst_v4l2_object_setup_format (GstV4l2Object * v4l2object,
2958     GstVideoInfo * info, GstVideoAlignment * align)
2959 {
2960   struct v4l2_fmtdesc *fmtdesc;
2961   struct v4l2_format fmt;
2962   struct v4l2_crop crop;
2963   GstVideoFormat format;
2964   guint width, height;
2965
2966   gst_video_info_init (info);
2967   gst_video_alignment_reset (align);
2968
2969   memset (&fmt, 0x00, sizeof (struct v4l2_format));
2970   fmt.type = v4l2object->type;
2971   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FMT, &fmt) < 0)
2972     goto get_fmt_failed;
2973
2974   fmtdesc = gst_v4l2_object_get_format_from_fourcc (v4l2object,
2975       fmt.fmt.pix.pixelformat);
2976   if (fmtdesc == NULL)
2977     goto unsupported_format;
2978
2979   /* No need to care about mplane, the four first params are the same */
2980   format = gst_v4l2_object_v4l2fourcc_to_video_format (fmt.fmt.pix.pixelformat);
2981
2982   /* FIXME do more work in the whole function if
2983    * format is GST_VIDEO_FORMAT_ENCODED
2984    * Also gst_v4l2_object_v4l2fourcc_to_video_format should be improved
2985    * because for now it never returns GST_VIDEO_FORMAT_ENCODED
2986    */
2987
2988   /* fails if we do no translate the fmt.pix.pixelformat to GstVideoFormat */
2989   if (format == GST_VIDEO_FORMAT_UNKNOWN)
2990     goto unsupported_format;
2991
2992   if (fmt.fmt.pix.width == 0 || fmt.fmt.pix.height == 0)
2993     goto invalid_dimensions;
2994
2995   width = fmt.fmt.pix.width;
2996   height = fmt.fmt.pix.height;
2997
2998   memset (&crop, 0, sizeof (struct v4l2_crop));
2999   crop.type = v4l2object->type;
3000   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CROP, &crop) >= 0) {
3001     align->padding_left = crop.c.left;
3002     align->padding_top = crop.c.top;
3003     align->padding_right = width - crop.c.width - crop.c.left;
3004     align->padding_bottom = height - crop.c.height - crop.c.top;
3005     width = crop.c.width;
3006     height = crop.c.height;
3007   }
3008
3009   gst_video_info_set_format (info, format, width, height);
3010
3011   switch (fmt.fmt.pix.field) {
3012     case V4L2_FIELD_ANY:
3013     case V4L2_FIELD_NONE:
3014       info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
3015       break;
3016     case V4L2_FIELD_INTERLACED:
3017     case V4L2_FIELD_INTERLACED_TB:
3018     case V4L2_FIELD_INTERLACED_BT:
3019       info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
3020       break;
3021     default:
3022       goto unsupported_field;
3023   }
3024
3025   gst_v4l2_object_save_format (v4l2object, fmtdesc, &fmt, info);
3026
3027   /* Shall we setup the pool ? */
3028
3029   return TRUE;
3030
3031 get_fmt_failed:
3032   {
3033     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
3034         (_("Video device did not provide output format.")), GST_ERROR_SYSTEM);
3035     return FALSE;
3036   }
3037 invalid_dimensions:
3038   {
3039     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
3040         (_("Video device returned invalid dimensions.")),
3041         ("Expected non 0 dimensions, got %dx%d", fmt.fmt.pix.width,
3042             fmt.fmt.pix.height));
3043     return FALSE;
3044   }
3045 unsupported_field:
3046   {
3047     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
3048         (_("Video devices uses an unsupported interlacing method.")),
3049         ("V4L2 field type %d not supported", fmt.fmt.pix.field));
3050     return FALSE;
3051   }
3052 unsupported_format:
3053   {
3054     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
3055         (_("Video devices uses an unsupported pixel format.")),
3056         ("V4L2 format %" GST_FOURCC_FORMAT " not supported",
3057             GST_FOURCC_ARGS (fmt.fmt.pix.pixelformat)));
3058     return FALSE;
3059   }
3060 }
3061
3062 gboolean
3063 gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
3064 {
3065   GstStructure *s;
3066   GstCaps *oldcaps;
3067
3068   if (!v4l2object->pool)
3069     return FALSE;
3070
3071   s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (v4l2object->pool));
3072   gst_buffer_pool_config_get_params (s, &oldcaps, NULL, NULL, NULL);
3073
3074   return oldcaps && gst_caps_is_equal (caps, oldcaps);
3075 }
3076
3077 gboolean
3078 gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
3079 {
3080   GST_LOG_OBJECT (v4l2object->element, "flush poll");
3081   gst_poll_set_flushing (v4l2object->poll, TRUE);
3082
3083   return TRUE;
3084 }
3085
3086 gboolean
3087 gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
3088 {
3089   GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
3090   gst_poll_set_flushing (v4l2object->poll, FALSE);
3091
3092   return TRUE;
3093 }
3094
3095 gboolean
3096 gst_v4l2_object_stop (GstV4l2Object * v4l2object)
3097 {
3098   GST_DEBUG_OBJECT (v4l2object->element, "stopping");
3099
3100   if (!GST_V4L2_IS_OPEN (v4l2object))
3101     goto done;
3102   if (!GST_V4L2_IS_ACTIVE (v4l2object))
3103     goto done;
3104
3105   if (v4l2object->pool) {
3106     GST_DEBUG_OBJECT (v4l2object->element, "deactivating pool");
3107     gst_buffer_pool_set_active (GST_BUFFER_POOL_CAST (v4l2object->pool), FALSE);
3108     gst_object_unref (v4l2object->pool);
3109     v4l2object->pool = NULL;
3110   }
3111
3112   GST_V4L2_SET_INACTIVE (v4l2object);
3113
3114 done:
3115   return TRUE;
3116 }
3117
3118 gboolean
3119 gst_v4l2_object_copy (GstV4l2Object * v4l2object, GstBuffer * dest,
3120     GstBuffer * src)
3121 {
3122   const GstVideoFormatInfo *finfo = v4l2object->info.finfo;
3123
3124   if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
3125           finfo->format != GST_VIDEO_FORMAT_ENCODED)) {
3126     GstVideoFrame src_frame, dest_frame;
3127
3128     GST_DEBUG_OBJECT (v4l2object->element, "copy video frame");
3129
3130     /* we have raw video, use videoframe copy to get strides right */
3131     if (!gst_video_frame_map (&src_frame, &v4l2object->info, src, GST_MAP_READ))
3132       goto invalid_buffer;
3133
3134     if (!gst_video_frame_map (&dest_frame, &v4l2object->info, dest,
3135             GST_MAP_WRITE)) {
3136       gst_video_frame_unmap (&src_frame);
3137       goto invalid_buffer;
3138     }
3139
3140     gst_video_frame_copy (&dest_frame, &src_frame);
3141
3142     gst_video_frame_unmap (&src_frame);
3143     gst_video_frame_unmap (&dest_frame);
3144   } else {
3145     GstMapInfo map;
3146
3147     GST_DEBUG_OBJECT (v4l2object->element, "copy raw bytes");
3148     gst_buffer_map (src, &map, GST_MAP_READ);
3149     gst_buffer_fill (dest, 0, map.data, gst_buffer_get_size (src));
3150     gst_buffer_unmap (src, &map);
3151     gst_buffer_resize (dest, 0, gst_buffer_get_size (src));
3152   }
3153   GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
3154       "slow copy into buffer %p", dest);
3155
3156   return TRUE;
3157
3158   /* ERRORS */
3159 invalid_buffer:
3160   {
3161     /* No Window available to put our image into */
3162     GST_WARNING_OBJECT (v4l2object->element, "could not map image");
3163     return FALSE;
3164   }
3165 }
3166
3167 GstCaps *
3168 gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter)
3169 {
3170   GstCaps *ret;
3171   GSList *walk;
3172   GSList *formats;
3173
3174   if (v4l2object->probed_caps == NULL) {
3175     formats = gst_v4l2_object_get_format_list (v4l2object);
3176
3177     ret = gst_caps_new_empty ();
3178
3179     for (walk = formats; walk; walk = walk->next) {
3180       struct v4l2_fmtdesc *format;
3181       GstStructure *template;
3182
3183       format = (struct v4l2_fmtdesc *) walk->data;
3184
3185       template = gst_v4l2_object_v4l2fourcc_to_structure (format->pixelformat);
3186
3187       if (template) {
3188         GstCaps *tmp;
3189
3190         tmp = gst_v4l2_object_probe_caps_for_format (v4l2object,
3191             format->pixelformat, template);
3192         if (tmp)
3193           gst_caps_append (ret, tmp);
3194
3195         gst_structure_free (template);
3196       } else {
3197         GST_DEBUG_OBJECT (v4l2object->element, "unknown format %u",
3198             format->pixelformat);
3199       }
3200     }
3201     v4l2object->probed_caps = ret;
3202   }
3203
3204   if (filter) {
3205     ret = gst_caps_intersect_full (filter, v4l2object->probed_caps,
3206         GST_CAPS_INTERSECT_FIRST);
3207   } else {
3208     ret = gst_caps_ref (v4l2object->probed_caps);
3209   }
3210
3211   GST_INFO_OBJECT (v4l2object->element, "probed caps: %" GST_PTR_FORMAT, ret);
3212   LOG_CAPS (v4l2object->element, ret);
3213
3214   return ret;
3215 }
3216
3217 gboolean
3218 gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query)
3219 {
3220   GstBufferPool *pool;
3221   guint size, min, max;
3222   gboolean update;
3223   struct v4l2_control ctl = { 0, };
3224
3225   GST_DEBUG_OBJECT (obj->element, "decide allocation");
3226
3227   g_return_val_if_fail (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
3228       obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, FALSE);
3229
3230   if (obj->pool == NULL) {
3231     GstCaps *caps;
3232     gst_query_parse_allocation (query, &caps, NULL);
3233
3234     if (!gst_v4l2_object_setup_pool (obj, caps))
3235       goto pool_failed;
3236   }
3237
3238   if (gst_query_get_n_allocation_pools (query) > 0) {
3239     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
3240     update = TRUE;
3241   } else {
3242     pool = NULL;
3243     min = max = 0;
3244     size = 0;
3245     update = FALSE;
3246   }
3247
3248   GST_DEBUG_OBJECT (obj->element, "allocation: size:%u min:%u max:%u pool:%"
3249       GST_PTR_FORMAT, size, min, max, pool);
3250
3251   if (min != 0) {
3252     /* if there is a min-buffers suggestion, use it. We add 1 because we need 1
3253      * buffer extra to capture while the other two buffers are downstream */
3254     min += 1;
3255   } else {
3256     min = 2;
3257   }
3258
3259   /* Certain driver may expose a minimum through controls */
3260   ctl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
3261   if (v4l2_ioctl (obj->video_fd, VIDIOC_G_CTRL, &ctl) >= 0) {
3262     GST_DEBUG_OBJECT (obj->element, "driver require a minimum of %d buffers",
3263         ctl.value);
3264     min += ctl.value;
3265   }
3266
3267   /* Request a bigger max, if one was suggested but it's too small */
3268   if (max != 0 && max < min)
3269     max = min;
3270
3271   /* select a pool */
3272   switch (obj->mode) {
3273     case GST_V4L2_IO_RW:
3274       if (pool == NULL) {
3275         /* no downstream pool, use our own then */
3276         GST_DEBUG_OBJECT (obj->element,
3277             "read/write mode: no downstream pool, using our own");
3278         pool = GST_BUFFER_POOL_CAST (obj->pool);
3279         size = obj->sizeimage;
3280       } else {
3281         /* in READ/WRITE mode, prefer a downstream pool because our own pool
3282          * doesn't help much, we have to write to it as well */
3283         GST_DEBUG_OBJECT (obj->element,
3284             "read/write mode: using downstream pool");
3285         /* use the bigest size, when we use our own pool we can't really do any
3286          * other size than what the hardware gives us but for downstream pools
3287          * we can try */
3288         size = MAX (size, obj->sizeimage);
3289       }
3290       break;
3291     case GST_V4L2_IO_MMAP:
3292     case GST_V4L2_IO_USERPTR:
3293     case GST_V4L2_IO_DMABUF:
3294       /* in streaming mode, prefer our own pool */
3295       if (pool)
3296         gst_object_unref (pool);
3297       pool = GST_BUFFER_POOL_CAST (obj->pool);
3298       size = obj->sizeimage;
3299       max = 0;
3300       GST_DEBUG_OBJECT (obj->element,
3301           "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
3302       break;
3303     case GST_V4L2_IO_AUTO:
3304     default:
3305       GST_WARNING_OBJECT (obj->element, "unhandled mode");
3306       break;
3307   }
3308
3309   if (pool) {
3310     GstStructure *config;
3311     GstCaps *caps;
3312
3313     config = gst_buffer_pool_get_config (pool);
3314     gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL);
3315     gst_buffer_pool_config_set_params (config, caps, size, min, max);
3316
3317     /* if downstream supports video metadata, add this to the pool config */
3318     if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
3319       GST_DEBUG_OBJECT (pool, "activate Video Meta");
3320       gst_buffer_pool_config_add_option (config,
3321           GST_BUFFER_POOL_OPTION_VIDEO_META);
3322     }
3323
3324     gst_buffer_pool_set_config (pool, config);
3325   }
3326
3327   if (update)
3328     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
3329   else
3330     gst_query_add_allocation_pool (query, pool, size, min, max);
3331
3332   return TRUE;
3333
3334 pool_failed:
3335   {
3336     GST_ELEMENT_ERROR (obj->element, RESOURCE, SETTINGS,
3337         (_("Video device could not create buffer pool.")), GST_ERROR_SYSTEM);
3338     return FALSE;
3339   }
3340 }