diff mbox

[FFmpeg-devel] libavdevice/v4l2: Return EAGAIN when receiving a frame of unexpected size

Message ID 20190317150553.GA13110@akuma.local
State New
Headers show

Commit Message

Alexander Strasser March 17, 2019, 3:06 p.m. UTC
I had found that when capturing video for some hours from
USB Camera-B4.09.24.1 (Manufacturer: OmniVision Technologies, Inc.),
sometimes when invoking the ioctl DQBUF, the returned buffer is not
filled with the size we expect for the raw video frame.

Here are two examples for such occurrences:

    [video4linux2,v4l2 @ 0x258b440] Dequeued v4l2 buffer contains 609596 bytes, but 614400 were expected. Flags: 0x00000001.
    /dev/video1: Invalid data found when processing input

    [video4linux2,v4l2 @ 0x225f440] Dequeued v4l2 buffer contains 609508 bytes, but 614400 were expected. Flags: 0x00000001.
    /dev/video1: Invalid data found when processing input

The ffmpeg CLI tool will then stop capturing and exit.

To avoid this, return AVERROR(EAGAIN) instead.

While searching for the above quoted error message I found a ticket
that mentions this type of problem on our tracker.

Probably fixes #4795
---

We re-discovered this problem that was reported many years ago, while running
the motion vector demo at Chemnitzer Linux-Tage yesterday and today.

 libavdevice/v4l2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Nicolas George March 17, 2019, 5:25 p.m. UTC | #1
Alexander Strasser (12019-03-17):
> I had found that when capturing video for some hours from
> USB Camera-B4.09.24.1 (Manufacturer: OmniVision Technologies, Inc.),
> sometimes when invoking the ioctl DQBUF, the returned buffer is not
> filled with the size we expect for the raw video frame.

Which seems like a kernel bug, does it not?

> To avoid this, return AVERROR(EAGAIN) instead.

Returning EAGAIN when not in non-blocking mode is invalid. FFERROR_REDO
would be the correct code in that case.

Regards,
Alexander Strasser March 17, 2019, 11:20 p.m. UTC | #2
On 2019-03-17 18:25 +0100, Nicolas George wrote:
> Alexander Strasser (12019-03-17):
> > I had found that when capturing video for some hours from
> > USB Camera-B4.09.24.1 (Manufacturer: OmniVision Technologies, Inc.),
> > sometimes when invoking the ioctl DQBUF, the returned buffer is not
> > filled with the size we expect for the raw video frame.
> 
> Which seems like a kernel bug, does it not?

Seems like a kernel bug, yes. Probably driver specific. Though I am not
100% sure it is strictly a bug. Might be that this is the best a driver
for a particular hardware can do.

In any case at least 2 different and probably more devices exhibited the
described behaviour, which was never a permanent failure. I suspect some
drivers will always exhibit this behavior sometimes. That's why I think
we should handle this particular case more graceful.


> > To avoid this, return AVERROR(EAGAIN) instead.
> 
> Returning EAGAIN when not in non-blocking mode is invalid. FFERROR_REDO
> would be the correct code in that case.

Maybe using EAGAIN wasn't a good choice :(

Using FFERROR_REDO sounds promising. I will try that.

I tested the EAGAIN version and it worked. I also tested returning a
zero-sized packet, like in the case where V4L flags the data as corrupt,
that worked too. See commit 28f20d2ff487aa589643d8f70eaf614b78839685

Do you think the zero-sized packet would be better than returning
FFERROR_REDO?


Thanks for your comments!

  Alexander
Nicolas George March 17, 2019, 11:24 p.m. UTC | #3
Alexander Strasser (12019-03-18):
> I tested the EAGAIN version and it worked. I also tested returning a

ffmpeg.c uses the non-blocking mode.

> zero-sized packet, like in the case where V4L flags the data as corrupt,
> that worked too. See commit 28f20d2ff487aa589643d8f70eaf614b78839685
> 
> Do you think the zero-sized packet would be better than returning
> FFERROR_REDO?

I think it depends on what happens exactly with that frame? What is the
partial packet returned? Is there a timestamp? Etc.

Regards,
Alexander Strasser March 18, 2019, 10:26 p.m. UTC | #4
Hi Nicolas!

On 2019-03-18 00:24 +0100, Nicolas George wrote:
> Alexander Strasser (12019-03-18):
> > I tested the EAGAIN version and it worked. I also tested returning a
> 
> ffmpeg.c uses the non-blocking mode.

That would explain it. I now tested, the FFERROR_REDO approach,
and I think it works fine. As I don't have it available anymore,
I can't test with the device that gave me the errors. So I modified
the code to create the error condition.

Using FFERROR_REDO would work for blocking mode as well as non-blocking,
right?

It handles the error on a lower level inside the libs and doesn't
bubble up to the lib user AFAICT.


> > zero-sized packet, like in the case where V4L flags the data as corrupt,
> > that worked too. See commit 28f20d2ff487aa589643d8f70eaf614b78839685
> > 
> > Do you think the zero-sized packet would be better than returning
> > FFERROR_REDO?
> 
> I think it depends on what happens exactly with that frame? What is the
> partial packet returned? Is there a timestamp? Etc.

As mentioned above I can't dump more data to get a clue. I guess
the frame was just truncated and the timestamps were correct.

As we wouldn't pass on frame data to the user anyway, I would actually
prefer the FFERROR_REDO version.


  Alexander
Alexander Strasser March 20, 2019, 7:06 p.m. UTC | #5
On 2019-03-18 23:26 +0100, Alexander Strasser wrote:
> On 2019-03-18 00:24 +0100, Nicolas George wrote:
> > Alexander Strasser (12019-03-18):
> > > I tested the EAGAIN version and it worked. I also tested returning a
> >
> > ffmpeg.c uses the non-blocking mode.
>
> That would explain it. I now tested, the FFERROR_REDO approach,
> and I think it works fine. As I don't have it available anymore,
> I can't test with the device that gave me the errors. So I modified
> the code to create the error condition.
>
> Using FFERROR_REDO would work for blocking mode as well as non-blocking,
> right?
>
> It handles the error on a lower level inside the libs and doesn't
> bubble up to the lib user AFAICT.
>
>
> > > zero-sized packet, like in the case where V4L flags the data as corrupt,
> > > that worked too. See commit 28f20d2ff487aa589643d8f70eaf614b78839685
> > >
> > > Do you think the zero-sized packet would be better than returning
> > > FFERROR_REDO?
> >
> > I think it depends on what happens exactly with that frame? What is the
> > partial packet returned? Is there a timestamp? Etc.
>
> As mentioned above I can't dump more data to get a clue. I guess
> the frame was just truncated and the timestamps were correct.
>
> As we wouldn't pass on frame data to the user anyway, I would actually
> prefer the FFERROR_REDO version.

I sent a new patch changing the returned error code to FFERROR_REDO.

This patch can be considered rejected.


  Alexander
diff mbox

Patch

diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 1b9c6e7..894692e 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -542,7 +542,7 @@  static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
                    "Dequeued v4l2 buffer contains %d bytes, but %d were expected. Flags: 0x%08X.\n",
                    buf.bytesused, s->frame_size, buf.flags);
             enqueue_buffer(s, &buf);
-            return AVERROR_INVALIDDATA;
+            return AVERROR(EAGAIN);
         }
     }