/** * gst_tuner_find_channel_by_name: * @tuner: A #GstTuner instance * @channel: A string containing the name of a #GstTunerChannel * * Look up a #GstTunerChannel by name. * * Returns: A #GstTunerChannel, or NULL if no channel with the provided name * is available. */ GstTunerChannel * gst_tuner_find_channel_by_name (GstTuner * tuner, gchar * channel) { GList *walk; g_return_val_if_fail (GST_IS_TUNER (tuner), NULL); g_return_val_if_fail (channel != NULL, NULL); walk = (GList *) gst_tuner_list_channels (tuner); while (walk) { if (strcmp (GST_TUNER_CHANNEL (walk->data)->label, channel) == 0) return GST_TUNER_CHANNEL (walk->data); walk = g_list_next (walk); } return NULL; }
static void gst_tuner_channel_dispose (GObject * object) { GstTunerChannel *channel = GST_TUNER_CHANNEL (object); if (channel->label) { g_free (channel->label); channel->label = NULL; } G_OBJECT_CLASS (gst_tuner_channel_parent_class)->dispose (object); }
static GstTunerChannel * gst_v4l_tuner_get_channel (GstTuner * tuner) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GList *item; gint channel; /* assert that we're opened */ g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); gst_v4l_get_chan_norm (v4lelement, &channel, NULL); for (item = v4lelement->channels; item != NULL; item = item->next) { if (channel == GST_V4L_TUNER_CHANNEL (item->data)->index) return GST_TUNER_CHANNEL (item->data); } return NULL; }
/****************************************************** * gst_v4l2_empty_lists() and gst_v4l2_fill_lists(): * fill/empty the lists of enumerations * return value: TRUE on success, FALSE on error ******************************************************/ static gboolean gst_v4l2_fill_lists (GstV4l2Object * v4l2object) { 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; 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; }