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