diff mbox series

[FFmpeg-devel,v4] avcodec/v4l2_m2m: handle the v4l2 eos event

Message ID 20200401023845.4861-1-ming.qian@nxp.com
State Accepted
Headers show
Series [FFmpeg-devel,v4] avcodec/v4l2_m2m: handle the v4l2 eos event | expand

Checks

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

Commit Message

Ming Qian April 1, 2020, 2:38 a.m. UTC
when the last frame of capture is dequeueed,
driver may send this V4L2_EVENT_EOS event,
If this event is received, then the capture buffers have been flushed and
avcodec_receive_packet()/avcodec_receive_frame() can return AVERROR_EOF.
Otherwise, the draining continues until all the capture buffers have been dequeued or VIDIOC_DQBUF ioctl returns an EPIPE error.

Some devices may not support V4L2_EVENT_EOS.
This is logged as a warning message and not treated as a fatal error during initialization.

Without this patch imx8qm often hangs at the end of encoding/decoding when
flushing the capture buffers

Signed-off-by: Ming Qian <ming.qian@nxp.com>
---
 libavcodec/v4l2_context.c |  6 ++++++
 libavcodec/v4l2_m2m_dec.c |  8 ++++++++
 libavcodec/v4l2_m2m_enc.c | 19 +++++++++++++++++++
 3 files changed, 33 insertions(+)

Comments

