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