Let's use g_strerror() instead of strerror()
[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, ##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, g_strerror(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, g_strerror(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, g_strerror(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, g_strerror(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, g_strerror(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, g_strerror(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, g_strerror(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, g_strerror(errno));
265                 goto error;
266         }
267
268         /* get capabilities */
269         if (!gst_v4l2_get_capabilities(v4l2element)) {
270                 goto error;
271         }
272
273         /* create enumerations */
274         if (!gst_v4l2_fill_lists(v4l2element))
275                 goto error;
276
277         gst_info("Opened device '%s' (%s) successfully\n",
278                 v4l2element->vcap.name, v4l2element->device);
279
280         return TRUE;
281
282 error:
283         if (GST_V4L2_IS_OPEN(v4l2element)) {
284                 /* close device */
285                 close(v4l2element->video_fd);
286                 v4l2element->video_fd = -1;
287         }
288         /* empty lists */
289         gst_v4l2_empty_lists(v4l2element);
290
291         return FALSE;
292 }
293
294
295 /******************************************************
296  * gst_v4l2_close():
297  *   close the video device (v4l2element->video_fd)
298  * return value: TRUE on success, FALSE on error
299  ******************************************************/
300
301 gboolean
302 gst_v4l2_close (GstV4l2Element *v4l2element)
303 {
304         DEBUG("Trying to close %s", v4l2element->device);
305         GST_V4L2_CHECK_OPEN(v4l2element);
306         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
307
308         /* close device */
309         close(v4l2element->video_fd);
310         v4l2element->video_fd = -1;
311
312         /* empty lists */
313         gst_v4l2_empty_lists(v4l2element);
314
315         return TRUE;
316 }
317
318
319 /******************************************************
320  * gst_v4l2_get_norm()
321  *   Get the norm of the current device
322  * return value: TRUE on success, FALSE on error
323  ******************************************************/
324
325 gboolean
326 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
327                    gint           *norm)
328 {
329         struct v4l2_standard standard;
330         gint n;
331
332         DEBUG("getting norm");
333         GST_V4L2_CHECK_OPEN(v4l2element);
334
335         if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
336                 gst_element_error(GST_ELEMENT(v4l2element),
337                         "Failed to get the current norm for device %s: %s",
338                         v4l2element->device, g_strerror(errno));
339                 return FALSE;
340         }
341
342         /* try to find out what norm number this actually is */
343         for (n=0;n<g_list_length(v4l2element->norms);n++) {
344                 struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
345                 if (!strcmp(stdptr->std.name, standard.name)) {
346                         *norm = n;
347                         return TRUE;
348                 }
349         }
350
351         gst_element_error(GST_ELEMENT(v4l2element),
352                 "Failed to find norm '%s' in our list of available norms for device %s",
353                 standard.name, v4l2element->device);
354         return FALSE;
355 }
356
357
358 /******************************************************
359  * gst_v4l2_set_norm()
360  *   Set the norm of the current device
361  * return value: TRUE on success, FALSE on error
362  ******************************************************/
363
364 gboolean
365 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
366                    gint            norm)
367 {
368         struct v4l2_enumstd *standard;
369
370         DEBUG("trying to set norm to %d", norm);
371         GST_V4L2_CHECK_OPEN(v4l2element);
372         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
373
374         if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
375                 gst_element_error(GST_ELEMENT(v4l2element),
376                         "Invalid norm number %d (%d-%d)",
377                         norm, 0, g_list_length(v4l2element->norms));
378                 return FALSE;
379         }
380
381         standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
382
383         if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
384                 gst_element_error(GST_ELEMENT(v4l2element),
385                         "Failed to set norm '%s' (%d) for device %s: %s",
386                         standard->std.name, norm, v4l2element->device, g_strerror(errno));
387                 return FALSE;
388         }
389
390         return TRUE;
391 }
392
393
394 /******************************************************
395  * gst_v4l2_get_norm_names()
396  *   Get the list of available norms
397  * return value: the list
398  ******************************************************/
399
400 GList *
401 gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
402 {
403         GList *names = NULL;
404         gint n;
405
406         DEBUG("getting a list of norm names");
407
408         for (n=0;n<g_list_length(v4l2element->norms);n++) {
409                 struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
410                 names = g_list_append(names, g_strdup(standard->std.name));
411         }
412
413         return names;
414 }
415
416
417 /******************************************************
418  * gst_v4l2_get_input()
419  *   Get the input of the current device
420  * return value: TRUE on success, FALSE on error
421  ******************************************************/
422
423 gboolean
424 gst_v4l2_get_input (GstV4l2Element *v4l2element,
425                     gint           *input)
426 {
427         gint n;
428
429         DEBUG("trying to get input");
430         GST_V4L2_CHECK_OPEN(v4l2element);
431
432         if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
433                 gst_element_error(GST_ELEMENT(v4l2element),
434                         "Failed to get current input on device %s: %s",
435                         v4l2element->device, g_strerror(errno));
436                 return FALSE;
437         }
438
439         *input = n;
440
441         return TRUE;
442 }
443
444
445 /******************************************************
446  * gst_v4l2_set_input()
447  *   Set the input of the current device
448  * return value: TRUE on success, FALSE on error
449  ******************************************************/
450
451 gboolean
452 gst_v4l2_set_input (GstV4l2Element *v4l2element,
453                     gint            input)
454 {
455         DEBUG("trying to set input to %d", input);
456         GST_V4L2_CHECK_OPEN(v4l2element);
457         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
458
459         if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
460                 gst_element_error(GST_ELEMENT(v4l2element),
461                         "Invalid input number %d (%d-%d)",
462                         input, 0, g_list_length(v4l2element->inputs));
463                 return FALSE;
464         }
465
466         if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
467                 gst_element_error(GST_ELEMENT(v4l2element),
468                         "Failed to set input %d on device %s: %s",
469                         input, v4l2element->device, g_strerror(errno));
470                 return FALSE;
471         }
472
473         return TRUE;
474 }
475
476
477 /******************************************************
478  * gst_v4l2_get_input_names()
479  *   Get the list of available input channels
480  * return value: the list
481  ******************************************************/
482
483 GList *
484 gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
485 {
486         GList *names = NULL;
487         gint n;
488
489         DEBUG("getting a list of input names");
490
491         for (n=0;n<g_list_length(v4l2element->inputs);n++) {
492                 struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
493                 names = g_list_append(names, g_strdup(input->name));
494         }
495
496         return names;
497 }
498
499
500 /******************************************************
501  * gst_v4l2_get_output()
502  *   Get the output of the current device
503  * return value: TRUE on success, FALSE on error
504  ******************************************************/
505
506 gboolean
507 gst_v4l2_get_output (GstV4l2Element *v4l2element,
508                      gint           *output)
509 {
510         gint n;
511
512         DEBUG("trying to get output");
513         GST_V4L2_CHECK_OPEN(v4l2element);
514
515         if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
516                 gst_element_error(GST_ELEMENT(v4l2element),
517                         "Failed to get current output on device %s: %s",
518                         v4l2element->device, g_strerror(errno));
519                 return FALSE;
520         }
521
522         *output = n;
523
524         return TRUE;
525 }
526
527
528 /******************************************************
529  * gst_v4l2_set_output()
530  *   Set the output of the current device
531  * return value: TRUE on success, FALSE on error
532  ******************************************************/
533
534 gboolean
535 gst_v4l2_set_output (GstV4l2Element *v4l2element,
536                      gint            output)
537 {
538         DEBUG("trying to set output to %d", output);
539         GST_V4L2_CHECK_OPEN(v4l2element);
540         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
541
542         if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
543                 gst_element_error(GST_ELEMENT(v4l2element),
544                         "Invalid output number %d (%d-%d)",
545                         output, 0, g_list_length(v4l2element->outputs));
546                 return FALSE;
547         }
548
549         if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
550                 gst_element_error(GST_ELEMENT(v4l2element),
551                         "Failed to set output %d on device %s: %s",
552                         output, v4l2element->device, g_strerror(errno));
553                 return FALSE;
554         }
555
556         return TRUE;
557 }
558
559
560 /******************************************************
561  * gst_v4l2_get_output_names()
562  *   Get the list of available output channels
563  * return value: the list, or NULL on error
564  ******************************************************/
565
566 GList *
567 gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
568 {
569         GList *names = NULL;
570         gint n;
571
572         DEBUG("getting a list of output names");
573
574         for (n=0;n<g_list_length(v4l2element->outputs);n++) {
575                 struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
576                 names = g_list_append(names, g_strdup(output->name));
577         }
578
579         return names;
580 }
581
582
583 /******************************************************
584  * gst_v4l_has_tuner():
585  *   Check whether the device has a tuner
586  * return value: TRUE if it has a tuner, else FALSE
587  ******************************************************/
588
589 gboolean
590 gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
591 {
592         gint input_num;
593         struct v4l2_input *input;
594
595         DEBUG("detecting whether device has a tuner");
596         GST_V4L2_CHECK_OPEN(v4l2element);
597
598         if (!gst_v4l2_get_input(v4l2element, &input_num))
599                 return FALSE;
600
601         input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
602
603         return (input->type == V4L2_INPUT_TYPE_TUNER &&
604                 v4l2element->vcap.flags & V4L2_FLAG_TUNER);
605 }
606
607
608 /******************************************************
609  * gst_v4l_get_frequency():
610  *   get the current frequency
611  * return value: TRUE on success, FALSE on error
612  ******************************************************/
613
614 gboolean
615 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
616                         gulong         *frequency)
617 {
618         gint n;
619
620         DEBUG("getting current tuner frequency");
621         GST_V4L2_CHECK_OPEN(v4l2element);
622
623         if (!gst_v4l2_has_tuner(v4l2element))
624                 return FALSE;
625
626         if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
627                 gst_element_error(GST_ELEMENT(v4l2element),
628                         "Failed to get current tuner frequency for device %s: %s",
629                         v4l2element->device, g_strerror(errno));
630                 return FALSE;
631         }
632
633         *frequency = n;
634
635         return TRUE;
636 }
637
638
639 /******************************************************
640  * gst_v4l_set_frequency():
641  *   set frequency
642  * return value: TRUE on success, FALSE on error
643  ******************************************************/
644
645 gboolean
646 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
647                         gulong          frequency)
648 {
649         gint n = frequency;
650
651         DEBUG("setting current tuner frequency to %lu", frequency);
652         GST_V4L2_CHECK_OPEN(v4l2element);
653         GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
654
655         if (!gst_v4l2_has_tuner(v4l2element))
656                 return FALSE;
657
658         if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
659                 gst_element_error(GST_ELEMENT(v4l2element),
660                         "Failed to set tuner frequency to %lu for device %s: %s",
661                         frequency, v4l2element->device, g_strerror(errno));
662                 return FALSE;
663         }
664
665         return TRUE;
666 }
667
668
669 /******************************************************
670  * gst_v4l_signal_strength():
671  *   get the strength of the signal on the current input
672  * return value: TRUE on success, FALSE on error
673  ******************************************************/
674
675 gboolean
676 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
677                           gulong         *signal_strength)
678 {
679         struct v4l2_tuner tuner;
680
681         DEBUG("trying to get signal strength");
682         GST_V4L2_CHECK_OPEN(v4l2element);
683
684         if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
685                 gst_element_error(GST_ELEMENT(v4l2element),
686                         "Failed to set signal strength for device %s: %s",
687                         v4l2element->device, g_strerror(errno));
688                 return FALSE;
689         }
690
691         *signal_strength = tuner.signal;
692
693         return TRUE;
694 }
695
696
697 /******************************************************
698  * gst_v4l_has_audio():
699  *   Check whether the device has audio capabilities
700  * return value: TRUE if it has a tuner, else FALSE
701  ******************************************************/
702
703 gboolean
704 gst_v4l2_has_audio (GstV4l2Element *v4l2element)
705 {
706         gint input_num;
707         struct v4l2_input *input;
708
709         DEBUG("detecting whether device has audio");
710         GST_V4L2_CHECK_OPEN(v4l2element);
711
712         if (!gst_v4l2_get_input(v4l2element, &input_num))
713                 return FALSE;
714
715         input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
716
717         return (input->capability & V4L2_INPUT_CAP_AUDIO);
718 }
719
720
721 /******************************************************
722  * gst_v4l_get_attributes():
723  *   get a list of attributes available on this device
724  * return value: the list
725  ******************************************************/
726
727 GList *
728 gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
729 {
730         gint i;
731         GList *list = NULL;
732
733         DEBUG("getting a list of available attributes");
734
735         for (i=0;i<g_list_length(v4l2element->controls);i++) {
736                 struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
737                 GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
738                 attribute->name = g_strdup(control->name);
739                 attribute->index = i;
740                 attribute->list_items = NULL;
741                 switch (control->type) {
742                         case V4L2_CTRL_TYPE_INTEGER:
743                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
744                                 break;
745                         case V4L2_CTRL_TYPE_BOOLEAN:
746                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
747                                 break;
748                         case V4L2_CTRL_TYPE_MENU: {
749                                 /* list items */
750                                 gint n;
751                                 GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
752                                 for (n=0;n<g_list_length(menus);n++) {
753                                         struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
754                                         attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
755                                 }
756                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
757                                 break; }
758                         case V4L2_CTRL_TYPE_BUTTON:
759                                 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
760                                 break;
761                 }
762                 switch (control->category) {
763                         case V4L2_CTRL_CAT_VIDEO:
764                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
765                                 break;
766                         case V4L2_CTRL_CAT_AUDIO:
767                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
768                                 break;
769                         case V4L2_CTRL_CAT_EFFECT:
770                                 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
771                                 break;
772                 }
773                 gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
774                 attribute->min = control->minimum;
775                 attribute->max = control->maximum;
776         }
777
778         return list;
779 }
780
781
782 /******************************************************
783  * gst_v4l_get_attribute():
784  *   try to get the value of one specific attribute
785  * return value: TRUE on success, FALSE on error
786  ******************************************************/
787
788 gboolean
789 gst_v4l2_get_attribute  (GstV4l2Element *v4l2element,
790                          gint            attribute_num,
791                          gint           *value)
792 {
793         struct v4l2_control control;
794
795         DEBUG("getting value of attribute %d", attribute_num);
796         GST_V4L2_CHECK_OPEN(v4l2element);
797
798         if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
799                 gst_element_error(GST_ELEMENT(v4l2element),
800                         "Invalid control ID %d", attribute_num);
801                 return FALSE;
802         }
803
804         control.id = attribute_num;
805
806         if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
807                 gst_element_error(GST_ELEMENT(v4l2element),
808                         "Failed to get value for control %d on device %s: %s",
809                         attribute_num, v4l2element->device, g_strerror(errno));
810                 return FALSE;
811         }
812
813         *value = control.value;
814
815         return TRUE;
816 }
817
818
819 /******************************************************
820  * gst_v4l_set_attribute():
821  *   try to set the value of one specific attribute
822  * return value: TRUE on success, FALSE on error
823  ******************************************************/
824
825 gboolean
826 gst_v4l2_set_attribute  (GstV4l2Element *v4l2element,
827                          gint            attribute_num,
828                          gint            value)
829 {
830         struct v4l2_control control;
831
832         DEBUG("setting value of attribute %d to %d", attribute_num, value);
833         GST_V4L2_CHECK_OPEN(v4l2element);
834
835         if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
836                 gst_element_error(GST_ELEMENT(v4l2element),
837                         "Invalid control ID %d", attribute_num);
838                 return FALSE;
839         }
840
841         control.id = attribute_num;
842         control.value = value;
843
844         if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
845                 gst_element_error(GST_ELEMENT(v4l2element),
846                         "Failed to set value %d for control %d on device %s: %s",
847                         value, attribute_num, v4l2element->device, g_strerror(errno));
848                 return FALSE;
849         }
850
851         return TRUE;
852 }
853