diff mbox

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

Message ID 20190320185333.GA5021@akuma.local
State New
Headers show

Commit Message

Alexander Strasser March 20, 2019, 6:56 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 FFERROR_REDO instead. I have not seen the
issue appearing twice or more often in a row. It was more like
one single error every two hours.

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

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

--

Comments

Alexander Strasser March 20, 2019, 9:26 p.m. UTC | #1
Hi all!

On 2019-03-20 19:56 +0100, Alexander Strasser wrote:
> 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 FFERROR_REDO instead. I have not seen the
> issue appearing twice or more often in a row. It was more like
> one single error every two hours.


After thinking about the FFERROR_REDO approach some more, I think it
is not ideal in the case where a driver permanently delivers frames
of unexpected size. The FFmpeg lib call would not return to the client,
potentially freezing the running program.

So maybe the zero-sized package approach, like we do with the corrupted
frames, is more robust here? Any opinions?


Best regards,
  Alexander


>
> While searching for the above quoted error message I found a ticket
> that mentions this type of problem on our tracker.
>
> Fixes #4795
> ---
>  libavdevice/v4l2.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
> index 1b9c6e7..5a1b324 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 FFERROR_REDO;
>          }
>      }
>
> --
Carl Eugen Hoyos March 20, 2019, 10:46 p.m. UTC | #2
2019-03-20 22:26 GMT+01:00, Alexander Strasser <eclipse7@gmx.net>:
> Hi all!
>
> On 2019-03-20 19:56 +0100, Alexander Strasser wrote:
>> 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 FFERROR_REDO instead. I have not seen the
>> issue appearing twice or more often in a row. It was more like
>> one single error every two hours.
>
>
> After thinking about the FFERROR_REDO approach some more, I think it
> is not ideal in the case where a driver permanently delivers frames
> of unexpected size. The FFmpeg lib call would not return to the client,
> potentially freezing the running program.
>
> So maybe the zero-sized package approach, like we do with the corrupted
> frames, is more robust here? Any opinions?

You could check if a sane frame was already received before the
wrong size.

Carl Eugen
Marton Balint March 20, 2019, 11:14 p.m. UTC | #3
On Wed, 20 Mar 2019, Carl Eugen Hoyos wrote:

> 2019-03-20 22:26 GMT+01:00, Alexander Strasser <eclipse7@gmx.net>:
>> Hi all!
>>
>> On 2019-03-20 19:56 +0100, Alexander Strasser wrote:
>>> 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 FFERROR_REDO instead. I have not seen the
>>> issue appearing twice or more often in a row. It was more like
>>> one single error every two hours.
>>
>>
>> After thinking about the FFERROR_REDO approach some more, I think it
>> is not ideal in the case where a driver permanently delivers frames
>> of unexpected size. The FFmpeg lib call would not return to the client,
>> potentially freezing the running program.
>>
>> So maybe the zero-sized package approach, like we do with the corrupted
>> frames, is more robust here? Any opinions?
>
> You could check if a sane frame was already received before the
> wrong size.

Maybe just set the packet corrupt flag and log an error, but return the 
partial buffer?

Regards,
Marton
Nicolas George March 21, 2019, 9:07 a.m. UTC | #4
Marton Balint (12019-03-21):
> Maybe just set the packet corrupt flag and log an error, but return the
> partial buffer?

I think it may be the best solution. But it would be interesting to know
how the tools react to it.

Regards,
Alexander Strasser March 21, 2019, 10:34 p.m. UTC | #5
Hi Marton,
hi Nicolas!

On 2019-03-21 10:07 +0100, Nicolas George wrote:
> Marton Balint (12019-03-21):
> > Maybe just set the packet corrupt flag and log an error, but return the
> > partial buffer?
>
> I think it may be the best solution. But it would be interesting to know
> how the tools react to it.

I agree that it might be the most sophisticated solution. But it is not
so clear how this would work out with ffmpeg and all other client apps.
It might also be more tricky/involved to implement correctly.

Personally I don't want to invest much more time into this ATM. I would
really like to achieve to prevent aborting the capture in case of a frame
once in a while being returned too short. I believe it would be a big win
that can hopefully be implemented without causing harm.

After considering the 3 variants I have implemented so far I am now
at the following conclusion:

1. Return AVERROR(EAGAIN) => this is not an option because it is not
   expected when using blocking mode
2. Return FFERROR_REDO => this could be used, but has the not completely
   unlikely downside to not return to the caller for a very long time.
   That is in the case the driver starts emitting too short frames in a
   row for a long time.
3. Return zero-sized packets => This works and is consistent with how
   we handle frames flagged to be corrupted (V4L2_BUF_FLAG_ERROR).
   See commit 28f20d2ff487aa589643d8f70eaf614b78839685 .

Choosing from the above 3 options, IMHO 3 is the best. If someone
decides to improve it at a later point, one could improve the
V4L2_BUF_FLAG_ERROR case too.

Do you think that going with 3 now is fine?
If yes I would send that patch for review.

Thanks for your comments!

  Alexander
diff mbox

Patch

diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 1b9c6e7..5a1b324 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 FFERROR_REDO;
         }
     }