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"
33 #include "gstv4l2tuner.h"
34 #include "gstv4l2xoverlay.h"
35 #include "gstv4l2colorbalance.h"
37 #include "gstv4l2src.h"
39 #define DEBUG(format, args...) \
41 GST_ELEMENT(v4l2element), \
42 "V4L2: " format, ##args)
45 /******************************************************
46 * gst_v4l2_get_capabilities():
47 * get the device's capturing capabilities
48 * return value: TRUE on success, FALSE on error
49 ******************************************************/
52 gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
54 DEBUG("getting capabilities");
55 GST_V4L2_CHECK_OPEN(v4l2element);
57 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
58 gst_element_error(GST_ELEMENT(v4l2element),
59 "Error getting %s capabilities: %s",
60 v4l2element->device, g_strerror(errno));
68 /******************************************************
69 * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
70 * fill/empty the lists of enumerations
71 * return value: TRUE on success, FALSE on error
72 ******************************************************/
75 gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
79 gst_element_get_pad_list (GST_ELEMENT (v4l2element));
80 GstPadDirection dir = GST_PAD_UNKNOWN;
82 DEBUG("getting enumerations");
83 GST_V4L2_CHECK_OPEN(v4l2element);
85 /* sinks have outputs, all others have inputs */
86 if (pads && g_list_length ((GList *) pads) == 1)
87 dir = GST_PAD_DIRECTION (GST_PAD (pads->data));
89 if (dir != GST_PAD_SINK) {
90 /* and now, the inputs */
92 struct v4l2_input input;
93 GstV4l2TunerChannel *v4l2channel;
94 GstTunerChannel *channel;
97 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT,
100 break; /* end of enumeration */
102 gst_element_error(GST_ELEMENT(v4l2element),
103 "Failed to get no. %d in input enumeration for %s: %s",
104 n, v4l2element->device,
111 g_object_new(GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
112 channel = GST_TUNER_CHANNEL(v4l2channel);
113 channel->label = g_strdup(input.name);
114 channel->flags = GST_TUNER_CHANNEL_INPUT;
115 v4l2channel->index = n;
116 if (input.type == V4L2_INPUT_TYPE_TUNER) {
117 struct v4l2_tuner vtun;
119 v4l2channel->tuner = input.tuner;
120 channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
122 vtun.index = input.tuner;
123 if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER,
125 gst_element_error(GST_ELEMENT(v4l2element),
126 "Failed to get tuner %d settings on %s: %s",
130 g_object_unref(G_OBJECT(channel));
133 channel->min_frequency = vtun.rangelow;
134 channel->max_frequency = vtun.rangehigh;
135 channel->min_signal = 0;
136 channel->max_signal = 0xffff;
138 if (input.audioset) {
139 /* we take the first. We don't care for
140 * the others for now */
141 while (!(input.audioset &
142 (1<<v4l2channel->audio)))
143 v4l2channel->audio++;
144 channel->flags |= GST_TUNER_CHANNEL_AUDIO;
147 v4l2element->channels =
148 g_list_append(v4l2element->channels,
154 struct v4l2_output output;
155 GstV4l2TunerChannel *v4l2channel;
156 GstTunerChannel *channel;
159 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT,
162 break; /* end of enumeration */
164 gst_element_error(GST_ELEMENT(v4l2element),
165 "Failed to get no. %d in output enumeration for %s: %s",
166 n, v4l2element->device,
172 v4l2channel = g_object_new(GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
173 channel = GST_TUNER_CHANNEL(v4l2channel);
174 channel->label = g_strdup(output.name);
175 channel->flags = GST_TUNER_CHANNEL_OUTPUT;
176 v4l2channel->index = n;
177 if (output.audioset) {
178 /* we take the first. We don't care for
179 * the others for now */
180 while (!(output.audioset &
181 (1<<v4l2channel->audio)))
182 v4l2channel->audio++;
183 channel->flags |= GST_TUNER_CHANNEL_AUDIO;
186 v4l2element->channels =
187 g_list_append(v4l2element->channels,
194 struct v4l2_standard standard;
195 GstV4l2TunerNorm *v4l2norm;
199 if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
201 break; /* end of enumeration */
203 gst_element_error(GST_ELEMENT(v4l2element),
204 "Failed to get no. %d in norm enumeration for %s: %s",
205 n, v4l2element->device, g_strerror(errno));
210 v4l2norm = g_object_new(GST_TYPE_V4L2_TUNER_NORM, NULL);
211 norm = GST_TUNER_NORM (v4l2norm);
212 norm->label = g_strdup(standard.name);
213 norm->fps = (gfloat) standard.frameperiod.denominator /
214 standard.frameperiod.numerator;
215 v4l2norm->index = standard.id;
217 v4l2element->norms = g_list_append(v4l2element->norms,
221 /* and lastly, controls+menus (if appropriate) */
222 for (n=V4L2_CID_BASE;;n++) {
223 struct v4l2_queryctrl control;
224 GstV4l2ColorBalanceChannel *v4l2channel;
225 GstColorBalanceChannel *channel;
228 if (n == V4L2_CID_LASTP1)
229 n = V4L2_CID_PRIVATE_BASE;
232 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
233 if (errno == EINVAL) {
234 if (n < V4L2_CID_PRIVATE_BASE)
239 gst_element_error(GST_ELEMENT(v4l2element),
240 "Failed to get no. %d in control enumeration for %s: %s",
241 n, v4l2element->device, g_strerror(errno));
245 if (control.flags & V4L2_CTRL_FLAG_DISABLED)
249 case V4L2_CID_BRIGHTNESS:
250 case V4L2_CID_CONTRAST:
251 case V4L2_CID_SATURATION:
253 case V4L2_CID_BLACK_LEVEL:
254 case V4L2_CID_AUTO_WHITE_BALANCE:
255 case V4L2_CID_DO_WHITE_BALANCE:
256 case V4L2_CID_RED_BALANCE:
257 case V4L2_CID_BLUE_BALANCE:
259 case V4L2_CID_EXPOSURE:
260 case V4L2_CID_AUTOGAIN:
262 /* we only handle these for now */
265 DEBUG("ControlID %s (%d) unhandled, FIXME",
273 v4l2channel = g_object_new(GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL,
275 channel = GST_COLOR_BALANCE_CHANNEL(v4l2channel);
276 channel->label = g_strdup(control.name);
277 v4l2channel->index = n;
280 if (control.type == V4L2_CTRL_TYPE_MENU) {
281 struct v4l2_querymenu menu, *mptr;
286 if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
288 break; /* end of enumeration */
290 gst_element_error(GST_ELEMENT(v4l2element),
291 "Failed to get no. %d in menu %d enumeration for %s: %s",
292 i, n, v4l2element->device, g_strerror(errno));
296 mptr = g_malloc(sizeof(menu));
297 memcpy(mptr, &menu, sizeof(menu));
298 menus = g_list_append(menus, mptr);
301 v4l2element->menus = g_list_append(v4l2element->menus, menus);
304 switch (control.type) {
305 case V4L2_CTRL_TYPE_INTEGER:
306 channel->min_value = control.minimum;
307 channel->max_value = control.maximum;
309 case V4L2_CTRL_TYPE_BOOLEAN:
310 channel->min_value = FALSE;
311 channel->max_value = TRUE;
315 channel->max_value = 0;
319 v4l2element->colors = g_list_append(v4l2element->colors,
328 gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
330 DEBUG("deleting enumerations");
332 g_list_foreach (v4l2element->channels, (GFunc) g_object_unref, NULL);
333 g_list_free (v4l2element->channels);
334 v4l2element->channels = NULL;
336 g_list_foreach (v4l2element->norms, (GFunc) g_object_unref, NULL);
337 g_list_free (v4l2element->norms);
338 v4l2element->norms = NULL;
340 g_list_foreach (v4l2element->colors, (GFunc) g_object_unref, NULL);
341 g_list_free (v4l2element->colors);
342 v4l2element->colors = NULL;
346 /******************************************************
348 * open the video device (v4l2element->device)
349 * return value: TRUE on success, FALSE on error
350 ******************************************************/
353 gst_v4l2_open (GstV4l2Element *v4l2element)
355 DEBUG("Trying to open device %s", v4l2element->device);
356 GST_V4L2_CHECK_NOT_OPEN(v4l2element);
357 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
359 /* be sure we have a device */
360 if (!v4l2element->device)
361 v4l2element->device = g_strdup("/dev/video");
363 /* open the device */
364 v4l2element->video_fd = open(v4l2element->device, O_RDWR);
365 if (!GST_V4L2_IS_OPEN(v4l2element)) {
366 gst_element_error(GST_ELEMENT(v4l2element),
367 "Failed to open device %s: %s",
368 v4l2element->device, g_strerror(errno));
372 /* get capabilities */
373 if (!gst_v4l2_get_capabilities(v4l2element)) {
377 /* do we need to be a capture device? */
378 if (GST_IS_V4L2SRC(v4l2element) &&
379 !(v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
380 gst_element_error(GST_ELEMENT(v4l2element),
381 "Not a capture device (0x%x)",
382 v4l2element->vcap.capabilities);
386 /* create enumerations */
387 if (!gst_v4l2_fill_lists(v4l2element))
390 gst_info("Opened device '%s' (%s) successfully\n",
391 v4l2element->vcap.card, v4l2element->device);
396 if (GST_V4L2_IS_OPEN(v4l2element)) {
398 close(v4l2element->video_fd);
399 v4l2element->video_fd = -1;
402 gst_v4l2_empty_lists(v4l2element);
408 /******************************************************
410 * close the video device (v4l2element->video_fd)
411 * return value: TRUE on success, FALSE on error
412 ******************************************************/
415 gst_v4l2_close (GstV4l2Element *v4l2element)
417 DEBUG("Trying to close %s", v4l2element->device);
418 GST_V4L2_CHECK_OPEN(v4l2element);
419 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
422 close(v4l2element->video_fd);
423 v4l2element->video_fd = -1;
426 gst_v4l2_empty_lists(v4l2element);
432 /******************************************************
433 * gst_v4l2_get_norm()
434 * Get the norm of the current device
435 * return value: TRUE on success, FALSE on error
436 ******************************************************/
439 gst_v4l2_get_norm (GstV4l2Element *v4l2element,
442 DEBUG("getting norm");
443 GST_V4L2_CHECK_OPEN(v4l2element);
445 if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, norm) < 0) {
446 gst_element_error(GST_ELEMENT(v4l2element),
447 "Failed to get the current norm for device %s: %s",
448 v4l2element->device, g_strerror(errno));
456 /******************************************************
457 * gst_v4l2_set_norm()
458 * Set the norm of the current device
459 * return value: TRUE on success, FALSE on error
460 ******************************************************/
463 gst_v4l2_set_norm (GstV4l2Element *v4l2element,
466 DEBUG("trying to set norm to %llx", norm);
467 GST_V4L2_CHECK_OPEN(v4l2element);
468 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
470 if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) {
471 gst_element_error(GST_ELEMENT(v4l2element),
472 "Failed to set norm 0x%llx for device %s: %s",
473 norm, v4l2element->device, g_strerror(errno));
481 /******************************************************
482 * gst_v4l2_get_input()
483 * Get the input of the current device
484 * return value: TRUE on success, FALSE on error
485 ******************************************************/
488 gst_v4l2_get_input (GstV4l2Element *v4l2element,
493 DEBUG("trying to get input");
494 GST_V4L2_CHECK_OPEN(v4l2element);
496 if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
497 gst_element_error(GST_ELEMENT(v4l2element),
498 "Failed to get current input on device %s: %s",
499 v4l2element->device, g_strerror(errno));
509 /******************************************************
510 * gst_v4l2_set_input()
511 * Set the input of the current device
512 * return value: TRUE on success, FALSE on error
513 ******************************************************/
516 gst_v4l2_set_input (GstV4l2Element *v4l2element,
519 DEBUG("trying to set input to %d", input);
520 GST_V4L2_CHECK_OPEN(v4l2element);
521 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
523 if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
524 gst_element_error(GST_ELEMENT(v4l2element),
525 "Failed to set input %d on device %s: %s",
526 input, v4l2element->device, g_strerror(errno));
534 /******************************************************
535 * gst_v4l2_get_output()
536 * Get the output of the current device
537 * return value: TRUE on success, FALSE on error
538 ******************************************************/
541 gst_v4l2_get_output (GstV4l2Element *v4l2element,
546 DEBUG("trying to get output");
547 GST_V4L2_CHECK_OPEN(v4l2element);
549 if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
550 gst_element_error(GST_ELEMENT(v4l2element),
551 "Failed to get current output on device %s: %s",
552 v4l2element->device, g_strerror(errno));
562 /******************************************************
563 * gst_v4l2_set_output()
564 * Set the output of the current device
565 * return value: TRUE on success, FALSE on error
566 ******************************************************/
569 gst_v4l2_set_output (GstV4l2Element *v4l2element,
572 DEBUG("trying to set output to %d", output);
573 GST_V4L2_CHECK_OPEN(v4l2element);
574 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
576 if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
577 gst_element_error(GST_ELEMENT(v4l2element),
578 "Failed to set output %d on device %s: %s",
579 output, v4l2element->device, g_strerror(errno));
587 /******************************************************
588 * gst_v4l2_get_frequency():
589 * get the current frequency
590 * return value: TRUE on success, FALSE on error
591 ******************************************************/
594 gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
598 struct v4l2_frequency freq;
600 DEBUG("getting current tuner frequency");
601 GST_V4L2_CHECK_OPEN(v4l2element);
603 freq.tuner = tunernum;
604 if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
605 gst_element_error(GST_ELEMENT(v4l2element),
606 "Failed to get current tuner frequency for device %s: %s",
607 v4l2element->device, g_strerror(errno));
611 *frequency = freq.frequency;
617 /******************************************************
618 * gst_v4l2_set_frequency():
620 * return value: TRUE on success, FALSE on error
621 ******************************************************/
624 gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
628 struct v4l2_frequency freq;
630 DEBUG("setting current tuner frequency to %lu", frequency);
631 GST_V4L2_CHECK_OPEN(v4l2element);
632 GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
634 freq.tuner = tunernum;
635 /* fill in type - ignore error */
636 ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq);
637 freq.frequency = frequency;
639 if (ioctl(v4l2element->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) {
640 gst_element_error(GST_ELEMENT(v4l2element),
641 "Failed to set tuner frequency to %lu for device %s: %s",
642 frequency, v4l2element->device, g_strerror(errno));
650 /******************************************************
651 * gst_v4l2_signal_strength():
652 * get the strength of the signal on the current input
653 * return value: TRUE on success, FALSE on error
654 ******************************************************/
657 gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
659 gulong *signal_strength)
661 struct v4l2_tuner tuner;
663 DEBUG("trying to get signal strength");
664 GST_V4L2_CHECK_OPEN(v4l2element);
666 tuner.index = tunernum;
667 if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
668 gst_element_error(GST_ELEMENT(v4l2element),
669 "Failed to get signal strength for device %s: %s",
670 v4l2element->device, g_strerror(errno));
674 *signal_strength = tuner.signal;
680 /******************************************************
681 * gst_v4l2_get_attribute():
682 * try to get the value of one specific attribute
683 * return value: TRUE on success, FALSE on error
684 ******************************************************/
687 gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
691 struct v4l2_control control;
693 GST_V4L2_CHECK_OPEN(v4l2element);
695 DEBUG("getting value of attribute %d", attribute_num);
697 control.id = attribute_num;
699 if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
700 gst_element_error(GST_ELEMENT(v4l2element),
701 "Failed to get value for control %d on device %s: %s",
702 attribute_num, v4l2element->device, g_strerror(errno));
706 *value = control.value;
712 /******************************************************
713 * gst_v4l2_set_attribute():
714 * try to set the value of one specific attribute
715 * return value: TRUE on success, FALSE on error
716 ******************************************************/
719 gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
723 struct v4l2_control control;
725 GST_V4L2_CHECK_OPEN(v4l2element);
727 DEBUG("setting value of attribute %d to %d", attribute_num, value);
729 control.id = attribute_num;
730 control.value = value;
732 if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
733 gst_element_error(GST_ELEMENT(v4l2element),
734 "Failed to set value %d for control %d on device %s: %s",
735 value, attribute_num, v4l2element->device, g_strerror(errno));