this adds video4linux2 source and element plugins. The division in v4l2* plugins...
[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 "v4l2_calls.h"
32
33 #define DEBUG(format, args...) \
34         GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
35                 GST_ELEMENT(v4l2element), \
36                 "V4L2: " format "\n", ##args)
37
38
39 /******************************************************
40  * gst_v4l2_get_capabilities():
41  *   get the device's capturing capabilities
42  * return value: TRUE on success, FALSE on error
43  ******************************************************/
44
45 static gboolean
46 gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
47 {
48         DEBUG("getting capabilities");
49         GST_V4L2_CHECK_OPEN(v4l2element);
50
51         if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
52                 gst_element_error(GST_ELEMENT(v4l2element),
53                         "Error getting %s capabilities: %s",
54                         v4l2element->device, sys_errlist[errno]);
55                 return FALSE;
56         }
57
58         return TRUE;
59 }
60
61
62 /******************************************************
63  * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
64  *   fill/empty the lists of enumerations
65  * return value: TRUE on success, FALSE on error
66  ******************************************************/
67
68 static gboolean
69 gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
70 {
71         gint n;
72
73         DEBUG("getting enumerations");
74         GST_V4L2_CHECK_OPEN(v4l2element);
75
76         /* create enumeration lists - let's start with format enumeration */
77         for (n=0;;n++) {
78                 struct v4l2_fmtdesc format, *fmtptr;
79                 format.index = n;
80                 if (ioctl(v4l2element->video_fd, VIDIOC_ENUM_PIXFMT, &format) < 0) {
81                         if (errno == EINVAL)
82                                 break; /* end of enumeration */
83                         else {
84                                 gst_element_error(GST_ELEMENT(v4l2element),
85                                         "Failed to get no. %d in pixelformat enumeration for %s: %s",
86                                         n, v4l2element->device, sys_errlist[errno]);
87                                 return FALSE;
88                         }
89                 }
90                 fmtptr = g_malloc(sizeof(format));
91                 memcpy(fmtptr, &format, sizeof(format));
92                 v4l2element->formats = g_list_append(v4l2element->formats, fmtptr);
93         }
94
95         /* and now, the inputs */
96         for (n=0;;n++) {
97                 struct v4l2_input input, *inpptr;
98                 input.index = n;
99                 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
100                         if (errno == EINVAL)
101                                 break; /* end of enumeration */
102                         else {
103                                 gst_element_error(GST_ELEMENT(v4l2element),
104                                         "Failed to get no. %d in input enumeration for %s: %s",
105                                         n, v4l2element->device, sys_errlist[errno]);
106                                 return FALSE;
107                         }
108                 }
109                 inpptr = g_malloc(sizeof(input));
110                 memcpy(inpptr, &input, sizeof(input));
111                 v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
112         }
113
114         /* outputs */
115         for (n=0;;n++) {
116                 struct v4l2_output output, *outptr;
117                 output.index = n;
118                 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
119                         if (errno == EINVAL)
120                                 break; /* end of enumeration */
121                         else {
122                                 gst_element_error(GST_ELEMENT(v4l2element),
123                                         "Failed to get no. %d in output enumeration for %s: %s",
124                                         n, v4l2element->device, sys_errlist[errno]);
125                                 return FALSE;
126                         }
127                 }
128                 outptr = g_malloc(sizeof(output));
129                 memcpy(outptr, &output, sizeof(output));
130                 v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
131         }
132
133         /* norms... */
134         for (n=0;;n++) {
135                 struct v4l2_enumstd standard, *stdptr;
136                 standard.index = n;
137                 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
138                         if (errno == EINVAL)
139                                 break; /* end of enumeration */
140                         else {
141                                 gst_element_error(GST_ELEMENT(v4l2element),
142                                         "Failed to get no. %d in norm enumeration for %s: %s",
143                                         n, v4l2element->device, sys_errlist[errno]);
144                                 return FALSE;
145                         }
146                 }
147                 stdptr = g_malloc(sizeof(standard));
148                 memcpy(stdptr, &standard, sizeof(standard));
149                 v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
150         }
151
152         /* and lastly, controls+menus (if appropriate) */
153         for (n=0;;n++) {
154                 struct v4l2_queryctrl control, *ctrlptr;
155                 GList *menus = NULL;
156                 control.id = n;
157                 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
158                         if (errno == EINVAL)
159                                 break; /* end of enumeration */
160                         else {
161                                 gst_element_error(GST_ELEMENT(v4l2element),
162                                         "Failed to get no. %d in control enumeration for %s: %s",
163                                         n, v4l2element->device, sys_errlist[errno]);
164                                 return FALSE;
165                         }
166                 }
167                 ctrlptr = g_malloc(sizeof(control));
168                 memcpy(ctrlptr, &control, sizeof(control));
169                 v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
170                 if (control.type == V4L2_CTRL_TYPE_MENU) {
171                         struct v4l2_querymenu menu, *mptr;
172                         int i;
173                         menu.id = n;
174                         for (i=0;;i++) {
175                                 menu.index = i;
176                                 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
177                                         if (errno == EINVAL)
178                                                 break; /* end of enumeration */
179                                         else {
180                                                 gst_element_error(GST_ELEMENT(v4l2element),
181                                                         "Failed to get no. %d in menu %d enumeration for %s: %s",
182                                                         i, n, v4l2element->device, sys_errlist[errno]);
183                                                 return FALSE;
184                                         }
185                                 }
186                                 mptr = g_malloc(sizeof(menu));
187                                 memcpy(mptr, &menu, sizeof(menu));
188                                 menus = g_list_append(menus, mptr);
189                         }
190                 }
191                 v4l2element->menus = g_list_append(v4l2element->menus, menus);
192         }
193
194         return TRUE;
195 }
196
197
198 static void
199 gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
200 {
201         DEBUG("deleting enumerations");
202
203         /* empty lists */
204         while (g_list_length(v4l2element->inputs) > 0) {
205                 gpointer data = g_list_nth_data(v4l2element->inputs, 0);
206                 v4l2element->inputs = g_list_remove(v4l2element->inputs, data);
207                 g_free(data);
208         }
209         while (g_list_length(v4l2element->outputs) > 0) {
210                 gpointer data = g_list_nth_data(v4l2element->outputs, 0);
211                 v4l2element->outputs = g_list_remove(v4l2element->outputs, data);
212                 g_free(data);
213         }
214         while (g_list_length(v4l2element->norms) > 0) {
215                 gpointer data = g_list_nth_data(v4l2element->norms, 0);
216                 v4l2element->norms = g_list_remove(v4l2element->norms, data);
217                 g_free(data);
218         }
219         while (g_list_length(v4l2element->formats) > 0) {
220                 gpointer data = g_list_nth_data(v4l2element->formats, 0);
221                 v4l2element->formats = g_list_remove(v4l2element->formats, data);
222                 g_free(data);
223         }
224         while (g_list_length(v4l2element->controls) > 0) {
225                 gpointer data = g_list_nth_data(v4l2element->controls, 0);
226                 v4l2element->controls = g_list_remove(v4l2element->controls, data);
227                 g_free(data);
228         }
229         v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL);
230         while (g_list_length(v4l2element->menus) > 0) {
231                 GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0);
232                 v4l2element->inputs = g_list_remove(v4l2element->inputs, items);
233                 while (g_list_length(items) > 0) {
234                         gpointer data = g_list_nth_data(v4l2element->menus, 0);
235                         items = g_list_remove(items, data);
236                         g_free(data);
237                 }
238         }
239 }
240
241
242 /******************************************************
243  * gst_v4l2_open():
244  *   open the video device (v4l2element->device)
245  * return value: TRUE on success, FALSE on error
246  ******************************************************/
247
248 gboolean
249 gst_v4l2_open (GstV4l2Element *v4l2element)
250 {
251         DEBUG("Trying to open device %s", v4l2element->device);
252         GST_V4L2_CHECK_NOT_OPEN(v4l2element);
253         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
254
255         /* be sure we have a device */
256         if (!v4l2element->device)
257                 v4l2element->device = g_strdup("/dev/video");
258
259         /* open the device */
260         v4l2element->video_fd = open(v4l2element->device, O_RDWR);
261         if (!GST_V4L2_IS_OPEN(v4l2element)) {
262                 gst_element_error(GST_ELEMENT(v4l2element),
263                         "Failed to open device %s: %s",
264                         v4l2element->device, sys_errlist[errno]);
265                 goto error;
266         }
267
268         /* get capabilities */
269         if (!gst_v4l2_get_capabilities(v4l2element)) {
270                 goto error;
271         }
272
273         /* and get the video window */
274         if (GST_V4L2_IS_OVERLAY(v4l2element)) {
275                 if (ioctl(v4l2element->video_fd, VIDIOC_G_WIN, &(v4l2element->vwin)) < 0) {
276                         gst_element_error(GST_ELEMENT(v4l2element),
277                                 "Failed to get video window properties of %s: %s",
278                                 v4l2element->device, sys_errlist[errno]);
279                         goto error;
280                 }
281         }
282
283         /* create enumerations */
284         if (!gst_v4l2_fill_lists(v4l2element))
285                 goto error;
286
287         gst_info("Opened device '%s' (%s) successfully\n",
288                 v4l2element->vcap.name, v4l2element->device);
289
290         return TRUE;
291
292 error:
293         if (GST_V4L2_IS_OPEN(v4l2element)) {
294                 /* close device */
295                 close(v4l2element->video_fd);
296                 v4l2element->video_fd = -1;
297         }
298         /* empty lists */
299         gst_v4l2_empty_lists(v4l2element);
300
301         return FALSE;
302 }
303
304
305 /******************************************************
306  * gst_v4l2_close():
307  *   close the video device (v4l2element->video_fd)
308  * return value: TRUE on success, FALSE on error
309  ******************************************************/
310
311 gboolean
312 gst_v4l2_close (GstV4l2Element *v4l2element)
313 {
314         DEBUG("Trying to close %s", v4l2element->device);
315         GST_V4L2_CHECK_OPEN(v4l2element);
316         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
317
318         /* close device */
319         close(v4l2element->video_fd);
320         v4l2element->video_fd = -1;
321
322         /* empty lists */
323         gst_v4l2_empty_lists(v4l2element);
324
325         return TRUE;
326 }
327
328
329 /******************************************************
330  * gst_v4l2_get_norm()
331  *   Get the norm of the current device
332  * return value: TRUE on success, FALSE on error
333  ******************************************************/
334
335 gboolean
336 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
337                    gint           *norm)
338 {
339         struct v4l2_standard standard;
340         gint n;
341
342         DEBUG("getting norm");
343         GST_V4L2_CHECK_OPEN(v4l2element);
344
345         if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
346                 gst_element_error(GST_ELEMENT(v4l2element),
347                         "Failed to get the current norm for device %s: %s",
348                         v4l2element->device, sys_errlist[errno]);
349                 return FALSE;
350         }
351
352         /* try to find out what norm number this actually is */
353         for (n=0;n<g_list_length(v4l2element->norms);n++) {
354                 struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
355                 if (!strcmp(stdptr->std.name, standard.name)) {
356                         *norm = n;
357                         return TRUE;
358                 }
359         }
360
361         gst_element_error(GST_ELEMENT(v4l2element),
362                 "Failed to find norm '%s' in our list of available norms for device %s",
363                 standard.name, v4l2element->device);
364         return FALSE;
365 }
366
367
368 /******************************************************
369  * gst_v4l2_set_norm()
370  *   Set the norm of the current device
371  * return value: TRUE on success, FALSE on error
372  ******************************************************/
373
374 gboolean
375 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
376                    gint            norm)
377 {
378         struct v4l2_enumstd *standard;
379
380         DEBUG("trying to set norm to %d", norm);
381         GST_V4L2_CHECK_OPEN(v4l2element);
382         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
383
384         if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
385                 gst_element_error(GST_ELEMENT(v4l2element),
386                         "Invalid norm number %d (%d-%d)",
387                         norm, 0, g_list_length(v4l2element->norms));
388                 return FALSE;
389         }
390
391         standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
392
393         if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
394                 gst_element_error(GST_ELEMENT(v4l2element),
395                         "Failed to set norm '%s' (%d) for device %s: %s",
396                         standard->std.name, norm, v4l2element->device, sys_errlist[errno]);
397                 return FALSE;
398         }
399
400         return TRUE;
401 }
402
403
404 /******************************************************
405  * gst_v4l2_get_norm_names()
406  *   Get the list of available norms
407  * return value: the list
408  ******************************************************/
409
410 GList *
411 gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
412 {
413         GList *names = NULL;
414         gint n;
415
416         DEBUG("getting a list of norm names");
417
418         for (n=0;n<g_list_length(v4l2element->norms);n++) {
419                 struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
420                 names = g_list_append(names, g_strdup(standard->std.name));
421         }
422
423         return names;
424 }
425
426
427 /******************************************************
428  * gst_v4l2_get_input()
429  *   Get the input of the current device
430  * return value: TRUE on success, FALSE on error
431  ******************************************************/
432
433 gboolean
434 gst_v4l2_get_input (GstV4l2Element *v4l2element,
435                     gint           *input)
436 {
437         gint n;
438
439         DEBUG("trying to get input");
440         GST_V4L2_CHECK_OPEN(v4l2element);
441
442         if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
443                 gst_element_error(GST_ELEMENT(v4l2element),
444                         "Failed to get current input on device %s: %s",
445                         v4l2element->device, sys_errlist[errno]);
446                 return FALSE;
447         }
448
449         *input = n;
450
451         return TRUE;
452 }
453
454
455 /******************************************************
456  * gst_v4l2_set_input()
457  *   Set the input of the current device
458  * return value: TRUE on success, FALSE on error
459  ******************************************************/
460
461 gboolean
462 gst_v4l2_set_input (GstV4l2Element *v4l2element,
463                     gint            input)
464 {
465         DEBUG("trying to set input to %d", input);
466         GST_V4L2_CHECK_OPEN(v4l2element);
467         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
468
469         if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
470                 gst_element_error(GST_ELEMENT(v4l2element),
471                         "Invalid input number %d (%d-%d)",
472                         input, 0, g_list_length(v4l2element->inputs));
473                 return FALSE;
474         }
475
476         if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
477                 gst_element_error(GST_ELEMENT(v4l2element),
478                         "Failed to set input %d on device %s: %s",
479                         input, v4l2element->device, sys_errlist[errno]);
480                 return FALSE;
481         }
482
483         return TRUE;
484 }
485
486
487 /******************************************************
488  * gst_v4l2_get_input_names()
489  *   Get the list of available input channels
490  * return value: the list
491  ******************************************************/
492
493 GList *
494 gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
495 {
496         GList *names = NULL;
497         gint n;
498
499         DEBUG("getting a list of input names");
500
501         for (n=0;n<g_list_length(v4l2element->inputs);n++) {
502                 struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
503                 names = g_list_append(names, g_strdup(input->name));
504         }
505
506         return names;
507 }
508
509
510 /******************************************************
511  * gst_v4l2_get_output()
512  *   Get the output of the current device
513  * return value: TRUE on success, FALSE on error
514  ******************************************************/
515
516 gboolean
517 gst_v4l2_get_output (GstV4l2Element *v4l2element,
518                      gint           *output)
519 {
520         gint n;
521
522         DEBUG("trying to get output");
523         GST_V4L2_CHECK_OPEN(v4l2element);
524
525         if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
526                 gst_element_error(GST_ELEMENT(v4l2element),
527                         "Failed to get current output on device %s: %s",
528                         v4l2element->device, sys_errlist[errno]);
529                 return FALSE;
530         }
531
532         *output = n;
533
534         return TRUE;
535 }
536
537
538 /******************************************************
539  * gst_v4l2_set_output()
540  *   Set the output of the current device
541  * return value: TRUE on success, FALSE on error
542  ******************************************************/
543
544 gboolean
545 gst_v4l2_set_output (GstV4l2Element *v4l2element,
546                      gint            output)
547 {
548         DEBUG("trying to set output to %d", output);
549         GST_V4L2_CHECK_OPEN(v4l2element);
550         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
551
552         if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
553                 gst_element_error(GST_ELEMENT(v4l2element),
554                         "Invalid output number %d (%d-%d)",
555                         output, 0, g_list_length(v4l2element->outputs));
556                 return FALSE;
557         }
558
559         if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
560                 gst_element_error(GST_ELEMENT(v4l2element),
561                         "Failed to set output %d on device %s: %s",
562                         output, v4l2element->device, sys_errlist[errno]);
563                 return FALSE;
564         }
565
566         return TRUE;
567 }
568
569
570 /******************************************************
571  * gst_v4l2_get_output_names()
572  *   Get the list of available output channels
573  * return value: the list, or NULL on error
574  ******************************************************/
575
576 GList *
577 gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
578 {
579         GList *names = NULL;
580         gint n;
581
582         DEBUG("getting a list of output names");
583
584         for (n=0;n<g_list_length(v4l2element->outputs);n++) {
585                 struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
586                 names = g_list_append(names, g_strdup(output->name));
587         }
588
589         return names;
590 }
591
592
593 /******************************************************
594  * gst_v4l_has_tuner():
595  *   Check whether the device has a tuner
596  * return value: TRUE if it has a tuner, else FALSE
597  ******************************************************/
598
599 gboolean
600 gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
601 {
602         gint input_num;
603         struct v4l2_input *input;
604
605         DEBUG("detecting whether device has a tuner");
606         GST_V4L2_CHECK_OPEN(v4l2element);
607
608         if (!gst_v4l2_get_input(v4l2element, &input_num))
609                 return FALSE;
610
611         input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
612
613         return (input->type == V4L2_INPUT_TYPE_TUNER &&
614                 v4l2element->vcap.flags & V4L2_FLAG_TUNER);
615 }
616
617
618 /******************************************************
619  * gst_v4l_get_frequency():
620  *   get the current frequency
621  * return value: TRUE on success, FALSE on error
622  ******************************************************/
623
624 gboolean
625 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
626                         gulong         *frequency)
627 {
628         gint n;
629
630         DEBUG("getting current tuner frequency");
631         GST_V4L2_CHECK_OPEN(v4l2element);
632
633         if (!gst_v4l2_has_tuner(v4l2element))
634                 return FALSE;
635
636         if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
637                 gst_element_error(GST_ELEMENT(v4l2element),
638                         "Failed to get current tuner frequency for device %s: %s",
639                         v4l2element->device, sys_errlist[errno]);
640                 return FALSE;
641         }
642
643         *frequency = n;
644
645         return TRUE;
646 }
647
648
649 /******************************************************
650  * gst_v4l_set_frequency():
651  *   set frequency
652  * return value: TRUE on success, FALSE on error
653  ******************************************************/
654
655 gboolean
656 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
657                         gulong          frequency)
658 {
659         gint n = frequency;
660
661         DEBUG("setting current tuner frequency to %lu", frequency);
662         GST_V4L2_CHECK_OPEN(v4l2element);
663         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
664
665         if (!gst_v4l2_has_tuner(v4l2element))
666                 return FALSE;
667
668         if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
669                 gst_element_error(GST_ELEMENT(v4l2element),
670                         "Failed to set tuner frequency to %lu for device %s: %s",
671                         frequency, v4l2element->device, sys_errlist[errno]);
672                 return FALSE;
673         }
674
675         return TRUE;
676 }
677
678
679 /******************************************************
680  * gst_v4l_signal_strength():
681  *   get the strength of the signal on the current input
682  * return value: TRUE on success, FALSE on error
683  ******************************************************/
684
685 gboolean
686 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
687                           gulong         *signal_strength)
688 {
689         struct v4l2_tuner tuner;
690
691         DEBUG("trying to get signal strength");
692         GST_V4L2_CHECK_OPEN(v4l2element);
693
694         if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
695                 gst_element_error(GST_ELEMENT(v4l2element),
696                         "Failed to set signal strength for device %s: %s",
697                         v4l2element->device, sys_errlist[errno]);
698                 return FALSE;
699         }
700
701         *signal_strength = tuner.signal;
702
703         return TRUE;
704 }
705
706
707 /******************************************************
708  * gst_v4l_has_audio():
709  *   Check whether the device has audio capabilities
710  * return value: TRUE if it has a tuner, else FALSE
711  ******************************************************/
712
713 gboolean
714 gst_v4l2_has_audio (GstV4l2Element *v4l2element)
715 {
716         gint input_num;
717         struct v4l2_input *input;
718
719         DEBUG("detecting whether device has audio");
720         GST_V4L2_CHECK_OPEN(v4l2element);
721
722         if (!gst_v4l2_get_input(v4l2element, &input_num))
723                 return FALSE;
724
725         input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
726
727         return (input->capability & V4L2_INPUT_CAP_AUDIO);
728 }
729
730
731 /******************************************************
732  * gst_v4l_get_attributes():
733  *   get a list of attributes available on this device
734  * return value: the list
735  ******************************************************/
736
737 GList *
738 gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
739 {
740         gint i;
741         GList *list = NULL;
742
743         DEBUG("getting a list of available attributes");
744
745         for (i=0;i<g_list_length(v4l2element->controls);i++) {
746                 struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
747                 GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
748                 attribute->name = g_strdup(control->name);
749                 attribute->index = i;
750                 attribute->list_items = NULL;
751                 switch (control->type) {
752                         case V4L2_CTRL_TYPE_INTEGER:
753                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
754                                 break;
755                         case V4L2_CTRL_TYPE_BOOLEAN:
756                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
757                                 break;
758                         case V4L2_CTRL_TYPE_MENU: {
759                                 /* list items */
760                                 gint n;
761                                 GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
762                                 for (n=0;n<g_list_length(menus);n++) {
763                                         struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
764                                         attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
765                                 }
766                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
767                                 break; }
768                         case V4L2_CTRL_TYPE_BUTTON:
769                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
770                                 break;
771                 }
772                 switch (control->category) {
773                         case V4L2_CTRL_CAT_VIDEO:
774                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
775                                 break;
776                         case V4L2_CTRL_CAT_AUDIO:
777                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
778                                 break;
779                         case V4L2_CTRL_CAT_EFFECT:
780                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
781                                 break;
782                 }
783                 gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
784                 attribute->min = control->minimum;
785                 attribute->max = control->maximum;
786         }
787
788         return list;
789 }
790
791
792 /******************************************************
793  * gst_v4l_get_attribute():
794  *   try to get the value of one specific attribute
795  * return value: TRUE on success, FALSE on error
796  ******************************************************/
797
798 gboolean
799 gst_v4l2_get_attribute  (GstV4l2Element *v4l2element,
800                          gint            attribute_num,
801                          gint           *value)
802 {
803         struct v4l2_control control;
804
805         DEBUG("getting value of attribute %d", attribute_num);
806         GST_V4L2_CHECK_OPEN(v4l2element);
807
808         if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
809                 gst_element_error(GST_ELEMENT(v4l2element),
810                         "Invalid control ID %d", attribute_num);
811                 return FALSE;
812         }
813
814         control.id = attribute_num;
815
816         if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
817                 gst_element_error(GST_ELEMENT(v4l2element),
818                         "Failed to get value for control %d on device %s: %s",
819                         attribute_num, v4l2element->device, sys_errlist[errno]);
820                 return FALSE;
821         }
822
823         *value = control.value;
824
825         return TRUE;
826 }
827
828
829 /******************************************************
830  * gst_v4l_set_attribute():
831  *   try to set the value of one specific attribute
832  * return value: TRUE on success, FALSE on error
833  ******************************************************/
834
835 gboolean
836 gst_v4l2_set_attribute  (GstV4l2Element *v4l2element,
837                          gint            attribute_num,
838                          gint            value)
839 {
840         struct v4l2_control control;
841
842         DEBUG("setting value of attribute %d to %d", attribute_num, value);
843         GST_V4L2_CHECK_OPEN(v4l2element);
844
845         if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
846                 gst_element_error(GST_ELEMENT(v4l2element),
847                         "Invalid control ID %d", attribute_num);
848                 return FALSE;
849         }
850
851         control.id = attribute_num;
852         control.value = value;
853
854         if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
855                 gst_element_error(GST_ELEMENT(v4l2element),
856                         "Failed to set value %d for control %d on device %s: %s",
857                         value, attribute_num, v4l2element->device, sys_errlist[errno]);
858                 return FALSE;
859         }
860
861         return TRUE;
862 }
863