sys/v4l2/: Fix pass at code cleanups, move errors cases out of the normal flow for additional code clarity.

Original commit message from CVS:
* sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices),
(gst_v4l2_probe_needs_probe),
(gst_v4l2_object_install_properties_helper), (gst_v4l2_object_new),
(gst_v4l2_object_destroy), (gst_v4l2_object_set_property_helper),
(gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults),
(gst_v4l2_object_start), (gst_v4l2_object_stop):
* sys/v4l2/gstv4l2object.h:
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
(gst_v4l2src_init), (gst_v4l2src_dispose),
(gst_v4l2src_set_property), (gst_v4l2src_get_property),
(gst_v4l2src_fixate), (gst_v4l2src_get_caps),
(gst_v4l2src_set_caps), (gst_v4l2src_get_read),
(gst_v4l2src_get_mmap), (gst_v4l2src_create):
* sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
(gst_v4l2_open), (gst_v4l2_close), (gst_v4l2_get_norm),
(gst_v4l2_set_norm), (gst_v4l2_get_frequency),
(gst_v4l2_set_frequency), (gst_v4l2_signal_strength),
(gst_v4l2_get_attribute), (gst_v4l2_set_attribute),
(gst_v4l2_get_input), (gst_v4l2_set_input):
* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
(gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
(gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
(gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
(gst_v4l2src_capture_stop), (gst_v4l2src_capture_deinit),
(gst_v4l2src_get_size_limits), (gst_v4l2src_set_fps),
(gst_v4l2src_get_fps), (gst_v4l2src_buffer_finalize),
(gst_v4l2src_buffer_new):
Fix pass at code cleanups, move errors cases out of the normal
flow for additional code clarity.
This commit is contained in:
Wim Taymans 2006-09-26 11:06:17 +00:00
parent 651b00563e
commit b90e11a094
6 changed files with 544 additions and 355 deletions

View file

@ -1,3 +1,35 @@
2006-09-26 Wim Taymans <wim@fluendo.com>
* sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices),
(gst_v4l2_probe_needs_probe),
(gst_v4l2_object_install_properties_helper), (gst_v4l2_object_new),
(gst_v4l2_object_destroy), (gst_v4l2_object_set_property_helper),
(gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults),
(gst_v4l2_object_start), (gst_v4l2_object_stop):
* sys/v4l2/gstv4l2object.h:
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
(gst_v4l2src_init), (gst_v4l2src_dispose),
(gst_v4l2src_set_property), (gst_v4l2src_get_property),
(gst_v4l2src_fixate), (gst_v4l2src_get_caps),
(gst_v4l2src_set_caps), (gst_v4l2src_get_read),
(gst_v4l2src_get_mmap), (gst_v4l2src_create):
* sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities),
(gst_v4l2_open), (gst_v4l2_close), (gst_v4l2_get_norm),
(gst_v4l2_set_norm), (gst_v4l2_get_frequency),
(gst_v4l2_set_frequency), (gst_v4l2_signal_strength),
(gst_v4l2_get_attribute), (gst_v4l2_set_attribute),
(gst_v4l2_get_input), (gst_v4l2_set_input):
* sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list),
(gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame),
(gst_v4l2src_get_capture), (gst_v4l2src_set_capture),
(gst_v4l2src_capture_init), (gst_v4l2src_capture_start),
(gst_v4l2src_capture_stop), (gst_v4l2src_capture_deinit),
(gst_v4l2src_get_size_limits), (gst_v4l2src_set_fps),
(gst_v4l2src_get_fps), (gst_v4l2src_buffer_finalize),
(gst_v4l2src_buffer_new):
Fix pass at code cleanups, move errors cases out of the normal
flow for additional code clarity.
2006-09-23 Wim Taymans <wim@fluendo.com> 2006-09-23 Wim Taymans <wim@fluendo.com>
* ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init), * ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init),

View file

