1 /* G-Streamer generic V4L2 element - generic V4L2 calls handling
2 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
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.
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.
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.
24 #include <sys/types.h>
27 #include <sys/ioctl.h>
32 #include "v4l2_calls.h"
34 #define DEBUG(format, args...) \
36 GST_ELEMENT(v4l2element), \
37 "V4L2: " format, ##args)
40 /******************************************************
41 * gst_v4l2_get_capabilities():
42 * get the device's capturing capabilities
43 * return value: TRUE on success, FALSE on error
44 ******************************************************/
47 gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
49 DEBUG("getting capabilities");
50 GST_V4L2_CHECK_OPEN(v4l2element);
52 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
53 gst_element_error(GST_ELEMENT(v4l2element),
54 "Error getting %s capabilities: %s",
55 v4l2element->device, g_strerror(errno));
63 /******************************************************
64 * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
65 * fill/empty the lists of enumerations
66 * return value: TRUE on success, FALSE on error
67 ******************************************************/
70 gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
74 DEBUG("getting enumerations");
75 GST_V4L2_CHECK_OPEN(v4l2element);
77 /* and now, the inputs */
79 struct v4l2_input input, *inpptr;
81 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
83 break; /* end of enumeration */
85 gst_element_error(GST_ELEMENT(v4l2element),
86 "Failed to get no. %d in input enumeration for %s: %s",
87 n, v4l2element->device, g_strerror(errno));
91 inpptr = g_malloc(sizeof(input));
92 memcpy(inpptr, &input, sizeof(input));
93 v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
95 v4l2element->input_names = g_list_append(v4l2element->input_names, inpptr->name);
100 struct v4l2_output output, *outptr;
102 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
104 break; /* end of enumeration */
106 gst_element_error(GST_ELEMENT(v4l2element),
107 "Failed to get no. %d in output enumeration for %s: %s",
108 n, v4l2element->device, g_strerror(errno));
112 outptr = g_malloc(sizeof(output));
113 memcpy(outptr, &output, sizeof(output));
114 v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
116 v4l2element->output_names = g_list_append(v4l2element->output_names, outptr->name);
121 struct v4l2_standard standard, *stdptr;
123 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
125 break; /* end of enumeration */
127 gst_element_error(GST_ELEMENT(v4l2element),
128 "Failed to get no. %d in norm enumeration for %s: %s",
129 n, v4l2element->device, g_strerror(errno));
133 stdptr = g_malloc(sizeof(standard));
134 memcpy(stdptr, &standard, sizeof(standard));
135 v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
137 v4l2element->norm_names = g_list_append(v4l2element->norm_names, stdptr->name);
140 /* and lastly, controls+menus (if appropriate) */
141 for (n=V4L2_CID_BASE;;n++) {
142 struct v4l2_queryctrl control, *ctrlptr;
144 GParamSpec *spec = NULL;
146 if (n == V4L2_CID_LASTP1)
147 n = V4L2_CID_PRIVATE_BASE;
149 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
150 if (errno == EINVAL) {
151 if (n < V4L2_CID_PRIVATE_BASE)
156 gst_element_error(GST_ELEMENT(v4l2element),
157 "Failed to get no. %d in control enumeration for %s: %s",
158 n, v4l2element->device, g_strerror(errno));
162 if (control.flags & V4L2_CTRL_FLAG_DISABLED)
164 ctrlptr = g_malloc(sizeof(control));
165 memcpy(ctrlptr, &control, sizeof(control));
166 v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
167 if (control.type == V4L2_CTRL_TYPE_MENU) {
168 struct v4l2_querymenu menu, *mptr;
173 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
175 break; /* end of enumeration */
177 gst_element_error(GST_ELEMENT(v4l2element),
178 "Failed to get no. %d in menu %d enumeration for %s: %s",
179 i, n, v4l2element->device, g_strerror(errno));
183 mptr = g_malloc(sizeof(menu));
184 memcpy(mptr, &menu, sizeof(menu));
185 menus = g_list_append(menus, mptr);
188 v4l2element->menus = g_list_append(v4l2element->menus, menus);
190 switch (control.type) {
191 case V4L2_CTRL_TYPE_INTEGER:
192 spec = g_param_spec_int(ctrlptr->name, ctrlptr->name,
193 ctrlptr->name, ctrlptr->minimum, ctrlptr->maximum,
194 ctrlptr->default_value, G_PARAM_READWRITE);
196 case V4L2_CTRL_TYPE_BOOLEAN:
197 spec = g_param_spec_boolean(ctrlptr->name, ctrlptr->name,
198 ctrlptr->name, ctrlptr->default_value,
201 case V4L2_CTRL_TYPE_MENU:
202 /* hacky... we abuse pointer for 'no value' */
203 spec = g_param_spec_pointer(ctrlptr->name, ctrlptr->name,
204 ctrlptr->name, G_PARAM_WRITABLE);
206 case V4L2_CTRL_TYPE_BUTTON:
212 v4l2element->control_specs = g_list_append(v4l2element->control_specs, spec);
220 gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
222 DEBUG("deleting enumerations");
225 while (g_list_length(v4l2element->inputs) > 0) {
226 gpointer data = g_list_nth_data(v4l2element->inputs, 0);
227 v4l2element->inputs = g_list_remove(v4l2element->inputs, data);
230 g_list_free(v4l2element->input_names);
231 v4l2element->input_names = NULL;
232 while (g_list_length(v4l2element->outputs) > 0) {
233 gpointer data = g_list_nth_data(v4l2element->outputs, 0);
234 v4l2element->outputs = g_list_remove(v4l2element->outputs, data);
237 g_list_free(v4l2element->output_names);
238 v4l2element->output_names = NULL;
239 while (g_list_length(v4l2element->norms) > 0) {
240 gpointer data = g_list_nth_data(v4l2element->norms, 0);
241 v4l2element->norms = g_list_remove(v4l2element->norms, data);
244 g_list_free(v4l2element->norm_names);
245 v4l2element->norm_names = NULL;
246 while (g_list_length(v4l2element->controls) > 0) {
247 gpointer data = g_list_nth_data(v4l2element->controls, 0);
248 v4l2element->controls = g_list_remove(v4l2element->controls, data);
251 v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL);
252 while (g_list_length(v4l2element->menus) > 0) {
253 GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0);
254 v4l2element->inputs = g_list_remove(v4l2element->inputs, items);
255 while (g_list_length(items) > 0) {
256 gpointer data = g_list_nth_data(v4l2element->menus, 0);
257 items = g_list_remove(items, data);
261 while (g_list_length(v4l2element->control_specs) > 0) {
262 gpointer data = g_list_nth_data(v4l2element->control_specs, 0);
263 v4l2element->control_specs = g_list_remove(v4l2element->control_specs, data);
264 g_param_spec_unref(G_PARAM_SPEC(data));
269 /******************************************************
271 * open the video device (v4l2element->device)
272 * return value: TRUE on success, FALSE on error
273 ******************************************************/
276 gst_v4l2_open (GstV4l2Element *v4l2element)
278 DEBUG("Trying to open device %s", v4l2element->device);
279 GST_V4L2_CHECK_NOT_OPEN(v4l2element);
280 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
282 /* be sure we have a device */
283 if (!v4l2element->device)
284 v4l2element->device = g_strdup("/dev/video");
286 /* open the device */
287 v4l2element->video_fd = open(v4l2element->device, O_RDWR);
288 if (!GST_V4L2_IS_OPEN(v4l2element)) {
289 gst_element_error(GST_ELEMENT(v4l2element),
290 "Failed to open device %s: %s",
291 v4l2element->device, g_strerror(errno));
295 /* get capabilities */
296 if (!gst_v4l2_get_capabilities(v4l2element)) {
300 /* create enumerations */
301 if (!gst_v4l2_fill_lists(v4l2element))
304 gst_info("Opened device '%s' (%s) successfully\n",
305 v4l2element->vcap.card, v4l2element->device);
310 if (GST_V4L2_IS_OPEN(v4l2element)) {
312 close(v4l2element->video_fd);
313 v4l2element->video_fd = -1;
316 gst_v4l2_empty_lists(v4l2element);
322 /******************************************************
324 * close the video device (v4l2element->video_fd)
325 * return value: TRUE on success, FALSE on error
326 ******************************************************/
329 gst_v4l2_close (GstV4l2Element *v4l2element)
331 DEBUG("Trying to close %s", v4l2element->device);
332 GST_V4L2_CHECK_OPEN(v4l2element);
333 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
336 close(v4l2element->video_fd);
337 v4l2element->video_fd = -1;
340 gst_v4l2_empty_lists(v4l2element);
346 /******************************************************
347 * gst_v4l2_get_norm()
348 * Get the norm of the current device
349 * return value: TRUE on success, FALSE on error
350 ******************************************************/
353 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
359 DEBUG("getting norm");
360 GST_V4L2_CHECK_OPEN(v4l2element);
362 if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &std_id) < 0) {
363 gst_element_error(GST_ELEMENT(v4l2element),
364 "Failed to get the current norm for device %s: %s",
365 v4l2element->device, g_strerror(errno));
369 /* try to find out what norm number this actually is */
370 for (n=0;n<g_list_length(v4l2element->norms);n++) {
371 struct v4l2_standard *stdptr = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n);
372 if (stdptr->id == std_id) {
378 gst_element_error(GST_ELEMENT(v4l2element),
379 "Failed to find norm '%llu' in our list of available norms for device %s",
380 std_id, v4l2element->device);
385 /******************************************************
386 * gst_v4l2_set_norm()
387 * Set the norm of the current device
388 * return value: TRUE on success, FALSE on error
389 ******************************************************/
392 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
395 struct v4l2_standard *standard;
397 DEBUG("trying to set norm to %d", norm);
398 GST_V4L2_CHECK_OPEN(v4l2element);
399 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
401 if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
402 gst_element_error(GST_ELEMENT(v4l2element),
403 "Invalid norm number %d (%d-%d)",
404 norm, 0, g_list_length(v4l2element->norms));
408 standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, norm);
410 if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->id) < 0) {
411 gst_element_error(GST_ELEMENT(v4l2element),
412 "Failed to set norm '%s' (%llu) for device %s: %s",
413 standard->name, standard->id, v4l2element->device, g_strerror(errno));
421 /******************************************************
422 * gst_v4l2_get_input()
423 * Get the input of the current device
424 * return value: TRUE on success, FALSE on error
425 ******************************************************/
428 gst_v4l2_get_input (GstV4l2Element *v4l2element,
433 DEBUG("trying to get input");
434 GST_V4L2_CHECK_OPEN(v4l2element);
436 if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
437 gst_element_error(GST_ELEMENT(v4l2element),
438 "Failed to get current input on device %s: %s",
439 v4l2element->device, g_strerror(errno));
449 /******************************************************
450 * gst_v4l2_set_input()
451 * Set the input of the current device
452 * return value: TRUE on success, FALSE on error
453 ******************************************************/
456 gst_v4l2_set_input (GstV4l2Element *v4l2element,
459 DEBUG("trying to set input to %d", input);
460 GST_V4L2_CHECK_OPEN(v4l2element);
461 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
463 if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
464 gst_element_error(GST_ELEMENT(v4l2element),
465 "Invalid input number %d (%d-%d)",
466 input, 0, g_list_length(v4l2element->inputs));
470 if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
471 gst_element_error(GST_ELEMENT(v4l2element),
472 "Failed to set input %d on device %s: %s",
473 input, v4l2element->device, g_strerror(errno));
481 /******************************************************
482 * gst_v4l2_get_output()
483 * Get the output of the current device
484 * return value: TRUE on success, FALSE on error
485 ******************************************************/
488 gst_v4l2_get_output (GstV4l2Element *v4l2element,
493 DEBUG("trying to get output");
494 GST_V4L2_CHECK_OPEN(v4l2element);
496 if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
497 gst_element_error(GST_ELEMENT(v4l2element),
498 "Failed to get current output on device %s: %s",
499 v4l2element->device, g_strerror(errno));
509 /******************************************************
510 * gst_v4l2_set_output()
511 * Set the output of the current device
512 * return value: TRUE on success, FALSE on error
513 ******************************************************/
516 gst_v4l2_set_output (GstV4l2Element *v4l2element,
519 DEBUG("trying to set output to %d", output);
520 GST_V4L2_CHECK_OPEN(v4l2element);
521 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
523 if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
524 gst_element_error(GST_ELEMENT(v4l2element),
525 "Invalid output number %d (%d-%d)",
526 output, 0, g_list_length(v4l2element->outputs));
530 if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
531 gst_element_error(GST_ELEMENT(v4l2element),
532 "Failed to set output %d on device %s: %s",
533 output, v4l2element->device, g_strerror(errno));
541 /******************************************************
542 * gst_v4l2_has_tuner():
543 * Check whether the device has a tuner
544 * return value: TRUE if it has a tuner, else FALSE
545 ******************************************************/
548 gst_v4l2_has_tuner (GstV4l2Element *v4l2element,
552 struct v4l2_input *input;
554 DEBUG("detecting whether device has a tuner");
555 GST_V4L2_CHECK_OPEN(v4l2element);
557 if (!gst_v4l2_get_input(v4l2element, &input_num))
560 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
562 if (input->type == V4L2_INPUT_TYPE_TUNER &&
563 v4l2element->vcap.capabilities & V4L2_CAP_TUNER) {
564 *tuner_num = input->tuner;
571 /******************************************************
572 * gst_v4l2_get_frequency():
573 * get the current frequency
574 * return value: TRUE on success, FALSE on error
575 ******************************************************/
578 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
581 struct v4l2_frequency freq;
583 DEBUG("getting current tuner frequency");
584 GST_V4L2_CHECK_OPEN(v4l2element);
586 if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
591 if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
592 gst_element_error(GST_ELEMENT(v4l2element),
593 "Failed to get current tuner frequency for device %s: %s",
594 v4l2element->device, g_strerror(errno));
598 *frequency = freq.frequency;
604 /******************************************************
605 * gst_v4l2_set_frequency():
607 * return value: TRUE on success, FALSE on error
608 ******************************************************/
611 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
614 struct v4l2_frequency freq;
616 DEBUG("setting current tuner frequency to %lu", frequency);
617 GST_V4L2_CHECK_OPEN(v4l2element);
618 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
620 if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
623 freq.frequency = frequency;
626 if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
627 gst_element_error(GST_ELEMENT(v4l2element),
628 "Failed to set tuner frequency to %lu for device %s: %s",
629 frequency, v4l2element->device, g_strerror(errno));
637 /******************************************************
638 * gst_v4l2_signal_strength():
639 * get the strength of the signal on the current input
640 * return value: TRUE on success, FALSE on error
641 ******************************************************/
644 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
645 gulong *signal_strength)
647 struct v4l2_tuner tuner;
649 DEBUG("trying to get signal strength");
650 GST_V4L2_CHECK_OPEN(v4l2element);
652 if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
653 gst_element_error(GST_ELEMENT(v4l2element),
654 "Failed to get signal strength for device %s: %s",
655 v4l2element->device, g_strerror(errno));
659 *signal_strength = tuner.signal;
665 /******************************************************
666 * gst_v4l2_has_audio():
667 * Check whether the device has audio capabilities
668 * return value: TRUE if it has a tuner, else FALSE
669 ******************************************************/
672 gst_v4l2_has_audio (GstV4l2Element *v4l2element)
675 struct v4l2_input *input;
677 DEBUG("detecting whether device has audio");
678 GST_V4L2_CHECK_OPEN(v4l2element);
680 if (!gst_v4l2_get_input(v4l2element, &input_num))
683 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
685 return (input->audioset != 0);
689 /******************************************************
690 * gst_v4l2_control_name_to_num():
691 * convert name to num (-1 if nothing)
692 ******************************************************/
695 gst_v4l2_control_name_to_num (GstV4l2Element *v4l2element,
700 for (item = v4l2element->controls; item != NULL; item = item->next) {
701 struct v4l2_queryctrl *ctrl = item->data;
702 if (!strcmp(ctrl->name, name))
710 /******************************************************
711 * gst_v4l2_get_attribute():
712 * try to get the value of one specific attribute
713 * return value: TRUE on success, FALSE on error
714 ******************************************************/
717 gst_v4l2_get_attribute (GstElement *element,
721 struct v4l2_control control;
722 GstV4l2Element *v4l2element;
723 gint attribute_num = -1;
725 g_return_val_if_fail(element != NULL && name != NULL && value != NULL, FALSE);
726 g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), FALSE);
727 v4l2element = GST_V4L2ELEMENT(element);
729 DEBUG("getting value of attribute %d", attribute_num);
730 GST_V4L2_CHECK_OPEN(v4l2element);
732 attribute_num = gst_v4l2_control_name_to_num(v4l2element, name);
734 if (attribute_num < 0) {
735 gst_element_error(GST_ELEMENT(v4l2element),
736 "Invalid control %s", name);
740 control.id = attribute_num;
742 if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
743 gst_element_error(GST_ELEMENT(v4l2element),
744 "Failed to get value for control %s (%d) on device %s: %s",
745 name, attribute_num, v4l2element->device, g_strerror(errno));
749 *value = control.value;
755 /******************************************************
756 * gst_v4l2_set_attribute():
757 * try to set the value of one specific attribute
758 * return value: TRUE on success, FALSE on error
759 ******************************************************/
762 gst_v4l2_set_attribute (GstElement *element,
766 struct v4l2_control control;
767 GstV4l2Element *v4l2element;
768 gint attribute_num = -1;
770 g_return_val_if_fail(element != NULL && name != NULL, FALSE);
771 g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), FALSE);
772 v4l2element = GST_V4L2ELEMENT(element);
774 DEBUG("setting value of attribute %d to %d", attribute_num, value);
775 GST_V4L2_CHECK_OPEN(v4l2element);
777 attribute_num = gst_v4l2_control_name_to_num(v4l2element, name);
779 if (attribute_num < 0) {
780 gst_element_error(GST_ELEMENT(v4l2element),
781 "Invalid control %s", name);
785 control.id = attribute_num;
786 control.value = value;
788 if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
789 gst_element_error(GST_ELEMENT(v4l2element),
790 "Failed to set value %d for control %s (%d) on device %s: %s",
791 value, name, attribute_num, v4l2element->device, g_strerror(errno));