Merge branch 'master' into 0.11
[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., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, 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;
113
114   GstElement *e;
115
116   e = v4l2object->element;
117
118   GST_DEBUG_OBJECT (e, "getting enumerations");
119   GST_V4L2_CHECK_OPEN (v4l2object);
120
121   GST_DEBUG_OBJECT (e, "  channels");
122   /* and now, the channels */
123   for (n = 0;; n++) {
124     struct v4l2_input input;
125     GstV4l2TunerChannel *v4l2channel;
126     GstTunerChannel *channel;
127
128     memset (&input, 0, sizeof (input));
129
130     input.index = n;
131     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
132       if (errno == EINVAL)
133         break;                  /* end of enumeration */
134       else {
135         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
136             (_("Failed to query attributes of input %d in device %s"),
137                 n, v4l2object->videodev),
138             ("Failed to get %d in input enumeration for %s. (%d - %s)",
139                 n, v4l2object->videodev, errno, strerror (errno)));
140         return FALSE;
141       }
142     }
143
144     GST_LOG_OBJECT (e, "   index:     %d", input.index);
145     GST_LOG_OBJECT (e, "   name:      '%s'", input.name);
146     GST_LOG_OBJECT (e, "   type:      %08x", input.type);
147     GST_LOG_OBJECT (e, "   audioset:  %08x", input.audioset);
148     GST_LOG_OBJECT (e, "   std:       %016x", (guint) input.std);
149     GST_LOG_OBJECT (e, "   status:    %08x", input.status);
150
151     v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
152     channel = GST_TUNER_CHANNEL (v4l2channel);
153     channel->label = g_strdup ((const gchar *) input.name);
154     channel->flags = GST_TUNER_CHANNEL_INPUT;
155     v4l2channel->index = n;
156
157     if (input.type == V4L2_INPUT_TYPE_TUNER) {
158       struct v4l2_tuner vtun;
159
160       v4l2channel->tuner = input.tuner;
161       channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
162
163       vtun.index = input.tuner;
164       if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
165         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
166             (_("Failed to get setting of tuner %d on device '%s'."),
167                 input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
168         g_object_unref (G_OBJECT (channel));
169         return FALSE;
170       }
171
172       channel->freq_multiplicator =
173           62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
174       channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
175       channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
176       channel->min_signal = 0;
177       channel->max_signal = 0xffff;
178     }
179     if (input.audioset) {
180       /* we take the first. We don't care for
181        * the others for now */
182       while (!(input.audioset & (1 << v4l2channel->audio)))
183         v4l2channel->audio++;
184       channel->flags |= GST_TUNER_CHANNEL_AUDIO;
185     }
186
187     v4l2object->channels =
188         g_list_prepend (v4l2object->channels, (gpointer) channel);
189   }
190   v4l2object->channels = g_list_reverse (v4l2object->channels);
191
192   GST_DEBUG_OBJECT (e, "  norms");
193   /* norms... */
194   for (n = 0;; n++) {
195     struct v4l2_standard standard = { 0, };
196     GstV4l2TunerNorm *v4l2norm;
197
198     GstTunerNorm *norm;
199
200     /* fill in defaults */
201     standard.frameperiod.numerator = 1;
202     standard.frameperiod.denominator = 0;
203     standard.index = n;
204
205     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
206       if (errno == EINVAL || errno == ENOTTY)
207         break;                  /* end of enumeration */
208       else {
209         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
210             (_("Failed to query norm on device '%s'."),
211                 v4l2object->videodev),
212             ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)",
213                 n, v4l2object->videodev, errno, strerror (errno)));
214         return FALSE;
215       }
216     }
217
218     GST_DEBUG_OBJECT (e, "    '%s', fps: %d / %d",
219         standard.name, standard.frameperiod.denominator,
220         standard.frameperiod.numerator);
221
222     v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
223     norm = GST_TUNER_NORM (v4l2norm);
224     norm->label = g_strdup ((const gchar *) standard.name);
225     gst_value_set_fraction (&norm->framerate,
226         standard.frameperiod.denominator, standard.frameperiod.numerator);
227     v4l2norm->index = standard.id;
228
229     GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
230         (unsigned int) v4l2norm->index, norm->label);
231
232     v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm);
233   }
234   v4l2object->norms = g_list_reverse (v4l2object->norms);
235
236   GST_DEBUG_OBJECT (e, "  controls+menus");
237
238   /* and lastly, controls+menus (if appropriate) */
239   for (n = V4L2_CID_BASE;; n++) {
240     struct v4l2_queryctrl control = { 0, };
241     GstV4l2ColorBalanceChannel *v4l2channel;
242     GstColorBalanceChannel *channel;
243
244     /* when we reached the last official CID, continue with private CIDs */
245     if (n == V4L2_CID_LASTP1) {
246       GST_DEBUG_OBJECT (e, "checking private CIDs");
247       n = V4L2_CID_PRIVATE_BASE;
248     }
249     GST_DEBUG_OBJECT (e, "checking control %08x", n);
250
251     control.id = n;
252     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
253       if (errno == EINVAL) {
254         if (n < V4L2_CID_PRIVATE_BASE) {
255           GST_DEBUG_OBJECT (e, "skipping control %08x", n);
256           /* continue so that we also check private controls */
257           continue;
258         } else {
259           GST_DEBUG_OBJECT (e, "controls finished");
260           break;
261         }
262       } else {
263         GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
264             (_("Failed getting controls attributes on device '%s'."),
265                 v4l2object->videodev),
266             ("Failed querying control %d on device '%s'. (%d - %s)",
267                 n, v4l2object->videodev, errno, strerror (errno)));
268         return FALSE;
269       }
270     }
271     if (control.flags & V4L2_CTRL_FLAG_DISABLED) {
272       GST_DEBUG_OBJECT (e, "skipping disabled control");
273       continue;
274     }
275
276     switch (n) {
277       case V4L2_CID_BRIGHTNESS:
278       case V4L2_CID_CONTRAST:
279       case V4L2_CID_SATURATION:
280       case V4L2_CID_HUE:
281       case V4L2_CID_BLACK_LEVEL:
282       case V4L2_CID_AUTO_WHITE_BALANCE:
283       case V4L2_CID_DO_WHITE_BALANCE:
284       case V4L2_CID_RED_BALANCE:
285       case V4L2_CID_BLUE_BALANCE:
286       case V4L2_CID_GAMMA:
287       case V4L2_CID_EXPOSURE:
288       case V4L2_CID_AUTOGAIN:
289       case V4L2_CID_GAIN:
290 #ifdef V4L2_CID_SHARPNESS
291       case V4L2_CID_SHARPNESS:
292 #endif
293         /* we only handle these for now (why?) */
294         break;
295       case V4L2_CID_HFLIP:
296       case V4L2_CID_VFLIP:
297       case V4L2_CID_HCENTER:
298       case V4L2_CID_VCENTER:
299 #ifdef V4L2_CID_PAN_RESET
300       case V4L2_CID_PAN_RESET:
301 #endif
302 #ifdef V4L2_CID_TILT_RESET
303       case V4L2_CID_TILT_RESET:
304 #endif
305         /* not handled here, handled by VideoOrientation interface */
306         control.id++;
307         break;
308       case V4L2_CID_AUDIO_VOLUME:
309       case V4L2_CID_AUDIO_BALANCE:
310       case V4L2_CID_AUDIO_BASS:
311       case V4L2_CID_AUDIO_TREBLE:
312       case V4L2_CID_AUDIO_MUTE:
313       case V4L2_CID_AUDIO_LOUDNESS:
314         /* FIXME: We should implement GstMixer interface */
315         /* fall through */
316       default:
317         GST_DEBUG_OBJECT (e,
318             "ControlID %s (%x) unhandled, FIXME", control.name, n);
319         control.id++;
320         break;
321     }
322     if (n != control.id)
323       continue;
324
325     GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n);
326     v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
327     channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
328     channel->label = g_strdup ((const gchar *) control.name);
329     v4l2channel->id = n;
330
331 #if 0
332     /* FIXME: it will be need just when handling private controls
333      *(currently none of base controls are of this type) */
334     if (control.type == V4L2_CTRL_TYPE_MENU) {
335       struct v4l2_querymenu menu, *mptr;
336
337       int i;
338
339       menu.id = n;
340       for (i = 0;; i++) {
341         menu.index = i;
342         if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
343           if (errno == EINVAL)
344             break;              /* end of enumeration */
345           else {
346             GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
347                 (_("Failed getting controls attributes on device '%s'."),
348                     v4l2object->videodev),
349                 ("Failed to get %d in menu enumeration for %s. (%d - %s)",
350                     n, v4l2object->videodev, errno, strerror (errno)));
351             return FALSE;
352           }
353         }
354         mptr = g_malloc (sizeof (menu));
355         memcpy (mptr, &menu, sizeof (menu));
356         menus = g_list_append (menus, mptr);
357       }
358     }
359     v4l2object->menus = g_list_append (v4l2object->menus, menus);
360 #endif
361
362     switch (control.type) {
363       case V4L2_CTRL_TYPE_INTEGER:
364         channel->min_value = control.minimum;
365         channel->max_value = control.maximum;
366         break;
367       case V4L2_CTRL_TYPE_BOOLEAN:
368         channel->min_value = FALSE;
369         channel->max_value = TRUE;
370         break;
371       default:
372         /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
373            BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
374            unset (0), but can't be queried */
375         GST_DEBUG_OBJECT (e,
376             "Control with non supported type %s (%x), type=%d",
377             control.name, n, control.type);
378         channel->min_value = channel->max_value = 0;
379         break;
380     }
381
382     v4l2object->colors =
383         g_list_prepend (v4l2object->colors, (gpointer) channel);
384   }
385   v4l2object->colors = g_list_reverse (v4l2object->colors);
386
387   GST_DEBUG_OBJECT (e, "done");
388   return TRUE;
389 }
390
391
392 static void
393 gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
394 {
395   GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations");
396
397   g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
398   g_list_free (v4l2object->channels);
399   v4l2object->channels = NULL;
400
401   g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL);
402   g_list_free (v4l2object->norms);
403   v4l2object->norms = NULL;
404
405   g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
406   g_list_free (v4l2object->colors);
407   v4l2object->colors = NULL;
408 }
409
410 /******************************************************
411  * gst_v4l2_open():
412  *   open the video device (v4l2object->videodev)
413  * return value: TRUE on success, FALSE on error
414  ******************************************************/
415 gboolean
416 gst_v4l2_open (GstV4l2Object * v4l2object)
417 {
418   struct stat st;
419   int libv4l2_fd;
420   GstPollFD pollfd = GST_POLL_FD_INIT;
421
422   GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
423       v4l2object->videodev);
424
425   GST_V4L2_CHECK_NOT_OPEN (v4l2object);
426   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
427
428   /* be sure we have a device */
429   if (!v4l2object->videodev)
430     v4l2object->videodev = g_strdup ("/dev/video");
431
432   /* check if it is a device */
433   if (stat (v4l2object->videodev, &st) == -1)
434     goto stat_failed;
435
436   if (!S_ISCHR (st.st_mode))
437     goto no_device;
438
439   /* open the device */
440   v4l2object->video_fd =
441       open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
442
443   if (!GST_V4L2_IS_OPEN (v4l2object))
444     goto not_open;
445
446   libv4l2_fd = v4l2_fd_open (v4l2object->video_fd,
447       V4L2_ENABLE_ENUM_FMT_EMULATION);
448   /* Note the v4l2_xxx functions are designed so that if they get passed an
449      unknown fd, the will behave exactly as their regular xxx counterparts, so
450      if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom
451      cam format to normal formats conversion). Chances are big we will still
452      fail then though, as normally v4l2_fd_open only fails if the device is not
453      a v4l2 device. */
454   if (libv4l2_fd != -1)
455     v4l2object->video_fd = libv4l2_fd;
456
457   v4l2object->can_poll_device = TRUE;
458
459   /* get capabilities, error will be posted */
460   if (!gst_v4l2_get_capabilities (v4l2object))
461     goto error;
462
463   /* do we need to be a capture device? */
464   if (GST_IS_V4L2SRC (v4l2object->element) &&
465       !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
466     goto not_capture;
467
468   if (GST_IS_V4L2SINK (v4l2object->element) &&
469       !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT))
470     goto not_output;
471
472   /* create enumerations, posts errors. */
473   if (!gst_v4l2_fill_lists (v4l2object))
474     goto error;
475
476   GST_INFO_OBJECT (v4l2object->element,
477       "Opened device '%s' (%s) successfully",
478       v4l2object->vcap.card, v4l2object->videodev);
479
480   pollfd.fd = v4l2object->video_fd;
481   gst_poll_add_fd (v4l2object->poll, &pollfd);
482   gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
483
484   return TRUE;
485
486   /* ERRORS */
487 stat_failed:
488   {
489     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
490         (_("Cannot identify device '%s'."), v4l2object->videodev),
491         GST_ERROR_SYSTEM);
492     goto error;
493   }
494 no_device:
495   {
496     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
497         (_("This isn't a device '%s'."), v4l2object->videodev),
498         GST_ERROR_SYSTEM);
499     goto error;
500   }
501 not_open:
502   {
503     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
504         (_("Could not open device '%s' for reading and writing."),
505             v4l2object->videodev), GST_ERROR_SYSTEM);
506     goto error;
507   }
508 not_capture:
509   {
510     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
511         (_("Device '%s' is not a capture device."),
512             v4l2object->videodev),
513         ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
514     goto error;
515   }
516 not_output:
517   {
518     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
519         (_("Device '%s' is not a output device."),
520             v4l2object->videodev),
521         ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
522     goto error;
523   }
524 error:
525   {
526     if (GST_V4L2_IS_OPEN (v4l2object)) {
527       /* close device */
528       v4l2_close (v4l2object->video_fd);
529       v4l2object->video_fd = -1;
530     }
531     /* empty lists */
532     gst_v4l2_empty_lists (v4l2object);
533
534     return FALSE;
535   }
536 }
537
538
539 /******************************************************
540  * gst_v4l2_close():
541  *   close the video device (v4l2object->video_fd)
542  * return value: TRUE on success, FALSE on error
543  ******************************************************/
544 gboolean
545 gst_v4l2_close (GstV4l2Object * v4l2object)
546 {
547   GstPollFD pollfd = GST_POLL_FD_INIT;
548   GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
549       v4l2object->videodev);
550
551   GST_V4L2_CHECK_OPEN (v4l2object);
552   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
553
554   /* close device */
555   v4l2_close (v4l2object->video_fd);
556   pollfd.fd = v4l2object->video_fd;
557   gst_poll_remove_fd (v4l2object->poll, &pollfd);
558   v4l2object->video_fd = -1;
559
560   /* empty lists */
561   gst_v4l2_empty_lists (v4l2object);
562
563   return TRUE;
564 }
565
566
567 /******************************************************
568  * gst_v4l2_get_norm()
569  *   Get the norm of the current device
570  * return value: TRUE on success, FALSE on error
571  ******************************************************/
572 gboolean
573 gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
574 {
575   GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
576
577   if (!GST_V4L2_IS_OPEN (v4l2object))
578     return FALSE;
579
580   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
581     goto std_failed;
582
583   return TRUE;
584
585   /* ERRORS */
586 std_failed:
587   {
588     GST_DEBUG ("Failed to get the current norm for device %s",
589         v4l2object->videodev);
590     return FALSE;
591   }
592 }
593
594
595 /******************************************************
596  * gst_v4l2_set_norm()
597  *   Set the norm of the current device
598  * return value: TRUE on success, FALSE on error
599  ******************************************************/
600 gboolean
601 gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
602 {
603   GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to "
604       "%" G_GINT64_MODIFIER "x", (guint64) norm);
605
606   if (!GST_V4L2_IS_OPEN (v4l2object))
607     return FALSE;
608
609   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
610     goto std_failed;
611
612   return TRUE;
613
614   /* ERRORS */
615 std_failed:
616   {
617     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
618         (_("Failed to set norm for device '%s'."),
619             v4l2object->videodev), GST_ERROR_SYSTEM);
620     return FALSE;
621   }
622 }
623
624 /******************************************************
625  * gst_v4l2_get_frequency():
626  *   get the current frequency
627  * return value: TRUE on success, FALSE on error
628  ******************************************************/
629 gboolean
630 gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
631     gint tunernum, gulong * frequency)
632 {
633   struct v4l2_frequency freq = { 0, };
634
635   GstTunerChannel *channel;
636
637   GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
638
639   if (!GST_V4L2_IS_OPEN (v4l2object))
640     return FALSE;
641
642   channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
643
644   freq.tuner = tunernum;
645   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
646     goto freq_failed;
647
648   *frequency = freq.frequency * channel->freq_multiplicator;
649
650   return TRUE;
651
652   /* ERRORS */
653 freq_failed:
654   {
655     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
656         (_("Failed to get current tuner frequency for device '%s'."),
657             v4l2object->videodev), GST_ERROR_SYSTEM);
658     return FALSE;
659   }
660 }
661
662
663 /******************************************************
664  * gst_v4l2_set_frequency():
665  *   set frequency
666  * return value: TRUE on success, FALSE on error
667  ******************************************************/
668 gboolean
669 gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
670     gint tunernum, gulong frequency)
671 {
672   struct v4l2_frequency freq = { 0, };
673
674   GstTunerChannel *channel;
675
676   GST_DEBUG_OBJECT (v4l2object->element,
677       "setting current tuner frequency to %lu", frequency);
678
679   if (!GST_V4L2_IS_OPEN (v4l2object))
680     return FALSE;
681
682   channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
683
684   freq.tuner = tunernum;
685   /* fill in type - ignore error */
686   v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
687   freq.frequency = frequency / channel->freq_multiplicator;
688
689   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
690     goto freq_failed;
691
692   return TRUE;
693
694   /* ERRORS */
695 freq_failed:
696   {
697     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
698         (_("Failed to set current tuner frequency for device '%s' to %lu Hz."),
699             v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
700     return FALSE;
701   }
702 }
703
704 /******************************************************
705  * gst_v4l2_signal_strength():
706  *   get the strength of the signal on the current input
707  * return value: TRUE on success, FALSE on error
708  ******************************************************/
709 gboolean
710 gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
711     gint tunernum, gulong * signal_strength)
712 {
713   struct v4l2_tuner tuner = { 0, };
714
715   GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
716
717   if (!GST_V4L2_IS_OPEN (v4l2object))
718     return FALSE;
719
720   tuner.index = tunernum;
721   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
722     goto tuner_failed;
723
724   *signal_strength = tuner.signal;
725
726   return TRUE;
727
728   /* ERRORS */
729 tuner_failed:
730   {
731     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
732         (_("Failed to get signal strength for device '%s'."),
733             v4l2object->videodev), GST_ERROR_SYSTEM);
734     return FALSE;
735   }
736 }
737
738 /******************************************************
739  * gst_v4l2_get_attribute():
740  *   try to get the value of one specific attribute
741  * return value: TRUE on success, FALSE on error
742  ******************************************************/
743 gboolean
744 gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
745     int attribute_num, int *value)
746 {
747   struct v4l2_control control = { 0, };
748
749   GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
750       attribute_num);
751
752   if (!GST_V4L2_IS_OPEN (v4l2object))
753     return FALSE;
754
755   control.id = attribute_num;
756
757   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
758     goto ctrl_failed;
759
760   *value = control.value;
761
762   return TRUE;
763
764   /* ERRORS */
765 ctrl_failed:
766   {
767     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
768         (_("Failed to get value for control %d on device '%s'."),
769             attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
770     return FALSE;
771   }
772 }
773
774
775 /******************************************************
776  * gst_v4l2_set_attribute():
777  *   try to set the value of one specific attribute
778  * return value: TRUE on success, FALSE on error
779  ******************************************************/
780 gboolean
781 gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
782     int attribute_num, const int value)
783 {
784   struct v4l2_control control = { 0, };
785
786   GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
787       attribute_num, value);
788
789   if (!GST_V4L2_IS_OPEN (v4l2object))
790     return FALSE;
791
792   control.id = attribute_num;
793   control.value = value;
794   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
795     goto ctrl_failed;
796
797   return TRUE;
798
799   /* ERRORS */
800 ctrl_failed:
801   {
802     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
803         (_("Failed to set value %d for control %d on device '%s'."),
804             value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
805     return FALSE;
806   }
807 }
808
809 gboolean
810 gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
811 {
812   gint n;
813
814   GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
815
816   if (!GST_V4L2_IS_OPEN (v4l2object))
817     return FALSE;
818
819   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
820     goto input_failed;
821
822   *input = n;
823
824   GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n);
825
826   return TRUE;
827
828   /* ERRORS */
829 input_failed:
830   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
831     /* only give a warning message if driver actually claims to have tuner
832      * support
833      */
834     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
835         (_("Failed to get current input on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
836   }
837   return FALSE;
838 }
839
840 gboolean
841 gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
842 {
843   GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
844
845   if (!GST_V4L2_IS_OPEN (v4l2object))
846     return FALSE;
847
848   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
849     goto input_failed;
850
851   return TRUE;
852
853   /* ERRORS */
854 input_failed:
855   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
856     /* only give a warning message if driver actually claims to have tuner
857      * support
858      */
859     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
860         (_("Failed to set input %d on device %s."),
861             input, v4l2object->videodev), GST_ERROR_SYSTEM);
862   }
863   return FALSE;
864 }
865
866 gboolean
867 gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
868 {
869   gint n;
870
871   GST_DEBUG_OBJECT (v4l2object->element, "trying to get output");
872
873   if (!GST_V4L2_IS_OPEN (v4l2object))
874     return FALSE;
875
876   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0)
877     goto output_failed;
878
879   *output = n;
880
881   GST_DEBUG_OBJECT (v4l2object->element, "output: %d", n);
882
883   return TRUE;
884
885   /* ERRORS */
886 output_failed:
887   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
888     /* only give a warning message if driver actually claims to have tuner
889      * support
890      */
891     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
892         (_("Failed to get current output on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
893   }
894   return FALSE;
895 }
896
897 gboolean
898 gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
899 {
900   GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output);
901
902   if (!GST_V4L2_IS_OPEN (v4l2object))
903     return FALSE;
904
905   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0)
906     goto output_failed;
907
908   return TRUE;
909
910   /* ERRORS */
911 output_failed:
912   if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
913     /* only give a warning message if driver actually claims to have tuner
914      * support
915      */
916     GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
917         (_("Failed to set output %d on device %s."),
918             output, v4l2object->videodev), GST_ERROR_SYSTEM);
919   }
920   return FALSE;
921 }