@ -110,7 +110,6 @@ gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check,
g_free (device); g_free (device);
} }
} }
init = TRUE; init = TRUE;
} }
@ -150,9 +149,7 @@ gst_v4l2_probe_needs_probe (GstPropertyProbe * probe,
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
break; break;
} }
return ret; return ret;
} }
static GValueArray * static GValueArray *
@ -254,19 +251,18 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class)
GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE)); GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE));
g_object_class_install_property g_object_class_install_property
(gobject_class, PROP_STD, (gobject_class, PROP_STD,
g_param_spec_string ("std", "std", g_param_spec_string ("std", "Std",
"standard (norm) to use", NULL, G_PARAM_READWRITE)); "Standard (norm) to use", NULL, G_PARAM_READWRITE));
g_object_class_install_property g_object_class_install_property
(gobject_class, PROP_INPUT, (gobject_class, PROP_INPUT,
g_param_spec_string ("input", g_param_spec_string ("input",
"input", "Input",
"input/output (channel) to switch to", NULL, G_PARAM_READWRITE)); "Input/output (channel) to switch to", NULL, G_PARAM_READWRITE));
g_object_class_install_property g_object_class_install_property
(gobject_class, PROP_FREQUENCY, (gobject_class, PROP_FREQUENCY,
g_param_spec_ulong ("frequency", g_param_spec_ulong ("frequency",
"frequency", "Frequency",
"frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE)); "Frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
} }
GstV4l2Object * GstV4l2Object *
@ -275,13 +271,11 @@ gst_v4l2_object_new (GstElement * element,
GstV4l2SetInOutFunction set_in_out_func, GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func) GstV4l2UpdateFpsFunction update_fps_func)
{ {
GstV4l2Object *v4l2object; GstV4l2Object *v4l2object;
/* /*
* some default values * some default values
*/ */
v4l2object = g_new0 (GstV4l2Object, 1); v4l2object = g_new0 (GstV4l2Object, 1);
v4l2object->element = element; v4l2object->element = element;
@ -300,16 +294,12 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->xwindow_id = 0; v4l2object->xwindow_id = 0;
return v4l2object; return v4l2object;
} }
void void
gst_v4l2_object_destroy (GstV4l2Object ** v4l2object) gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
{ {
if (*v4l2object) { if (*v4l2object) {
if ((*v4l2object)->videodev) { if ((*v4l2object)->videodev) {
g_free ((*v4l2object)->videodev); g_free ((*v4l2object)->videodev);
(*v4l2object)->videodev = NULL; (*v4l2object)->videodev = NULL;
@ -317,29 +307,24 @@ gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
g_free (*v4l2object); g_free (*v4l2object);
*v4l2object = NULL; *v4l2object = NULL;
} }
} }
gboolean gboolean
gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object, gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
guint prop_id, const GValue * value, GParamSpec * pspec) guint prop_id, const GValue * value, GParamSpec * pspec)
{ {
switch (prop_id) { switch (prop_id) {
case PROP_DEVICE: case PROP_DEVICE:
if (v4l2object->videodev) if (v4l2object->videodev)
g_free (v4l2object->videodev); g_free (v4l2object->videodev);
v4l2object->videodev = g_strdup (g_value_get_string (value)); v4l2object->videodev = g_value_dup_string (value);
break; break;
case PROP_STD: case PROP_STD:
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
GstTuner *tuner = GST_TUNER (v4l2object->element); GstTuner *tuner = GST_TUNER (v4l2object->element);
GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner, GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner,
(gchar *) (gchar *) g_value_get_string (value));
g_value_get_string (value));
if (norm) { if (norm) {
/* like gst_tuner_set_norm (tuner, norm) /* like gst_tuner_set_norm (tuner, norm)
@ -355,8 +340,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
GstTuner *tuner = GST_TUNER (v4l2object->element); GstTuner *tuner = GST_TUNER (v4l2object->element);
GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner, GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
(gchar *) (gchar *) g_value_get_string (value));
g_value_get_string (value));
if (channel) { if (channel) {
/* like gst_tuner_set_channel (tuner, channel) /* like gst_tuner_set_channel (tuner, channel)
@ -389,9 +373,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
return FALSE; return FALSE;
break; break;
} }
return TRUE; return TRUE;
} }
@ -405,15 +387,15 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
break; break;
case PROP_DEVICE_NAME: case PROP_DEVICE_NAME:
{ {
gchar *new = NULL; const guchar *new = NULL;
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
new = (gchar *) v4l2object->vcap.card; new = v4l2object->vcap.card;
} else if (gst_v4l2_open (v4l2object)) { } else if (gst_v4l2_open (v4l2object)) {
new = (gchar *) v4l2object->vcap.card; new = v4l2object->vcap.card;
gst_v4l2_close (v4l2object); gst_v4l2_close (v4l2object);
} }
g_value_set_string (value, new); g_value_set_string (value, (gchar *) new);
break; break;
} }
case PROP_FLAGS: case PROP_FLAGS:
@ -425,6 +407,8 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
(V4L2_CAP_VIDEO_CAPTURE | (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_TUNER | V4L2_CAP_AUDIO); V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
/* FIXME. if there is something with AUDIO we add something with
* video? this needs some explanation.. */
if (v4l2object->vcap.capabilities & V4L2_CAP_AUDIO) if (v4l2object->vcap.capabilities & V4L2_CAP_AUDIO)
flags |= V4L2_FBUF_CAP_CHROMAKEY; flags |= V4L2_FBUF_CAP_CHROMAKEY;
} }
@ -444,9 +428,7 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
return FALSE; return FALSE;
break; break;
} }
return TRUE; return TRUE;
} }
static void static void
@ -464,6 +446,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
norm = norm =
GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element))); GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
if (norm) { if (norm) {
/* FIXME, free old? */
v4l2object->std = g_strdup (norm->label); v4l2object->std = g_strdup (norm->label);
gst_tuner_norm_changed (tuner, norm); gst_tuner_norm_changed (tuner, norm);
g_object_notify (G_OBJECT (v4l2object->element), "std"); g_object_notify (G_OBJECT (v4l2object->element), "std");
@ -478,6 +461,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
channel = channel =
GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object-> GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object->
element))); element)));
/* FIXME, free old? */
v4l2object->input = g_strdup (channel->label); v4l2object->input = g_strdup (channel->label);
gst_tuner_channel_changed (tuner, channel); gst_tuner_channel_changed (tuner, channel);
g_object_notify (G_OBJECT (v4l2object->element), "input"); g_object_notify (G_OBJECT (v4l2object->element), "input");
@ -498,7 +482,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
} }
} }
gboolean gboolean
gst_v4l2_object_start (GstV4l2Object * v4l2object) gst_v4l2_object_start (GstV4l2Object * v4l2object)
{ {
@ -507,7 +490,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
else else
return FALSE; return FALSE;
#ifdef HAVE_XVIDEO #ifdef HAVE_XVIDEO
gst_v4l2_xoverlay_start (v4l2object); gst_v4l2_xoverlay_start (v4l2object);
#endif #endif
@ -518,7 +500,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
gboolean gboolean
gst_v4l2_object_stop (GstV4l2Object * v4l2object) gst_v4l2_object_stop (GstV4l2Object * v4l2object)
{ {
#ifdef HAVE_XVIDEO #ifdef HAVE_XVIDEO
gst_v4l2_xoverlay_stop (v4l2object); gst_v4l2_xoverlay_stop (v4l2object);
#endif #endif

View file

@ -99,19 +99,15 @@ struct _GstV4l2Object {
GstV4l2GetInOutFunction get_in_out_func; GstV4l2GetInOutFunction get_in_out_func;
GstV4l2SetInOutFunction set_in_out_func; GstV4l2SetInOutFunction set_in_out_func;
GstV4l2UpdateFpsFunction update_fps_func; GstV4l2UpdateFpsFunction update_fps_func;
}; };
struct _GstV4l2ObjectClassHelper { struct _GstV4l2ObjectClassHelper {
/* probed devices */ /* probed devices */
GList *devices; GList *devices;
}; };
GType gst_v4l2_object_get_type(void); GType gst_v4l2_object_get_type(void);
#define V4L2_STD_OBJECT_PROPS \ #define V4L2_STD_OBJECT_PROPS \
PROP_DEVICE, \ PROP_DEVICE, \
PROP_DEVICE_NAME, \ PROP_DEVICE_NAME, \

View file

@ -37,7 +37,7 @@
* <programlisting> * <programlisting>
* gst-launch v4l2src use-fixed-fps=true ! xvimagesink * gst-launch v4l2src use-fixed-fps=true ! xvimagesink
* </programlisting> * </programlisting>
* This exemple should be used to capture from web-cams * This example should be used to capture from web-cams
* </para> * </para>
* </refsect2> * </refsect2>
*/ */
@ -130,7 +130,6 @@ static const guint32 gst_v4l2_formats[] = {
#endif #endif
}; };
#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats)) #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src); GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
@ -297,13 +296,11 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
pushsrc_class->create = gst_v4l2src_create; pushsrc_class->create = gst_v4l2src_create;
gobject_class->dispose = gst_v4l2src_dispose; gobject_class->dispose = gst_v4l2src_dispose;
} }
static void static void
gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
{ {
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src), v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps); gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps);
@ -335,8 +332,7 @@ gst_v4l2src_dispose (GObject * object)
gst_v4l2src_clear_format_list (v4l2src); gst_v4l2src_clear_format_list (v4l2src);
} }
if (((GObjectClass *) parent_class)->dispose) G_OBJECT_CLASS (parent_class)->dispose (object);
((GObjectClass *) parent_class)->dispose (object);
} }
@ -349,24 +345,19 @@ gst_v4l2src_set_property (GObject * object,
g_return_if_fail (GST_IS_V4L2SRC (object)); g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object); v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object, if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) { prop_id, value, pspec)) {
switch (prop_id) { switch (prop_id) {
case PROP_USE_FIXED_FPS: case PROP_USE_FIXED_FPS:
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
v4l2src->use_fixed_fps = g_value_get_boolean (value); v4l2src->use_fixed_fps = g_value_get_boolean (value);
} }
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
} }
@ -381,18 +372,15 @@ gst_v4l2src_get_property (GObject * object,
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object, if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) { prop_id, value, pspec)) {
switch (prop_id) { switch (prop_id) {
case PROP_USE_FIXED_FPS: case PROP_USE_FIXED_FPS:
g_value_set_boolean (value, v4l2src->use_fixed_fps); g_value_set_boolean (value, v4l2src->use_fixed_fps);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
} }
} }
} }
@ -412,6 +400,8 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
structure = gst_caps_get_structure (caps, i); structure = gst_caps_get_structure (caps, i);
const GValue *v; const GValue *v;
/* FIXME such sizes? we usually fixate to something in the 320x200
* range... */
gst_structure_fixate_field_nearest_int (structure, "width", 4096); gst_structure_fixate_field_nearest_int (structure, "width", 4096);
gst_structure_fixate_field_nearest_int (structure, "height", 4096); gst_structure_fixate_field_nearest_int (structure, "height", 4096);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2); gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
@ -755,7 +745,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
&min_w, &max_w, &min_h, &max_h)) { &min_w, &max_w, &min_h, &max_h)) {
continue; continue;
} }
/* template */ /* template, FIXME, why limit if the device reported correct results. */
min_w = CLAMP (min_w, 1, 4096); min_w = CLAMP (min_w, 1, 4096);
min_h = CLAMP (min_h, 1, 4096); min_h = CLAMP (min_h, 1, 4096);
max_w = CLAMP (max_w, min_w, 4096); max_w = CLAMP (max_w, min_w, 4096);
@ -769,11 +759,11 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
"width", GST_TYPE_INT_RANGE, min_w, max_w, "width", GST_TYPE_INT_RANGE, min_w, max_w,
"height", GST_TYPE_INT_RANGE, min_h, max_h, NULL); "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
/* FIXME, why random range? */
gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE, gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
1, 1, 100, 1, NULL); 1, 1, 100, 1, NULL);
gst_caps_append_structure (caps, structure); gst_caps_append_structure (caps, structure);
} }
} }
@ -860,13 +850,12 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
"framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL); "framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
} }
} }
return TRUE; return TRUE;
} }
/* start and stop are not symmetric -- start will open the device, but not start /* start and stop are not symmetric -- start will open the device, but not start
capture. it's setcaps that will start capture, which is called via basesrc's * capture. it's setcaps that will start capture, which is called via basesrc's
negotiate method. stop will both stop capture and close the device. * negotiate method. stop will both stop capture and close the device.
*/ */
static gboolean static gboolean
gst_v4l2src_start (GstBaseSrc * src) gst_v4l2src_start (GstBaseSrc * src)
@ -920,37 +909,42 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
} else if (amount == -1) { } else if (amount == -1) {
if (errno == EAGAIN || errno == EINTR) { if (errno == EAGAIN || errno == EINTR) {
continue; continue;
} else { } else
goto read_error;
} else
goto short_read;
} while (TRUE);
return GST_FLOW_OK;
/* ERRORS */
read_error:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
(_("error read()ing %d bytes on device %s"), (_("error read()ing %d bytes on device %s"),
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
gst_buffer_unref (*buf); gst_buffer_unref (*buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
} else { short_read:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d", ("error read()ing a buffer on device %s: got only %d bytes instead of expected %d",
v4l2src->v4l2object->videodev, amount, buffersize)); v4l2src->v4l2object->videodev, amount, buffersize));
gst_buffer_unref (*buf); gst_buffer_unref (*buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
} while (TRUE);
return GST_FLOW_OK;
} }
static GstFlowReturn static GstFlowReturn
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf) gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
{ {
gint i, num = -1; gint i, num;
/* grab a frame from the device, post an error */
/* grab a frame from the device */
num = gst_v4l2src_grab_frame (v4l2src); num = gst_v4l2src_grab_frame (v4l2src);
if (num == -1) if (num == -1)
return GST_FLOW_ERROR; goto grab_failed;
i = v4l2src->format.fmt.pix.sizeimage; i = v4l2src->format.fmt.pix.sizeimage;
@ -958,23 +952,37 @@ gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
to avoid framedrops and deadlocks because of stupid elements */ to avoid framedrops and deadlocks because of stupid elements */
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) { if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer"); GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
*buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL); *buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i); memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i);
if (!gst_v4l2src_queue_frame (v4l2src, num)) {
gst_buffer_unref (*buf); /* posts an error message if something went wrong */
return GST_FLOW_ERROR; if (!gst_v4l2src_queue_frame (v4l2src, num))
} goto queue_failed;
} else { } else {
GST_LOG_OBJECT (v4l2src, "using mmap'd buffer"); GST_LOG_OBJECT (v4l2src, "using mmap'd buffer");
*buf = *buf =
gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start, gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start,
&v4l2src->pool->buffers[num]); &v4l2src->pool->buffers[num]);
/* no need to be careful here, both are > 0, because the element uses them */ /* no need to be careful here, both are > 0, because the element uses them */
g_atomic_int_inc (&v4l2src->pool->buffers[num].refcount); g_atomic_int_inc (&v4l2src->pool->buffers[num].refcount);
g_atomic_int_inc (&v4l2src->pool->refcount); g_atomic_int_inc (&v4l2src->pool->refcount);
} }
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERRORS */
grab_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to grab a frame");
return GST_FLOW_ERROR;
}
queue_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to queue frame");
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
} }
static GstFlowReturn static GstFlowReturn
@ -983,17 +991,22 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
GstV4l2Src *v4l2src = GST_V4L2SRC (src); GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstFlowReturn ret; GstFlowReturn ret;
if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0) { if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, goto no_framerate;
(_("could not get frame rate for %s, try to set use-fixed-fps property to false"), v4l2src->v4l2object->videodev), (NULL));
return GST_FLOW_ERROR;
}
if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) { if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
ret = gst_v4l2src_get_mmap (v4l2src, buf); ret = gst_v4l2src_get_mmap (v4l2src, buf);
} else { } else {
ret = gst_v4l2src_get_read (v4l2src, buf); ret = gst_v4l2src_get_read (v4l2src, buf);
} }
return ret; return ret;
/* ERRORS */
no_framerate:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("could not get frame rate for %s, try to set use-fixed-fps "
"property to false"), v4l2src->v4l2object->videodev), (NULL));
return GST_FLOW_ERROR;
}
} }

