gst-indent
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2_calls.c
1 /* G-Streamer generic V4L2 element - generic V4L2 calls handling
2  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include "v4l2_calls.h"
33 #include "gstv4l2tuner.h"
34 #include "gstv4l2xoverlay.h"
35 #include "gstv4l2colorbalance.h"
36
37 #include "gstv4l2src.h"
38
39 #define DEBUG(format, args...) \
40         GST_DEBUG_OBJECT (\
41                 GST_ELEMENT(v4l2element), \
42                 "V4L2: " format, ##args)
43
44
45 /******************************************************
46  * gst_v4l2_get_capabilities():
47  *   get the device's capturing capabilities
48  * return value: TRUE on success, FALSE on error
49  ******************************************************/
50
51 static gboolean
52 gst_v4l2_get_capabilities (GstV4l2Element * v4l2element)
53 {
54   DEBUG ("getting capabilities");
55   GST_V4L2_CHECK_OPEN (v4l2element);
56
57   if (ioctl (v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
58     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
59         ("Error getting %s capabilities: %s",
60             v4l2element->device, g_strerror (errno)));
61     return FALSE;
62   }
63
64   return TRUE;
65 }
66
67
68 /******************************************************
69  * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
70  *   fill/empty the lists of enumerations
71  * return value: TRUE on success, FALSE on error
72  ******************************************************/
73
74 static gboolean
75 gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
76 {
77   gint n;
78   const GList *pads = gst_element_get_pad_list (GST_ELEMENT (v4l2element));
79   GstPadDirection dir = GST_PAD_UNKNOWN;
80
81   DEBUG ("getting enumerations");
82   GST_V4L2_CHECK_OPEN (v4l2element);
83
84   /* sinks have outputs, all others have inputs */
85   if (pads && g_list_length ((GList *) pads) == 1)
86     dir = GST_PAD_DIRECTION (GST_PAD (pads->data));
87
88   if (dir != GST_PAD_SINK) {
89     /* and now, the inputs */
90     for (n = 0;; n++) {
91       struct v4l2_input input;
92       GstV4l2TunerChannel *v4l2channel;
93       GstTunerChannel *channel;
94
95       input.index = n;
96       if (ioctl (v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
97         if (errno == EINVAL)
98           break;                /* end of enumeration */
99         else {
100           GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
101               ("Failed to get %d in input enumeration for %s: %s",
102                   n, v4l2element->device, g_strerror (errno)));
103           return FALSE;
104         }
105       }
106
107       v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
108       channel = GST_TUNER_CHANNEL (v4l2channel);
109       channel->label = g_strdup (input.name);
110       channel->flags = GST_TUNER_CHANNEL_INPUT;
111       v4l2channel->index = n;
112       if (input.type == V4L2_INPUT_TYPE_TUNER) {
113         struct v4l2_tuner vtun;
114
115         v4l2channel->tuner = input.tuner;
116         channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
117
118         vtun.index = input.tuner;
119         if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
120           GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
121               ("Failed to get tuner %d settings on %s: %s",
122                   input.tuner, v4l2element->device, g_strerror (errno)));
123           g_object_unref (G_OBJECT (channel));
124           return FALSE;
125         }
126         channel->min_frequency = vtun.rangelow;
127         channel->max_frequency = vtun.rangehigh;
128         channel->min_signal = 0;
129         channel->max_signal = 0xffff;
130       }
131       if (input.audioset) {
132         /* we take the first. We don't care for
133          * the others for now */
134         while (!(input.audioset & (1 << v4l2channel->audio)))
135           v4l2channel->audio++;
136         channel->flags |= GST_TUNER_CHANNEL_AUDIO;
137       }
138
139       v4l2element->channels =
140           g_list_append (v4l2element->channels, (gpointer) channel);
141     }
142   } else {
143     /* outputs */
144     for (n = 0;; n++) {
145       struct v4l2_output output;
146       GstV4l2TunerChannel *v4l2channel;
147       GstTunerChannel *channel;
148
149       output.index = n;
150       if (ioctl (v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
151         if (errno == EINVAL)
152           break;                /* end of enumeration */
153         else {
154           GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
155               ("Failed to get %d in output enumeration for %s: %s",
156                   n, v4l2element->device, g_strerror (errno)));
157           return FALSE;
158         }
159       }
160
161       v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
162       channel = GST_TUNER_CHANNEL (v4l2channel);
163       channel->label = g_strdup (output.name);
164       channel->flags = GST_TUNER_CHANNEL_OUTPUT;
165       v4l2channel->index = n;
166       if (output.audioset) {
167         /* we take the first. We don't care for
168          * the others for now */
169         while (!(output.audioset & (1 << v4l2channel->audio)))
170           v4l2channel->audio++;
171         channel->flags |= GST_TUNER_CHANNEL_AUDIO;
172       }
173
174       v4l2element->channels =
175           g_list_append (v4l2element->channels, (gpointer) channel);
176     }
177   }
178
179   /* norms... */
180   for (n = 0;; n++) {
181     struct v4l2_standard standard;
182     GstV4l2TunerNorm *v4l2norm;
183     GstTunerNorm *norm;
184
185     standard.index = n;
186     if (ioctl (v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
187       if (errno == EINVAL)
188         break;                  /* end of enumeration */
189       else {
190         GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
191             ("Failed to get %d in norm enumeration for %s: %s",
192                 n, v4l2element->device, g_strerror (errno)));
193         return FALSE;
194       }
195     }
196
197     v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
198     norm = GST_TUNER_NORM (v4l2norm);
199     norm->label = g_strdup (standard.name);
200     norm->fps = (gfloat) standard.frameperiod.denominator /
201         standard.frameperiod.numerator;
202     v4l2norm->index = standard.id;
203
204     v4l2element->norms = g_list_append (v4l2element->norms, (gpointer) norm);
205   }
206
207   /* and lastly, controls+menus (if appropriate) */
208   for (n = V4L2_CID_BASE;; n++) {
209     struct v4l2_queryctrl control;
210     GstV4l2ColorBalanceChannel *v4l2channel;
211     GstColorBalanceChannel *channel;
212
213     /* hacky... */
214     if (n == V4L2_CID_LASTP1)
215       n = V4L2_CID_PRIVATE_BASE;
216
217     control.id = n;
218     if (ioctl (v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
219       if (errno == EINVAL) {
220         if (n < V4L2_CID_PRIVATE_BASE)
221           continue;
222         else
223           break;
224       } else {
225         GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
226             ("Failed to get %d in control enumeration for %s: %s",
227                 n, v4l2element->device, g_strerror (errno)));
228         return FALSE;
229       }
230     }
231     if (control.flags & V4L2_CTRL_FLAG_DISABLED)
232       continue;
233
234     switch (n) {
235       case V4L2_CID_BRIGHTNESS:
236       case V4L2_CID_CONTRAST:
237       case V4L2_CID_SATURATION:
238       case V4L2_CID_HUE:
239       case V4L2_CID_BLACK_LEVEL:
240       case V4L2_CID_AUTO_WHITE_BALANCE:
241       case V4L2_CID_DO_WHITE_BALANCE:
242       case V4L2_CID_RED_BALANCE:
243       case V4L2_CID_BLUE_BALANCE:
244       case V4L2_CID_GAMMA:
245       case V4L2_CID_EXPOSURE:
246       case V4L2_CID_AUTOGAIN:
247       case V4L2_CID_GAIN:
248         /* we only handle these for now */
249         break;
250       default:
251         DEBUG ("ControlID %s (%d) unhandled, FIXME", control.name, n);
252         control.id++;
253         break;
254     }
255     if (n != control.id)
256       continue;
257
258     v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
259     channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
260     channel->label = g_strdup (control.name);
261     v4l2channel->index = n;
262
263 #if 0
264     if (control.type == V4L2_CTRL_TYPE_MENU) {
265       struct v4l2_querymenu menu, *mptr;
266       int i;
267
268       menu.id = n;
269       for (i = 0;; i++) {
270         menu.index = i;
271         if (ioctl (v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
272           if (errno == EINVAL)
273             break;              /* end of enumeration */
274           else {
275             GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
276                 ("Failed to get %d in menu enumeration for %s: %s",
277                     n, v4l2element->device, g_strerror (errno)));
278             return FALSE;
279           }
280         }
281         mptr = g_malloc (sizeof (menu));
282         memcpy (mptr, &menu, sizeof (menu));
283         menus = g_list_append (menus, mptr);
284       }
285     }
286     v4l2element->menus = g_list_append (v4l2element->menus, menus);
287 #endif
288
289     switch (control.type) {
290       case V4L2_CTRL_TYPE_INTEGER:
291         channel->min_value = control.minimum;
292         channel->max_value = control.maximum;
293         break;
294       case V4L2_CTRL_TYPE_BOOLEAN:
295         channel->min_value = FALSE;
296         channel->max_value = TRUE;
297         break;
298       default:
299         channel->min_value = channel->max_value = 0;
300         break;
301     }
302
303     v4l2element->colors = g_list_append (v4l2element->colors,
304         (gpointer) channel);
305   }
306
307   return TRUE;
308 }
309
310
311 static void
312 gst_v4l2_empty_lists (GstV4l2Element * v4l2element)
313 {
314   DEBUG ("deleting enumerations");
315
316   g_list_foreach (v4l2element->channels, (GFunc) g_object_unref, NULL);
317   g_list_free (v4l2element->channels);
318   v4l2element->channels = NULL;
319
320   g_list_foreach (v4l2element->norms, (GFunc) g_object_unref, NULL);
321   g_list_free (v4l2element->norms);
322   v4l2element->norms = NULL;
323
324   g_list_foreach (v4l2element->colors, (GFunc) g_object_unref, NULL);
325   g_list_free (v4l2element->colors);
326   v4l2element->colors = NULL;
327 }
328
329 /* FIXME: move this stuff to gstv4l2tuner.c? */
330
331 static void
332 gst_v4l2_set_defaults (GstV4l2Element * v4l2element)
333 {
334   GstTunerNorm *norm = NULL;
335   GstTunerChannel *channel = NULL;
336   GstTuner *tuner = GST_TUNER (v4l2element);
337
338   if (v4l2element->norm)
339     norm = gst_tuner_find_norm_by_name (tuner, v4l2element->norm);
340   if (norm) {
341     gst_tuner_set_norm (tuner, norm);
342   } else {
343     norm = GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2element)));
344     v4l2element->norm = g_strdup (norm->label);
345     gst_tuner_norm_changed (tuner, norm);
346     g_object_notify (G_OBJECT (v4l2element), "norm");
347   }
348
349   if (v4l2element->channel)
350     channel = gst_tuner_find_channel_by_name (tuner, v4l2element->channel);
351   if (channel) {
352     gst_tuner_set_channel (tuner, channel);
353   } else {
354     channel =
355         GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2element)));
356     v4l2element->channel = g_strdup (channel->label);
357     gst_tuner_channel_changed (tuner, channel);
358     g_object_notify (G_OBJECT (v4l2element), "channel");
359   }
360   if (v4l2element->frequency != 0) {
361     gst_tuner_set_frequency (tuner, channel, v4l2element->frequency);
362   } else {
363     v4l2element->frequency = gst_tuner_get_frequency (tuner, channel);
364     if (v4l2element->frequency == 0) {
365       /* guess */
366       gst_tuner_set_frequency (tuner, channel, 1000);
367     } else {
368       g_object_notify (G_OBJECT (v4l2element), "frequency");
369     }
370   }
371 }
372
373
374 /******************************************************
375  * gst_v4l2_open():
376  *   open the video device (v4l2element->device)
377  * return value: TRUE on success, FALSE on error
378  ******************************************************/
379
380 gboolean
381 gst_v4l2_open (GstV4l2Element * v4l2element)
382 {
383   DEBUG ("Trying to open device %s", v4l2element->device);
384   GST_V4L2_CHECK_NOT_OPEN (v4l2element);
385   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
386
387   /* be sure we have a device */
388   if (!v4l2element->device)
389     v4l2element->device = g_strdup ("/dev/video");
390
391   /* open the device */
392   v4l2element->video_fd = open (v4l2element->device, O_RDWR);
393   if (!GST_V4L2_IS_OPEN (v4l2element)) {
394     GST_ELEMENT_ERROR (v4l2element, RESOURCE, OPEN_READ_WRITE,
395         (_("Could not open device \"%s\" for reading and writing."),
396             v4l2element->device), GST_ERROR_SYSTEM);
397     goto error;
398   }
399
400   /* get capabilities */
401   if (!gst_v4l2_get_capabilities (v4l2element)) {
402     goto error;
403   }
404
405   /* do we need to be a capture device? */
406   if (GST_IS_V4L2SRC (v4l2element) &&
407       !(v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
408     GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND,
409         (_("Device \"%s\" is not a capture device."), v4l2element->device),
410         ("Capabilities: 0x%x", v4l2element->vcap.capabilities));
411     goto error;
412   }
413
414   /* create enumerations */
415   if (!gst_v4l2_fill_lists (v4l2element))
416     goto error;
417
418   /* set defaults */
419   gst_v4l2_set_defaults (v4l2element);
420
421   GST_INFO_OBJECT (v4l2element, "Opened device '%s' (%s) successfully\n",
422       v4l2element->vcap.card, v4l2element->device);
423
424   return TRUE;
425
426 error:
427   if (GST_V4L2_IS_OPEN (v4l2element)) {
428     /* close device */
429     close (v4l2element->video_fd);
430     v4l2element->video_fd = -1;
431   }
432   /* empty lists */
433   gst_v4l2_empty_lists (v4l2element);
434
435   return FALSE;
436 }
437
438
439 /******************************************************
440  * gst_v4l2_close():
441  *   close the video device (v4l2element->video_fd)
442  * return value: TRUE on success, FALSE on error
443  ******************************************************/
444
445 gboolean
446 gst_v4l2_close (GstV4l2Element * v4l2element)
447 {
448   DEBUG ("Trying to close %s", v4l2element->device);
449   GST_V4L2_CHECK_OPEN (v4l2element);
450   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
451
452   /* close device */
453   close (v4l2element->video_fd);
454   v4l2element->video_fd = -1;
455
456   /* empty lists */
457   gst_v4l2_empty_lists (v4l2element);
458
459   return TRUE;
460 }
461
462
463 /******************************************************
464  * gst_v4l2_get_norm()
465  *   Get the norm of the current device
466  * return value: TRUE on success, FALSE on error
467  ******************************************************/
468
469 gboolean
470 gst_v4l2_get_norm (GstV4l2Element * v4l2element, v4l2_std_id * norm)
471 {
472   DEBUG ("getting norm");
473   GST_V4L2_CHECK_OPEN (v4l2element);
474
475   if (ioctl (v4l2element->video_fd, VIDIOC_G_STD, norm) < 0) {
476     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
477         ("Failed to get the current norm for device %s: %s",
478             v4l2element->device, g_strerror (errno)));
479     return FALSE;
480   }
481
482   return TRUE;
483 }
484
485
486 /******************************************************
487  * gst_v4l2_set_norm()
488  *   Set the norm of the current device
489  * return value: TRUE on success, FALSE on error
490  ******************************************************/
491
492 gboolean
493 gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm)
494 {
495   DEBUG ("trying to set norm to %llx", norm);
496   GST_V4L2_CHECK_OPEN (v4l2element);
497   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
498
499   if (ioctl (v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) {
500     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
501         ("Failed to set norm 0x%llx for device %s: %s",
502             norm, v4l2element->device, g_strerror (errno)));
503     return FALSE;
504   }
505
506   return TRUE;
507 }
508
509
510 /******************************************************
511  * gst_v4l2_get_input()
512  *   Get the input of the current device
513  * return value: TRUE on success, FALSE on error
514  ******************************************************/
515
516 gboolean
517 gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input)
518 {
519   gint n;
520
521   DEBUG ("trying to get input");
522   GST_V4L2_CHECK_OPEN (v4l2element);
523
524   if (ioctl (v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
525     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
526         ("Failed to get current input on device %s: %s",
527             v4l2element->device, g_strerror (errno)));
528     return FALSE;
529   }
530
531   *input = n;
532
533   return TRUE;
534 }
535
536
537 /******************************************************
538  * gst_v4l2_set_input()
539  *   Set the input of the current device
540  * return value: TRUE on success, FALSE on error
541  ******************************************************/
542
543 gboolean
544 gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input)
545 {
546   DEBUG ("trying to set input to %d", input);
547   GST_V4L2_CHECK_OPEN (v4l2element);
548   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
549
550   if (ioctl (v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
551     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
552         ("Failed to set input %d on device %s: %s",
553             input, v4l2element->device, g_strerror (errno)));
554     return FALSE;
555   }
556
557   return TRUE;
558 }
559
560
561 /******************************************************
562  * gst_v4l2_get_output()
563  *   Get the output of the current device
564  * return value: TRUE on success, FALSE on error
565  ******************************************************/
566
567 gboolean
568 gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output)
569 {
570   gint n;
571
572   DEBUG ("trying to get output");
573   GST_V4L2_CHECK_OPEN (v4l2element);
574
575   if (ioctl (v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
576     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
577         ("Failed to get current output on device %s: %s",
578             v4l2element->device, g_strerror (errno)));
579     return FALSE;
580   }
581
582   *output = n;
583
584   return TRUE;
585 }
586
587
588 /******************************************************
589  * gst_v4l2_set_output()
590  *   Set the output of the current device
591  * return value: TRUE on success, FALSE on error
592  ******************************************************/
593
594 gboolean
595 gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output)
596 {
597   DEBUG ("trying to set output to %d", output);
598   GST_V4L2_CHECK_OPEN (v4l2element);
599   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
600
601   if (ioctl (v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
602     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
603         ("Failed to set output %d on device %s: %s",
604             output, v4l2element->device, g_strerror (errno)));
605     return FALSE;
606   }
607
608   return TRUE;
609 }
610
611
612 /******************************************************
613  * gst_v4l2_get_frequency():
614  *   get the current frequency
615  * return value: TRUE on success, FALSE on error
616  ******************************************************/
617
618 gboolean
619 gst_v4l2_get_frequency (GstV4l2Element * v4l2element,
620     gint tunernum, gulong * frequency)
621 {
622   struct v4l2_frequency freq;
623
624   DEBUG ("getting current tuner frequency");
625   GST_V4L2_CHECK_OPEN (v4l2element);
626
627   freq.tuner = tunernum;
628   if (ioctl (v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
629     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
630         ("Failed to get current tuner frequency for device %s: %s",
631             v4l2element->device, g_strerror (errno)));
632     return FALSE;
633   }
634
635   *frequency = freq.frequency;
636
637   return TRUE;
638 }
639
640
641 /******************************************************
642  * gst_v4l2_set_frequency():
643  *   set frequency
644  * return value: TRUE on success, FALSE on error
645  ******************************************************/
646
647 gboolean
648 gst_v4l2_set_frequency (GstV4l2Element * v4l2element,
649     gint tunernum, gulong frequency)
650 {
651   struct v4l2_frequency freq;
652
653   DEBUG ("setting current tuner frequency to %lu", frequency);
654   GST_V4L2_CHECK_OPEN (v4l2element);
655   GST_V4L2_CHECK_NOT_ACTIVE (v4l2element);
656
657   freq.tuner = tunernum;
658   /* fill in type - ignore error */
659   ioctl (v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq);
660   freq.frequency = frequency;
661
662   if (ioctl (v4l2element->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) {
663     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
664         ("Failed to set tuner frequency to %lu for device %s: %s",
665             frequency, v4l2element->device, g_strerror (errno)));
666     return FALSE;
667   }
668
669   return TRUE;
670 }
671
672
673 /******************************************************
674  * gst_v4l2_signal_strength():
675  *   get the strength of the signal on the current input
676  * return value: TRUE on success, FALSE on error
677  ******************************************************/
678
679 gboolean
680 gst_v4l2_signal_strength (GstV4l2Element * v4l2element,
681     gint tunernum, gulong * signal_strength)
682 {
683   struct v4l2_tuner tuner;
684
685   DEBUG ("trying to get signal strength");
686   GST_V4L2_CHECK_OPEN (v4l2element);
687
688   tuner.index = tunernum;
689   if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
690     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
691         ("Failed to get signal strength for device %s: %s",
692             v4l2element->device, g_strerror (errno)));
693     return FALSE;
694   }
695
696   *signal_strength = tuner.signal;
697
698   return TRUE;
699 }
700
701
702 /******************************************************
703  * gst_v4l2_get_attribute():
704  *   try to get the value of one specific attribute
705  * return value: TRUE on success, FALSE on error
706  ******************************************************/
707
708 gboolean
709 gst_v4l2_get_attribute (GstV4l2Element * v4l2element,
710     int attribute_num, int *value)
711 {
712   struct v4l2_control control;
713
714   GST_V4L2_CHECK_OPEN (v4l2element);
715
716   DEBUG ("getting value of attribute %d", attribute_num);
717
718   control.id = attribute_num;
719
720   if (ioctl (v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
721     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
722         ("Failed to get value for control %d on device %s: %s",
723             attribute_num, v4l2element->device, g_strerror (errno)));
724     return FALSE;
725   }
726
727   *value = control.value;
728
729   return TRUE;
730 }
731
732
733 /******************************************************
734  * gst_v4l2_set_attribute():
735  *   try to set the value of one specific attribute
736  * return value: TRUE on success, FALSE on error
737  ******************************************************/
738
739 gboolean
740 gst_v4l2_set_attribute (GstV4l2Element * v4l2element,
741     int attribute_num, const int value)
742 {
743   struct v4l2_control control;
744
745   GST_V4L2_CHECK_OPEN (v4l2element);
746
747   DEBUG ("setting value of attribute %d to %d", attribute_num, value);
748
749   control.id = attribute_num;
750   control.value = value;
751
752   if (ioctl (v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
753     GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL),
754         ("Failed to set value %d for control %d on device %s: %s",
755             value, attribute_num, v4l2element->device, g_strerror (errno)));
756     return FALSE;
757   }
758
759   return TRUE;
760 }