Commit d9db447d authored by Wim Taymans's avatar Wim Taymans
Browse files

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

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.
parent 9cadd004
......@@ -110,7 +110,6 @@ gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check,
g_free (device);
}
}
init = TRUE;
}
......@@ -150,9 +149,7 @@ gst_v4l2_probe_needs_probe (GstPropertyProbe * probe,
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
break;
}
return ret;
}
static GValueArray *
......@@ -254,19 +251,18 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class)
GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE));
g_object_class_install_property
(gobject_class, PROP_STD,
g_param_spec_string ("std", "std",
"standard (norm) to use", NULL, G_PARAM_READWRITE));
g_param_spec_string ("std", "Std",
"Standard (norm) to use", NULL, G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_INPUT,
g_param_spec_string ("input",
"input",
"input/output (channel) to switch to", NULL, G_PARAM_READWRITE));
"Input",
"Input/output (channel) to switch to", NULL, G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class, PROP_FREQUENCY,
g_param_spec_ulong ("frequency",
"frequency",
"frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
"Frequency",
"Frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
}
GstV4l2Object *
......@@ -275,13 +271,11 @@ gst_v4l2_object_new (GstElement * element,
GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func)
{
GstV4l2Object *v4l2object;
/*
* some default values
*/
v4l2object = g_new0 (GstV4l2Object, 1);
v4l2object->element = element;
......@@ -300,16 +294,12 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->xwindow_id = 0;
return v4l2object;
}
void
gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
{
if (*v4l2object) {
if ((*v4l2object)->videodev) {
g_free ((*v4l2object)->videodev);
(*v4l2object)->videodev = NULL;
......@@ -317,29 +307,24 @@ gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
g_free (*v4l2object);
*v4l2object = NULL;
}
}
gboolean
gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
case PROP_DEVICE:
if (v4l2object->videodev)
g_free (v4l2object->videodev);
v4l2object->videodev = g_strdup (g_value_get_string (value));
v4l2object->videodev = g_value_dup_string (value);
break;
case PROP_STD:
if (GST_V4L2_IS_OPEN (v4l2object)) {
GstTuner *tuner = GST_TUNER (v4l2object->element);
GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner,
(gchar *)
g_value_get_string (value));
(gchar *) g_value_get_string (value));
if (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)) {
GstTuner *tuner = GST_TUNER (v4l2object->element);
GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
(gchar *)
g_value_get_string (value));
(gchar *) g_value_get_string (value));
if (channel) {
/* like gst_tuner_set_channel (tuner, channel)
......@@ -389,9 +373,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
return FALSE;
break;
}
return TRUE;
}
......@@ -405,15 +387,15 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
break;
case PROP_DEVICE_NAME:
{
gchar *new = NULL;
const guchar *new = NULL;
if (GST_V4L2_IS_OPEN (v4l2object)) {
new = (gchar *) v4l2object->vcap.card;
new = v4l2object->vcap.card;
} else if (gst_v4l2_open (v4l2object)) {
new = (gchar *) v4l2object->vcap.card;
new = v4l2object->vcap.card;
gst_v4l2_close (v4l2object);
}
g_value_set_string (value, new);
g_value_set_string (value, (gchar *) new);
break;
}
case PROP_FLAGS:
......@@ -425,6 +407,8 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
(V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OUTPUT |
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)
flags |= V4L2_FBUF_CAP_CHROMAKEY;
}
......@@ -444,9 +428,7 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
return FALSE;
break;
}
return TRUE;
}
static void
......@@ -464,6 +446,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
norm =
GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
if (norm) {
/* FIXME, free old? */
v4l2object->std = g_strdup (norm->label);
gst_tuner_norm_changed (tuner, norm);
g_object_notify (G_OBJECT (v4l2object->element), "std");
......@@ -478,6 +461,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
channel =
GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object->
element)));
/* FIXME, free old? */
v4l2object->input = g_strdup (channel->label);
gst_tuner_channel_changed (tuner, channel);
g_object_notify (G_OBJECT (v4l2object->element), "input");
......@@ -498,7 +482,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
}
}
gboolean
gst_v4l2_object_start (GstV4l2Object * v4l2object)
{
......@@ -507,7 +490,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
else
return FALSE;
#ifdef HAVE_XVIDEO
gst_v4l2_xoverlay_start (v4l2object);
#endif
......@@ -518,7 +500,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
gboolean
gst_v4l2_object_stop (GstV4l2Object * v4l2object)
{
#ifdef HAVE_XVIDEO
gst_v4l2_xoverlay_stop (v4l2object);
#endif
......
......@@ -99,21 +99,17 @@ struct _GstV4l2Object {
GstV4l2GetInOutFunction get_in_out_func;
GstV4l2SetInOutFunction set_in_out_func;
GstV4l2UpdateFpsFunction update_fps_func;
};
struct _GstV4l2ObjectClassHelper {
/* probed devices */
GList *devices;
};
GType gst_v4l2_object_get_type(void);
#define V4L2_STD_OBJECT_PROPS \
PROP_DEVICE, \
PROP_DEVICE, \
PROP_DEVICE_NAME, \
PROP_FLAGS, \
PROP_STD, \
......
......@@ -37,7 +37,7 @@
* <programlisting>
* gst-launch v4l2src use-fixed-fps=true ! xvimagesink
* </programlisting>
* This exemple should be used to capture from web-cams
* This example should be used to capture from web-cams
* </para>
* </refsect2>
*/
......@@ -130,7 +130,6 @@ static const guint32 gst_v4l2_formats[] = {
#endif
};
#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
......@@ -297,13 +296,11 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
pushsrc_class->create = gst_v4l2src_create;
gobject_class->dispose = gst_v4l2src_dispose;
}
static void
gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
{
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
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);
}
if (((GObjectClass *) parent_class)->dispose)
((GObjectClass *) parent_class)->dispose (object);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
......@@ -349,24 +345,19 @@ gst_v4l2src_set_property (GObject * object,
g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
case PROP_USE_FIXED_FPS:
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
v4l2src->use_fixed_fps = g_value_get_boolean (value);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
}
......@@ -381,18 +372,15 @@ gst_v4l2src_get_property (GObject * object,
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
case PROP_USE_FIXED_FPS:
g_value_set_boolean (value, v4l2src->use_fixed_fps);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
}
......@@ -412,6 +400,8 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
structure = gst_caps_get_structure (caps, i);
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, "height", 4096);
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)) {
continue;
}
/* template */
/* template, FIXME, why limit if the device reported correct results. */
min_w = CLAMP (min_w, 1, 4096);
min_h = CLAMP (min_h, 1, 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,
"height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
/* FIXME, why random range? */
gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
1, 1, 100, 1, NULL);
gst_caps_append_structure (caps, structure);
}
}
......@@ -860,14 +850,13 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
"framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
}
}
return TRUE;
}
/* 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
negotiate method. stop will both stop capture and close the device.
*/
* 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.
*/
static gboolean
gst_v4l2src_start (GstBaseSrc * src)
{
......@@ -920,37 +909,42 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
} else if (amount == -1) {
if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
(_("error read()ing %d bytes on device %s"),
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
} else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d",
v4l2src->v4l2object->videodev, amount, buffersize));
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
} else
goto read_error;
} else
goto short_read;
} while (TRUE);
return GST_FLOW_OK;
/* ERRORS */
read_error:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
(_("error read()ing %d bytes on device %s"),
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
short_read:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d",
v4l2src->v4l2object->videodev, amount, buffersize));
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
{
gint i, num = -1;
gint i, num;
/* grab a frame from the device */
/* grab a frame from the device, post an error */
num = gst_v4l2src_grab_frame (v4l2src);
if (num == -1)
return GST_FLOW_ERROR;
goto grab_failed;
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 */
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
*buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i);
if (!gst_v4l2src_queue_frame (v4l2src, num)) {
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
/* posts an error message if something went wrong */
if (!gst_v4l2src_queue_frame (v4l2src, num))
goto queue_failed;
} else {
GST_LOG_OBJECT (v4l2src, "using mmap'd buffer");
*buf =
gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start,
&v4l2src->pool->buffers[num]);
/* 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->refcount);
}
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
......@@ -983,17 +991,22 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstFlowReturn ret;
if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0) {
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;
}
if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0)
goto no_framerate;
if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
ret = gst_v4l2src_get_mmap (v4l2src, buf);
} else {
ret = gst_v4l2src_get_read (v4l2src, buf);
}
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;
}
}
......@@ -48,23 +48,28 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
* get the device's capturing capabilities
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
{
GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities");
if (!GST_V4L2_IS_OPEN (v4l2object))
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,
(_("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;
}
return TRUE;
}
......@@ -73,7 +78,6 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
* fill/empty the lists of enumerations
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
{
......@@ -354,7 +358,6 @@ gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
* open the video device (v4l2object->videodev)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_open (GstV4l2Object * v4l2object)
{
......@@ -362,6 +365,7 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
v4l2object->videodev);
GST_V4L2_CHECK_NOT_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
......@@ -370,65 +374,80 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
v4l2object->videodev = g_strdup ("/dev/video");
/* check if it is a device */
if (-1 == stat (v4l2object->videodev, &st)) {
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;
/* 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) &&
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
goto not_capture;
/* 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);
return TRUE;
/* ERRORS */
stat_failed:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Cannot identify device '%s'"), v4l2object->videodev),
GST_ERROR_SYSTEM);
goto error;
}
if (!S_ISCHR (st.st_mode)) {
no_device:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("This isn't a device '%s'"), v4l2object->videodev),
GST_ERROR_SYSTEM);
goto error;
}
/* open the device */
v4l2object->video_fd =
open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
if (!GST_V4L2_IS_OPEN (v4l2object)) {
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;
}
/* get capabilities */
if (!gst_v4l2_get_capabilities (v4l2object)) {
goto error;
}
/* do we need to be a capture device? */
if (GST_IS_V4L2SRC (v4l2object) &&
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
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;
}
/* create enumerations */
if (!gst_v4l2_fill_lists (v4l2object))
goto error;
GST_INFO_OBJECT (v4l2object->element,
"Opened device '%s' (%s) successfully",
v4l2object->vcap.card, v4l2object->videodev);
return TRUE;