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>
31 #include "v4l2_calls.h"
33 #define DEBUG(format, args...) \
34 GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
35 GST_ELEMENT(v4l2element), \
36 "V4L2: " format, ##args)
39 /******************************************************
40 * gst_v4l2_get_capabilities():
41 * get the device's capturing capabilities
42 * return value: TRUE on success, FALSE on error
43 ******************************************************/
46 gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
48 DEBUG("getting capabilities");
49 GST_V4L2_CHECK_OPEN(v4l2element);
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, strerror(errno));
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 ******************************************************/
69 gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
73 DEBUG("getting enumerations");
74 GST_V4L2_CHECK_OPEN(v4l2element);
76 /* create enumeration lists - let's start with format enumeration */
78 struct v4l2_fmtdesc format, *fmtptr;
80 if (ioctl(v4l2element->video_fd, VIDIOC_ENUM_PIXFMT, &format) < 0) {
82 break; /* end of enumeration */
84 gst_element_error(GST_ELEMENT(v4l2element),
85 "Failed to get no. %d in pixelformat enumeration for %s: %s",
86 n, v4l2element->device, strerror(errno));
90 fmtptr = g_malloc(sizeof(format));
91 memcpy(fmtptr, &format, sizeof(format));
92 v4l2element->formats = g_list_append(v4l2element->formats, fmtptr);
95 /* and now, the inputs */
97 struct v4l2_input input, *inpptr;
99 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
101 break; /* end of enumeration */
103 gst_element_error(GST_ELEMENT(v4l2element),
104 "Failed to get no. %d in input enumeration for %s: %s",
105 n, v4l2element->device, strerror(errno));
109 inpptr = g_malloc(sizeof(input));
110 memcpy(inpptr, &input, sizeof(input));
111 v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
116 struct v4l2_output output, *outptr;
118 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
120 break; /* end of enumeration */
122 gst_element_error(GST_ELEMENT(v4l2element),
123 "Failed to get no. %d in output enumeration for %s: %s",
124 n, v4l2element->device, strerror(errno));
128 outptr = g_malloc(sizeof(output));
129 memcpy(outptr, &output, sizeof(output));
130 v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
135 struct v4l2_enumstd standard, *stdptr;
137 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
139 break; /* end of enumeration */
141 gst_element_error(GST_ELEMENT(v4l2element),
142 "Failed to get no. %d in norm enumeration for %s: %s",
143 n, v4l2element->device, strerror(errno));
147 stdptr = g_malloc(sizeof(standard));
148 memcpy(stdptr, &standard, sizeof(standard));
149 v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
152 /* and lastly, controls+menus (if appropriate) */
154 struct v4l2_queryctrl control, *ctrlptr;
157 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
159 break; /* end of enumeration */
161 gst_element_error(GST_ELEMENT(v4l2element),
162 "Failed to get no. %d in control enumeration for %s: %s",
163 n, v4l2element->device, strerror(errno));
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;
176 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
178 break; /* end of enumeration */
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, strerror(errno));
186 mptr = g_malloc(sizeof(menu));
187 memcpy(mptr, &menu, sizeof(menu));
188 menus = g_list_append(menus, mptr);
191 v4l2element->menus = g_list_append(v4l2element->menus, menus);
199 gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
201 DEBUG("deleting enumerations");
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);
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);
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);
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);
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);
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);
242 /******************************************************
244 * open the video device (v4l2element->device)
245 * return value: TRUE on success, FALSE on error
246 ******************************************************/
249 gst_v4l2_open (GstV4l2Element *v4l2element)
251 DEBUG("Trying to open device %s", v4l2element->device);
252 GST_V4L2_CHECK_NOT_OPEN(v4l2element);
253 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
255 /* be sure we have a device */
256 if (!v4l2element->device)
257 v4l2element->device = g_strdup("/dev/video");
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, strerror(errno));
268 /* get capabilities */
269 if (!gst_v4l2_get_capabilities(v4l2element)) {
273 /* create enumerations */
274 if (!gst_v4l2_fill_lists(v4l2element))
277 gst_info("Opened device '%s' (%s) successfully\n",
278 v4l2element->vcap.name, v4l2element->device);
283 if (GST_V4L2_IS_OPEN(v4l2element)) {
285 close(v4l2element->video_fd);
286 v4l2element->video_fd = -1;
289 gst_v4l2_empty_lists(v4l2element);
295 /******************************************************
297 * close the video device (v4l2element->video_fd)
298 * return value: TRUE on success, FALSE on error
299 ******************************************************/
302 gst_v4l2_close (GstV4l2Element *v4l2element)
304 DEBUG("Trying to close %s", v4l2element->device);
305 GST_V4L2_CHECK_OPEN(v4l2element);
306 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
309 close(v4l2element->video_fd);
310 v4l2element->video_fd = -1;
313 gst_v4l2_empty_lists(v4l2element);
319 /******************************************************
320 * gst_v4l2_get_norm()
321 * Get the norm of the current device
322 * return value: TRUE on success, FALSE on error
323 ******************************************************/
326 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
329 struct v4l2_standard standard;
332 DEBUG("getting norm");
333 GST_V4L2_CHECK_OPEN(v4l2element);
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, strerror(errno));
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)) {
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);
358 /******************************************************
359 * gst_v4l2_set_norm()
360 * Set the norm of the current device
361 * return value: TRUE on success, FALSE on error
362 ******************************************************/
365 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
368 struct v4l2_enumstd *standard;
370 DEBUG("trying to set norm to %d", norm);
371 GST_V4L2_CHECK_OPEN(v4l2element);
372 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
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));
381 standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
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, strerror(errno));
394 /******************************************************
395 * gst_v4l2_get_norm_names()
396 * Get the list of available norms
397 * return value: the list
398 ******************************************************/
401 gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
406 DEBUG("getting a list of norm names");
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));
417 /******************************************************
418 * gst_v4l2_get_input()
419 * Get the input of the current device
420 * return value: TRUE on success, FALSE on error
421 ******************************************************/
424 gst_v4l2_get_input (GstV4l2Element *v4l2element,
429 DEBUG("trying to get input");
430 GST_V4L2_CHECK_OPEN(v4l2element);
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, strerror(errno));
445 /******************************************************
446 * gst_v4l2_set_input()
447 * Set the input of the current device
448 * return value: TRUE on success, FALSE on error
449 ******************************************************/
452 gst_v4l2_set_input (GstV4l2Element *v4l2element,
455 DEBUG("trying to set input to %d", input);
456 GST_V4L2_CHECK_OPEN(v4l2element);
457 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
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));
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, strerror(errno));
477 /******************************************************
478 * gst_v4l2_get_input_names()
479 * Get the list of available input channels
480 * return value: the list
481 ******************************************************/
484 gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
489 DEBUG("getting a list of input names");
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));
500 /******************************************************
501 * gst_v4l2_get_output()
502 * Get the output of the current device
503 * return value: TRUE on success, FALSE on error
504 ******************************************************/
507 gst_v4l2_get_output (GstV4l2Element *v4l2element,
512 DEBUG("trying to get output");
513 GST_V4L2_CHECK_OPEN(v4l2element);
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, strerror(errno));
528 /******************************************************
529 * gst_v4l2_set_output()
530 * Set the output of the current device
531 * return value: TRUE on success, FALSE on error
532 ******************************************************/
535 gst_v4l2_set_output (GstV4l2Element *v4l2element,
538 DEBUG("trying to set output to %d", output);
539 GST_V4L2_CHECK_OPEN(v4l2element);
540 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
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));
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, strerror(errno));
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 ******************************************************/
567 gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
572 DEBUG("getting a list of output names");
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));
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 ******************************************************/
590 gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
593 struct v4l2_input *input;
595 DEBUG("detecting whether device has a tuner");
596 GST_V4L2_CHECK_OPEN(v4l2element);
598 if (!gst_v4l2_get_input(v4l2element, &input_num))
601 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
603 return (input->type == V4L2_INPUT_TYPE_TUNER &&
604 v4l2element->vcap.flags & V4L2_FLAG_TUNER);
608 /******************************************************
609 * gst_v4l_get_frequency():
610 * get the current frequency
611 * return value: TRUE on success, FALSE on error
612 ******************************************************/
615 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
620 DEBUG("getting current tuner frequency");
621 GST_V4L2_CHECK_OPEN(v4l2element);
623 if (!gst_v4l2_has_tuner(v4l2element))
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, strerror(errno));
639 /******************************************************
640 * gst_v4l_set_frequency():
642 * return value: TRUE on success, FALSE on error
643 ******************************************************/
646 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
651 DEBUG("setting current tuner frequency to %lu", frequency);
652 GST_V4L2_CHECK_OPEN(v4l2element);
653 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
655 if (!gst_v4l2_has_tuner(v4l2element))
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, strerror(errno));
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 ******************************************************/
676 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
677 gulong *signal_strength)
679 struct v4l2_tuner tuner;
681 DEBUG("trying to get signal strength");
682 GST_V4L2_CHECK_OPEN(v4l2element);
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, strerror(errno));
691 *signal_strength = tuner.signal;
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 ******************************************************/
704 gst_v4l2_has_audio (GstV4l2Element *v4l2element)
707 struct v4l2_input *input;
709 DEBUG("detecting whether device has audio");
710 GST_V4L2_CHECK_OPEN(v4l2element);
712 if (!gst_v4l2_get_input(v4l2element, &input_num))
715 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
717 return (input->capability & V4L2_INPUT_CAP_AUDIO);
721 /******************************************************
722 * gst_v4l_get_attributes():
723 * get a list of attributes available on this device
724 * return value: the list
725 ******************************************************/
728 gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
733 DEBUG("getting a list of available attributes");
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;
745 case V4L2_CTRL_TYPE_BOOLEAN:
746 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
748 case V4L2_CTRL_TYPE_MENU: {
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));
756 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
758 case V4L2_CTRL_TYPE_BUTTON:
759 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
762 switch (control->category) {
763 case V4L2_CTRL_CAT_VIDEO:
764 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
766 case V4L2_CTRL_CAT_AUDIO:
767 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
769 case V4L2_CTRL_CAT_EFFECT:
770 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
773 gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
774 attribute->min = control->minimum;
775 attribute->max = control->maximum;
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 ******************************************************/
789 gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
793 struct v4l2_control control;
795 DEBUG("getting value of attribute %d", attribute_num);
796 GST_V4L2_CHECK_OPEN(v4l2element);
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);
804 control.id = attribute_num;
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, strerror(errno));
813 *value = control.value;
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 ******************************************************/
826 gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
830 struct v4l2_control control;
832 DEBUG("setting value of attribute %d to %d", attribute_num, value);
833 GST_V4L2_CHECK_OPEN(v4l2element);
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);
841 control.id = attribute_num;
842 control.value = value;
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, strerror(errno));