mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
v4l2: add a property for arbitrary v4l2 controls
This makes it possible to set any controls that can be set with VIDIOC_S_CTRL. The controls are set when the property is set (if the device is open) and when the device is opened. https://bugzilla.gnome.org/show_bug.cgi?id=698837
This commit is contained in:
parent
52282b5faa
commit
0fb59275b0
4 changed files with 93 additions and 1 deletions
|
@ -490,6 +490,20 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
|
||||||
"I/O mode",
|
"I/O mode",
|
||||||
GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
|
GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstV4l2Src:extra-controls
|
||||||
|
*
|
||||||
|
* Additional v4l2 controls for the device. The controls are identified
|
||||||
|
* by the control name (lowercase with '_' for any non-alphanumeric
|
||||||
|
* characters).
|
||||||
|
*
|
||||||
|
* Since: 1.2
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_class, PROP_EXTRA_CONTROLS,
|
||||||
|
g_param_spec_boxed ("extra-controls", "Extra Controls",
|
||||||
|
"Extra v4l2 controls (CIDs) for the device",
|
||||||
|
GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
GstV4l2Object *
|
GstV4l2Object *
|
||||||
|
@ -654,6 +668,17 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
|
||||||
case PROP_IO_MODE:
|
case PROP_IO_MODE:
|
||||||
v4l2object->req_mode = g_value_get_enum (value);
|
v4l2object->req_mode = g_value_get_enum (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_EXTRA_CONTROLS:{
|
||||||
|
const GstStructure *s = gst_value_get_structure (value);
|
||||||
|
|
||||||
|
if (v4l2object->extra_controls)
|
||||||
|
gst_structure_free (v4l2object->extra_controls);
|
||||||
|
|
||||||
|
v4l2object->extra_controls = s ? gst_structure_copy (s) : NULL;
|
||||||
|
if (GST_V4L2_IS_OPEN (v4l2object))
|
||||||
|
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -730,6 +755,9 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
|
||||||
case PROP_IO_MODE:
|
case PROP_IO_MODE:
|
||||||
g_value_set_enum (value, v4l2object->req_mode);
|
g_value_set_enum (value, v4l2object->req_mode);
|
||||||
break;
|
break;
|
||||||
|
case PROP_EXTRA_CONTROLS:
|
||||||
|
gst_value_set_structure (value, v4l2object->extra_controls);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -143,11 +143,13 @@ struct _GstV4l2Object {
|
||||||
GList *colors;
|
GList *colors;
|
||||||
GList *norms;
|
GList *norms;
|
||||||
GList *channels;
|
GList *channels;
|
||||||
|
GData *controls;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
v4l2_std_id tv_norm;
|
v4l2_std_id tv_norm;
|
||||||
gchar *channel;
|
gchar *channel;
|
||||||
gulong frequency;
|
gulong frequency;
|
||||||
|
GstStructure *extra_controls;
|
||||||
|
|
||||||
/* X-overlay */
|
/* X-overlay */
|
||||||
GstV4l2Xv *xv;
|
GstV4l2Xv *xv;
|
||||||
|
@ -176,7 +178,8 @@ GType gst_v4l2_object_get_type (void);
|
||||||
PROP_SATURATION, \
|
PROP_SATURATION, \
|
||||||
PROP_HUE, \
|
PROP_HUE, \
|
||||||
PROP_TV_NORM, \
|
PROP_TV_NORM, \
|
||||||
PROP_IO_MODE
|
PROP_IO_MODE, \
|
||||||
|
PROP_EXTRA_CONTROLS
|
||||||
|
|
||||||
/* create/destroy */
|
/* create/destroy */
|
||||||
GstV4l2Object * gst_v4l2_object_new (GstElement * element,
|
GstV4l2Object * gst_v4l2_object_new (GstElement * element,
|
||||||
|
|
|
@ -270,6 +270,32 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
|
||||||
GST_DEBUG_OBJECT (e, "skipping disabled control");
|
GST_DEBUG_OBJECT (e, "skipping disabled control");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
switch (control.type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER_MENU:
|
||||||
|
case V4L2_CTRL_TYPE_BITMASK:
|
||||||
|
case V4L2_CTRL_TYPE_BUTTON:{
|
||||||
|
int i;
|
||||||
|
control.name[31] = '\0';
|
||||||
|
for (i = 0; control.name[i]; ++i) {
|
||||||
|
control.name[i] = g_ascii_tolower (control.name[i]);
|
||||||
|
if (!g_ascii_isalnum (control.name[i]))
|
||||||
|
control.name[i] = '_';
|
||||||
|
}
|
||||||
|
GST_INFO_OBJECT (e, "adding generic controls '%s'", control.name);
|
||||||
|
g_datalist_id_set_data (&v4l2object->controls,
|
||||||
|
g_quark_from_string ((const gchar *) control.name),
|
||||||
|
GINT_TO_POINTER (n));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GST_DEBUG_OBJECT (e,
|
||||||
|
"Control type for '%s' not suppored for extra controls.",
|
||||||
|
control.name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case V4L2_CID_BRIGHTNESS:
|
case V4L2_CID_BRIGHTNESS:
|
||||||
|
@ -407,6 +433,8 @@ gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
|
||||||
g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
|
g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
|
||||||
g_list_free (v4l2object->colors);
|
g_list_free (v4l2object->colors);
|
||||||
v4l2object->colors = NULL;
|
v4l2object->colors = NULL;
|
||||||
|
|
||||||
|
g_datalist_clear (&v4l2object->controls);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************
|
/******************************************************
|
||||||
|
@ -486,6 +514,9 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
||||||
else
|
else
|
||||||
gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
|
gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
|
||||||
|
|
||||||
|
if (v4l2object->extra_controls)
|
||||||
|
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -811,6 +842,33 @@ ctrl_failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
set_contol (GQuark field_id, const GValue * value, gpointer user_data)
|
||||||
|
{
|
||||||
|
GstV4l2Object *v4l2object = user_data;
|
||||||
|
gpointer *d = g_datalist_id_get_data (&v4l2object->controls, field_id);
|
||||||
|
if (!d) {
|
||||||
|
GST_WARNING_OBJECT (v4l2object,
|
||||||
|
"Control '%s' does not exist or has an unsupported type.",
|
||||||
|
g_quark_to_string (field_id));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (!G_VALUE_HOLDS (value, G_TYPE_INT)) {
|
||||||
|
GST_WARNING_OBJECT (v4l2object,
|
||||||
|
"'int' value expected for control '%s'.", g_quark_to_string (field_id));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
gst_v4l2_set_attribute (v4l2object, GPOINTER_TO_INT (d),
|
||||||
|
g_value_get_int (value));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_v4l2_set_controls (GstV4l2Object * v4l2object, GstStructure * controls)
|
||||||
|
{
|
||||||
|
return gst_structure_foreach (controls, set_contol, v4l2object);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
|
gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
|
||||||
{
|
{
|
||||||
|
|
|
@ -126,6 +126,9 @@ gboolean gst_v4l2_set_attribute (GstV4l2Object *v4l2object,
|
||||||
int attribute,
|
int attribute,
|
||||||
const int value);
|
const int value);
|
||||||
|
|
||||||
|
gboolean gst_v4l2_set_controls (GstV4l2Object * v4l2object,
|
||||||
|
GstStructure * controls);
|
||||||
|
|
||||||
gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object);
|
gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue