3 * v4l_calls.c: generic V4L calls
5 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include <sys/types.h>
30 #include <sys/ioctl.h>
37 #include <gst/interfaces/tuner.h>
38 #include <gst/interfaces/colorbalance.h>
40 #include "v4l_calls.h"
41 #include "gstv4ltuner.h"
42 #include "gstv4lcolorbalance.h"
44 #include "gstv4lsrc.h"
45 /* #include "gstv4lmjpegsrc.h" */
46 /* #include "gstv4lmjpegsink.h" */
48 GST_DEBUG_CATEGORY_EXTERN (v4l_debug);
49 #define GST_CAT_DEFAULT v4l_debug
51 static const char *picture_name[] = {
59 G_GNUC_UNUSED static const char *audio_name[] = {
66 static const char *norm_name[] = {
73 /******************************************************
74 * gst_v4l_get_capabilities():
75 * get the device's capturing capabilities
76 * sets v4lelement->vcap and v4lelement->vwin
77 * return value: TRUE on success, FALSE on error
78 ******************************************************/
81 gst_v4l_get_capabilities (GstV4lElement * v4lelement)
83 GST_DEBUG_OBJECT (v4lelement, "getting capabilities");
84 GST_V4L_CHECK_OPEN (v4lelement);
86 if (ioctl (v4lelement->video_fd, VIDIOCGCAP, &(v4lelement->vcap)) < 0) {
87 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
88 ("error getting capabilities %s of from device %s",
89 g_strerror (errno), v4lelement->videodev));
93 if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(v4lelement->vwin)) < 0) {
94 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
95 ("error getting window properties %s of from device %s",
96 g_strerror (errno), v4lelement->videodev));
103 /******************************************************
104 * gst_v4l_set_window_properties():
105 * set the device's capturing parameters (vwin)
106 * return value: TRUE on success, FALSE on error
107 ******************************************************/
110 gst_v4l_set_window_properties (GstV4lElement * v4lelement)
112 struct video_window vwin;
114 GST_DEBUG_OBJECT (v4lelement, "setting window flags 0x%x to device %s",
115 v4lelement->vwin.flags, v4lelement->videodev);
116 GST_V4L_CHECK_OPEN (v4lelement);
118 if (ioctl (v4lelement->video_fd, VIDIOCSWIN, &(v4lelement->vwin)) < 0) {
119 GST_DEBUG_OBJECT (v4lelement,
120 "could not ioctl window properties 0x%x to device %s",
121 v4lelement->vwin.flags, v4lelement->videodev);
125 /* get it again to make sure we have it correctly */
126 if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(vwin)) < 0) {
127 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
128 ("error getting window properties %s of from device %s",
129 g_strerror (errno), v4lelement->videodev));
132 if (vwin.flags != v4lelement->vwin.flags) {
133 GST_DEBUG_OBJECT (v4lelement, "set 0x%x but got 0x%x back",
134 v4lelement->vwin.flags, vwin.flags);
141 /******************************************************
143 * open the video device (v4lelement->videodev)
144 * return value: TRUE on success, FALSE on error
145 ******************************************************/
148 gst_v4l_open (GstV4lElement * v4lelement)
152 GST_DEBUG_OBJECT (v4lelement, "opening device %s", v4lelement->videodev);
153 GST_V4L_CHECK_NOT_OPEN (v4lelement);
154 GST_V4L_CHECK_NOT_ACTIVE (v4lelement);
156 /* be sure we have a device */
157 if (!v4lelement->videodev) {
158 GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND,
159 (_("No device specified.")), (NULL));
163 /* open the device */
164 v4lelement->video_fd = open (v4lelement->videodev, O_RDWR);
165 if (!GST_V4L_IS_OPEN (v4lelement)) {
166 if (errno == ENODEV || errno == ENOENT) {
167 GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND,
168 (_("Device \"%s\" does not exist."), v4lelement->videodev), (NULL));
171 if (errno == EBUSY) {
172 GST_ELEMENT_ERROR (v4lelement, RESOURCE, BUSY,
173 (_("Device \"%s\" is already being used."), v4lelement->videodev),
177 GST_ELEMENT_ERROR (v4lelement, RESOURCE, OPEN_READ_WRITE,
178 (_("Could not open device \"%s\" for reading and writing."),
179 v4lelement->videodev), GST_ERROR_SYSTEM);
183 /* get capabilities */
184 if (!gst_v4l_get_capabilities (v4lelement)) {
185 close (v4lelement->video_fd);
186 v4lelement->video_fd = -1;
190 /* device type check */
191 if ((GST_IS_V4LSRC (v4lelement) &&
192 !(v4lelement->vcap.type & VID_TYPE_CAPTURE))) {
193 /* (GST_IS_V4LMJPEGSRC (v4lelement) && */
194 /* !(v4lelement->vcap.type & VID_TYPE_MJPEG_ENCODER)) || */
195 /* (GST_IS_V4LMJPEGSINK (v4lelement) && */
196 /* !(v4lelement->vcap.type & VID_TYPE_MJPEG_DECODER))) { */
197 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
198 ("Device opened, but wrong type (0x%x)", v4lelement->vcap.type));
199 close (v4lelement->video_fd);
200 v4lelement->video_fd = -1;
204 GST_INFO_OBJECT (v4lelement, "Opened device \'%s\' (\'%s\') successfully",
205 v4lelement->vcap.name, v4lelement->videodev);
207 /* norms + inputs, for the tuner interface */
208 for (num = 0; norm_name[num] != NULL; num++) {
209 GstV4lTunerNorm *v4lnorm = g_object_new (GST_TYPE_V4L_TUNER_NORM,
211 GstTunerNorm *norm = GST_TUNER_NORM (v4lnorm);
213 norm->label = g_strdup (norm_name[num]);
215 gst_value_set_fraction (&norm->framerate, 30000, 1001);
217 gst_value_set_fraction (&norm->framerate, 25, 1);
219 v4lnorm->index = num;
220 v4lelement->norms = g_list_append (v4lelement->norms, (gpointer) norm);
222 v4lelement->channels = gst_v4l_get_chan_names (v4lelement);
224 for (num = 0; picture_name[num] != NULL; num++) {
225 GstV4lColorBalanceChannel *v4lchannel =
226 g_object_new (GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, NULL);
227 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (v4lchannel);
229 channel->label = g_strdup (picture_name[num]);
230 channel->min_value = 0;
231 channel->max_value = 65535;
232 v4lchannel->index = num;
233 v4lelement->colors = g_list_append (v4lelement->colors, channel);
236 GST_DEBUG_OBJECT (v4lelement, "Setting default norm/input");
237 gst_v4l_set_chan_norm (v4lelement, 0, 0);
243 /******************************************************
245 * close the video device (v4lelement->video_fd)
246 * return value: TRUE on success, FALSE on error
247 ******************************************************/
250 gst_v4l_close (GstV4lElement * v4lelement)
252 GST_DEBUG_OBJECT (v4lelement, "closing device");
253 GST_V4L_CHECK_OPEN (v4lelement);
254 GST_V4L_CHECK_NOT_ACTIVE (v4lelement);
256 close (v4lelement->video_fd);
257 v4lelement->video_fd = -1;
259 g_list_foreach (v4lelement->channels, (GFunc) g_object_unref, NULL);
260 g_list_free (v4lelement->channels);
261 v4lelement->channels = NULL;
263 g_list_foreach (v4lelement->norms, (GFunc) g_object_unref, NULL);
264 g_list_free (v4lelement->norms);
265 v4lelement->norms = NULL;
267 g_list_foreach (v4lelement->colors, (GFunc) g_object_unref, NULL);
268 g_list_free (v4lelement->colors);
269 v4lelement->colors = NULL;
275 /******************************************************
276 * gst_v4l_get_num_chans()
277 * return value: the number of video input channels
278 ******************************************************/
281 gst_v4l_get_num_chans (GstV4lElement * v4lelement)
283 GST_DEBUG_OBJECT (v4lelement, "getting number of channels");
284 GST_V4L_CHECK_OPEN (v4lelement);
286 return v4lelement->vcap.channels;
290 /******************************************************
291 * gst_v4l_get_chan_names()
292 * return value: a GList containing the channel names
293 ******************************************************/
296 gst_v4l_get_chan_names (GstV4lElement * v4lelement)
298 struct video_channel vchan = { 0 };
302 GST_DEBUG_OBJECT (v4lelement, "getting channel names");
304 if (!GST_V4L_IS_OPEN (v4lelement))
307 for (i = 0; i < gst_v4l_get_num_chans (v4lelement); i++) {
308 GstV4lTunerChannel *v4lchannel;
309 GstTunerChannel *channel;
312 if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0) {
313 /* Skip this channel */
316 v4lchannel = g_object_new (GST_TYPE_V4L_TUNER_CHANNEL, NULL);
317 v4lchannel->index = i;
319 channel = GST_TUNER_CHANNEL (v4lchannel);
320 channel->label = g_strdup (vchan.name);
321 channel->flags = GST_TUNER_CHANNEL_INPUT;
322 if (vchan.flags & VIDEO_VC_TUNER) {
323 struct video_tuner vtun;
326 for (n = 0; n < vchan.tuners; n++) {
328 if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0)
329 continue; /* no more tuners */
330 if (strcmp (vtun.name, vchan.name) != 0) {
331 continue; /* not this one */
334 v4lchannel->tuner = n;
335 channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
336 channel->freq_multiplicator =
337 62.5 * ((vtun.flags & VIDEO_TUNER_LOW) ? 1 : 1000);
338 channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
339 channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
340 channel->min_signal = 0;
341 channel->max_signal = 0xffff;
346 if (vchan.flags & VIDEO_VC_AUDIO) {
347 struct video_audio vaud;
350 for (n = 0; n < v4lelement->vcap.audios; n++) {
352 if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vaud) < 0)
354 if (!strcmp (vaud.name, vchan.name)) {
355 v4lchannel->audio = n;
356 channel->flags |= GST_TUNER_CHANNEL_AUDIO;
361 list = g_list_prepend (list, (gpointer) channel);
364 return g_list_reverse (list);
368 /******************************************************
369 * gst_v4l_get_chan_norm():
370 * get the currently active video-channel and it's
371 * norm (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
372 * return value: TRUE on success, FALSE on error
373 ******************************************************/
376 gst_v4l_get_chan_norm (GstV4lElement * v4lelement, gint * channel, gint * norm)
378 GST_DEBUG_OBJECT (v4lelement, "getting current channel and norm");
379 GST_V4L_CHECK_OPEN (v4lelement);
382 *channel = v4lelement->vchan.channel;
384 *norm = v4lelement->vchan.norm;
390 /******************************************************
391 * gst_v4l_set_chan_norm():
392 * set a new active channel and it's norm
393 * (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
394 * return value: TRUE on success, FALSE on error
395 ******************************************************/
398 gst_v4l_set_chan_norm (GstV4lElement * v4lelement, gint channel, gint norm)
400 GST_DEBUG_OBJECT (v4lelement, "setting channel = %d, norm = %d (%s)",
401 channel, norm, norm_name[norm]);
402 GST_V4L_CHECK_OPEN (v4lelement);
403 //GST_V4L_CHECK_NOT_ACTIVE (v4lelement);
405 v4lelement->vchan.channel = channel;
406 v4lelement->vchan.norm = norm;
408 if (ioctl (v4lelement->video_fd, VIDIOCSCHAN, &(v4lelement->vchan)) < 0) {
409 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
410 ("Error setting the channel/norm settings: %s", g_strerror (errno)));
414 if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &(v4lelement->vchan)) < 0) {
415 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
416 ("Error getting the channel/norm settings: %s", g_strerror (errno)));
424 /******************************************************
425 * gst_v4l_get_signal():
426 * get the current signal
427 * return value: TRUE on success, FALSE on error
428 ******************************************************/
431 gst_v4l_get_signal (GstV4lElement * v4lelement, gint tunernum, guint * signal)
433 struct video_tuner tuner;
435 GST_DEBUG_OBJECT (v4lelement, "getting tuner signal");
436 GST_V4L_CHECK_OPEN (v4lelement);
438 tuner.tuner = tunernum;
439 if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &tuner) < 0) {
440 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
441 ("Error getting tuner signal: %s", g_strerror (errno)));
445 *signal = tuner.signal;
451 /******************************************************
452 * gst_v4l_get_frequency():
453 * get the current frequency
454 * return value: TRUE on success, FALSE on error
455 ******************************************************/
458 gst_v4l_get_frequency (GstV4lElement * v4lelement,
459 gint tunernum, gulong * frequency)
461 struct video_tuner vtun;
462 GstTunerChannel *channel;
464 GST_DEBUG_OBJECT (v4lelement, "getting tuner frequency");
465 GST_V4L_CHECK_OPEN (v4lelement);
467 channel = gst_tuner_get_channel (GST_TUNER (v4lelement));
469 /* check that this is the current input */
470 vtun.tuner = tunernum;
471 if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0)
473 if (strcmp (vtun.name, v4lelement->vchan.name))
476 if (ioctl (v4lelement->video_fd, VIDIOCGFREQ, frequency) < 0) {
477 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
478 ("Error getting tuner frequency: %s", g_strerror (errno)));
482 *frequency = *frequency * channel->freq_multiplicator;
488 /******************************************************
489 * gst_v4l_set_frequency():
491 * return value: TRUE on success, FALSE on error
492 ******************************************************/
495 gst_v4l_set_frequency (GstV4lElement * v4lelement,
496 gint tunernum, gulong frequency)
498 struct video_tuner vtun;
499 GstTunerChannel *channel;
501 GST_DEBUG_OBJECT (v4lelement, "setting tuner frequency to %lu", frequency);
502 GST_V4L_CHECK_OPEN (v4lelement);
504 channel = gst_tuner_get_channel (GST_TUNER (v4lelement));
506 /* check that this is the current input */
507 vtun.tuner = tunernum;
508 if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0)
510 if (strcmp (vtun.name, v4lelement->vchan.name))
513 frequency = frequency / channel->freq_multiplicator;
515 if (ioctl (v4lelement->video_fd, VIDIOCSFREQ, &frequency) < 0) {
516 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
517 ("Error setting tuner frequency: %s", g_strerror (errno)));
525 /******************************************************
526 * gst_v4l_get_picture():
527 * get a picture value
528 * return value: TRUE on success, FALSE on error
529 ******************************************************/
532 gst_v4l_get_picture (GstV4lElement * v4lelement,
533 GstV4lPictureType type, gint * value)
535 struct video_picture vpic;
537 GST_DEBUG_OBJECT (v4lelement, "getting picture property type %d (%s)", type,
539 GST_V4L_CHECK_OPEN (v4lelement);
541 if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) {
542 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
543 ("Error getting picture parameters: %s", g_strerror (errno)));
548 case V4L_PICTURE_HUE:
551 case V4L_PICTURE_BRIGHTNESS:
552 *value = vpic.brightness;
554 case V4L_PICTURE_CONTRAST:
555 *value = vpic.contrast;
557 case V4L_PICTURE_SATURATION:
558 *value = vpic.colour;
561 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
562 ("Error getting picture parameters: unknown type %d", type));
570 /******************************************************
571 * gst_v4l_set_picture():
572 * set a picture value
573 * return value: TRUE on success, FALSE on error
574 ******************************************************/
577 gst_v4l_set_picture (GstV4lElement * v4lelement,
578 GstV4lPictureType type, gint value)
580 struct video_picture vpic;
582 GST_DEBUG_OBJECT (v4lelement, "setting picture type %d (%s) to value %d",
583 type, picture_name[type], value);
584 GST_V4L_CHECK_OPEN (v4lelement);
586 if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) {
587 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
588 ("Error getting picture parameters: %s", g_strerror (errno)));
593 case V4L_PICTURE_HUE:
596 case V4L_PICTURE_BRIGHTNESS:
597 vpic.brightness = value;
599 case V4L_PICTURE_CONTRAST:
600 vpic.contrast = value;
602 case V4L_PICTURE_SATURATION:
606 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
607 ("Error setting picture parameters: unknown type %d", type));
611 if (ioctl (v4lelement->video_fd, VIDIOCSPICT, &vpic) < 0) {
612 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
613 ("Error setting picture parameters: %s", g_strerror (errno)));
621 /******************************************************
622 * gst_v4l_get_audio():
623 * get some audio value
624 * return value: TRUE on success, FALSE on error
625 ******************************************************/
628 gst_v4l_get_audio (GstV4lElement * v4lelement,
629 gint audionum, GstV4lAudioType type, gint * value)
631 struct video_audio vau;
633 GST_DEBUG_OBJECT (v4lelement, "getting audio parameter type %d (%s)", type,
635 GST_V4L_CHECK_OPEN (v4lelement);
637 vau.audio = audionum;
638 if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) {
639 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
640 ("Error getting audio parameters: %s", g_strerror (errno)));
646 *value = (vau.flags & VIDEO_AUDIO_MUTE);
648 case V4L_AUDIO_VOLUME:
655 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
656 ("Error getting audio parameters: unknown type %d", type));
664 /******************************************************
665 * gst_v4l_set_audio():
666 * set some audio value
667 * return value: TRUE on success, FALSE on error
668 ******************************************************/
671 gst_v4l_set_audio (GstV4lElement * v4lelement,
672 gint audionum, GstV4lAudioType type, gint value)
674 struct video_audio vau;
676 GST_DEBUG_OBJECT (v4lelement,
677 "setting audio parameter type %d (%s) to value %d", type,
678 audio_name[type], value);
679 GST_V4L_CHECK_OPEN (v4lelement);
681 vau.audio = audionum;
682 if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) {
683 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
684 ("Error getting audio parameters: %s", g_strerror (errno)));
690 if (!(vau.flags & VIDEO_AUDIO_MUTABLE)) {
691 GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL),
692 ("Error setting audio mute: (un)setting mute is not supported"));
696 vau.flags |= VIDEO_AUDIO_MUTE;
698 vau.flags &= ~VIDEO_AUDIO_MUTE;
700 case V4L_AUDIO_VOLUME:
701 if (!(vau.flags & VIDEO_AUDIO_VOLUME)) {
702 GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL),
703 ("Error setting audio volume: setting volume is not supported"));
712 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
713 ("Error setting audio parameters: unknown type %d", type));
717 if (ioctl (v4lelement->video_fd, VIDIOCSAUDIO, &vau) < 0) {
718 GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
719 ("Error setting audio parameters: %s", g_strerror (errno)));