-/* G-Streamer generic V4L2 element - generic V4L2 calls handling
+/* GStreamer
+ *
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ *
+ * v4l2_calls.c - generic V4L2 calls handling
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
+#include <unistd.h>
+#ifdef __sun
+/* Needed on older Solaris Nevada builds (72 at least) */
+#include <stropts.h>
+#include <sys/ioccom.h>
+#endif
#include "v4l2_calls.h"
+#include "gstv4l2tuner.h"
+#if 0
+#include "gstv4l2xoverlay.h"
+#endif
+#include "gstv4l2colorbalance.h"
-#define DEBUG(format, args...) \
- GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
- GST_ELEMENT(v4l2element), \
- "V4L2: " format, ##args)
+#include "gstv4l2src.h"
+#include "gstv4l2sink.h"
+#include "gst/gst-i18n-plugin.h"
+
+/* Those are ioctl calls */
+#ifndef V4L2_CID_HCENTER
+#define V4L2_CID_HCENTER V4L2_CID_HCENTER_DEPRECATED
+#endif
+#ifndef V4L2_CID_VCENTER
+#define V4L2_CID_VCENTER V4L2_CID_VCENTER_DEPRECATED
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
+#define GST_CAT_DEFAULT v4l2_debug
/******************************************************
* gst_v4l2_get_capabilities():
* get the device's capturing capabilities
* return value: TRUE on success, FALSE on error
******************************************************/
-
-static gboolean
-gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
+gboolean
+gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
{
- DEBUG("getting capabilities");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ GstElement *e;
+
+ e = v4l2object->element;
+
+ GST_DEBUG_OBJECT (e, "getting capabilities");
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Error getting %s capabilities: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
+ goto cap_failed;
- return TRUE;
+ GST_LOG_OBJECT (e, "driver: '%s'", v4l2object->vcap.driver);
+ GST_LOG_OBJECT (e, "card: '%s'", v4l2object->vcap.card);
+ GST_LOG_OBJECT (e, "bus_info: '%s'", v4l2object->vcap.bus_info);
+ GST_LOG_OBJECT (e, "version: %08x", v4l2object->vcap.version);
+ GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities);
+
+ return TRUE;
+
+ /* ERRORS */
+cap_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Error getting capabilities for device '%s': "
+ "It isn't a v4l2 driver. Check if it is a v4l1 driver."),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
* fill/empty the lists of enumerations
* return value: TRUE on success, FALSE on error
******************************************************/
-
static gboolean
-gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
+gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
{
- gint n;
-
- DEBUG("getting enumerations");
- GST_V4L2_CHECK_OPEN(v4l2element);
-
- /* and now, the inputs */
- for (n=0;;n++) {
- struct v4l2_input input, *inpptr;
- input.index = n;
- if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
- if (errno == EINVAL)
- break; /* end of enumeration */
- else {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get no. %d in input enumeration for %s: %s",
- n, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
- }
- inpptr = g_malloc(sizeof(input));
- memcpy(inpptr, &input, sizeof(input));
- v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
- }
-
- /* outputs */
- for (n=0;;n++) {
- struct v4l2_output output, *outptr;
- output.index = n;
- if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
- if (errno == EINVAL)
- break; /* end of enumeration */
- else {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get no. %d in output enumeration for %s: %s",
- n, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
- }
- outptr = g_malloc(sizeof(output));
- memcpy(outptr, &output, sizeof(output));
- v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
- }
-
- /* norms... */
- for (n=0;;n++) {
- struct v4l2_standard standard, *stdptr;
- standard.index = n;
- if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
- if (errno == EINVAL)
- break; /* end of enumeration */
- else {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get no. %d in norm enumeration for %s: %s",
- n, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
- }
- stdptr = g_malloc(sizeof(standard));
- memcpy(stdptr, &standard, sizeof(standard));
- v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
- }
-
- /* and lastly, controls+menus (if appropriate) */
- for (n=V4L2_CID_BASE;;n++) {
- struct v4l2_queryctrl control, *ctrlptr;
- GList *menus = NULL;
- /* hacky... */
- if (n == V4L2_CID_LASTP1)
- n = V4L2_CID_PRIVATE_BASE;
- control.id = n;
- if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
- if (errno == EINVAL) {
- if (n < V4L2_CID_PRIVATE_BASE)
- continue;
- else
- break;
- } else {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get no. %d in control enumeration for %s: %s",
- n, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
- }
- if (control.flags & V4L2_CTRL_FLAG_DISABLED)
- continue;
- ctrlptr = g_malloc(sizeof(control));
- memcpy(ctrlptr, &control, sizeof(control));
- v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
- if (control.type == V4L2_CTRL_TYPE_MENU) {
- struct v4l2_querymenu menu, *mptr;
- int i;
- menu.id = n;
- for (i=0;;i++) {
- menu.index = i;
- if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
- if (errno == EINVAL)
- break; /* end of enumeration */
- else {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get no. %d in menu %d enumeration for %s: %s",
- i, n, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
- }
- mptr = g_malloc(sizeof(menu));
- memcpy(mptr, &menu, sizeof(menu));
- menus = g_list_append(menus, mptr);
- }
- }
- v4l2element->menus = g_list_append(v4l2element->menus, menus);
- }
-
- return TRUE;
+ gint n;
+
+ GstElement *e;
+
+ e = v4l2object->element;
+
+ GST_DEBUG_OBJECT (e, "getting enumerations");
+ GST_V4L2_CHECK_OPEN (v4l2object);
+
+ GST_DEBUG_OBJECT (e, " channels");
+ /* and now, the channels */
+ for (n = 0;; n++) {
+ struct v4l2_input input;
+ GstV4l2TunerChannel *v4l2channel;
+ GstTunerChannel *channel;
+
+ memset (&input, 0, sizeof (input));
+
+ input.index = n;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
+ if (errno == EINVAL)
+ break; /* end of enumeration */
+ else {
+ GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+ (_("Failed to query attributes of input %d in device %s"),
+ n, v4l2object->videodev),
+ ("Failed to get %d in input enumeration for %s. (%d - %s)",
+ n, v4l2object->videodev, errno, strerror (errno)));
+ return FALSE;
+ }
+ }
+
+ GST_LOG_OBJECT (e, " index: %d", input.index);
+ GST_LOG_OBJECT (e, " name: '%s'", input.name);
+ GST_LOG_OBJECT (e, " type: %08x", input.type);
+ GST_LOG_OBJECT (e, " audioset: %08x", input.audioset);
+ GST_LOG_OBJECT (e, " std: %016x", (guint) input.std);
+ GST_LOG_OBJECT (e, " status: %08x", input.status);
+
+ v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
+ channel = GST_TUNER_CHANNEL (v4l2channel);
+ channel->label = g_strdup ((const gchar *) input.name);
+ channel->flags = GST_TUNER_CHANNEL_INPUT;
+ v4l2channel->index = n;
+
+ if (input.type == V4L2_INPUT_TYPE_TUNER) {
+ struct v4l2_tuner vtun;
+
+ v4l2channel->tuner = input.tuner;
+ channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
+
+ vtun.index = input.tuner;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
+ GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+ (_("Failed to get setting of tuner %d on device '%s'."),
+ input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
+ g_object_unref (G_OBJECT (channel));
+ return FALSE;
+ }
+
+ channel->freq_multiplicator =
+ 62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
+ channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
+ channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
+ channel->min_signal = 0;
+ channel->max_signal = 0xffff;
+ }
+ if (input.audioset) {
+ /* we take the first. We don't care for
+ * the others for now */
+ while (!(input.audioset & (1 << v4l2channel->audio)))
+ v4l2channel->audio++;
+ channel->flags |= GST_TUNER_CHANNEL_AUDIO;
+ }
+
+ v4l2object->channels =
+ g_list_prepend (v4l2object->channels, (gpointer) channel);
+ }
+ v4l2object->channels = g_list_reverse (v4l2object->channels);
+
+ GST_DEBUG_OBJECT (e, " norms");
+ /* norms... */
+ for (n = 0;; n++) {
+ struct v4l2_standard standard = { 0, };
+ GstV4l2TunerNorm *v4l2norm;
+
+ GstTunerNorm *norm;
+
+ /* fill in defaults */
+ standard.frameperiod.numerator = 1;
+ standard.frameperiod.denominator = 0;
+ standard.index = n;
+
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
+ if (errno == EINVAL || errno == ENOTTY)
+ break; /* end of enumeration */
+ else {
+ GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+ (_("Failed to query norm on device '%s'."),
+ v4l2object->videodev),
+ ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)",
+ n, v4l2object->videodev, errno, strerror (errno)));
+ return FALSE;
+ }
+ }
+
+ GST_DEBUG_OBJECT (e, " '%s', fps: %d / %d",
+ standard.name, standard.frameperiod.denominator,
+ standard.frameperiod.numerator);
+
+ v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
+ norm = GST_TUNER_NORM (v4l2norm);
+ norm->label = g_strdup ((const gchar *) standard.name);
+ gst_value_set_fraction (&norm->framerate,
+ standard.frameperiod.denominator, standard.frameperiod.numerator);
+ v4l2norm->index = standard.id;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
+ (unsigned int) v4l2norm->index, norm->label);
+
+ v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm);
+ }
+ v4l2object->norms = g_list_reverse (v4l2object->norms);
+
+ GST_DEBUG_OBJECT (e, " controls+menus");
+
+ /* and lastly, controls+menus (if appropriate) */
+ for (n = V4L2_CID_BASE;; n++) {
+ struct v4l2_queryctrl control = { 0, };
+ GstV4l2ColorBalanceChannel *v4l2channel;
+ GstColorBalanceChannel *channel;
+
+ /* when we reached the last official CID, continue with private CIDs */
+ if (n == V4L2_CID_LASTP1) {
+ GST_DEBUG_OBJECT (e, "checking private CIDs");
+ n = V4L2_CID_PRIVATE_BASE;
+ }
+ GST_DEBUG_OBJECT (e, "checking control %08x", n);
+
+ control.id = n;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
+ if (errno == EINVAL) {
+ if (n < V4L2_CID_PRIVATE_BASE) {
+ GST_DEBUG_OBJECT (e, "skipping control %08x", n);
+ /* continue so that we also check private controls */
+ continue;
+ } else {
+ GST_DEBUG_OBJECT (e, "controls finished");
+ break;
+ }
+ } else {
+ GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+ (_("Failed getting controls attributes on device '%s'."),
+ v4l2object->videodev),
+ ("Failed querying control %d on device '%s'. (%d - %s)",
+ n, v4l2object->videodev, errno, strerror (errno)));
+ return FALSE;
+ }
+ }
+ if (control.flags & V4L2_CTRL_FLAG_DISABLED) {
+ GST_DEBUG_OBJECT (e, "skipping disabled control");
+ continue;
+ }
+
+ switch (n) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_BLACK_LEVEL:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ case V4L2_CID_DO_WHITE_BALANCE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_GAIN:
+#ifdef V4L2_CID_SHARPNESS
+ case V4L2_CID_SHARPNESS:
+#endif
+ /* we only handle these for now (why?) */
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HCENTER:
+ case V4L2_CID_VCENTER:
+#ifdef V4L2_CID_PAN_RESET
+ case V4L2_CID_PAN_RESET:
+#endif
+#ifdef V4L2_CID_TILT_RESET
+ case V4L2_CID_TILT_RESET:
+#endif
+ /* not handled here, handled by VideoOrientation interface */
+ control.id++;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ /* FIXME: We should implement GstMixer interface */
+ /* fall through */
+ default:
+ GST_DEBUG_OBJECT (e,
+ "ControlID %s (%x) unhandled, FIXME", control.name, n);
+ control.id++;
+ break;
+ }
+ if (n != control.id)
+ continue;
+
+ GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n);
+ v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
+ channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
+ channel->label = g_strdup ((const gchar *) control.name);
+ v4l2channel->id = n;
+
+#if 0
+ /* FIXME: it will be need just when handling private controls
+ *(currently none of base controls are of this type) */
+ if (control.type == V4L2_CTRL_TYPE_MENU) {
+ struct v4l2_querymenu menu, *mptr;
+
+ int i;
+
+ menu.id = n;
+ for (i = 0;; i++) {
+ menu.index = i;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
+ if (errno == EINVAL)
+ break; /* end of enumeration */
+ else {
+ GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS,
+ (_("Failed getting controls attributes on device '%s'."),
+ v4l2object->videodev),
+ ("Failed to get %d in menu enumeration for %s. (%d - %s)",
+ n, v4l2object->videodev, errno, strerror (errno)));
+ return FALSE;
+ }
+ }
+ mptr = g_malloc (sizeof (menu));
+ memcpy (mptr, &menu, sizeof (menu));
+ menus = g_list_append (menus, mptr);
+ }
+ }
+ v4l2object->menus = g_list_append (v4l2object->menus, menus);
+#endif
+
+ switch (control.type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ channel->min_value = control.minimum;
+ channel->max_value = control.maximum;
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ channel->min_value = FALSE;
+ channel->max_value = TRUE;
+ break;
+ default:
+ /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
+ BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
+ unset (0), but can't be queried */
+ GST_DEBUG_OBJECT (e,
+ "Control with non supported type %s (%x), type=%d",
+ control.name, n, control.type);
+ channel->min_value = channel->max_value = 0;
+ break;
+ }
+
+ v4l2object->colors =
+ g_list_prepend (v4l2object->colors, (gpointer) channel);
+ }
+ v4l2object->colors = g_list_reverse (v4l2object->colors);
+
+ GST_DEBUG_OBJECT (e, "done");
+ return TRUE;
}
static void
-gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
+gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
{
- DEBUG("deleting enumerations");
-
- /* empty lists */
- while (g_list_length(v4l2element->inputs) > 0) {
- gpointer data = g_list_nth_data(v4l2element->inputs, 0);
- v4l2element->inputs = g_list_remove(v4l2element->inputs, data);
- g_free(data);
- }
- while (g_list_length(v4l2element->outputs) > 0) {
- gpointer data = g_list_nth_data(v4l2element->outputs, 0);
- v4l2element->outputs = g_list_remove(v4l2element->outputs, data);
- g_free(data);
- }
- while (g_list_length(v4l2element->norms) > 0) {
- gpointer data = g_list_nth_data(v4l2element->norms, 0);
- v4l2element->norms = g_list_remove(v4l2element->norms, data);
- g_free(data);
- }
- while (g_list_length(v4l2element->controls) > 0) {
- gpointer data = g_list_nth_data(v4l2element->controls, 0);
- v4l2element->controls = g_list_remove(v4l2element->controls, data);
- g_free(data);
- }
- v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL);
- while (g_list_length(v4l2element->menus) > 0) {
- GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0);
- v4l2element->inputs = g_list_remove(v4l2element->inputs, items);
- while (g_list_length(items) > 0) {
- gpointer data = g_list_nth_data(v4l2element->menus, 0);
- items = g_list_remove(items, data);
- g_free(data);
- }
- }
-}
+ GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations");
+ g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
+ g_list_free (v4l2object->channels);
+ v4l2object->channels = NULL;
+
+ g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL);
+ g_list_free (v4l2object->norms);
+ v4l2object->norms = NULL;
+
+ g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
+ g_list_free (v4l2object->colors);
+ v4l2object->colors = NULL;
+}
/******************************************************
* gst_v4l2_open():
- * open the video device (v4l2element->device)
+ * open the video device (v4l2object->videodev)
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_open (GstV4l2Element *v4l2element)
+gst_v4l2_open (GstV4l2Object * v4l2object)
{
- DEBUG("Trying to open device %s", v4l2element->device);
- GST_V4L2_CHECK_NOT_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
-
- /* be sure we have a device */
- if (!v4l2element->device)
- v4l2element->device = g_strdup("/dev/video");
-
- /* open the device */
- v4l2element->video_fd = open(v4l2element->device, O_RDWR);
- if (!GST_V4L2_IS_OPEN(v4l2element)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to open device %s: %s",
- v4l2element->device, g_strerror(errno));
- goto error;
- }
-
- /* get capabilities */
- if (!gst_v4l2_get_capabilities(v4l2element)) {
- goto error;
- }
-
- /* create enumerations */
- if (!gst_v4l2_fill_lists(v4l2element))
- goto error;
-
- gst_info("Opened device '%s' (%s) successfully\n",
- v4l2element->vcap.card, v4l2element->device);
-
- return TRUE;
-
+ struct stat st;
+ int libv4l2_fd;
+ GstPollFD pollfd = GST_POLL_FD_INIT;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
+ v4l2object->videodev);
+
+ GST_V4L2_CHECK_NOT_OPEN (v4l2object);
+ GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+ /* be sure we have a device */
+ if (!v4l2object->videodev)
+ v4l2object->videodev = g_strdup ("/dev/video");
+
+ /* check if it is a device */
+ if (stat (v4l2object->videodev, &st) == -1)
+ goto stat_failed;
+
+ if (!S_ISCHR (st.st_mode))
+ goto no_device;
+
+ /* open the device */
+ v4l2object->video_fd =
+ open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ goto not_open;
+
+ libv4l2_fd = v4l2_fd_open (v4l2object->video_fd,
+ V4L2_ENABLE_ENUM_FMT_EMULATION);
+ /* Note the v4l2_xxx functions are designed so that if they get passed an
+ unknown fd, the will behave exactly as their regular xxx counterparts, so
+ if v4l2_fd_open fails, we continue as normal (missing the libv4l2 custom
+ cam format to normal formats conversion). Chances are big we will still
+ fail then though, as normally v4l2_fd_open only fails if the device is not
+ a v4l2 device. */
+ if (libv4l2_fd != -1)
+ v4l2object->video_fd = libv4l2_fd;
+
+ v4l2object->can_poll_device = TRUE;
+
+ /* get capabilities, error will be posted */
+ if (!gst_v4l2_get_capabilities (v4l2object))
+ goto error;
+
+ /* do we need to be a capture device? */
+ if (GST_IS_V4L2SRC (v4l2object->element) &&
+ !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+ goto not_capture;
+
+ if (GST_IS_V4L2SINK (v4l2object->element) &&
+ !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT))
+ goto not_output;
+
+ /* create enumerations, posts errors. */
+ if (!gst_v4l2_fill_lists (v4l2object))
+ goto error;
+
+ GST_INFO_OBJECT (v4l2object->element,
+ "Opened device '%s' (%s) successfully",
+ v4l2object->vcap.card, v4l2object->videodev);
+
+ pollfd.fd = v4l2object->video_fd;
+ gst_poll_add_fd (v4l2object->poll, &pollfd);
+ gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
+
+ return TRUE;
+
+ /* ERRORS */
+stat_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+ (_("Cannot identify device '%s'."), v4l2object->videodev),
+ GST_ERROR_SYSTEM);
+ goto error;
+ }
+no_device:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+ (_("This isn't a device '%s'."), v4l2object->videodev),
+ GST_ERROR_SYSTEM);
+ goto error;
+ }
+not_open:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
+ (_("Could not open device '%s' for reading and writing."),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ goto error;
+ }
+not_capture:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+ (_("Device '%s' is not a capture device."),
+ v4l2object->videodev),
+ ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
+ goto error;
+ }
+not_output:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
+ (_("Device '%s' is not a output device."),
+ v4l2object->videodev),
+ ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
+ goto error;
+ }
error:
- if (GST_V4L2_IS_OPEN(v4l2element)) {
- /* close device */
- close(v4l2element->video_fd);
- v4l2element->video_fd = -1;
- }
- /* empty lists */
- gst_v4l2_empty_lists(v4l2element);
-
- return FALSE;
+ {
+ if (GST_V4L2_IS_OPEN (v4l2object)) {
+ /* close device */
+ v4l2_close (v4l2object->video_fd);
+ v4l2object->video_fd = -1;
+ }
+ /* empty lists */
+ gst_v4l2_empty_lists (v4l2object);
+
+ return FALSE;
+ }
}
/******************************************************
* gst_v4l2_close():
- * close the video device (v4l2element->video_fd)
+ * close the video device (v4l2object->video_fd)
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_close (GstV4l2Element *v4l2element)
+gst_v4l2_close (GstV4l2Object * v4l2object)
{
- DEBUG("Trying to close %s", v4l2element->device);
- GST_V4L2_CHECK_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+ GstPollFD pollfd = GST_POLL_FD_INIT;
+ GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
+ v4l2object->videodev);
- /* close device */
- close(v4l2element->video_fd);
- v4l2element->video_fd = -1;
+ GST_V4L2_CHECK_OPEN (v4l2object);
+ GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
- /* empty lists */
- gst_v4l2_empty_lists(v4l2element);
+ /* close device */
+ v4l2_close (v4l2object->video_fd);
+ pollfd.fd = v4l2object->video_fd;
+ gst_poll_remove_fd (v4l2object->poll, &pollfd);
+ v4l2object->video_fd = -1;
- return TRUE;
+ /* empty lists */
+ gst_v4l2_empty_lists (v4l2object);
+
+ return TRUE;
}
* Get the norm of the current device
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_get_norm (GstV4l2Element *v4l2element,
- gint *norm)
+gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
{
- v4l2_std_id std_id;
- gint n;
-
- DEBUG("getting norm");
- GST_V4L2_CHECK_OPEN(v4l2element);
-
- if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &std_id) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get the current norm for device %s: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
-
- /* try to find out what norm number this actually is */
- for (n=0;n<g_list_length(v4l2element->norms);n++) {
- struct v4l2_standard *stdptr = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n);
- if (stdptr->id == std_id) {
- *norm = n;
- return TRUE;
- }
- }
-
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to find norm '%llu' in our list of available norms for device %s",
- std_id, v4l2element->device);
- return FALSE;
-}
-
-
-/******************************************************
- * gst_v4l2_set_norm()
- * Set the norm of the current device
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-
-gboolean
-gst_v4l2_set_norm (GstV4l2Element *v4l2element,
- gint norm)
-{
- struct v4l2_standard *standard;
-
- DEBUG("trying to set norm to %d", norm);
- GST_V4L2_CHECK_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
-
- if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Invalid norm number %d (%d-%d)",
- norm, 0, g_list_length(v4l2element->norms));
- return FALSE;
- }
-
- standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, norm);
-
- if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->id) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to set norm '%s' (%llu) for device %s: %s",
- standard->name, standard->id, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
- return TRUE;
-}
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
+ goto std_failed;
-/******************************************************
- * gst_v4l2_get_norm_names()
- * Get the list of available norms
- * return value: the list
- ******************************************************/
-
-GList *
-gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
-{
- GList *names = NULL;
- gint n;
+ return TRUE;
- DEBUG("getting a list of norm names");
-
- for (n=0;n<g_list_length(v4l2element->norms);n++) {
- struct v4l2_standard *standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n);
- names = g_list_append(names, g_strdup(standard->name));
- }
-
- return names;
+ /* ERRORS */
+std_failed:
+ {
+ GST_DEBUG ("Failed to get the current norm for device %s",
+ v4l2object->videodev);
+ return FALSE;
+ }
}
/******************************************************
- * gst_v4l2_get_input()
- * Get the input of the current device
+ * gst_v4l2_set_norm()
+ * Set the norm of the current device
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_get_input (GstV4l2Element *v4l2element,
- gint *input)
+gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
{
- gint n;
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to "
+ "%" G_GINT64_MODIFIER "x", (guint64) norm);
- DEBUG("trying to get input");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get current input on device %s: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
+ goto std_failed;
- *input = n;
+ return TRUE;
- return TRUE;
+ /* ERRORS */
+std_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to set norm for device '%s'."),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
-
/******************************************************
- * gst_v4l2_set_input()
- * Set the input of the current device
+ * gst_v4l2_get_frequency():
+ * get the current frequency
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_set_input (GstV4l2Element *v4l2element,
- gint input)
+gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
+ gint tunernum, gulong * frequency)
{
- DEBUG("trying to set input to %d", input);
- GST_V4L2_CHECK_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
-
- if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Invalid input number %d (%d-%d)",
- input, 0, g_list_length(v4l2element->inputs));
- return FALSE;
- }
-
- if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to set input %d on device %s: %s",
- input, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
+ struct v4l2_frequency freq = { 0, };
+ GstTunerChannel *channel;
-/******************************************************
- * gst_v4l2_get_input_names()
- * Get the list of available input channels
- * return value: the list
- ******************************************************/
+ GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
-GList *
-gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
-{
- GList *names = NULL;
- gint n;
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- DEBUG("getting a list of input names");
+ channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
- for (n=0;n<g_list_length(v4l2element->inputs);n++) {
- struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
- names = g_list_append(names, g_strdup(input->name));
- }
+ freq.tuner = tunernum;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
+ goto freq_failed;
- return names;
-}
-
-
-/******************************************************
- * gst_v4l2_get_output()
- * Get the output of the current device
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-
-gboolean
-gst_v4l2_get_output (GstV4l2Element *v4l2element,
- gint *output)
-{
- gint n;
+ *frequency = freq.frequency * channel->freq_multiplicator;
- DEBUG("trying to get output");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ return TRUE;
- if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get current output on device %s: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
-
- *output = n;
-
- return TRUE;
+ /* ERRORS */
+freq_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to get current tuner frequency for device '%s'."),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
/******************************************************
- * gst_v4l2_set_output()
- * Set the output of the current device
+ * gst_v4l2_set_frequency():
+ * set frequency
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_set_output (GstV4l2Element *v4l2element,
- gint output)
-{
- DEBUG("trying to set output to %d", output);
- GST_V4L2_CHECK_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
-
- if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Invalid output number %d (%d-%d)",
- output, 0, g_list_length(v4l2element->outputs));
- return FALSE;
- }
-
- if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to set output %d on device %s: %s",
- output, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/******************************************************
- * gst_v4l2_get_output_names()
- * Get the list of available output channels
- * return value: the list, or NULL on error
- ******************************************************/
-
-GList *
-gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
+gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
+ gint tunernum, gulong frequency)
{
- GList *names = NULL;
- gint n;
+ struct v4l2_frequency freq = { 0, };
- DEBUG("getting a list of output names");
+ GstTunerChannel *channel;
- for (n=0;n<g_list_length(v4l2element->outputs);n++) {
- struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
- names = g_list_append(names, g_strdup(output->name));
- }
-
- return names;
-}
+ GST_DEBUG_OBJECT (v4l2object->element,
+ "setting current tuner frequency to %lu", frequency);
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
-/******************************************************
- * gst_v4l_has_tuner():
- * Check whether the device has a tuner
- * return value: TRUE if it has a tuner, else FALSE
- ******************************************************/
-
-gint
-gst_v4l2_has_tuner (GstV4l2Element *v4l2element,
- gint *tuner_num)
-{
- gint input_num;
- struct v4l2_input *input;
+ channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
- DEBUG("detecting whether device has a tuner");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ freq.tuner = tunernum;
+ /* fill in type - ignore error */
+ v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
+ freq.frequency = frequency / channel->freq_multiplicator;
- if (!gst_v4l2_get_input(v4l2element, &input_num))
- return FALSE;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
+ goto freq_failed;
- input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
+ return TRUE;
- if (input->type == V4L2_INPUT_TYPE_TUNER &&
- v4l2element->vcap.capabilities & V4L2_CAP_TUNER) {
- *tuner_num = input->tuner;
- return TRUE;
- }
- return FALSE;
+ /* ERRORS */
+freq_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to set current tuner frequency for device '%s' to %lu Hz."),
+ v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
-
/******************************************************
- * gst_v4l_get_frequency():
- * get the current frequency
+ * gst_v4l2_signal_strength():
+ * get the strength of the signal on the current input
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
- gulong *frequency)
+gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
+ gint tunernum, gulong * signal_strength)
{
- struct v4l2_frequency freq;
+ struct v4l2_tuner tuner = { 0, };
- DEBUG("getting current tuner frequency");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
- if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
- return FALSE;
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- freq.type = 0;
+ tuner.index = tunernum;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
+ goto tuner_failed;
- if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get current tuner frequency for device %s: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ *signal_strength = tuner.signal;
- *frequency = freq.frequency;
+ return TRUE;
- return TRUE;
+ /* ERRORS */
+tuner_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to get signal strength for device '%s'."),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
-
/******************************************************
- * gst_v4l_set_frequency():
- * set frequency
+ * gst_v4l2_get_attribute():
+ * try to get the value of one specific attribute
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
- gulong frequency)
+gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
+ int attribute_num, int *value)
{
- struct v4l2_frequency freq;
+ struct v4l2_control control = { 0, };
- DEBUG("setting current tuner frequency to %lu", frequency);
- GST_V4L2_CHECK_OPEN(v4l2element);
- GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+ GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
+ attribute_num);
- if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner))
- return FALSE;
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- freq.frequency = frequency;
- freq.type = 0;
+ control.id = attribute_num;
- if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to set tuner frequency to %lu for device %s: %s",
- frequency, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
+ goto ctrl_failed;
- return TRUE;
+ *value = control.value;
+
+ return TRUE;
+
+ /* ERRORS */
+ctrl_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to get value for control %d on device '%s'."),
+ attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
/******************************************************
- * gst_v4l_signal_strength():
- * get the strength of the signal on the current input
+ * gst_v4l2_set_attribute():
+ * try to set the value of one specific attribute
* return value: TRUE on success, FALSE on error
******************************************************/
-
gboolean
-gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
- gulong *signal_strength)
+gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
+ int attribute_num, const int value)
{
- struct v4l2_tuner tuner;
+ struct v4l2_control control = { 0, };
- DEBUG("trying to get signal strength");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
+ attribute_num, value);
- if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get signal strength for device %s: %s",
- v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- *signal_strength = tuner.signal;
-
- return TRUE;
-}
+ control.id = attribute_num;
+ control.value = value;
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
+ goto ctrl_failed;
+ return TRUE;
-/******************************************************
- * gst_v4l_has_audio():
- * Check whether the device has audio capabilities
- * return value: TRUE if it has a tuner, else FALSE
- ******************************************************/
+ /* ERRORS */
+ctrl_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to set value %d for control %d on device '%s'."),
+ value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+}
gboolean
-gst_v4l2_has_audio (GstV4l2Element *v4l2element)
+gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
{
- gint input_num;
- struct v4l2_input *input;
+ gint n;
- DEBUG("detecting whether device has audio");
- GST_V4L2_CHECK_OPEN(v4l2element);
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
- if (!gst_v4l2_get_input(v4l2element, &input_num))
- return FALSE;
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
+ goto input_failed;
- return (input->audioset != 0);
-}
+ *input = n;
+ GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n);
-/******************************************************
- * gst_v4l_get_attributes():
- * get a list of attributes available on this device
- * return value: the list
- ******************************************************/
+ return TRUE;
-GList *
-gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
-{
- gint i;
- GList *list = NULL;
-
- DEBUG("getting a list of available attributes");
-
- for (i=0;i<g_list_length(v4l2element->controls);i++) {
- struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
- GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
- attribute->name = g_strdup(control->name);
- attribute->index = i;
- attribute->list_items = NULL;
- attribute->val_type = control->type;
- if (control->type == V4L2_CTRL_TYPE_MENU) {
- /* list items */
- gint n;
- GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
- for (n=0;n<g_list_length(menus);n++) {
- struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
- attribute->list_items = g_list_append(attribute->list_items,
- g_strdup(menu->name));
- }
- }
- switch (control->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_BLACK_LEVEL:
- case V4L2_CID_AUTO_WHITE_BALANCE:
- case V4L2_CID_DO_WHITE_BALANCE:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case V4L2_CID_GAMMA:
- case V4L2_CID_EXPOSURE:
- case V4L2_CID_AUTOGAIN:
- case V4L2_CID_GAIN:
- case V4L2_CID_HFLIP:
- case V4L2_CID_VFLIP:
- case V4L2_CID_HCENTER:
- case V4L2_CID_VCENTER:
- attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_LOUDNESS:
- attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
- break;
- default:
- attribute->type = GST_V4L2_ATTRIBUTE_TYPE_OTHER;
- break;
- }
- gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
- attribute->min = control->minimum;
- attribute->max = control->maximum;
- }
-
- return list;
+ /* ERRORS */
+input_failed:
+ if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+ /* only give a warning message if driver actually claims to have tuner
+ * support
+ */
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to get current input on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
+ }
+ return FALSE;
}
-
-/******************************************************
- * gst_v4l_get_attribute():
- * try to get the value of one specific attribute
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-
gboolean
-gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
- gint attribute_num,
- gint *value)
+gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
{
- struct v4l2_control control;
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
+
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
+ goto input_failed;
+
+ return TRUE;
+
+ /* ERRORS */
+input_failed:
+ if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+ /* only give a warning message if driver actually claims to have tuner
+ * support
+ */
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to set input %d on device %s."),
+ input, v4l2object->videodev), GST_ERROR_SYSTEM);
+ }
+ return FALSE;
+}
- DEBUG("getting value of attribute %d", attribute_num);
- GST_V4L2_CHECK_OPEN(v4l2element);
+gboolean
+gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
+{
+ gint n;
- if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Invalid control ID %d", attribute_num);
- return FALSE;
- }
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to get output");
- control.id = attribute_num;
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
- if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to get value for control %d on device %s: %s",
- attribute_num, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0)
+ goto output_failed;
- *value = control.value;
+ *output = n;
- return TRUE;
-}
+ GST_DEBUG_OBJECT (v4l2object->element, "output: %d", n);
+ return TRUE;
-/******************************************************
- * gst_v4l_set_attribute():
- * try to set the value of one specific attribute
- * return value: TRUE on success, FALSE on error
- ******************************************************/
+ /* ERRORS */
+output_failed:
+ if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+ /* only give a warning message if driver actually claims to have tuner
+ * support
+ */
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to get current output on device '%s'. May be it is a radio device"), v4l2object->videodev), GST_ERROR_SYSTEM);
+ }
+ return FALSE;
+}
gboolean
-gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
- gint attribute_num,
- gint value)
+gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
{
- struct v4l2_control control;
-
- DEBUG("setting value of attribute %d to %d", attribute_num, value);
- GST_V4L2_CHECK_OPEN(v4l2element);
-
- if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Invalid control ID %d", attribute_num);
- return FALSE;
- }
-
- control.id = attribute_num;
- control.value = value;
-
- if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
- gst_element_error(GST_ELEMENT(v4l2element),
- "Failed to set value %d for control %d on device %s: %s",
- value, attribute_num, v4l2element->device, g_strerror(errno));
- return FALSE;
- }
-
- return TRUE;
+ GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output);
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ return FALSE;
+
+ if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0)
+ goto output_failed;
+
+ return TRUE;
+
+ /* ERRORS */
+output_failed:
+ if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+ /* only give a warning message if driver actually claims to have tuner
+ * support
+ */
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Failed to set output %d on device %s."),
+ output, v4l2object->videodev), GST_ERROR_SYSTEM);
+ }
+ return FALSE;
}
-