View file

@ -48,23 +48,28 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
* get the device's capturing capabilities * get the device's capturing capabilities
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
{ {
GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities"); GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities");
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &(v4l2object->vcap)) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
goto cap_failed;
return TRUE;
/* ERRORS */
cap_failed:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Error getting capabilities for device '%s':" (_("Error getting capabilities for device '%s':"
" It isn't a v4l2 driver. Check if it is a v4l1 driver"), " It isn't a v4l2 driver. Check if it is a v4l1 driver"),
v4l2object->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
@ -73,7 +78,6 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
* fill/empty the lists of enumerations * fill/empty the lists of enumerations
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
static gboolean static gboolean
gst_v4l2_fill_lists (GstV4l2Object * v4l2object) gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
{ {
@ -354,7 +358,6 @@ gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
* open the video device (v4l2object->videodev) * open the video device (v4l2object->videodev)
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_open (GstV4l2Object * v4l2object) gst_v4l2_open (GstV4l2Object * v4l2object)
{ {
@ -362,6 +365,7 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s", GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
v4l2object->videodev); v4l2object->videodev);
GST_V4L2_CHECK_NOT_OPEN (v4l2object); GST_V4L2_CHECK_NOT_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
@ -370,46 +374,29 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
v4l2object->videodev = g_strdup ("/dev/video"); v4l2object->videodev = g_strdup ("/dev/video");
/* check if it is a device */ /* check if it is a device */
if (-1 == stat (v4l2object->videodev, &st)) { if (stat (v4l2object->videodev, &st) == -1)
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, goto stat_failed;
(_("Cannot identify device '%s'"), v4l2object->videodev),
GST_ERROR_SYSTEM); if (!S_ISCHR (st.st_mode))
goto error; goto no_device;
}
if (!S_ISCHR (st.st_mode)) {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("This isn't a device '%s'"), v4l2object->videodev),
GST_ERROR_SYSTEM);
goto error;
}
/* open the device */ /* open the device */
v4l2object->video_fd = v4l2object->video_fd =
open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ ); open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
if (!GST_V4L2_IS_OPEN (v4l2object)) { if (!GST_V4L2_IS_OPEN (v4l2object))
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE, goto not_open;
(_("Could not open device \"%s\" for reading and writing."),
v4l2object->videodev), GST_ERROR_SYSTEM);
goto error;
}
/* get capabilities */ /* get capabilities, error will be posted */
if (!gst_v4l2_get_capabilities (v4l2object)) { if (!gst_v4l2_get_capabilities (v4l2object))
goto error; goto error;
}
/* do we need to be a capture device? */ /* do we need to be a capture device? */
if (GST_IS_V4L2SRC (v4l2object) && if (GST_IS_V4L2SRC (v4l2object) &&
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, goto not_capture;
(_("Device \"%s\" is not a capture device."),
v4l2object->videodev),
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
goto error;
}
/* create enumerations */ /* create enumerations, posts errors. */
if (!gst_v4l2_fill_lists (v4l2object)) if (!gst_v4l2_fill_lists (v4l2object))
goto error; goto error;
@ -419,7 +406,38 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
return 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;
}
error: error:
{
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
/* close device */ /* close device */
close (v4l2object->video_fd); close (v4l2object->video_fd);
@ -430,6 +448,7 @@ error:
return FALSE; return FALSE;
} }
}
/****************************************************** /******************************************************
@ -437,12 +456,12 @@ error:
* close the video device (v4l2object->video_fd) * close the video device (v4l2object->video_fd)
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_close (GstV4l2Object * v4l2object) gst_v4l2_close (GstV4l2Object * v4l2object)
{ {
GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s", GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
v4l2object->videodev); v4l2object->videodev);
GST_V4L2_CHECK_OPEN (v4l2object); GST_V4L2_CHECK_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
@ -462,24 +481,27 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
* Get the norm of the current device * Get the norm of the current device
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm) gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
{ {
GST_DEBUG_OBJECT (v4l2object->element, "getting norm"); GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
goto std_failed;
return TRUE;
/* ERRORS */
std_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get the current norm for device %s"), (_("Failed to get the current norm for device %s"),
v4l2object->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
@ -488,22 +510,27 @@ gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
* Set the norm of the current device * Set the norm of the current device
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm) gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
{ {
GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm); GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm);
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
goto std_failed;
return TRUE;
/* ERRORS */
std_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set norm 0x%llx for device %s: %s"), (_("Failed to set norm 0x%llx for device %s: %s"),
norm, v4l2object->videodev), GST_ERROR_SYSTEM); norm, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
/****************************************************** /******************************************************
@ -511,7 +538,6 @@ gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
* get the current frequency * get the current frequency
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_frequency (GstV4l2Object * v4l2object, gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong * frequency) gint tunernum, gulong * frequency)
@ -520,22 +546,28 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
GstTunerChannel *channel; GstTunerChannel *channel;
GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency"); GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum; freq.tuner = tunernum;
if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
goto freq_failed;
*frequency = freq.frequency * channel->freq_multiplicator;
return TRUE;
/* ERRORS */
freq_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get current tuner frequency for device %s"), (_("Failed to get current tuner frequency for device %s"),
v4l2object->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
*frequency = freq.frequency * channel->freq_multiplicator;
return TRUE;
} }
@ -544,7 +576,6 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
* set frequency * set frequency
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_set_frequency (GstV4l2Object * v4l2object, gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong frequency) gint tunernum, gulong frequency)
@ -554,6 +585,7 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
GST_DEBUG_OBJECT (v4l2object->element, GST_DEBUG_OBJECT (v4l2object->element,
"setting current tuner frequency to %lu", frequency); "setting current tuner frequency to %lu", frequency);
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
@ -564,23 +596,26 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq); ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
freq.frequency = frequency / channel->freq_multiplicator; freq.frequency = frequency / channel->freq_multiplicator;
if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
goto freq_failed;
return TRUE;
/* ERRORS */
freq_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set current tuner frequency for device %s to %lu"), (_("Failed to set current tuner frequency for device %s to %lu"),
v4l2object->videodev, frequency), GST_ERROR_SYSTEM); v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
/****************************************************** /******************************************************
* gst_v4l2_signal_strength(): * gst_v4l2_signal_strength():
* get the strength of the signal on the current input * get the strength of the signal on the current input
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_signal_strength (GstV4l2Object * v4l2object, gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
gint tunernum, gulong * signal_strength) gint tunernum, gulong * signal_strength)
@ -588,53 +623,62 @@ gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
struct v4l2_tuner tuner; struct v4l2_tuner tuner;
GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength"); GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
tuner.index = tunernum; tuner.index = tunernum;
if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
goto tuner_failed;
*signal_strength = tuner.signal;
return TRUE;
/* ERRORS */
tuner_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get signal strength for device %s"), (_("Failed to get signal strength for device %s"),
v4l2object->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
*signal_strength = tuner.signal;
return TRUE;
} }
/****************************************************** /******************************************************
* gst_v4l2_get_attribute(): * gst_v4l2_get_attribute():
* try to get the value of one specific attribute * try to get the value of one specific attribute
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_attribute (GstV4l2Object * v4l2object, gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
int attribute_num, int *value) int attribute_num, int *value)
{ {
struct v4l2_control control; struct v4l2_control control;
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d", GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
attribute_num); attribute_num);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
control.id = attribute_num; control.id = attribute_num;
if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
goto ctrl_failed;
*value = control.value;
return TRUE;
/* ERRORS */
ctrl_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get value for control %d on device %s"), (_("Failed to get value for control %d on device %s"),
attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM); attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
*value = control.value;
return TRUE;
} }
@ -643,30 +687,33 @@ gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
* try to set the value of one specific attribute * try to set the value of one specific attribute
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_set_attribute (GstV4l2Object * v4l2object, gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
int attribute_num, const int value) int attribute_num, const int value)
{ {
struct v4l2_control control; struct v4l2_control control;
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d", GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
attribute_num, value); attribute_num, value);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
control.id = attribute_num; control.id = attribute_num;
control.value = value; control.value = value;
if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
goto ctrl_failed;
if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { return TRUE;
/* ERRORS */
ctrl_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set value %d for control %d on device %s"), (_("Failed to set value %d for control %d on device %s"),
value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM); value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
gboolean gboolean
@ -675,36 +722,48 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
gint n; gint n;
GST_DEBUG_OBJECT (v4l2object->element, "trying to get input"); GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
goto input_failed;
*input = n;
return TRUE;
/* ERRORS */
input_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get current input on device %s"), (_("Failed to get current input on device %s"),
v4l2object->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
*input = n;
return TRUE;
} }
gboolean gboolean
gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input) gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
{ {
GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
goto input_failed;
return TRUE;
/* ERRORS */
input_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set input %d on device %s"), (_("Failed to set input %d on device %s"),
input, v4l2object->videodev), GST_ERROR_SYSTEM); input, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }

