v4l2: Fix typo contol -> control
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2_calls.c
1 /* GStreamer
2  *
3  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
4  *               2006 Edgard Lima <edgard.lima@indt.org.br>
5  *
6  * v4l2_calls.c - generic V4L2 calls handling
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #ifdef __sun
37 /* Needed on older Solaris Nevada builds (72 at least) */
38 #include <stropts.h>
39 #include <sys/ioccom.h>
40 #endif
41 #include "v4l2_calls.h"
42 #include "gstv4l2tuner.h"
43 #if 0
44 #include "gstv4l2xoverlay.h"
45 #endif
46 #include "gstv4l2colorbalance.h"
47
48 #include "gstv4l2src.h"
49 #include "gstv4l2sink.h"
50 #include "gstv4l2videodec.h"
51
52 #include "gst/gst-i18n-plugin.h"
53
54 /* Those are ioctl calls */
55 #ifndef V4L2_CID_HCENTER
56 #define V4L2_CID_HCENTER V4L2_CID_HCENTER_DEPRECATED
57 #endif
58 #ifndef V4L2_CID_VCENTER
59 #define V4L2_CID_VCENTER V4L2_CID_VCENTER_DEPRECATED
60 #endif
61
62 #ifndef V4L2_CAP_VIDEO_M2M
63 #define V4L2_CAP_VIDEO_M2M              0x00008000
64 #endif
65 #ifndef V4L2_CAP_VIDEO_M2M_MPLANE
66 #define V4L2_CAP_VIDEO_M2M_MPLANE       0x00004000
67 #endif
68
69 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
70 #define GST_CAT_DEFAULT v4l2_debug
71
72 /******************************************************
73  * gst_v4l2_get_capabilities():
74  *   get the device's capturing capabilities
75  * return value: TRUE on success, FALSE on error
76  ******************************************************/
77 gboolean
78 gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
79 {
80   GstElement *e;
81
82   e = v4l2object->element;
83
84   GST_DEBUG_OBJECT (e, "getting capabilities");
85
86   if (!GST_V4L2_IS_OPEN (v4l2object))
87     return FALSE;
88
89   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
90     goto cap_failed;
91
92   GST_LOG_OBJECT (e, "driver:      '%s'", v4l2object->vcap.driver);
93   GST_LOG_OBJECT (e, "card:        '%s'", v4l2object->vcap.card);
94   GST_LOG_OBJECT (e, "bus_info:    '%s'", v4l2object->vcap.bus_info);
95   GST_LOG_OBJECT (e, "version:     %08x", v4l2object->vcap.version);
96   GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities);
97
98   return TRUE;
99
100   /* ERRORS */
101 cap_failed:
102   {
103     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
104         (_("Error getting capabilities for device '%s': "
105                 "It isn't a v4l2 driver. Check if it is a v4l1 driver."),
106             v4l2object->videodev), GST_ERROR_SYSTEM);
107     return FALSE;
108   }
109 }
110
111 /******************************************************
112  * The video4linux command line tool v4l2-ctrl
113  * normalises the names of the controls received from
114  * the kernel like:
115  *
116  *     "Exposure (absolute)" -> "exposure_absolute"
117  *
118  * We follow their lead here.  @name is modified
119  * in-place.
120  ******************************************************/
121 static void
122 gst_v4l2_normalise_control_name (gchar * name)
123 {
124   int i, j;
125   for (i = 0, j = 0; name[j]; ++j) {
126     if (g_ascii_isalnum (name[j])) {
127       if (i > 0 && !g_ascii_isalnum (name[j - 1]))
128         name[i++] = '_';
129       name[i++] = g_ascii_tolower (name[j]);
130     }
131   }
132   name[i++] = '\0';
133 }
134
135 /******************************************************
136  * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
137  *   fill/empty the lists of enumerations
138  * return value: TRUE on success, FALSE on error
139  ******************************************************/
140 static gboolean
141 gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
142 {
143   gint n, next;
144   struct v4l2_queryctrl control = { 0, };
145
146   GstElement *e;
147
148   e = v4l2object->element;
149
150   GST_DEBUG_OBJECT (e, "getting enumerations");
151   GST_V4L2_CHECK_OPEN (v4l2object);
152
153   GST_DEBUG_OBJECT (e, "  channels");
154   /* and now, the channels */
155   for (n = 0;; n++) {
156     struct v4l2_input input;
157     GstV4l2TunerChannel *v4l2channel;
158     GstTunerChannel *channel;
159
160     memset (&input, 0, sizeof (input));
161
162     input.index = n;
163     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
164       if (errno == EINVAL || errno == ENOTTY)
165         break;                  /* end of enumeration */
166       else {
167         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
168             (_("Failed to query attributes of input %d in device %s"),
169                 n, v4l2object->videodev),
170             ("Failed to get %d in input enumeration for %s. (%d - %s)",
171                 n, v4l2object->videodev, errno, strerror (errno)));
172         return FALSE;
173       }
174     }
175
176     GST_LOG_OBJECT (e, "   index:     %d", input.index);
177     GST_LOG_OBJECT (e, "   name:      '%s'", input.name);
178     GST_LOG_OBJECT (e, "   type:      %08x", input.type);
179     GST_LOG_OBJECT (e, "   audioset:  %08x", input.audioset);
180     GST_LOG_OBJECT (e, "   std:       %016" G_GINT64_MODIFIER "x",
181         (guint64) input.std);
182     GST_LOG_OBJECT (e, "   status:    %08x", input.status);
183
184     v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
185     channel = GST_TUNER_CHANNEL (v4l2channel);
186     channel->label = g_strdup ((const gchar *) input.name);
187     channel->flags = GST_TUNER_CHANNEL_INPUT;
188     v4l2channel->index = n;
189
190     if (input.type == V4L2_INPUT_TYPE_TUNER) {
191       struct v4l2_tuner vtun;
192
193       v4l2channel->tuner = input.tuner;
194       channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
195
196       vtun.index = input.tuner;
197       if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
198         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
199             (_("Failed to get setting of tuner %d on device '%s'."),
200                 input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
201         g_object_unref (G_OBJECT (channel));
202         return FALSE;
203       }
204
205       channel->freq_multiplicator =
206           62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
207       channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
208       channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
209       channel->min_signal = 0;
210       channel->max_signal = 0xffff;
211     }
212     if (input.audioset) {
213       /* we take the first. We don't care for
214        * the others for now */
215       while (!(input.audioset & (1 << v4l2channel->audio)))
216         v4l2channel->audio++;
217       channel->flags |= GST_TUNER_CHANNEL_AUDIO;
218     }
219
220     v4l2object->channels =
221         g_list_prepend (v4l2object->channels, (gpointer) channel);
222   }
223   v4l2object->channels = g_list_reverse (v4l2object->channels);
224
225   GST_DEBUG_OBJECT (e, "  norms");
226   /* norms... */
227   for (n = 0;; n++) {
228     struct v4l2_standard standard = { 0, };
229     GstV4l2TunerNorm *v4l2norm;
230
231     GstTunerNorm *norm;
232
233     /* fill in defaults */
234     standard.frameperiod.numerator = 1;
235     standard.frameperiod.denominator = 0;
236     standard.index = n;
237
238     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
239       if (errno == EINVAL || errno == ENOTTY)
240         break;                  /* end of enumeration */
241 #ifdef ENODATA
242       else if (errno == ENODATA)
243         break;                  /* end of enumeration, as of Linux 3.7-rc1 */
244 #endif
245       else {
246         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
247             (_("Failed to query norm on device '%s'."),
248                 v4l2object->videodev),
249             ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)",
250                 n, v4l2object->videodev, errno, strerror (errno)));
251         return FALSE;
252       }
253     }
254
255     GST_DEBUG_OBJECT (e, "    '%s', fps: %d / %d",
256         standard.name, standard.frameperiod.denominator,
257         standard.frameperiod.numerator);
258
259     v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
260     norm = GST_TUNER_NORM (v4l2norm);
261     norm->label = g_strdup ((const gchar *) standard.name);
262     gst_value_set_fraction (&norm->framerate,
263         standard.frameperiod.denominator, standard.frameperiod.numerator);
264     v4l2norm->index = standard.id;
265
266     GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
267         (unsigned int) v4l2norm->index, norm->label);
268
269     v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm);
270   }
271   v4l2object->norms = g_list_reverse (v4l2object->norms);
272
273   GST_DEBUG_OBJECT (e, "  controls+menus");
274
275   /* and lastly, controls+menus (if appropriate) */
276 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
277   next = V4L2_CTRL_FLAG_NEXT_CTRL;
278   n = 0;
279 #else
280   next = 0;
281   n = V4L2_CID_BASE;
282 #endif
283   control.id = next;
284   while (TRUE) {
285     GstV4l2ColorBalanceChannel *v4l2channel;
286     GstColorBalanceChannel *channel;
287
288     if (!next)
289       n++;
290
291   retry:
292     /* when we reached the last official CID, continue with private CIDs */
293     if (n == V4L2_CID_LASTP1) {
294       GST_DEBUG_OBJECT (e, "checking private CIDs");
295       n = V4L2_CID_PRIVATE_BASE;
296     }
297     GST_DEBUG_OBJECT (e, "checking control %08x", n);
298
299     control.id = n | next;
300     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
301       if (next) {
302         if (n > 0) {
303           GST_DEBUG_OBJECT (e, "controls finished");
304           break;
305         } else {
306           GST_DEBUG_OBJECT (e, "V4L2_CTRL_FLAG_NEXT_CTRL not supported.");
307           next = 0;
308           n = V4L2_CID_BASE;
309           goto retry;
310         }
311       }
312       if (errno == EINVAL || errno == ENOTTY || errno == EIO || errno == ENOENT) {
313         if (n < V4L2_CID_PRIVATE_BASE) {
314           GST_DEBUG_OBJECT (e, "skipping control %08x", n);
315           /* continue so that we also check private controls */
316           continue;
317         } else {
318           GST_DEBUG_OBJECT (e, "controls finished");
319           break;
320         }
321       } else {
322         GST_WARNING_OBJECT (e, "Failed querying control %d on device '%s'. "
323             "(%d - %s)", n, v4l2object->videodev, errno, strerror (errno));
324         continue;
325       }
326     }
327     /* bogus driver might mess with id in unexpected ways (e.g. set to 0), so
328      * make sure to simply try all if V4L2_CTRL_FLAG_NEXT_CTRL not supported */
329     if (next)
330       n = control.id;
331     if (control.flags & V4L2_CTRL_FLAG_DISABLED) {
332       GST_DEBUG_OBJECT (e, "skipping disabled control");
333       continue;
334     }
335 #ifdef V4L2_CTRL_TYPE_CTRL_CLASS
336     if (control.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
337       GST_DEBUG_OBJECT (e, "starting control class '%s'", control.name);
338       continue;
339     }
340 #endif
341     switch (control.type) {
342       case V4L2_CTRL_TYPE_INTEGER:
343       case V4L2_CTRL_TYPE_BOOLEAN:
344       case V4L2_CTRL_TYPE_MENU:
345 #ifdef V4L2_CTRL_TYPE_INTEGER_MENU
346       case V4L2_CTRL_TYPE_INTEGER_MENU:
347 #endif
348 #ifdef V4L2_CTRL_TYPE_BITMASK
349       case V4L2_CTRL_TYPE_BITMASK:
350 #endif
351       case V4L2_CTRL_TYPE_BUTTON:{
352         control.name[31] = '\0';
353         gst_v4l2_normalise_control_name ((gchar *) control.name);
354         g_datalist_id_set_data (&v4l2object->controls,
355             g_quark_from_string ((const gchar *) control.name),
356             GINT_TO_POINTER (n));
357         break;
358       }
359       default:
360         GST_DEBUG_OBJECT (e,
361             "Control type for '%s' not suppored for extra controls.",
362             control.name);
363         break;
364     }
365
366     switch (n) {
367       case V4L2_CID_BRIGHTNESS:
368       case V4L2_CID_CONTRAST:
369       case V4L2_CID_SATURATION:
370       case V4L2_CID_HUE:
371       case V4L2_CID_BLACK_LEVEL:
372       case V4L2_CID_AUTO_WHITE_BALANCE:
373       case V4L2_CID_DO_WHITE_BALANCE:
374       case V4L2_CID_RED_BALANCE:
375       case V4L2_CID_BLUE_BALANCE:
376       case V4L2_CID_GAMMA:
377       case V4L2_CID_EXPOSURE:
378       case V4L2_CID_AUTOGAIN:
379       case V4L2_CID_GAIN:
380 #ifdef V4L2_CID_SHARPNESS
381       case V4L2_CID_SHARPNESS:
382 #endif
383         /* we only handle these for now (why?) */
384         break;
385       case V4L2_CID_HFLIP:
386       case V4L2_CID_VFLIP:
387 #ifndef V4L2_CID_PAN_RESET
388       case V4L2_CID_HCENTER:
389 #endif
390 #ifndef V4L2_CID_TILT_RESET
391       case V4L2_CID_VCENTER:
392 #endif
393 #ifdef V4L2_CID_PAN_RESET
394       case V4L2_CID_PAN_RESET:
395 #endif
396 #ifdef V4L2_CID_TILT_RESET
397       case V4L2_CID_TILT_RESET:
398 #endif
399         /* not handled here, handled by VideoOrientation interface */
400         control.id++;
401         break;
402       case V4L2_CID_AUDIO_VOLUME:
403       case V4L2_CID_AUDIO_BALANCE:
404       case V4L2_CID_AUDIO_BASS:
405       case V4L2_CID_AUDIO_TREBLE:
406       case V4L2_CID_AUDIO_MUTE:
407       case V4L2_CID_AUDIO_LOUDNESS:
408         /* FIXME: We should implement GstMixer interface instead */
409         /* but let's not be pedantic and make element more useful for now */
410         break;
411       default:
412         GST_DEBUG_OBJECT (e,
413             "ControlID %s (%x) unhandled, FIXME", control.name, n);
414         control.id++;
415         break;
416     }
417     if (n != control.id)
418       continue;
419
420     GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n);
421     v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
422     channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
423     channel->label = g_strdup ((const gchar *) control.name);
424     v4l2channel->id = n;
425
426 #if 0
427     /* FIXME: it will be need just when handling private controls
428      *(currently none of base controls are of this type) */
429     if (control.type == V4L2_CTRL_TYPE_MENU) {
430       struct v4l2_querymenu menu, *mptr;
431
432       int i;
433
434       menu.id = n;
435       for (i = 0;; i++) {
436         menu.index = i;
437         if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
438           if (errno == EINVAL)
439             break;              /* end of enumeration */
440           else {
441             GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
442                 (_("Failed getting controls attributes on device '%s'."),
443                     v4l2object->videodev),
444                 ("Failed to get %d in menu enumeration for %s. (%d - %s)",
445                     n, v4l2object->videodev, errno, strerror (errno)));
446             return FALSE;
447           }
448         }
449         mptr = g_malloc (sizeof (menu));
450         memcpy (mptr, &menu, sizeof (menu));
451         menus = g_list_append (menus, mptr);
452       }
453     }
454     v4l2object->menus = g_list_append (v4l2object->menus, menus);
455 #endif
456
457     switch (control.type) {
458       case V4L2_CTRL_TYPE_INTEGER:
459         channel->min_value = control.minimum;
460         channel->max_value = control.maximum;
461         break;
462       case V4L2_CTRL_TYPE_BOOLEAN:
463         channel->min_value = FALSE;
464         channel->max_value = TRUE;
465         break;
466       default:
467         /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
468            BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
469            unset (0), but can't be queried */
470         GST_DEBUG_OBJECT (e,
471             "Control with non supported type %s (%x), type=%d",
472             control.name, n, control.type);
473         channel->min_value = channel->max_value = 0;
474         break;
475     }
476
477     v4l2object->colors =
478         g_list_prepend (v4l2object->colors, (gpointer) channel);
479   }
480   v4l2object->colors = g_list_reverse (v4l2object->colors);
481
482   GST_DEBUG_OBJECT (e, "done");
483   return TRUE;
484 }
485
486
487 static void
488 gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
489 {
490   GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations");
491
492   g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
493   g_list_free (v4l2object->channels);
494   v4l2object->channels = NULL;
495
496   g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL);
497   g_list_free (v4l2object->norms);
498   v4l2object->norms = NULL;
499
500   g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
501   g_list_free (v4l2object->colors);
502   v4l2object->colors = NULL;
503
504   g_datalist_clear (&v4l2object->controls);
505 }
506
507 static void
508 gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
509 {
510   /* when calling gst_v4l2_object_new the user decides the initial type
511    * so adjust it if multi-planar is supported
512    * the driver should make it exclusive. So the driver should
513    * not support both MPLANE and non-PLANE.
514    * Because even when using MPLANE it still possibles to use it
515    * in a contiguous manner. In this case the first v4l2 plane
516    * contains all the gst planes.
517    */
518 #ifdef V4L2_CAP_VIDEO_M2M_MPLANE
519 #define CHECK_CAPS (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)
520 #else
521 #define CHECK_CAPS (V4L2_CAP_VIDEO_OUTPUT_MPLANE)
522 #endif
523
524   switch (v4l2object->type) {
525     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
526       if (v4l2object->vcap.capabilities & CHECK_CAPS) {
527         GST_DEBUG ("adjust type to multi-planar output");
528         v4l2object->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
529       }
530       break;
531     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
532       if (v4l2object->vcap.capabilities & CHECK_CAPS) {
533         GST_DEBUG ("adjust type to multi-planar capture");
534         v4l2object->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
535       }
536       break;
537     default:
538       break;
539   }
540 }
541
542 /******************************************************
543  * gst_v4l2_open():
544  *   open the video device (v4l2object->videodev)
545  * return value: TRUE on success, FALSE on error
546  ******************************************************/
547 gboolean
548 gst_v4l2_open (GstV4l2Object * v4l2object)
549 {
550   struct stat st;
551   int libv4l2_fd;
552   GstPollFD pollfd = GST_POLL_FD_INIT;
553
554   GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
555       v4l2object->videodev);
556
557   GST_V4L2_CHECK_NOT_OPEN (v4l2object);
558   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
559
560   /* be sure we have a device */
561   if (!v4l2object->videodev)
562     v4l2object->videodev = g_strdup ("/dev/video");
563
564   /* check if it is a device */
565   if (stat (v4l2object->videodev, &st) == -1)
566     goto stat_failed;
567
568   if (!S_ISCHR (st.st_mode))
569     goto no_device;
570
571   /* open the device */
572   v4l2object->video_fd =
573       open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
574
575   if (!GST_V4L2_IS_OPEN (v4l2object))
576     goto not_open;
577
578   libv4l2_fd = v4l2_fd_open (v4l2object->video_fd,
579       V4L2_ENABLE_ENUM_FMT_EMULATION);
580   /* Note the v4l2_xxx functions are designed so that if they get passed an
581      unknown fd, the will behave exactly as their regular xxx counterparts, so
582      if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom
583      cam format to normal formats conversion). Chances are big we will still
584      fail then though, as normally v4l2_fd_open only fails if the device is not
585      a v4l2 device. */
586   if (libv4l2_fd != -1)
587     v4l2object->video_fd = libv4l2_fd;
588
589   v4l2object->can_poll_device = TRUE;
590
591   /* get capabilities, error will be posted */
592   if (!gst_v4l2_get_capabilities (v4l2object))
593     goto error;
594
595   /* do we need to be a capture device? */
596   if (GST_IS_V4L2SRC (v4l2object->element) &&
597       !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_CAPTURE |
598               V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
599     goto not_capture;
600
601   if (GST_IS_V4L2SINK (v4l2object->element) &&
602       !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT |
603               V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
604     goto not_output;
605
606   if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
607       /* Today's M2M device only expose M2M */
608       !((v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_M2M |
609                   V4L2_CAP_VIDEO_M2M_MPLANE)) ||
610           /* But legacy driver may expose both CAPTURE and OUTPUT */
611           ((v4l2object->vcap.capabilities &
612                   (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
613               (v4l2object->vcap.capabilities &
614                   (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
615     goto not_m2m;
616
617   gst_v4l2_adjust_buf_type (v4l2object);
618
619   /* create enumerations, posts errors. */
620   if (!gst_v4l2_fill_lists (v4l2object))
621     goto error;
622
623   GST_INFO_OBJECT (v4l2object->element,
624       "Opened device '%s' (%s) successfully",
625       v4l2object->vcap.card, v4l2object->videodev);
626
627   pollfd.fd = v4l2object->video_fd;
628   gst_poll_add_fd (v4l2object->poll, &pollfd);
629   if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
630       || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
631     gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
632   else
633     gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
634
635   if (v4l2object->extra_controls)
636     gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
637
638   /* UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
639    * causes expensive and slow USB IO, so don't probe them for interlaced
640    */
641   if (!strcmp ((char *) v4l2object->vcap.driver, "uvcusb")) {
642     v4l2object->never_interlaced = TRUE;
643   }
644
645   return TRUE;
646
647   /* ERRORS */
648 stat_failed:
649   {
650     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
651         (_("Cannot identify device '%s'."), v4l2object->videodev),
652         GST_ERROR_SYSTEM);
653     goto error;
654   }
655 no_device:
656   {
657     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
658         (_("This isn't a device '%s'."), v4l2object->videodev),
659         GST_ERROR_SYSTEM);
660     goto error;
661   }
662 not_open:
663   {
664     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
665         (_("Could not open device '%s' for reading and writing."),
666             v4l2object->videodev), GST_ERROR_SYSTEM);
667     goto error;
668   }
669 not_capture:
670   {
671     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
672         (_("Device '%s' is not a capture device."),
673             v4l2object->videodev),
674         ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
675     goto error;
676   }
677 not_output:
678   {
679     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
680         (_("Device '%s' is not a output device."),
681             v4l2object->videodev),
682         ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
683     goto error;
684   }
685 not_m2m:
686   {
687     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
688         (_("Device '%s' is not a M2M device."),
689             v4l2object->videodev),
690         ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
691     goto error;
692   }
693 error:
694   {
695     if (GST_V4L2_IS_OPEN (v4l2object)) {
696       /* close device */
697       v4l2_close (v4l2object->video_fd);
698       v4l2object->video_fd = -1;
699     }
700     /* empty lists */
701     gst_v4l2_empty_lists (v4l2object);
702
703     return FALSE;
704   }
705 }
706
707 gboolean
708 gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
709 {
710   GstPollFD pollfd = GST_POLL_FD_INIT;
711
712   GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s",
713       other->videodev);
714
715   GST_V4L2_CHECK_OPEN (other);
716   GST_V4L2_CHECK_NOT_OPEN (v4l2object);
717   GST_V4L2_CHECK_NOT_ACTIVE (other);
718   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
719
720   v4l2object->vcap = other->vcap;
721   gst_v4l2_adjust_buf_type (v4l2object);
722
723   v4l2object->video_fd = v4l2_dup (other->video_fd);
724   if (!GST_V4L2_IS_OPEN (v4l2object))
725     goto not_open;
726
727   g_free (v4l2object->videodev);
728   v4l2object->videodev = g_strdup (other->videodev);
729
730   GST_INFO_OBJECT (v4l2object->element,
731       "Cloned device '%s' (%s) successfully",
732       v4l2object->vcap.card, v4l2object->videodev);
733
734   pollfd.fd = v4l2object->video_fd;
735   gst_poll_add_fd (v4l2object->poll, &pollfd);
736   if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
737       || v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
738     gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
739   else
740     gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
741
742   v4l2object->never_interlaced = other->never_interlaced;
743   v4l2object->can_poll_device = TRUE;
744
745   return TRUE;
746
747 not_open:
748   {
749     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
750         (_("Could not dup device '%s' for reading and writing."),
751             v4l2object->videodev), GST_ERROR_SYSTEM);
752
753     return FALSE;
754   }
755 }
756
757
758 /******************************************************
759  * gst_v4l2_close():
760  *   close the video device (v4l2object->video_fd)
761  * return value: TRUE on success, FALSE on error
762  ******************************************************/
763 gboolean
764 gst_v4l2_close (GstV4l2Object * v4l2object)
765 {
766   GstPollFD pollfd = GST_POLL_FD_INIT;
767   GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
768       v4l2object->videodev);
769
770   GST_V4L2_CHECK_OPEN (v4l2object);
771   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
772
773   /* close device */
774   v4l2_close (v4l2object->video_fd);
775   pollfd.fd = v4l2object->video_fd;
776   gst_poll_remove_fd (v4l2object->poll, &pollfd);
777   v4l2object->video_fd = -1;
778
779   /* empty lists */
780   gst_v4l2_empty_lists (v4l2object);
781
782   return TRUE;
783 }
784
785
786 /******************************************************
787  * gst_v4l2_get_norm()
788  *   Get the norm of the current device
789  * return value: TRUE on success, FALSE on error
790  ******************************************************/
791 gboolean
792 gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
793 {
794   GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
795
796   if (!GST_V4L2_IS_OPEN (v4l2object))
797     return FALSE;
798
799   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
800     goto std_failed;
801
802   return TRUE;
803
804   /* ERRORS */
805 std_failed:
806   {
807     GST_DEBUG ("Failed to get the current norm for device %s",
808         v4l2object->videodev);
809     return FALSE;
810   }
811 }
812
813
814 /******************************************************
815  * gst_v4l2_set_norm()
816  *   Set the norm of the current device
817  * return value: TRUE on success, FALSE on error
818  ******************************************************/
819 gboolean
820 gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
821 {
822   GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to "
823       "%" G_GINT64_MODIFIER "x", (guint64) norm);
824
825   if (!GST_V4L2_IS_OPEN (v4l2object))
826     return FALSE;
827
828   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
829     goto std_failed;
830
831   return TRUE;
832
833   /* ERRORS */
834 std_failed:
835   {
836     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
837         (_("Failed to set norm for device '%s'."),
838             v4l2object->videodev), GST_ERROR_SYSTEM);
839     return FALSE;
840   }
841 }
842
843 /******************************************************
844  * gst_v4l2_get_frequency():
845  *   get the current frequency
846  * return value: TRUE on success, FALSE on error
847  ******************************************************/
848 gboolean
849 gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
850     gint tunernum, gulong * frequency)
851 {
852   struct v4l2_frequency freq = { 0, };
853
854   GstTunerChannel *channel;
855
856   GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
857
858   if (!GST_V4L2_IS_OPEN (v4l2object))
859     return FALSE;
860
861   channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
862
863   freq.tuner = tunernum;
864   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
865     goto freq_failed;
866
867   *frequency = freq.frequency * channel->freq_multiplicator;
868
869   return TRUE;
870
871   /* ERRORS */
872 freq_failed:
873   {
874     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
875         (_("Failed to get current tuner frequency for device '%s'."),
876             v4l2object->videodev), GST_ERROR_SYSTEM);
877     return FALSE;
878   }
879 }
880
881
882 /******************************************************
883  * gst_v4l2_set_frequency():
884  *   set frequency
885  * return value: TRUE on success, FALSE on error
886  ******************************************************/
887 gboolean
888 gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
889     gint tunernum, gulong frequency)
890 {
891   struct v4l2_frequency freq = { 0, };
892
893   GstTunerChannel *channel;
894
895   GST_DEBUG_OBJECT (v4l2object->element,
896       "setting current tuner frequency to %lu", frequency);
897
898   if (!GST_V4L2_IS_OPEN (v4l2object))
899     return FALSE;
900
901   channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
902
903   freq.tuner = tunernum;
904   /* fill in type - ignore error */
905   v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
906   freq.frequency = frequency / channel->freq_multiplicator;
907
908   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
909     goto freq_failed;
910
911   return TRUE;
912
913   /* ERRORS */
914 freq_failed:
915   {
916     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
917         (_("Failed to set current tuner frequency for device '%s' to %lu Hz."),
918             v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
919     return FALSE;
920   }
921 }
922
923 /******************************************************
924  * gst_v4l2_signal_strength():
925  *   get the strength of the signal on the current input
926  * return value: TRUE on success, FALSE on error
927  ******************************************************/
928 gboolean
929 gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
930     gint tunernum, gulong * signal_strength)
931 {
932   struct v4l2_tuner tuner = { 0, };
933
934   GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
935
936   if (!GST_V4L2_IS_OPEN (v4l2object))
937     return FALSE;
938
939   tuner.index = tunernum;
940   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
941     goto tuner_failed;
942
943   *signal_strength = tuner.signal;
944
945   return TRUE;
946
947   /* ERRORS */
948 tuner_failed:
949   {
950     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
951         (_("Failed to get signal strength for device '%s'."),
952             v4l2object->videodev), GST_ERROR_SYSTEM);
953     return FALSE;
954   }
955 }
956
957 /******************************************************
958  * gst_v4l2_get_attribute():
959  *   try to get the value of one specific attribute
960  * return value: TRUE on success, FALSE on error
961  ******************************************************/
962 gboolean
963 gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
964     int attribute_num, int *value)
965 {
966   struct v4l2_control control = { 0, };
967
968   GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
969       attribute_num);
970
971   if (!GST_V4L2_IS_OPEN (v4l2object))
972     return FALSE;
973
974   control.id = attribute_num;
975
976   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
977     goto ctrl_failed;
978
979   *value = control.value;
980
981   return TRUE;
982
983   /* ERRORS */
984 ctrl_failed:
985   {
986     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
987         (_("Failed to get value for control %d on device '%s'."),
988             attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
989     return FALSE;
990   }
991 }
992
993
994 /******************************************************
995  * gst_v4l2_set_attribute():
996  *   try to set the value of one specific attribute
997  * return value: TRUE on success, FALSE on error
998  ******************************************************/
999 gboolean
1000 gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
1001     int attribute_num, const int value)
1002 {
1003   struct v4l2_control control = { 0, };
1004
1005   GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
1006       attribute_num, value);
1007
1008   if (!GST_V4L2_IS_OPEN (v4l2object))
1009     return FALSE;
1010
1011   control.id = attribute_num;
1012   control.value = value;
1013   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
1014     goto ctrl_failed;
1015
1016   return TRUE;
1017
1018   /* ERRORS */
1019 ctrl_failed:
1020   {
1021     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
1022         (_("Failed to set value %d for control %d on device '%s'."),
1023             value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
1024     return FALSE;
1025   }
1026 }
1027
1028 static gboolean
1029 set_control (GQuark field_id, const GValue * value, gpointer user_data)
1030 {
1031   GstV4l2Object *v4l2object = user_data;
1032   GQuark normalised_field_id;
1033   gpointer *d;
1034
1035   /* 32 bytes is the maximum size for a control name according to v4l2 */
1036   gchar name[32];
1037
1038   /* Backwards compatibility: in the past GStreamer would normalise strings in
1039      a subtly different way to v4l2-ctl.  e.g. the kernel's "Focus (absolute)"
1040      would become "focus__absolute_" whereas now it becomes "focus_absolute".
1041      Please remove the following in GStreamer 1.5 for 1.6 */
1042   strncpy (name, g_quark_to_string (field_id), sizeof (name));
1043   name[31] = '\0';
1044   gst_v4l2_normalise_control_name (name);
1045   normalised_field_id = g_quark_from_string (name);
1046   if (normalised_field_id != field_id)
1047     g_warning ("In GStreamer 1.4 the way V4L2 control names were normalised "
1048         "changed.  Instead of setting \"%s\" please use \"%s\".  The former is "
1049         "deprecated and will be removed in a future version of GStreamer",
1050         g_quark_to_string (field_id), name);
1051   field_id = normalised_field_id;
1052
1053   d = g_datalist_id_get_data (&v4l2object->controls, field_id);
1054   if (!d) {
1055     GST_WARNING_OBJECT (v4l2object,
1056         "Control '%s' does not exist or has an unsupported type.",
1057         g_quark_to_string (field_id));
1058     return TRUE;
1059   }
1060   if (!G_VALUE_HOLDS (value, G_TYPE_INT)) {
1061     GST_WARNING_OBJECT (v4l2object,
1062         "'int' value expected for control '%s'.", g_quark_to_string (field_id));
1063     return TRUE;
1064   }
1065   gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d),
1066       g_value_get_int (value));
1067   return TRUE;
1068 }
1069
1070 gboolean
1071 gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls)
1072 {
1073   return gst_structure_foreach (controls, set_control, v4l2object);
1074 }
1075
1076 gboolean
1077 gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
1078 {
1079   gint n;
1080
1081   GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
1082
1083   if (!GST_V4L2_IS_OPEN (v4l2object))
1084     return FALSE;
1085
1086   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
1087     goto input_failed;
1088
1089   *input = n;
1090
1091   GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n);
1092
1093   return TRUE;
1094
1095   /* ERRORS */
1096 input_failed:
1097   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
1098     /* only give a warning message if driver actually claims to have tuner
1099      * support
1100      */
1101     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
1102         (_("Failed to get current input on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
1103   }
1104   return FALSE;
1105 }
1106
1107 gboolean
1108 gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
1109 {
1110   GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
1111
1112   if (!GST_V4L2_IS_OPEN (v4l2object))
1113     return FALSE;
1114
1115   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
1116     goto input_failed;
1117
1118   return TRUE;
1119
1120   /* ERRORS */
1121 input_failed:
1122   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
1123     /* only give a warning message if driver actually claims to have tuner
1124      * support
1125      */
1126     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
1127         (_("Failed to set input %d on device %s."),
1128             input, v4l2object->videodev), GST_ERROR_SYSTEM);
1129   }
1130   return FALSE;
1131 }
1132
1133 gboolean
1134 gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
1135 {
1136   gint n;
1137
1138   GST_DEBUG_OBJECT (v4l2object->element, "trying to get output");
1139
1140   if (!GST_V4L2_IS_OPEN (v4l2object))
1141     return FALSE;
1142
1143   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0)
1144     goto output_failed;
1145
1146   *output = n;
1147
1148   GST_DEBUG_OBJECT (v4l2object->element, "output: %d", n);
1149
1150   return TRUE;
1151
1152   /* ERRORS */
1153 output_failed:
1154   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
1155     /* only give a warning message if driver actually claims to have tuner
1156      * support
1157      */
1158     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
1159         (_("Failed to get current output on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
1160   }
1161   return FALSE;
1162 }
1163
1164 gboolean
1165 gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
1166 {
1167   GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output);
1168
1169   if (!GST_V4L2_IS_OPEN (v4l2object))
1170     return FALSE;
1171
1172   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0)
1173     goto output_failed;
1174
1175   return TRUE;
1176
1177   /* ERRORS */
1178 output_failed:
1179   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
1180     /* only give a warning message if driver actually claims to have tuner
1181      * support
1182      */
1183     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
1184         (_("Failed to set output %d on device %s."),
1185             output, v4l2object->videodev), GST_ERROR_SYSTEM);
1186   }
1187   return FALSE;
1188 }