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