Andriy Gelman April 9, 2020, 12:51 a.m. UTC | #1
On Wed, 01. Apr 10:38, Ming Qian wrote:
> when the last frame of capture is dequeueed,
> driver may send this V4L2_EVENT_EOS event,
> If this event is received, then the capture buffers have been flushed and
> avcodec_receive_packet()/avcodec_receive_frame() can return AVERROR_EOF.
> Otherwise, the draining continues until all the capture buffers have been dequeued or VIDIOC_DQBUF ioctl returns an EPIPE error.
> 
> Some devices may not support V4L2_EVENT_EOS.
> This is logged as a warning message and not treated as a fatal error during initialization.
> 
> Without this patch imx8qm often hangs at the end of encoding/decoding when
> flushing the capture buffers
> 
> Signed-off-by: Ming Qian <ming.qian@nxp.com>
> ---
>  libavcodec/v4l2_context.c |  6 ++++++
>  libavcodec/v4l2_m2m_dec.c |  8 ++++++++
>  libavcodec/v4l2_m2m_enc.c | 19 +++++++++++++++++++
>  3 files changed, 33 insertions(+)
> 
> diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
> index 8110bbb555..6b1f65fe4c 100644
> --- a/libavcodec/v4l2_context.c
> +++ b/libavcodec/v4l2_context.c
> @@ -154,6 +154,7 @@ static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_upd
>  }
>  
>  /**
> + * handle resolution change event and end of stream event
>   * returns 1 if reinit was successful, negative if it failed
>   * returns 0 if reinit was not executed
>   */
> @@ -171,6 +172,11 @@ static int v4l2_handle_event(V4L2Context *ctx)
>          return 0;
>      }
>  
> +    if (evt.type == V4L2_EVENT_EOS) {
> +        ctx->done = 1;
> +        return 0;
> +    }
> +
>      if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
>          return 0;
>  
> diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> index d666edffe4..9989649784 100644
> --- a/libavcodec/v4l2_m2m_dec.c
> +++ b/libavcodec/v4l2_m2m_dec.c
> @@ -123,6 +123,14 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s)
>          }
>      }
>  
> +    memset(&sub, 0, sizeof(sub));
> +    sub.type = V4L2_EVENT_EOS;
> +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> +    if (ret < 0) {
> +        av_log(s->avctx, AV_LOG_WARNING,
> +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> +    }
> +
>      return 0;
>  }
>  
> diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> index 84de63ec9d..78cf9ba47a 100644
> --- a/libavcodec/v4l2_m2m_enc.c
> +++ b/libavcodec/v4l2_m2m_enc.c
> @@ -155,6 +155,23 @@ static int v4l2_check_b_frame_support(V4L2m2mContext *s)
>      return AVERROR_PATCHWELCOME;
>  }
>  
> +static int v4l2_subscribe_eos_event(V4L2m2mContext *s)
> +{
> +    struct v4l2_event_subscription sub;
> +    int ret;
> +
> +    memset(&sub, 0, sizeof(sub));
> +    sub.type = V4L2_EVENT_EOS;
> +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> +    if (ret < 0) {
> +        av_log(s->avctx, AV_LOG_WARNING,
> +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
>  static int v4l2_prepare_encoder(V4L2m2mContext *s)
>  {
>      AVCodecContext *avctx = s->avctx;
> @@ -164,6 +181,8 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
>      /**
>       * requirements
>       */
> +    v4l2_subscribe_eos_event(s);
> +
>      ret = v4l2_check_b_frame_support(s);
>      if (ret)
>          return ret;
> -- 
> 2.26.0
> 

lgtm
Tested on RPi4 and Odroid XU4. 

Thanks,
Andriy Gelman April 11, 2020, 3:20 p.m. UTC | #2
On Wed, 08. Apr 20:51, Andriy Gelman wrote:
> On Wed, 01. Apr 10:38, Ming Qian wrote:
> > when the last frame of capture is dequeueed,
> > driver may send this V4L2_EVENT_EOS event,
> > If this event is received, then the capture buffers have been flushed and
> > avcodec_receive_packet()/avcodec_receive_frame() can return AVERROR_EOF.
> > Otherwise, the draining continues until all the capture buffers have been dequeued or VIDIOC_DQBUF ioctl returns an EPIPE error.
> > 
> > Some devices may not support V4L2_EVENT_EOS.
> > This is logged as a warning message and not treated as a fatal error during initialization.
> > 
> > Without this patch imx8qm often hangs at the end of encoding/decoding when
> > flushing the capture buffers
> > 
> > Signed-off-by: Ming Qian <ming.qian@nxp.com>
> > ---
> >  libavcodec/v4l2_context.c |  6 ++++++
> >  libavcodec/v4l2_m2m_dec.c |  8 ++++++++
> >  libavcodec/v4l2_m2m_enc.c | 19 +++++++++++++++++++
> >  3 files changed, 33 insertions(+)
> > 
> > diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
> > index 8110bbb555..6b1f65fe4c 100644
> > --- a/libavcodec/v4l2_context.c
> > +++ b/libavcodec/v4l2_context.c
> > @@ -154,6 +154,7 @@ static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_upd
> >  }
> >  
> >  /**
> > + * handle resolution change event and end of stream event
> >   * returns 1 if reinit was successful, negative if it failed
> >   * returns 0 if reinit was not executed
> >   */
> > @@ -171,6 +172,11 @@ static int v4l2_handle_event(V4L2Context *ctx)
> >          return 0;
> >      }
> >  
> > +    if (evt.type == V4L2_EVENT_EOS) {
> > +        ctx->done = 1;
> > +        return 0;
> > +    }
> > +
> >      if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
> >          return 0;
> >  
> > diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> > index d666edffe4..9989649784 100644
> > --- a/libavcodec/v4l2_m2m_dec.c
> > +++ b/libavcodec/v4l2_m2m_dec.c
> > @@ -123,6 +123,14 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s)
> >          }
> >      }
> >  
> > +    memset(&sub, 0, sizeof(sub));
> > +    sub.type = V4L2_EVENT_EOS;
> > +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> > +    if (ret < 0) {
> > +        av_log(s->avctx, AV_LOG_WARNING,
> > +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> > +    }
> > +
> >      return 0;
> >  }
> >  
> > diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> > index 84de63ec9d..78cf9ba47a 100644
> > --- a/libavcodec/v4l2_m2m_enc.c
> > +++ b/libavcodec/v4l2_m2m_enc.c
> > @@ -155,6 +155,23 @@ static int v4l2_check_b_frame_support(V4L2m2mContext *s)
> >      return AVERROR_PATCHWELCOME;
> >  }
> >  
> > +static int v4l2_subscribe_eos_event(V4L2m2mContext *s)
> > +{
> > +    struct v4l2_event_subscription sub;
> > +    int ret;
> > +
> > +    memset(&sub, 0, sizeof(sub));
> > +    sub.type = V4L2_EVENT_EOS;
> > +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> > +    if (ret < 0) {
> > +        av_log(s->avctx, AV_LOG_WARNING,
> > +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> > +        return ret;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  static int v4l2_prepare_encoder(V4L2m2mContext *s)
> >  {
> >      AVCodecContext *avctx = s->avctx;
> > @@ -164,6 +181,8 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
> >      /**
> >       * requirements
> >       */
> > +    v4l2_subscribe_eos_event(s);
> > +
> >      ret = v4l2_check_b_frame_support(s);
> >      if (ret)
> >          return ret;
> > -- 
> > 2.26.0
> > 
> 
> lgtm
> Tested on RPi4 and Odroid XU4. 
> 

Would anyone object if I push this on Tuesday?
(I would align the commit message before pushing)

Thanks,
Andriy Gelman April 15, 2020, 4 a.m. UTC | #3
On Wed, 08. Apr 20:51, Andriy Gelman wrote:
> On Wed, 01. Apr 10:38, Ming Qian wrote:
> > when the last frame of capture is dequeueed,
> > driver may send this V4L2_EVENT_EOS event,
> > If this event is received, then the capture buffers have been flushed and
> > avcodec_receive_packet()/avcodec_receive_frame() can return AVERROR_EOF.
> > Otherwise, the draining continues until all the capture buffers have been dequeued or VIDIOC_DQBUF ioctl returns an EPIPE error.
> > 
> > Some devices may not support V4L2_EVENT_EOS.
> > This is logged as a warning message and not treated as a fatal error during initialization.
> > 
> > Without this patch imx8qm often hangs at the end of encoding/decoding when
> > flushing the capture buffers
> > 
> > Signed-off-by: Ming Qian <ming.qian@nxp.com>
> > ---
> >  libavcodec/v4l2_context.c |  6 ++++++
> >  libavcodec/v4l2_m2m_dec.c |  8 ++++++++
> >  libavcodec/v4l2_m2m_enc.c | 19 +++++++++++++++++++
> >  3 files changed, 33 insertions(+)
> > 
> > diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
> > index 8110bbb555..6b1f65fe4c 100644
> > --- a/libavcodec/v4l2_context.c
> > +++ b/libavcodec/v4l2_context.c
> > @@ -154,6 +154,7 @@ static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_upd
> >  }
> >  
> >  /**
> > + * handle resolution change event and end of stream event
> >   * returns 1 if reinit was successful, negative if it failed
> >   * returns 0 if reinit was not executed
> >   */
> > @@ -171,6 +172,11 @@ static int v4l2_handle_event(V4L2Context *ctx)
> >          return 0;
> >      }
> >  
> > +    if (evt.type == V4L2_EVENT_EOS) {
> > +        ctx->done = 1;
> > +        return 0;
> > +    }
> > +
> >      if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
> >          return 0;
> >  
> > diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> > index d666edffe4..9989649784 100644
> > --- a/libavcodec/v4l2_m2m_dec.c
> > +++ b/libavcodec/v4l2_m2m_dec.c
> > @@ -123,6 +123,14 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s)
> >          }
> >      }
> >  
> > +    memset(&sub, 0, sizeof(sub));
> > +    sub.type = V4L2_EVENT_EOS;
> > +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> > +    if (ret < 0) {
> > +        av_log(s->avctx, AV_LOG_WARNING,
> > +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> > +    }
> > +
> >      return 0;
> >  }
> >  
> > diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> > index 84de63ec9d..78cf9ba47a 100644
> > --- a/libavcodec/v4l2_m2m_enc.c
> > +++ b/libavcodec/v4l2_m2m_enc.c
> > @@ -155,6 +155,23 @@ static int v4l2_check_b_frame_support(V4L2m2mContext *s)
> >      return AVERROR_PATCHWELCOME;
> >  }
> >  
> > +static int v4l2_subscribe_eos_event(V4L2m2mContext *s)
> > +{
> > +    struct v4l2_event_subscription sub;
> > +    int ret;
> > +
> > +    memset(&sub, 0, sizeof(sub));
> > +    sub.type = V4L2_EVENT_EOS;
> > +    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
> > +    if (ret < 0) {
> > +        av_log(s->avctx, AV_LOG_WARNING,
> > +                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
> > +        return ret;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  static int v4l2_prepare_encoder(V4L2m2mContext *s)
> >  {
> >      AVCodecContext *avctx = s->avctx;
> > @@ -164,6 +181,8 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
> >      /**
> >       * requirements
> >       */
> > +    v4l2_subscribe_eos_event(s);
> > +
> >      ret = v4l2_check_b_frame_support(s);
> >      if (ret)
> >          return ret;
> > -- 
> > 2.26.0
> > 
> 
> lgtm
> Tested on RPi4 and Odroid XU4. 
> 

Applied. 

Thanks,
diff mbox series

Patch

diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index 8110bbb555..6b1f65fe4c 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -154,6 +154,7 @@  static inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_upd
 }
 
 /**
+ * handle resolution change event and end of stream event
  * returns 1 if reinit was successful, negative if it failed
  * returns 0 if reinit was not executed
  */
@@ -171,6 +172,11 @@  static int v4l2_handle_event(V4L2Context *ctx)
         return 0;
     }
 
+    if (evt.type == V4L2_EVENT_EOS) {
+        ctx->done = 1;
+        return 0;
+    }
+
     if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
         return 0;
 
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index d666edffe4..9989649784 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -123,6 +123,14 @@  static int v4l2_prepare_decoder(V4L2m2mContext *s)
         }
     }
 