View file

@ -61,7 +61,6 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
* create list of supported capture formats * create list of supported capture formats
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src) gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
{ {
@ -79,7 +78,19 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
if (errno == EINVAL) { if (errno == EINVAL) {
break; /* end of enumeration */ break; /* end of enumeration */
} else { } else
goto failed;
}
GST_LOG_OBJECT (v4l2src, "got format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format->pixelformat));
v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
}
return TRUE;
/* ERRORS */
failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("failed to get number %d in pixelformat enumeration for %s: %s"), (_("failed to get number %d in pixelformat enumeration for %s: %s"),
n, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); n, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
@ -87,21 +98,12 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
return FALSE; return FALSE;
} }
} }
GST_LOG_OBJECT (v4l2src, "got format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format->pixelformat));
v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
}
return TRUE;
}
/****************************************************** /******************************************************
* gst_v4l2src_clear_format_list(): * gst_v4l2src_clear_format_list():
* free list of supported capture formats * free list of supported capture formats
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src) gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
{ {
@ -118,14 +120,20 @@ gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
* queue a frame for capturing * queue a frame for capturing
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i) gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
{ {
GST_LOG_OBJECT (v4l2src, "queueing frame %u", i); GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF,
&v4l2src->pool->buffers[i].buffer) < 0) { &v4l2src->pool->buffers[i].buffer) < 0)
goto failed;
return TRUE;
/* ERRORS */
failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE, GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
(_("Could not write to device '%s'."), (_("Could not write to device '%s'."),
v4l2src->v4l2object->videodev), v4l2src->v4l2object->videodev),
@ -133,17 +141,13 @@ gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
v4l2src->v4l2object->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
return TRUE;
} }
/****************************************************** /******************************************************
* gst_v4l2src_grab_frame (): * gst_v4l2src_grab_frame ():
* grab a frame for capturing * grab a frame for capturing
* return value: TRUE on success, FALSE on error * return value: The captured frame number or -1 on error.
******************************************************/ ******************************************************/
gint gint
gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
{ {
@ -163,17 +167,9 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
v4l2src->v4l2object->videodev); v4l2src->v4l2object->videodev);
break; break;
case EINVAL: case EINVAL:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED, goto einval;
(_("Failed trying to get frames from device %s"),
v4l2src->v4l2object->videodev),
(_("The buffer type is not supported, or the index is out of bounds," " or no buffers have been allocated yet, or the userptr" " or length are invalid. device %s"), v4l2src->v4l2object->videodev));
break;
case ENOMEM: case ENOMEM:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED, goto nomem;
(_("Failed trying to get frames from device %s. Not enough memory"),
v4l2src->v4l2object->videodev),
(_("isufficient memory to enqueue a user pointer buffer. device %s"), v4l2src->v4l2object->videodev));
break;
case EIO: case EIO:
GST_DEBUG_OBJECT (v4l2src, GST_DEBUG_OBJECT (v4l2src,
"VIDIOC_DQBUF failed due to an internal error." "VIDIOC_DQBUF failed due to an internal error."
@ -195,19 +191,49 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
} }
if (--trials == -1) { if (--trials == -1) {
return -1; goto too_many_trials;
} else { } else {
ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer); ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer);
memset (&buffer, 0x00, sizeof (buffer)); memset (&buffer, 0x00, sizeof (buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = v4l2src->breq.memory; buffer.memory = v4l2src->breq.memory;
} }
} }
GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index); GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
return buffer.index; return buffer.index;
/* ERRORS */
einval:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s"),
v4l2src->v4l2object->videodev),
(_("The buffer type is not supported, or the index is out of bounds,"
" or no buffers have been allocated yet, or the userptr"
" or length are invalid. device %s"),
v4l2src->v4l2object->videodev));
return -1;
}
nomem:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s. Not enough memory"),
v4l2src->v4l2object->videodev),
(_("insufficient memory to enqueue a user pointer buffer. device %s"),
v4l2src->v4l2object->videodev));
return -1;
}
too_many_trials:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s"),
v4l2src->v4l2object->videodev),
(_("Failed after 100 tries. device %s"),
v4l2src->v4l2object->videodev));
return -1;
}
} }
@ -216,7 +242,6 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
* get capture parameters * get capture parameters
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_get_capture (GstV4l2Src * v4l2src) gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
{ {
@ -226,14 +251,20 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
memset (&v4l2src->format, 0, sizeof (struct v4l2_format)); memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0)
goto fmt_failed;
return TRUE;
/* ERRORS */
fmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("failed to get pixelformat for device %s"), (_("failed to get pixelformat for device %s"),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
return TRUE;
} }
@ -242,13 +273,11 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
* set capture parameters * set capture parameters
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_set_capture (GstV4l2Src * v4l2src, gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc * fmt, gint * width, gint * height, struct v4l2_fmtdesc * fmt, gint * width, gint * height,
guint * fps_n, guint * fps_d) guint * fps_n, guint * fps_d)
{ {
guint new_fps_n = *fps_n; guint new_fps_n = *fps_n;
guint new_fps_d = *fps_d; guint new_fps_d = *fps_d;
@ -258,9 +287,9 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
if (!gst_v4l2src_get_capture (v4l2src)) { /* error was posted */
if (!gst_v4l2src_get_capture (v4l2src))
goto fail; goto fail;
}
v4l2src->format.fmt.pix.width = *width; v4l2src->format.fmt.pix.width = *width;
v4l2src->format.fmt.pix.height = *height; v4l2src->format.fmt.pix.height = *height;
@ -268,13 +297,8 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED; v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, goto fmt_failed;
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
goto fail;
}
if (*width != v4l2src->format.fmt.pix.width || if (*width != v4l2src->format.fmt.pix.width ||
*height != v4l2src->format.fmt.pix.height) { *height != v4l2src->format.fmt.pix.height) {
@ -283,18 +307,12 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
v4l2src->format.fmt.pix.height, fmt->description); v4l2src->format.fmt.pix.height, fmt->description);
} }
/* update internal info */ /* update internal info, posted error */
if (!gst_v4l2src_get_capture (v4l2src)) { if (!gst_v4l2src_get_capture (v4l2src))
goto fail; goto fail;
}
if (fmt->pixelformat != v4l2src->format.fmt.pix.pixelformat) { if (fmt->pixelformat != v4l2src->format.fmt.pix.pixelformat)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, goto pixfmt_failed;
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
goto fail;
}
if (*fps_n) { if (*fps_n) {
if (gst_v4l2src_set_fps (v4l2src, &new_fps_n, &new_fps_d)) { if (gst_v4l2src_set_fps (v4l2src, &new_fps_n, &new_fps_d)) {
@ -313,30 +331,45 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
} }
} }
*width = v4l2src->format.fmt.pix.width; *width = v4l2src->format.fmt.pix.width;
*height = v4l2src->format.fmt.pix.height; *height = v4l2src->format.fmt.pix.height;
return TRUE; return TRUE;
fail: /* ERRORS */
fmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
pixfmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
return FALSE;
}
fail:
{
return FALSE;
}
}
/****************************************************** /******************************************************
* gst_v4l2src_capture_init(): * gst_v4l2src_capture_init():
* initialize the capture system * initialize the capture system
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_capture_init (GstV4l2Src * v4l2src) gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
{ {
gint n; gint n;
guint buffers; guint buffers;
GstV4l2Buffer *buffer;
GST_DEBUG_OBJECT (v4l2src, "initting the capture system"); GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
@ -345,36 +378,25 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
/* request buffer info */ /* request buffer info */
buffers = v4l2src->breq.count; buffers = v4l2src->breq.count;
if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) {
if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS)
v4l2src->breq.count = GST_V4L2_MAX_BUFFERS; v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
} else if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
v4l2src->breq.count = GST_V4L2_MIN_BUFFERS; v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
}
v4l2src->breq.type = v4l2src->format.type; v4l2src->breq.type = v4l2src->format.type;
if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
v4l2src->breq.memory = V4L2_MEMORY_MMAP; v4l2src->breq.memory = V4L2_MEMORY_MMAP;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS,
&v4l2src->breq) < 0) { &v4l2src->breq) < 0)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, goto reqbufs_failed;
(_("Could not get buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("error requesting %d buffers. system error: %s",
v4l2src->breq.count, g_strerror (errno)));
return FALSE;
}
GST_LOG_OBJECT (v4l2src, "using default mmap method"); GST_LOG_OBJECT (v4l2src, "using default mmap method");
} else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) { } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
v4l2src->breq.memory = 0; v4l2src->breq.memory = 0;
GST_INFO_OBJECT (v4l2src, "using fallback read method"); GST_INFO_OBJECT (v4l2src, "using fallback read method");
} else { } else
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, goto broken_driver;
(_("the driver of device '%s' is broken."),
v4l2src->v4l2object->videodev),
("no supported read capability from %s",
v4l2src->v4l2object->videodev));
return FALSE;
}
/* Determine the device's framerate */ /* Determine the device's framerate */
if (!gst_v4l2src_update_fps (v4l2src->v4l2object)) { if (!gst_v4l2src_update_fps (v4l2src->v4l2object)) {
@ -384,15 +406,9 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
} }
if (v4l2src->breq.memory > 0) { if (v4l2src->breq.memory > 0) {
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) { if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, goto no_buffers;
(_("Could not get enough buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("we received %d, we want at least %d",
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
v4l2src->breq.count = buffers;
return FALSE;
}
if (v4l2src->breq.count != buffers) if (v4l2src->breq.count != buffers)
g_object_notify (G_OBJECT (v4l2src), "num_buffers"); g_object_notify (G_OBJECT (v4l2src), "num_buffers");
@ -412,7 +428,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count); v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
for (n = 0; n < v4l2src->breq.count; n++) { for (n = 0; n < v4l2src->breq.count; n++) {
GstV4l2Buffer *buffer = &v4l2src->pool->buffers[n]; buffer = &v4l2src->pool->buffers[n];
gst_atomic_int_set (&buffer->refcount, 1); gst_atomic_int_set (&buffer->refcount, 1);
buffer->pool = v4l2src->pool; buffer->pool = v4l2src->pool;
@ -422,28 +438,19 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
buffer->buffer.memory = v4l2src->breq.memory; buffer->buffer.memory = v4l2src->breq.memory;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QUERYBUF, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QUERYBUF,
&buffer->buffer) < 0) { &buffer->buffer) < 0)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, goto querybuf_failed;
(_("Could not get buffer properties of buffer %d"), n),
GST_ERROR_SYSTEM);
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
buffer->start = buffer->start =
mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
v4l2src->v4l2object->video_fd, buffer->buffer.m.offset); v4l2src->v4l2object->video_fd, buffer->buffer.m.offset);
if (buffer->start == MAP_FAILED) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, if (buffer->start == MAP_FAILED)
(_("Could not mmap video buffer %d: %s"), n), GST_ERROR_SYSTEM); goto mmap_failed;
buffer->start = 0;
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
buffer->length = buffer->buffer.length; buffer->length = buffer->buffer.length;
if (!gst_v4l2src_queue_frame (v4l2src, n)) { if (!gst_v4l2src_queue_frame (v4l2src, n))
gst_v4l2src_capture_deinit (v4l2src); goto queue_failed;
return FALSE;
}
} }
} else { } else {
GST_LOG_OBJECT (v4l2src, "no buffer pool used"); GST_LOG_OBJECT (v4l2src, "no buffer pool used");
@ -453,6 +460,57 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
GST_V4L2_SET_ACTIVE (v4l2src->v4l2object); GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
return TRUE; return TRUE;
/* ERRORS */
reqbufs_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("error requesting %d buffers. system error: %s",
v4l2src->breq.count, g_strerror (errno)));
return FALSE;
}
broken_driver:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("the driver of device '%s' is broken."),
v4l2src->v4l2object->videodev),
("no supported read capability from %s",
v4l2src->v4l2object->videodev));
return FALSE;
}
no_buffers:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get enough buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("we received %d, we want at least %d",
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
v4l2src->breq.count = buffers;
return FALSE;
}
querybuf_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get buffer properties of buffer %d"), n),
GST_ERROR_SYSTEM);
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
mmap_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not mmap video buffer %d: %s"), n), GST_ERROR_SYSTEM);
gst_v4l2src_capture_deinit (v4l2src);
buffer->start = 0;
return FALSE;
}
queue_failed:
{
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
} }
@ -461,7 +519,6 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
* start streaming capture * start streaming capture
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_capture_start (GstV4l2Src * v4l2src) gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
{ {
@ -470,15 +527,22 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
GST_DEBUG_OBJECT (v4l2src, "starting the capturing"); GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
/* gst_pad_renegotiate (v4l2src->srcpad); FIX: is it still required in 0.10 */
}
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
v4l2src->quit = FALSE; v4l2src->quit = FALSE;
if (v4l2src->breq.memory != 0) { if (v4l2src->breq.memory != 0) {
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0)
goto streamon_failed;
}
v4l2src->is_capturing = TRUE;
return TRUE;
/* ERRORS */
streamon_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ,
(_("Error starting streaming capture from device %s"), (_("Error starting streaming capture from device %s"),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM); v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
@ -486,36 +550,26 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
} }
} }
v4l2src->is_capturing = TRUE;
return TRUE;
}
/****************************************************** /******************************************************
* gst_v4l2src_capture_stop(): * gst_v4l2src_capture_stop():
* stop streaming capture * stop streaming capture
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_capture_stop (GstV4l2Src * v4l2src) gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
{ {
gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE; gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
GST_DEBUG_OBJECT (v4l2src, "stopping capturing"); GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
if (v4l2src->breq.memory != 0) { if (v4l2src->breq.memory != 0) {
/* we actually need to sync on all queued buffers but not /* we actually need to sync on all queued buffers but not
* on the non-queued ones */ * on the non-queued ones */
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0)
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, goto streamoff_failed;
(_("Error stopping streaming capture from device %s: %s"),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
} }
/* make an optional pending wait stop */ /* make an optional pending wait stop */
@ -523,6 +577,15 @@ gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
v4l2src->is_capturing = FALSE; v4l2src->is_capturing = FALSE;
return TRUE; return TRUE;
/* ERRORS */
streamoff_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE,
(_("Error stopping streaming capture from device %s: %s"),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
} }
static void static void
@ -570,7 +633,6 @@ gst_v4l2src_free_buffer (GstBuffer * buffer)
* deinitialize the capture system * deinitialize the capture system
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
{ {
@ -608,20 +670,20 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
*/ */
if (try_reinit) { if (try_reinit) {
if (!gst_v4l2src_capture_start (v4l2src) || if (!gst_v4l2src_capture_start (v4l2src) ||
!gst_v4l2src_capture_stop (v4l2src)) !gst_v4l2src_capture_stop (v4l2src)) {
GST_DEBUG_OBJECT (v4l2src, "failed reinit device");
return FALSE; return FALSE;
} }
} }
}
GST_V4L2_SET_INACTIVE (v4l2src->v4l2object); GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
return TRUE; return TRUE;
} }
/* /*
*/ */
gboolean gboolean
gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc * format, struct v4l2_fmtdesc * format,
@ -642,6 +704,8 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
fmt.fmt.pix.pixelformat = format->pixelformat; fmt.fmt.pix.pixelformat = format->pixelformat;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get min size: %s",
g_strerror (errno));
return FALSE; return FALSE;
} }
@ -649,12 +713,15 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
*min_w = fmt.fmt.pix.width; *min_w = fmt.fmt.pix.width;
if (min_h) if (min_h)
*min_h = fmt.fmt.pix.height; *min_h = fmt.fmt.pix.height;
GST_LOG_OBJECT (v4l2src, GST_LOG_OBJECT (v4l2src,
"got min size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); "got min size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
fmt.fmt.pix.width = 4096; fmt.fmt.pix.width = 4096;
fmt.fmt.pix.height = 4096; fmt.fmt.pix.height = 4096;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get max size: %s",
g_strerror (errno));
return FALSE; return FALSE;
} }
@ -662,6 +729,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
*max_w = fmt.fmt.pix.width; *max_w = fmt.fmt.pix.width;
if (max_h) if (max_h)
*max_h = fmt.fmt.pix.height; *max_h = fmt.fmt.pix.height;
GST_LOG_OBJECT (v4l2src, GST_LOG_OBJECT (v4l2src,
"got max size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); "got max size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
@ -680,29 +748,49 @@ gst_v4l2src_update_fps (GstV4l2Object * v4l2object)
gboolean gboolean
gst_v4l2src_set_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) gst_v4l2src_set_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
{ {
GstV4l2Object *v4l2object = v4l2src->v4l2object; GstV4l2Object *v4l2object = v4l2src->v4l2object;
struct v4l2_streamparm stream; struct v4l2_streamparm stream;
GST_LOG_OBJECT (v4l2src, "setting fps %d, %d", *fps_n, *fps_d);
memset (&stream, 0x00, sizeof (struct v4l2_streamparm)); memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 && if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0)
stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { goto gparm_failed;
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
goto no_timeperframe;
stream.parm.capture.timeperframe.denominator = *fps_n; stream.parm.capture.timeperframe.denominator = *fps_n;
stream.parm.capture.timeperframe.numerator = *fps_d; stream.parm.capture.timeperframe.numerator = *fps_d;
if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) == 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) < 0)
goto sparm_failed;
*fps_n = stream.parm.capture.timeperframe.denominator; *fps_n = stream.parm.capture.timeperframe.denominator;
*fps_d = stream.parm.capture.timeperframe.numerator; *fps_d = stream.parm.capture.timeperframe.numerator;
GST_LOG_OBJECT (v4l2src, "fps set to %d, %d", *fps_n, *fps_d);
return TRUE; return TRUE;
}
}
/* ERRORS */
gparm_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
return FALSE; return FALSE;
} }
no_timeperframe:
{
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
return FALSE;
}
sparm_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to set PARM: %s", g_strerror (errno));
return FALSE;
}
}
gboolean gboolean
gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
@ -711,6 +799,7 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
v4l2_std_id std; v4l2_std_id std;
struct v4l2_streamparm stream; struct v4l2_streamparm stream;
const GList *item; const GList *item;
gboolean found;
if (!GST_V4L2_IS_OPEN (v4l2object)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
@ -718,36 +807,60 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
/* Try to get the frame rate directly from the device using VIDIOC_G_PARM */ /* Try to get the frame rate directly from the device using VIDIOC_G_PARM */
memset (&stream, 0x00, sizeof (struct v4l2_streamparm)); memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 &&
stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
goto try_stds;
}
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
goto try_stds;
}
/* Note: V4L2 gives us the frame interval, we need the frame rate */ /* Note: V4L2 gives us the frame interval, we need the frame rate */
*fps_n = stream.parm.capture.timeperframe.denominator; *fps_n = stream.parm.capture.timeperframe.denominator;
*fps_d = stream.parm.capture.timeperframe.numerator; *fps_d = stream.parm.capture.timeperframe.numerator;
GST_DEBUG_OBJECT (v4l2src, GST_DEBUG_OBJECT (v4l2src,
"frame rate returned by G_PARM: %d/%d fps", *fps_n, *fps_d); "frame rate returned by G_PARM: %d/%d fps", *fps_n, *fps_d);
return TRUE; /* and we are done now */
} goto done;
try_stds:
/* If G_PARM failed, try to get the same information from the video standard */ /* If G_PARM failed, try to get the same information from the video standard */
if (!gst_v4l2_get_norm (v4l2object, &std)) if (!gst_v4l2_get_norm (v4l2object, &std))
return FALSE; return FALSE;
found = FALSE;
for (item = v4l2object->stds; item != NULL; item = item->next) { for (item = v4l2object->stds; item != NULL; item = item->next) {
GstV4l2TunerNorm *v4l2norm = item->data; GstV4l2TunerNorm *v4l2norm = item->data;
if (v4l2norm->index == std) { if (v4l2norm->index == std) {
*fps_n = GValue *framerate = &GST_TUNER_NORM (v4l2norm)->framerate;
gst_value_get_fraction_numerator (&GST_TUNER_NORM (v4l2norm)->
framerate); *fps_n = gst_value_get_fraction_numerator (framerate);
*fps_d = *fps_d = gst_value_get_fraction_denominator (framerate);
gst_value_get_fraction_denominator (&GST_TUNER_NORM (v4l2norm)->
framerate);
GST_DEBUG_OBJECT (v4l2src, GST_DEBUG_OBJECT (v4l2src,
"frame rate returned by get_norm: %d/%d fps", *fps_n, *fps_d); "frame rate returned by get_norm: %d/%d fps", *fps_n, *fps_d);
return TRUE; found = TRUE;
break;
} }
} }
return FALSE; /* nothing found, that's an error */
if (!found)
goto failed;
done:
return TRUE;
/* ERRORS */
failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to get framerate");
return FALSE;
}
} }
#define GST_TYPE_V4L2SRC_BUFFER (gst_v4l2src_buffer_get_type()) #define GST_TYPE_V4L2SRC_BUFFER (gst_v4l2src_buffer_get_type())
@ -812,7 +925,6 @@ gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer)
GstV4l2Buffer *buf = v4l2src_buffer->buf; GstV4l2Buffer *buf = v4l2src_buffer->buf;
if (buf) { if (buf) {
GST_LOG ("freeing buffer %p (nr. %d)", buf, buf->buffer.index); GST_LOG ("freeing buffer %p (nr. %d)", buf, buf->buffer.index);
if (!g_atomic_int_dec_and_test (&buf->refcount)) { if (!g_atomic_int_dec_and_test (&buf->refcount)) {
@ -825,7 +937,6 @@ gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer)
/* we're last thing that used all this */ /* we're last thing that used all this */
gst_v4l2src_buffer_pool_free (buf->pool, TRUE); gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
} }
} }
} }
@ -845,9 +956,6 @@ gst_v4l2src_buffer_new (GstV4l2Src * v4l2src, guint size, guint8 * data,
GST_LOG_OBJECT (v4l2src, GST_LOG_OBJECT (v4l2src,
"creating buffer %p (nr. %d)", srcbuf, srcbuf->buffer.index); "creating buffer %p (nr. %d)", srcbuf, srcbuf->buffer.index);
} }
GST_BUFFER_SIZE (buf) = size; GST_BUFFER_SIZE (buf) = size;
GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (buf) =