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