From fdd167aeb1c6b502ea64bff91416f79e97d8d1d7 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 17 Jan 2007 14:30:50 +0000 Subject: [PATCH] sys/v4l2/: Fix EIO handing when capturing. Add new property to specify the number of buffers to enque (and remove the... Original commit message from CVS: * sys/v4l2/gstv4l2object.c: (gst_v4l2_object_install_properties_helper), (gst_v4l2_object_set_property_helper), (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults): * sys/v4l2/gstv4l2object.h: * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_init), (gst_v4l2src_set_property), (gst_v4l2src_get_property), (gst_v4l2src_set_caps): * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list), (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture), (gst_v4l2src_capture_init), (gst_v4l2src_capture_start), (gst_v4l2src_capture_deinit): Fix EIO handing when capturing. Add new property to specify the number of buffers to enque (and remove the borked num-buffers usage). --- ChangeLog | 29 ++++++++++++++++++++++ sys/v4l2/gstv4l2object.c | 34 ++----------------------- sys/v4l2/gstv4l2object.h | 14 ++++------- sys/v4l2/gstv4l2src.c | 17 ++++++++++++- sys/v4l2/v4l2src_calls.c | 64 +++++++++++++++++++++++++++++++----------------- 5 files changed, 93 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index ae37a80..5d77475 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2007-01-17 Stefan Kost + + * sys/v4l2/gstv4l2object.c: + (gst_v4l2_object_install_properties_helper), + (gst_v4l2_object_set_property_helper), + (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults): + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), + (gst_v4l2src_init), (gst_v4l2src_set_property), + (gst_v4l2src_get_property), (gst_v4l2src_set_caps): + * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list), + (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture), + (gst_v4l2src_capture_init), (gst_v4l2src_capture_start), + (gst_v4l2src_capture_deinit): + Fix EIO handing when capturing. Add new property to specify the number of + buffers to enque (and remove the borked num-buffers usage). + +2007-01-16 Stefan Kost + + * gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query), + (gst_avi_demux_parse_index), (gst_avi_demux_stream_index), + (gst_avi_demux_sync), (gst_avi_demux_next_data_buffer), + (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index), + (gst_avi_demux_calculate_durations_from_index), + (gst_avi_demux_push_event), (gst_avi_demux_stream_header_pull), + (gst_avi_demux_handle_seek), (gst_avi_demux_stream_data), + (gst_avi_demux_loop): + Fix hanging when demuxing fuzzed file (#397229). Add some more debug. + 2007-01-16 Stefan Kost Patch by: Sebastian Dröge diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 32d1a55..7f8df17 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -244,20 +244,6 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class) g_object_class_install_property (gobject_class, PROP_FLAGS, g_param_spec_flags ("flags", "Flags", "Device type flags", GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS, G_PARAM_READABLE)); -/* FIXME norm, channel, frequency are part of the tuner interface, so they - should be removed from the properties - g_object_class_install_property (gobject_class, PROP_NORM, - g_param_spec_string ("norm", "Norm", "Standard norm to use", - DEFAULT_PROP_NORM, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_CHANNEL, - g_param_spec_string ("channel", "Channel", - "Input/output channel to switch to", DEFAULT_PROP_CHANNEL, - 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, DEFAULT_PROP_FREQUENCY, - G_PARAM_READWRITE)); -*/ } GstV4l2Object * @@ -314,6 +300,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object, g_free (v4l2object->videodev); v4l2object->videodev = g_value_dup_string (value); break; +#if 0 case PROP_NORM: if (GST_V4L2_IS_OPEN (v4l2object)) { GstTuner *tuner = GST_TUNER (v4l2object->element); @@ -363,6 +350,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object, v4l2object->frequency = g_value_get_ulong (value); } break; +#endif default: return FALSE; break; @@ -407,15 +395,6 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object, g_value_set_flags (value, flags); break; } - case PROP_NORM: - g_value_set_string (value, v4l2object->norm); - break; - case PROP_CHANNEL: - g_value_set_string (value, v4l2object->channel); - break; - case PROP_FREQUENCY: - g_value_set_ulong (value, v4l2object->frequency); - break; default: return FALSE; break; @@ -441,9 +420,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object) g_free (v4l2object->norm); v4l2object->norm = g_strdup (norm->label); gst_tuner_norm_changed (tuner, norm); -/* FIXME: remove - g_object_notify (G_OBJECT (v4l2object->element), "norm"); -*/ } } @@ -458,9 +434,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object) g_free (v4l2object->channel); v4l2object->channel = g_strdup (channel->label); gst_tuner_channel_changed (tuner, channel); -/* FIXME: remove - g_object_notify (G_OBJECT (v4l2object->element), "channel"); -*/ } if (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { @@ -472,9 +445,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object) /* guess */ gst_tuner_set_frequency (tuner, channel, 1000); } else { -/* FIXME: remove - g_object_notify (G_OBJECT (v4l2object->element), "frequency"); -*/ } } } diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index 3447073..906cff9 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -105,16 +105,12 @@ struct _GstV4l2ObjectClassHelper { GList *devices; }; -GType gst_v4l2_object_get_type(void); - -#define V4L2_STD_OBJECT_PROPS \ - PROP_DEVICE, \ - PROP_DEVICE_NAME, \ - PROP_FLAGS, \ - PROP_NORM, \ - PROP_CHANNEL, \ - PROP_FREQUENCY +GType gst_v4l2_object_get_type (void); +#define V4L2_STD_OBJECT_PROPS \ + PROP_DEVICE, \ + PROP_DEVICE_NAME, \ + PROP_FLAGS /* create/destroy */ GstV4l2Object * gst_v4l2_object_new (GstElement * element, diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 3b28475..862114b 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -58,7 +58,6 @@ GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source", "Ronald Bultje ," " Edgard Lima "); - GST_DEBUG_CATEGORY (v4l2src_debug); #define GST_CAT_DEFAULT v4l2src_debug @@ -66,6 +65,7 @@ enum { PROP_0, V4L2_STD_OBJECT_PROPS, + PROP_QUEUE_SIZE }; static const guint32 gst_v4l2_formats[] = { @@ -274,6 +274,11 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass) gobject_class->get_property = gst_v4l2src_get_property; gst_v4l2_object_install_properties_helper (gobject_class); + g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE, + g_param_spec_uint ("queue-size", "Queue size", + "Number of buffers to be enqueud in the driver", + GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, GST_V4L2_MIN_BUFFERS, + G_PARAM_READWRITE)); basesrc_class->get_caps = gst_v4l2src_get_caps; basesrc_class->set_caps = gst_v4l2src_set_caps; @@ -289,6 +294,7 @@ 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); + /* number of buffers requested */ v4l2src->breq.count = 0; v4l2src->formats = NULL; @@ -332,6 +338,9 @@ gst_v4l2src_set_property (GObject * object, if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object, prop_id, value, pspec)) { switch (prop_id) { + case PROP_QUEUE_SIZE: + v4l2src->breq.count = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -352,6 +361,9 @@ gst_v4l2src_get_property (GObject * object, if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object, prop_id, value, pspec)) { switch (prop_id) { + case PROP_QUEUE_SIZE: + g_value_set_uint (value, v4l2src->breq.count); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -776,6 +788,7 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) /* make sure we stop capturing and dealloc buffers */ if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { + /* both will throw an element-error on failure */ if (!gst_v4l2src_capture_stop (v4l2src)) return FALSE; if (!gst_v4l2src_capture_deinit (v4l2src)) @@ -786,6 +799,8 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) /* we want our own v4l2 type of fourcc codes */ if (!(format = gst_v4l2_caps_to_v4l2fourcc (v4l2src, structure))) { + GST_DEBUG_OBJECT (v4l2src, "can't get capture format from caps %" + GST_PTR_FORMAT, caps); return FALSE; } diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 79b9f69..fd956ae 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -150,7 +150,7 @@ qbuf_failed: gint gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) { -#define NUM_TRIALS 100 +#define NUM_TRIALS 50 struct v4l2_buffer buffer; gint32 trials = NUM_TRIALS; @@ -158,6 +158,12 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = v4l2src->breq.memory; while (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF, &buffer) < 0) { + + GST_LOG_OBJECT (v4l2src, + "problem grabbing frame %ld (ix=%ld), trials=%ld, pool-ct=%d, buf.flags=%d", + buffer.sequence, buffer.index, trials, v4l2src->pool->refcount, + buffer.flags); + /* if the sync() got interrupted, we can retry */ switch (errno) { case EAGAIN: @@ -169,14 +175,31 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) case EINVAL: goto einval; case ENOMEM: - goto nomem; + goto enomem; case EIO: - GST_WARNING_OBJECT (v4l2src, + GST_INFO_OBJECT (v4l2src, "VIDIOC_DQBUF failed due to an internal error." " Can also indicate temporary problems like signal loss." " Note the driver might dequeue an (empty) buffer despite" " returning an error, or even stop capturing." " device %s", v4l2src->v4l2object->videodev); + /* have we de-queued a buffer ? */ + if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { + /* this fails + if ((buffer.index >= 0) && (buffer.index < v4l2src->breq.count)) { + GST_DEBUG_OBJECT (v4l2src, "reenqueing buffer (ix=%ld)", buffer.index); + gst_v4l2src_queue_frame (v4l2src, buffer.index); + } + else { + */ + GST_DEBUG_OBJECT (v4l2src, "reenqueing buffer"); + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer) < 0) { + GST_WARNING_OBJECT (v4l2src, + "Error queueing buffer on device %s. system error: %s", + v4l2src->v4l2object->videodev, g_strerror (errno)); + } + /*} */ + } break; case EINTR: GST_WARNING_OBJECT (v4l2src, @@ -194,15 +217,14 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) if (--trials == -1) { goto too_many_trials; } else { - if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer) < 0) - goto qbuf_failed; memset (&buffer, 0x00, sizeof (buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = v4l2src->breq.memory; } } - GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index); + GST_LOG_OBJECT (v4l2src, "grabbed frame %ld (ix=%ld), pool-ct=%d", + buffer.sequence, buffer.index, v4l2src->pool->refcount); return buffer.index; @@ -218,7 +240,7 @@ einval: v4l2src->v4l2object->videodev)); return -1; } -nomem: +enomem: { GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED, (_("Failed trying to get video frames from device '%s'. Not enough memory."), v4l2src->v4l2object->videodev), (_("insufficient memory to enqueue a user pointer buffer. device %s."), v4l2src->v4l2object->videodev)); @@ -233,15 +255,6 @@ too_many_trials: NUM_TRIALS, v4l2src->v4l2object->videodev, g_strerror (errno))); return -1; } -qbuf_failed: - { - GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE, - (_("Could not exchange data with device '%s'."), - v4l2src->v4l2object->videodev), - ("Error queueing buffer on device %s. system error: %s", - v4l2src->v4l2object->videodev, g_strerror (errno))); - return -1; - } } @@ -390,7 +403,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) guint buffers; GstV4l2Buffer *buffer; - GST_DEBUG_OBJECT (v4l2src, "initting the capture system"); + GST_DEBUG_OBJECT (v4l2src, "initializing the capture system"); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); @@ -398,10 +411,8 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) /* request buffer info */ buffers = v4l2src->breq.count; - if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) - v4l2src->breq.count = GST_V4L2_MAX_BUFFERS; - else if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) - v4l2src->breq.count = GST_V4L2_MIN_BUFFERS; + v4l2src->breq.count = CLAMP (v4l2src->breq.count, GST_V4L2_MIN_BUFFERS, + GST_V4L2_MAX_BUFFERS); v4l2src->breq.type = v4l2src->format.type; if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { @@ -429,7 +440,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) goto no_buffers; if (v4l2src->breq.count != buffers) - g_object_notify (G_OBJECT (v4l2src), "num_buffers"); + g_object_notify (G_OBJECT (v4l2src), "queue-size"); GST_INFO_OBJECT (v4l2src, "Got %d buffers (%" GST_FOURCC_FORMAT ") of size %d KB", @@ -532,6 +543,11 @@ mmap_failed: } queue_failed: { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Could not enqueue buffers in device '%s'."), + v4l2src->v4l2object->videodev), + ("enqueing buffer %d/%d failed. (%d - %s)", + n, v4l2src->breq.count, errno, g_strerror (errno))); gst_v4l2src_capture_deinit (v4l2src); return FALSE; } @@ -549,6 +565,7 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src) gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE; GST_DEBUG_OBJECT (v4l2src, "starting the capturing"); + //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); v4l2src->quit = FALSE; @@ -680,7 +697,8 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) if (try_reinit) { gst_v4l2src_capture_start (v4l2src); if (!gst_v4l2src_capture_stop (v4l2src)) { - GST_DEBUG_OBJECT (v4l2src, "failed reinit device"); + /* stop throws an element-error on failure */ + GST_WARNING_OBJECT (v4l2src, "failed reinit device"); return FALSE; } } -- 2.7.4