Hello, as Reimar pointed out the proposed patch is not the correct solution. Please see/test attached patch. Regards,
Giorgio Vazzana 2014-08-31 14:35 GMT+02:00 Dmitry Volyntsev <xeioexcept...@gmail.com>: >>why is this condition true ? > > I tried several configuration and problem occurred only under certain > circumstances: > 1. webcam type: Logitech C310 (tried also: C350) > 2. capturing settings: 640*480, 422p > 3. simultaneous capturing from two webcams > 4. relatively old laptop (Lenovo Z470, Z570, L420) > > I think it somehow relate to usb hub bandwidth and laptop performance > issue (and maybe length of usb cable?) > > I use my own app (24/7 surveillance home recording) which depends on > libavdevice and prefer to ignore AVERROR_INVALIDDATA in this case > (just skip the broken frame and continue) because reconnect to devices > required more than a half of second. With my patch everything goes > fine (more than 2 week of continuous recording) > > logs: > [video4linux2,v4l2 @ 0x2efec00]The v4l2 frame is 614396 bytes, but > 614400 bytes are expected > [video4linux2,v4l2 @ 0x2efec00]The v4l2 frame is 614396 bytes, but > 614400 bytes are expected > > > > On Sat, Aug 30, 2014 at 9:17 PM, Michael Niedermayer <michae...@gmx.at> wrote: >> On Sat, Aug 30, 2014 at 08:19:37PM +0400, Dmitry Volyntsev wrote: >>> To understand the problem one needs to see the original code around >>> and to think what would happen if from time to time while capturing >>> condition (s->frame_size > 0 && buf.bytesused != s->frame_size) >>> happens to be true (this is not critical error so capturing would >>> continue). It is obvious that eventually buffers_queued would become < >>> 1. >> >> why is this condition true, what are these mismatching buffers ? >> >> >>> >>> static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) >>> { >>> ... >>> if (buf.index >= s->buffers) { >>> av_log(ctx, AV_LOG_ERROR, "Invalid buffer index received.\n"); >>> >>> return AVERROR(EINVAL); >>> } >>> >>> avpriv_atomic_int_add_and_fetch(&s->buffers_queued, -1); >>> // always keep at least one buffer queued >>> av_assert0(avpriv_atomic_int_get(&s->buffers_queued) >= 1); >>> >>> if (s->frame_size > 0 && buf.bytesused != s->frame_size) { >>> av_log(ctx, AV_LOG_ERROR, >>> "The v4l2 frame is %d bytes, but %d bytes are expected\n", >>> buf.bytesused, s->frame_size); >>> return AVERROR_INVALIDDATA; >>> >>> } >>> >>> So my solution: we should make all checks here before decrementing >>> buffers_queued >>> >>> On Wed, Aug 27, 2014 at 1:20 AM, Michael Niedermayer <michae...@gmx.at> >>> wrote: >>> > On Wed, Aug 13, 2014 at 07:04:01PM +0400, Dmitry Volyntsev wrote: >>> >> From: Dmitry Volyntsev <xeioexcept...@gmail.com> >>> >> >>> >> s->buffers_queued constantly decremented and not incremented >>> >> in case of (s->frame_size > 0 && buf.bytesused != s->frame_size) >>> >> condition (caught on long run capture of Logitech C310) >>> > >>> > can you explain why this happens ? where do this misatching >>> > bufs come from ? >>> > why is droping them correct ? >>> > >>> > >>> > [...] >>> > -- >>> > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB >>> > >>> > Dictatorship naturally arises out of democracy, and the most aggravated >>> > form of tyranny and slavery out of the most extreme liberty. -- Plato >>> >>> >>> >>> -- >>> Be happy, >>> Best regards, >>> Dmitry Volyntsev >>> _______________________________________________ >>> ffmpeg-devel mailing list >>> ffmpeg-devel@ffmpeg.org >>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >>> >> >> -- >> Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB >> >> In a rich man's house there is no place to spit but his face. >> -- Diogenes of Sinope > > > > -- > Be happy, > Best regards, > Dmitry Volyntsev > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
From 241b1310bf7925a62bccba2151c2ca5d2bc61f15 Mon Sep 17 00:00:00 2001 From: Giorgio Vazzana <mywin...@gmail.com> Date: Mon, 1 Sep 2014 22:20:05 +0200 Subject: [PATCH] lavd/v4l2: introduce enqueue_buffer() Additionally, make sure a buffer gets enqueued again (even in error paths) after it has been succesfully dequeued. --- libavdevice/v4l2.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 9f9f944..b55052a 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -403,10 +403,23 @@ static void dummy_release_buffer(AVPacket *pkt) } #endif +static int enqueue_buffer(struct video_data *s, struct v4l2_buffer *buf) +{ + int res = 0; + + if (v4l2_ioctl(s->fd, VIDIOC_QBUF, buf) < 0) { + res = AVERROR(errno); + av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res)); + } else { + avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); + } + + return res; +} + static void mmap_release_buffer(void *opaque, uint8_t *data) { struct v4l2_buffer buf = { 0 }; - int res; struct buff_data *buf_descriptor = opaque; struct video_data *s = buf_descriptor->s; @@ -415,13 +428,7 @@ static void mmap_release_buffer(void *opaque, uint8_t *data) buf.index = buf_descriptor->index; av_free(buf_descriptor); - if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { - res = AVERROR(errno); - av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", - av_err2str(res)); - } - - avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); + enqueue_buffer(s, &buf); } #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) @@ -524,6 +531,7 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) av_log(ctx, AV_LOG_ERROR, "The v4l2 frame is %d bytes, but %d bytes are expected\n", buf.bytesused, s->frame_size); + enqueue_buffer(s, &buf); return AVERROR_INVALIDDATA; } @@ -533,19 +541,16 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) res = av_new_packet(pkt, buf.bytesused); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); - if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) - avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); + enqueue_buffer(s, &buf); return res; } memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused); - if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { - res = AVERROR(errno); - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res)); + res = enqueue_buffer(s, &buf); + if (res) { av_free_packet(pkt); return res; } - avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); } else { struct buff_data *buf_descriptor; @@ -563,8 +568,7 @@ FF_ENABLE_DEPRECATION_WARNINGS * allocate a buffer for memcpying into it */ av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); - if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) - avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); + enqueue_buffer(s, &buf); return AVERROR(ENOMEM); } @@ -575,8 +579,7 @@ FF_ENABLE_DEPRECATION_WARNINGS buf_descriptor, 0); if (!pkt->buf) { av_log(ctx, AV_LOG_ERROR, "Failed to create a buffer\n"); - if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) == 0) - avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1); + enqueue_buffer(s, &buf); av_freep(&buf_descriptor); return AVERROR(ENOMEM); } -- 1.7.9.5
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel