avcodec/v4l2_m2m: handle v4l2 end of stream event

When flushing the capture buffers, the driver may send a V4L2_EVENT_EOS
to notify that draining is completed. Currently, v4l2_m2m does not
subscribe to this event, which can cause some devices (i.e. imx8qm) to
hang at the end of encoding/decoding. Support for handling the event is
added in this commit.

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

Signed-off-by: Ming Qian <ming.qian@nxp.com>
Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
Ming Qian 2020-04-01 10:38:45 +08:00 committed by Andriy Gelman
parent 0607f1bcb0
commit 8ac8e905e9
3 changed files with 26 additions and 0 deletions

View File

@ -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;

View File

@ -123,6 +123,13 @@ 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;
}

View File

@ -155,6 +155,17 @@ static int v4l2_check_b_frame_support(V4L2m2mContext *s)
return AVERROR_PATCHWELCOME;
}
static inline void v4l2_subscribe_eos_event(V4L2m2mContext *s)
{
struct v4l2_event_subscription sub;
memset(&sub, 0, sizeof(sub));
sub.type = V4L2_EVENT_EOS;
if (ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0)
av_log(s->avctx, AV_LOG_WARNING,
"the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n");
}
static int v4l2_prepare_encoder(V4L2m2mContext *s)
{
AVCodecContext *avctx = s->avctx;
@ -164,6 +175,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;