+    memset(&sub, 0, sizeof(sub));
+    sub.type = V4L2_EVENT_EOS;
+    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+    if (ret < 0) {
+        av_log(s->avctx, AV_LOG_WARNING,
+                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
+    }
+
     return 0;
 }
 
diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
index 84de63ec9d..78cf9ba47a 100644
--- a/libavcodec/v4l2_m2m_enc.c
+++ b/libavcodec/v4l2_m2m_enc.c
@@ -155,6 +155,23 @@  static int v4l2_check_b_frame_support(V4L2m2mContext *s)
     return AVERROR_PATCHWELCOME;
 }
 
+static int v4l2_subscribe_eos_event(V4L2m2mContext *s)
+{
+    struct v4l2_event_subscription sub;
+    int ret;
+
+    memset(&sub, 0, sizeof(sub));
+    sub.type = V4L2_EVENT_EOS;
+    ret = ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+    if (ret < 0) {
+        av_log(s->avctx, AV_LOG_WARNING,
+                "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
+        return ret;
+    }
+
+    return 0;
+}
+
 static int v4l2_prepare_encoder(V4L2m2mContext *s)
 {
     AVCodecContext *avctx = s->avctx;
@@ -164,6 +181,8 @@  static int v4l2_prepare_encoder(V4L2m2mContext *s)
     /**
      * requirements
      */
+    v4l2_subscribe_eos_event(s);
+
     ret = v4l2_check_b_frame_support(s);
     if (ret)
         return ret;