diff mbox series

[FFmpeg-devel] avcodec/v4l2_m2m_enc: Add option to remove ivf container

Message ID 20200404202622.22348-1-andriy.gelman@gmail.com
State Accepted
Headers show
Series [FFmpeg-devel] avcodec/v4l2_m2m_enc: Add option to remove ivf container | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Andriy Gelman April 4, 2020, 8:26 p.m. UTC
From: Andriy Gelman <andriy.gelman@gmail.com>

The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
which breaks the stream when the packets are muxed in avformat. This commit
adds an option to remove the container and thus support the encoder.

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
---
 libavcodec/v4l2_m2m.h     |  2 ++
 libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
 2 files changed, 45 insertions(+), 10 deletions(-)

Comments

Mark Thompson April 11, 2020, 2:56 p.m. UTC | #1
On 04/04/2020 21:26, Andriy Gelman wrote:
> From: Andriy Gelman <andriy.gelman@gmail.com>
> 
> The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
> which breaks the stream when the packets are muxed in avformat. This commit
> adds an option to remove the container and thus support the encoder.
> 
> Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
> ---
>  libavcodec/v4l2_m2m.h     |  2 ++
>  libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
>  2 files changed, 45 insertions(+), 10 deletions(-)
> 
> diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
> index 456281f48c..525f9456e9 100644
> --- a/libavcodec/v4l2_m2m.h
> +++ b/libavcodec/v4l2_m2m.h
> @@ -73,6 +73,8 @@ typedef struct V4L2m2mPriv {
>  
>      int num_output_buffers;
>      int num_capture_buffers;
> +    int strip_ivf;
> +    int ivf_detected;
>  } V4L2m2mPriv;
>  
>  /**
> diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> index c9f1741bfd..9c11f90567 100644
> --- a/libavcodec/v4l2_m2m_enc.c
> +++ b/libavcodec/v4l2_m2m_enc.c
> @@ -25,6 +25,8 @@
>  #include <sys/ioctl.h>
>  #include <search.h>
>  #include "libavcodec/avcodec.h"
> +#include "libavcodec/internal.h"
> +#include "libavutil/intreadwrite.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavutil/pixfmt.h"
>  #include "libavutil/opt.h"
> @@ -256,6 +258,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
>  
>  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
>  {
> +    V4L2m2mPriv *priv = avctx->priv_data;
>      V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
>      V4L2Context *const capture = &s->capture;
>      V4L2Context *const output = &s->output;
> @@ -281,7 +284,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
>      }
>  
>  dequeue:
> -    return ff_v4l2_context_dequeue_packet(capture, avpkt);
> +    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
> +    if (ret)
> +        return ret;
> +
> +    if (priv->strip_ivf) {
> +        int header_offset = 0;
> +        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
> +            header_offset = 32;
> +            priv->ivf_detected = 1;
> +        } else if (priv->ivf_detected) {
> +            header_offset = 12;
> +        }
> +        header_offset = FFMIN(header_offset, avpkt->size);
> +        avpkt->data  += header_offset;
> +        avpkt->size  -= header_offset;
> +
> +        if (avpkt->size == 0) {

Does this case ever happen?  Wouldn't something have gone very wrong here to get here?

> +            av_packet_unref(avpkt);
> +            goto dequeue;
> +        }
> +    }
> +    return 0;
>  }

Could the presence of the IVF container be autodetected?  I suspect it can, because the tag will collide with the fixed start code in the intra frame at the start of the stream.  If that were possible then it would avoid having the tricky option which users are not going to easily know about.

Otherwise seems ok.  It's rather horrible, but it looks like the best solution to the problem.

Thanks,

- Mark
Andriy Gelman April 11, 2020, 3:14 p.m. UTC | #2
On Sat, 11. Apr 15:56, Mark Thompson wrote:
> On 04/04/2020 21:26, Andriy Gelman wrote:
> > From: Andriy Gelman <andriy.gelman@gmail.com>
> > 
> > The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
> > which breaks the stream when the packets are muxed in avformat. This commit
> > adds an option to remove the container and thus support the encoder.
> > 
> > Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
> > ---
> >  libavcodec/v4l2_m2m.h     |  2 ++
> >  libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
> >  2 files changed, 45 insertions(+), 10 deletions(-)
> > 
> > diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
> > index 456281f48c..525f9456e9 100644
> > --- a/libavcodec/v4l2_m2m.h
> > +++ b/libavcodec/v4l2_m2m.h
> > @@ -73,6 +73,8 @@ typedef struct V4L2m2mPriv {
> >  
> >      int num_output_buffers;
> >      int num_capture_buffers;
> > +    int strip_ivf;
> > +    int ivf_detected;
> >  } V4L2m2mPriv;
> >  
> >  /**
> > diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> > index c9f1741bfd..9c11f90567 100644
> > --- a/libavcodec/v4l2_m2m_enc.c
> > +++ b/libavcodec/v4l2_m2m_enc.c
> > @@ -25,6 +25,8 @@
> >  #include <sys/ioctl.h>
> >  #include <search.h>
> >  #include "libavcodec/avcodec.h"
> > +#include "libavcodec/internal.h"
> > +#include "libavutil/intreadwrite.h"
> >  #include "libavutil/pixdesc.h"
> >  #include "libavutil/pixfmt.h"
> >  #include "libavutil/opt.h"
> > @@ -256,6 +258,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> >  
> >  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> >  {
> > +    V4L2m2mPriv *priv = avctx->priv_data;
> >      V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
> >      V4L2Context *const capture = &s->capture;
> >      V4L2Context *const output = &s->output;
> > @@ -281,7 +284,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> >      }
> >  
> >  dequeue:
> > -    return ff_v4l2_context_dequeue_packet(capture, avpkt);
> > +    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
> > +    if (ret)
> > +        return ret;
> > +
> > +    if (priv->strip_ivf) {
> > +        int header_offset = 0;
> > +        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
> > +            header_offset = 32;
> > +            priv->ivf_detected = 1;
> > +        } else if (priv->ivf_detected) {
> > +            header_offset = 12;
> > +        }
> > +        header_offset = FFMIN(header_offset, avpkt->size);
> > +        avpkt->data  += header_offset;
> > +        avpkt->size  -= header_offset;
> > +
> > +        if (avpkt->size == 0) {

> 
> Does this case ever happen?  Wouldn't something have gone very wrong here to get here?

It happens on the first packet, when the dequeued packet only contains the
32byte ivf header.

Also when draining (not related to this patch), avpkt->size == 0 indicates that
all the capture buffers are flushed.

> 
> > +            av_packet_unref(avpkt);
> > +            goto dequeue;
> > +        }
> > +    }
> > +    return 0;
> >  }

> 
> Could the presence of the IVF container be autodetected?  I suspect it can, because the tag will collide with the fixed start code in the intra frame at the start of the stream.  If that were possible then it would avoid having the tricky option which users are not going to easily know about.

I think it can. Will test this approach.

> 
> Otherwise seems ok.  It's rather horrible, but it looks like the best solution to the problem.

I agree it's quite ugly. I'll look into whether auto inserted bsf can be
extended to encoders.

Thanks,
Lynne April 11, 2020, 3:37 p.m. UTC | #3
Apr 11, 2020, 15:56 by sw@jkqxz.net:

> On 04/04/2020 21:26, Andriy Gelman wrote:
>
>> From: Andriy Gelman <andriy.gelman@gmail.com>
>>
>> The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
>> which breaks the stream when the packets are muxed in avformat. This commit
>> adds an option to remove the container and thus support the encoder.
>>
>> Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
>> ---
>>  libavcodec/v4l2_m2m.h     |  2 ++
>>  libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
>>  2 files changed, 45 insertions(+), 10 deletions(-)
>>
>> diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
>> index 456281f48c..525f9456e9 100644
>> --- a/libavcodec/v4l2_m2m.h
>> +++ b/libavcodec/v4l2_m2m.h
>> @@ -73,6 +73,8 @@ typedef struct V4L2m2mPriv {
>>  
>>  int num_output_buffers;
>>  int num_capture_buffers;
>> +    int strip_ivf;
>> +    int ivf_detected;
>>  } V4L2m2mPriv;
>>  
>>  /**
>> diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
>> index c9f1741bfd..9c11f90567 100644
>> --- a/libavcodec/v4l2_m2m_enc.c
>> +++ b/libavcodec/v4l2_m2m_enc.c
>> @@ -25,6 +25,8 @@
>>  #include <sys/ioctl.h>
>>  #include <search.h>
>>  #include "libavcodec/avcodec.h"
>> +#include "libavcodec/internal.h"
>> +#include "libavutil/intreadwrite.h"
>>  #include "libavutil/pixdesc.h"
>>  #include "libavutil/pixfmt.h"
>>  #include "libavutil/opt.h"
>> @@ -256,6 +258,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
>>  
>>  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
>>  {
>> +    V4L2m2mPriv *priv = avctx->priv_data;
>>  V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
>>  V4L2Context *const capture = &s->capture;
>>  V4L2Context *const output = &s->output;
>> @@ -281,7 +284,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
>>  }
>>  
>>  dequeue:
>> -    return ff_v4l2_context_dequeue_packet(capture, avpkt);
>> +    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
>> +    if (ret)
>> +        return ret;
>> +
>> +    if (priv->strip_ivf) {
>> +        int header_offset = 0;
>> +        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
>> +            header_offset = 32;
>> +            priv->ivf_detected = 1;
>> +        } else if (priv->ivf_detected) {
>> +            header_offset = 12;
>> +        }
>> +        header_offset = FFMIN(header_offset, avpkt->size);
>> +        avpkt->data  += header_offset;
>> +        avpkt->size  -= header_offset;
>> +
>> +        if (avpkt->size == 0) {
>>
>
> Does this case ever happen?  Wouldn't something have gone very wrong here to get here?
>
>> +            av_packet_unref(avpkt);
>> +            goto dequeue;
>> +        }
>> +    }
>> +    return 0;
>>  }
>>
>
> Could the presence of the IVF container be autodetected?  I suspect it can, because the tag will collide with the fixed start code in the intra frame at the start of the stream.  If that were possible then it would avoid having the tricky option which users are not going to easily know about.
>
> Otherwise seems ok.  It's rather horrible, but it looks like the best solution to the problem.
>

I really, really don't think its a good idea to probe the packets of encoders, so I think I'm NAK on this patch for now.
If a spec-compliant encoder cannot produce a packet that starts with DKIF, I'd be okay with it though.
Or if ivf had a CRC at the end like ogg where a match would practically guarantee its an ivf packet. Otherwise, its just too fragile.
Jan Ekström April 11, 2020, 3:56 p.m. UTC | #4
On Sat, Apr 11, 2020 at 6:43 PM Andriy Gelman <andriy.gelman@gmail.com> wrote:
>
> On Sat, 11. Apr 15:56, Mark Thompson wrote:
> > On 04/04/2020 21:26, Andriy Gelman wrote:
> > > From: Andriy Gelman <andriy.gelman@gmail.com>
> > >
> > > The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
> > > which breaks the stream when the packets are muxed in avformat. This commit
> > > adds an option to remove the container and thus support the encoder.
> > >
> > > Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
> > > ---
> > >  libavcodec/v4l2_m2m.h     |  2 ++
> > >  libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
> > >  2 files changed, 45 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
> > > index 456281f48c..525f9456e9 100644
> > > --- a/libavcodec/v4l2_m2m.h
> > > +++ b/libavcodec/v4l2_m2m.h
> > > @@ -73,6 +73,8 @@ typedef struct V4L2m2mPriv {
> > >
> > >      int num_output_buffers;
> > >      int num_capture_buffers;
> > > +    int strip_ivf;
> > > +    int ivf_detected;
> > >  } V4L2m2mPriv;
> > >
> > >  /**
> > > diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> > > index c9f1741bfd..9c11f90567 100644
> > > --- a/libavcodec/v4l2_m2m_enc.c
> > > +++ b/libavcodec/v4l2_m2m_enc.c
> > > @@ -25,6 +25,8 @@
> > >  #include <sys/ioctl.h>
> > >  #include <search.h>
> > >  #include "libavcodec/avcodec.h"
> > > +#include "libavcodec/internal.h"
> > > +#include "libavutil/intreadwrite.h"
> > >  #include "libavutil/pixdesc.h"
> > >  #include "libavutil/pixfmt.h"
> > >  #include "libavutil/opt.h"
> > > @@ -256,6 +258,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> > >
> > >  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> > >  {
> > > +    V4L2m2mPriv *priv = avctx->priv_data;
> > >      V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
> > >      V4L2Context *const capture = &s->capture;
> > >      V4L2Context *const output = &s->output;
> > > @@ -281,7 +284,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> > >      }
> > >
> > >  dequeue:
> > > -    return ff_v4l2_context_dequeue_packet(capture, avpkt);
> > > +    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
> > > +    if (ret)
> > > +        return ret;
> > > +
> > > +    if (priv->strip_ivf) {
> > > +        int header_offset = 0;
> > > +        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
> > > +            header_offset = 32;
> > > +            priv->ivf_detected = 1;
> > > +        } else if (priv->ivf_detected) {
> > > +            header_offset = 12;
> > > +        }
> > > +        header_offset = FFMIN(header_offset, avpkt->size);
> > > +        avpkt->data  += header_offset;
> > > +        avpkt->size  -= header_offset;
> > > +
> > > +        if (avpkt->size == 0) {
>
> >
> > Does this case ever happen?  Wouldn't something have gone very wrong here to get here?
>
> It happens on the first packet, when the dequeued packet only contains the
> 32byte ivf header.
>
> Also when draining (not related to this patch), avpkt->size == 0 indicates that
> all the capture buffers are flushed.
>
> >
> > > +            av_packet_unref(avpkt);
> > > +            goto dequeue;
> > > +        }
> > > +    }
> > > +    return 0;
> > >  }
>
> >
> > Could the presence of the IVF container be autodetected?  I suspect it can, because the tag will collide with the fixed start code in the intra frame at the start of the stream.  If that were possible then it would avoid having the tricky option which users are not going to easily know about.
>
> I think it can. Will test this approach.
>
> >
> > Otherwise seems ok.  It's rather horrible, but it looks like the best solution to the problem.
>
> I agree it's quite ugly. I'll look into whether auto inserted bsf can be
> extended to encoders.
>

For the record, does this relate at all to
https://patchwork.kernel.org/patch/3781601/ ?

It sounds like the driver has an option to disable IVF output.

Best regards,
Jan

> Thanks,
> --
> Andriy
Andriy Gelman April 11, 2020, 4:09 p.m. UTC | #5
On Sat, 11. Apr 18:56, Jan Ekström wrote:
> On Sat, Apr 11, 2020 at 6:43 PM Andriy Gelman <andriy.gelman@gmail.com> wrote:
> >
> > On Sat, 11. Apr 15:56, Mark Thompson wrote:
> > > On 04/04/2020 21:26, Andriy Gelman wrote:
> > > > From: Andriy Gelman <andriy.gelman@gmail.com>
> > > >
> > > > The dequeued packets from vp8 (s5p-mfc) encoder are output in ivf format
> > > > which breaks the stream when the packets are muxed in avformat. This commit
> > > > adds an option to remove the container and thus support the encoder.
> > > >
> > > > Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
> > > > ---
> > > >  libavcodec/v4l2_m2m.h     |  2 ++
> > > >  libavcodec/v4l2_m2m_enc.c | 53 +++++++++++++++++++++++++++++++--------
> > > >  2 files changed, 45 insertions(+), 10 deletions(-)
> > > >
> > > > diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
> > > > index 456281f48c..525f9456e9 100644
> > > > --- a/libavcodec/v4l2_m2m.h
> > > > +++ b/libavcodec/v4l2_m2m.h
> > > > @@ -73,6 +73,8 @@ typedef struct V4L2m2mPriv {
> > > >
> > > >      int num_output_buffers;
> > > >      int num_capture_buffers;
> > > > +    int strip_ivf;
> > > > +    int ivf_detected;
> > > >  } V4L2m2mPriv;
> > > >
> > > >  /**
> > > > diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> > > > index c9f1741bfd..9c11f90567 100644
> > > > --- a/libavcodec/v4l2_m2m_enc.c
> > > > +++ b/libavcodec/v4l2_m2m_enc.c
> > > > @@ -25,6 +25,8 @@
> > > >  #include <sys/ioctl.h>
> > > >  #include <search.h>
> > > >  #include "libavcodec/avcodec.h"
> > > > +#include "libavcodec/internal.h"
> > > > +#include "libavutil/intreadwrite.h"
> > > >  #include "libavutil/pixdesc.h"
> > > >  #include "libavutil/pixfmt.h"
> > > >  #include "libavutil/opt.h"
> > > > @@ -256,6 +258,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> > > >
> > > >  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> > > >  {
> > > > +    V4L2m2mPriv *priv = avctx->priv_data;
> > > >      V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
> > > >      V4L2Context *const capture = &s->capture;
> > > >      V4L2Context *const output = &s->output;
> > > > @@ -281,7 +284,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
> > > >      }
> > > >
> > > >  dequeue:
> > > > -    return ff_v4l2_context_dequeue_packet(capture, avpkt);
> > > > +    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
> > > > +    if (ret)
> > > > +        return ret;
> > > > +
> > > > +    if (priv->strip_ivf) {
> > > > +        int header_offset = 0;
> > > > +        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
> > > > +            header_offset = 32;
> > > > +            priv->ivf_detected = 1;
> > > > +        } else if (priv->ivf_detected) {
> > > > +            header_offset = 12;
> > > > +        }
> > > > +        header_offset = FFMIN(header_offset, avpkt->size);
> > > > +        avpkt->data  += header_offset;
> > > > +        avpkt->size  -= header_offset;
> > > > +
> > > > +        if (avpkt->size == 0) {
> >
> > >
> > > Does this case ever happen?  Wouldn't something have gone very wrong here to get here?
> >
> > It happens on the first packet, when the dequeued packet only contains the
> > 32byte ivf header.
> >
> > Also when draining (not related to this patch), avpkt->size == 0 indicates that
> > all the capture buffers are flushed.
> >
> > >
> > > > +            av_packet_unref(avpkt);
> > > > +            goto dequeue;
> > > > +        }
> > > > +    }
> > > > +    return 0;
> > > >  }
> >
> > >
> > > Could the presence of the IVF container be autodetected?  I suspect it can, because the tag will collide with the fixed start code in the intra frame at the start of the stream.  If that were possible then it would avoid having the tricky option which users are not going to easily know about.
> >
> > I think it can. Will test this approach.
> >
> > >
> > > Otherwise seems ok.  It's rather horrible, but it looks like the best solution to the problem.
> >
> > I agree it's quite ugly. I'll look into whether auto inserted bsf can be
> > extended to encoders.
> >

Hi Jan

> 
> For the record, does this relate at all to
> https://patchwork.kernel.org/patch/3781601/ ?
> 
> It sounds like the driver has an option to disable IVF output.
> 

This patch hasn't been merged, so the option is not available.
I've pinged a few times on #v4l, but didn't get a response (the patch is from
2014...)

I also tested the patch, but s5p-mfc errors out during encoding. 
Probably the register in the patch is wrong. 

Thanks,
diff mbox series

Patch

diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
index 456281f48c..525f9456e9 100644
--- a/libavcodec/v4l2_m2m.h
+++ b/libavcodec/v4l2_m2m.h
@@ -73,6 +73,8 @@  typedef struct V4L2m2mPriv {
 
     int num_output_buffers;
     int num_capture_buffers;
+    int strip_ivf;
+    int ivf_detected;
 } V4L2m2mPriv;
 
 /**
diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
index c9f1741bfd..9c11f90567 100644
--- a/libavcodec/v4l2_m2m_enc.c
+++ b/libavcodec/v4l2_m2m_enc.c
@@ -25,6 +25,8 @@ 
 #include <sys/ioctl.h>
 #include <search.h>
 #include "libavcodec/avcodec.h"
+#include "libavcodec/internal.h"
+#include "libavutil/intreadwrite.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/pixfmt.h"
 #include "libavutil/opt.h"
@@ -256,6 +258,7 @@  static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame)
 
 static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
 {
+    V4L2m2mPriv *priv = avctx->priv_data;
     V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
     V4L2Context *const capture = &s->capture;
     V4L2Context *const output = &s->output;
@@ -281,7 +284,28 @@  static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
     }
 
 dequeue:
-    return ff_v4l2_context_dequeue_packet(capture, avpkt);
+    ret = ff_v4l2_context_dequeue_packet(capture, avpkt);
+    if (ret)
+        return ret;
+
+    if (priv->strip_ivf) {
+        int header_offset = 0;
+        if (avpkt->size >= 32 && AV_RL32(avpkt->data) == MKTAG('D','K','I','F')) {
+            header_offset = 32;
+            priv->ivf_detected = 1;
+        } else if (priv->ivf_detected) {
+            header_offset = 12;
+        }
+        header_offset = FFMIN(header_offset, avpkt->size);
+        avpkt->data  += header_offset;
+        avpkt->size  -= header_offset;
+
+        if (avpkt->size == 0) {
+            av_packet_unref(avpkt);
+            goto dequeue;
+        }
+    }
+    return 0;
 }
 
 static av_cold int v4l2_encode_init(AVCodecContext *avctx)
@@ -349,16 +373,25 @@  static const AVOption options[] = {
     { NULL },
 };
 
-#define M2MENC_CLASS(NAME) \
+static const AVOption vp8_options[] = {
+    V4L_M2M_DEFAULT_OPTS,
+    { "num_capture_buffers", "Number of buffers in the capture context",
+        OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, { .i64 = 4 }, 4, INT_MAX, FLAGS },
+    { "strip_ivf", "Strip ivf container",
+        OFFSET(strip_ivf), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
+    { NULL },
+};
+
+#define M2MENC_CLASS(NAME, OPTIONS) \
     static const AVClass v4l2_m2m_ ## NAME ## _enc_class = { \
         .class_name = #NAME "_v4l2m2m_encoder", \
         .item_name  = av_default_item_name, \
-        .option     = options, \
+        .option     = OPTIONS, \
         .version    = LIBAVUTIL_VERSION_INT, \
     };
 
-#define M2MENC(NAME, LONGNAME, CODEC) \
-    M2MENC_CLASS(NAME) \
+#define M2MENC(NAME, LONGNAME, CODEC, OPTIONS) \
+    M2MENC_CLASS(NAME, OPTIONS) \
     AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
         .name           = #NAME "_v4l2m2m" , \
         .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"), \
@@ -374,8 +407,8 @@  static const AVOption options[] = {
         .wrapper_name   = "v4l2m2m", \
     };
 
-M2MENC(mpeg4,"MPEG4", AV_CODEC_ID_MPEG4);
-M2MENC(h263, "H.263", AV_CODEC_ID_H263);
-M2MENC(h264, "H.264", AV_CODEC_ID_H264);
-M2MENC(hevc, "HEVC",  AV_CODEC_ID_HEVC);
-M2MENC(vp8,  "VP8",   AV_CODEC_ID_VP8);
+M2MENC(mpeg4,"MPEG4", AV_CODEC_ID_MPEG4, options);
+M2MENC(h263, "H.263", AV_CODEC_ID_H263,  options);
+M2MENC(h264, "H.264", AV_CODEC_ID_H264,  options);
+M2MENC(hevc, "HEVC",  AV_CODEC_ID_HEVC,  options);
+M2MENC(vp8,  "VP8",   AV_CODEC_ID_VP8,   vp8_options);