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 "\n", ##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, sys_errlist[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, sys_errlist[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, sys_errlist[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, sys_errlist[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, sys_errlist[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, sys_errlist[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, sys_errlist[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, sys_errlist[errno]);
268 /* get capabilities */
269 if (!gst_v4l2_get_capabilities(v4l2element)) {
273 /* and get the video window */
274 if (GST_V4L2_IS_OVERLAY(v4l2element)) {
275 if (ioctl(v4l2element->video_fd, VIDIOC_G_WIN, &(v4l2element->vwin)) < 0) {
276 gst_element_error(GST_ELEMENT(v4l2element),
277 "Failed to get video window properties of %s: %s",
278 v4l2element->device, sys_errlist[errno]);
283 /* create enumerations */
284 if (!gst_v4l2_fill_lists(v4l2element))
287 gst_info("Opened device '%s' (%s) successfully\n",
288 v4l2element->vcap.name, v4l2element->device);
293 if (GST_V4L2_IS_OPEN(v4l2element)) {
295 close(v4l2element->video_fd);
296 v4l2element->video_fd = -1;
299 gst_v4l2_empty_lists(v4l2element);
305 /******************************************************
307 * close the video device (v4l2element->video_fd)
308 * return value: TRUE on success, FALSE on error
309 ******************************************************/
312 gst_v4l2_close (GstV4l2Element *v4l2element)
314 DEBUG("Trying to close %s", v4l2element->device);
315 GST_V4L2_CHECK_OPEN(v4l2element);
316 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
319 close(v4l2element->video_fd);
320 v4l2element->video_fd = -1;
323 gst_v4l2_empty_lists(v4l2element);
329 /******************************************************
330 * gst_v4l2_get_norm()
331 * Get the norm of the current device
332 * return value: TRUE on success, FALSE on error
333 ******************************************************/
336 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
339 struct v4l2_standard standard;
342 DEBUG("getting norm");
343 GST_V4L2_CHECK_OPEN(v4l2element);
345 if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
346 gst_element_error(GST_ELEMENT(v4l2element),
347 "Failed to get the current norm for device %s: %s",
348 v4l2element->device, sys_errlist[errno]);
352 /* try to find out what norm number this actually is */
353 for (n=0;n<g_list_length(v4l2element->norms);n++) {
354 struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
355 if (!strcmp(stdptr->std.name, standard.name)) {
361 gst_element_error(GST_ELEMENT(v4l2element),
362 "Failed to find norm '%s' in our list of available norms for device %s",
363 standard.name, v4l2element->device);
368 /******************************************************
369 * gst_v4l2_set_norm()
370 * Set the norm of the current device
371 * return value: TRUE on success, FALSE on error
372 ******************************************************/
375 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
378 struct v4l2_enumstd *standard;
380 DEBUG("trying to set norm to %d", norm);
381 GST_V4L2_CHECK_OPEN(v4l2element);
382 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
384 if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
385 gst_element_error(GST_ELEMENT(v4l2element),
386 "Invalid norm number %d (%d-%d)",
387 norm, 0, g_list_length(v4l2element->norms));
391 standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
393 if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
394 gst_element_error(GST_ELEMENT(v4l2element),
395 "Failed to set norm '%s' (%d) for device %s: %s",
396 standard->std.name, norm, v4l2element->device, sys_errlist[errno]);
404 /******************************************************
405 * gst_v4l2_get_norm_names()
406 * Get the list of available norms
407 * return value: the list
408 ******************************************************/
411 gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
416 DEBUG("getting a list of norm names");
418 for (n=0;n<g_list_length(v4l2element->norms);n++) {
419 struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
420 names = g_list_append(names, g_strdup(standard->std.name));
427 /******************************************************
428 * gst_v4l2_get_input()
429 * Get the input of the current device
430 * return value: TRUE on success, FALSE on error
431 ******************************************************/
434 gst_v4l2_get_input (GstV4l2Element *v4l2element,
439 DEBUG("trying to get input");
440 GST_V4L2_CHECK_OPEN(v4l2element);
442 if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
443 gst_element_error(GST_ELEMENT(v4l2element),
444 "Failed to get current input on device %s: %s",
445 v4l2element->device, sys_errlist[errno]);
455 /******************************************************
456 * gst_v4l2_set_input()
457 * Set the input of the current device
458 * return value: TRUE on success, FALSE on error
459 ******************************************************/
462 gst_v4l2_set_input (GstV4l2Element *v4l2element,
465 DEBUG("trying to set input to %d", input);
466 GST_V4L2_CHECK_OPEN(v4l2element);
467 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
469 if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
470 gst_element_error(GST_ELEMENT(v4l2element),
471 "Invalid input number %d (%d-%d)",
472 input, 0, g_list_length(v4l2element->inputs));
476 if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
477 gst_element_error(GST_ELEMENT(v4l2element),
478 "Failed to set input %d on device %s: %s",
479 input, v4l2element->device, sys_errlist[errno]);
487 /******************************************************
488 * gst_v4l2_get_input_names()
489 * Get the list of available input channels
490 * return value: the list
491 ******************************************************/
494 gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
499 DEBUG("getting a list of input names");
501 for (n=0;n<g_list_length(v4l2element->inputs);n++) {
502 struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
503 names = g_list_append(names, g_strdup(input->name));
510 /******************************************************
511 * gst_v4l2_get_output()
512 * Get the output of the current device
513 * return value: TRUE on success, FALSE on error
514 ******************************************************/
517 gst_v4l2_get_output (GstV4l2Element *v4l2element,
522 DEBUG("trying to get output");
523 GST_V4L2_CHECK_OPEN(v4l2element);
525 if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
526 gst_element_error(GST_ELEMENT(v4l2element),
527 "Failed to get current output on device %s: %s",
528 v4l2element->device, sys_errlist[errno]);
538 /******************************************************
539 * gst_v4l2_set_output()
540 * Set the output of the current device
541 * return value: TRUE on success, FALSE on error
542 ******************************************************/
545 gst_v4l2_set_output (GstV4l2Element *v4l2element,
548 DEBUG("trying to set output to %d", output);
549 GST_V4L2_CHECK_OPEN(v4l2element);
550 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
552 if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
553 gst_element_error(GST_ELEMENT(v4l2element),
554 "Invalid output number %d (%d-%d)",
555 output, 0, g_list_length(v4l2element->outputs));
559 if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
560 gst_element_error(GST_ELEMENT(v4l2element),
561 "Failed to set output %d on device %s: %s",
562 output, v4l2element->device, sys_errlist[errno]);
570 /******************************************************
571 * gst_v4l2_get_output_names()
572 * Get the list of available output channels
573 * return value: the list, or NULL on error
574 ******************************************************/
577 gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
582 DEBUG("getting a list of output names");
584 for (n=0;n<g_list_length(v4l2element->outputs);n++) {
585 struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
586 names = g_list_append(names, g_strdup(output->name));
593 /******************************************************
594 * gst_v4l_has_tuner():
595 * Check whether the device has a tuner
596 * return value: TRUE if it has a tuner, else FALSE
597 ******************************************************/
600 gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
603 struct v4l2_input *input;
605 DEBUG("detecting whether device has a tuner");
606 GST_V4L2_CHECK_OPEN(v4l2element);
608 if (!gst_v4l2_get_input(v4l2element, &input_num))
611 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
613 return (input->type == V4L2_INPUT_TYPE_TUNER &&
614 v4l2element->vcap.flags & V4L2_FLAG_TUNER);
618 /******************************************************
619 * gst_v4l_get_frequency():
620 * get the current frequency
621 * return value: TRUE on success, FALSE on error
622 ******************************************************/
625 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
630 DEBUG("getting current tuner frequency");
631 GST_V4L2_CHECK_OPEN(v4l2element);
633 if (!gst_v4l2_has_tuner(v4l2element))
636 if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
637 gst_element_error(GST_ELEMENT(v4l2element),
638 "Failed to get current tuner frequency for device %s: %s",
639 v4l2element->device, sys_errlist[errno]);
649 /******************************************************
650 * gst_v4l_set_frequency():
652 * return value: TRUE on success, FALSE on error
653 ******************************************************/
656 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
661 DEBUG("setting current tuner frequency to %lu", frequency);
662 GST_V4L2_CHECK_OPEN(v4l2element);
663 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
665 if (!gst_v4l2_has_tuner(v4l2element))
668 if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
669 gst_element_error(GST_ELEMENT(v4l2element),
670 "Failed to set tuner frequency to %lu for device %s: %s",
671 frequency, v4l2element->device, sys_errlist[errno]);
679 /******************************************************
680 * gst_v4l_signal_strength():
681 * get the strength of the signal on the current input
682 * return value: TRUE on success, FALSE on error
683 ******************************************************/
686 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
687 gulong *signal_strength)
689 struct v4l2_tuner tuner;
691 DEBUG("trying to get signal strength");
692 GST_V4L2_CHECK_OPEN(v4l2element);
694 if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
695 gst_element_error(GST_ELEMENT(v4l2element),
696 "Failed to set signal strength for device %s: %s",
697 v4l2element->device, sys_errlist[errno]);
701 *signal_strength = tuner.signal;
707 /******************************************************
708 * gst_v4l_has_audio():
709 * Check whether the device has audio capabilities
710 * return value: TRUE if it has a tuner, else FALSE
711 ******************************************************/
714 gst_v4l2_has_audio (GstV4l2Element *v4l2element)
717 struct v4l2_input *input;
719 DEBUG("detecting whether device has audio");
720 GST_V4L2_CHECK_OPEN(v4l2element);
722 if (!gst_v4l2_get_input(v4l2element, &input_num))
725 input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
727 return (input->capability & V4L2_INPUT_CAP_AUDIO);
731 /******************************************************
732 * gst_v4l_get_attributes():
733 * get a list of attributes available on this device
734 * return value: the list
735 ******************************************************/
738 gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
743 DEBUG("getting a list of available attributes");
745 for (i=0;i<g_list_length(v4l2element->controls);i++) {
746 struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
747 GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
748 attribute->name = g_strdup(control->name);
749 attribute->index = i;
750 attribute->list_items = NULL;
751 switch (control->type) {
752 case V4L2_CTRL_TYPE_INTEGER:
753 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
755 case V4L2_CTRL_TYPE_BOOLEAN:
756 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
758 case V4L2_CTRL_TYPE_MENU: {
761 GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
762 for (n=0;n<g_list_length(menus);n++) {
763 struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
764 attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
766 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
768 case V4L2_CTRL_TYPE_BUTTON:
769 attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
772 switch (control->category) {
773 case V4L2_CTRL_CAT_VIDEO:
774 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
776 case V4L2_CTRL_CAT_AUDIO:
777 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
779 case V4L2_CTRL_CAT_EFFECT:
780 attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
783 gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
784 attribute->min = control->minimum;
785 attribute->max = control->maximum;
792 /******************************************************
793 * gst_v4l_get_attribute():
794 * try to get the value of one specific attribute
795 * return value: TRUE on success, FALSE on error
796 ******************************************************/
799 gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
803 struct v4l2_control control;
805 DEBUG("getting value of attribute %d", attribute_num);
806 GST_V4L2_CHECK_OPEN(v4l2element);
808 if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
809 gst_element_error(GST_ELEMENT(v4l2element),
810 "Invalid control ID %d", attribute_num);
814 control.id = attribute_num;
816 if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
817 gst_element_error(GST_ELEMENT(v4l2element),
818 "Failed to get value for control %d on device %s: %s",
819 attribute_num, v4l2element->device, sys_errlist[errno]);
823 *value = control.value;
829 /******************************************************
830 * gst_v4l_set_attribute():
831 * try to set the value of one specific attribute
832 * return value: TRUE on success, FALSE on error
833 ******************************************************/
836 gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
840 struct v4l2_control control;
842 DEBUG("setting value of attribute %d to %d", attribute_num, value);
843 GST_V4L2_CHECK_OPEN(v4l2element);
845 if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
846 gst_element_error(GST_ELEMENT(v4l2element),
847 "Invalid control ID %d", attribute_num);
851 control.id = attribute_num;
852 control.value = value;
854 if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
855 gst_element_error(GST_ELEMENT(v4l2element),
856 "Failed to set value %d for control %d on device %s: %s",
857 value, attribute_num, v4l2element->device, sys_errlist[errno]);