It shouldn't allocate buffer before the resolution
change event appeared in decoder setup.
And it should not apply to new resolution before
the buffer from the previous sequence is dequeued.
Change-Id: Id04550b0f17e1501b670a3bcbdd860d5836259bf
Signed-off-by: Hsia-Jun(Randy) Li<randy...@synaptics.com>
---
libavcodec/v4l2_context.c | 89 ++++++++++++++++++++++++++-------------
libavcodec/v4l2_context.h | 6 +++
libavcodec/v4l2_m2m_dec.c | 14 +++---
3 files changed, 73 insertions(+), 36 deletions(-)
diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index a40be94690..87771601a9 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -169,30 +169,17 @@ static int v4l2_start_decode(V4L2Context *ctx)
}
/**
- * handle resolution change event and end of stream event
+ * handle resolution change event
* returns 1 if reinit was successful, negative if it failed
* returns 0 if reinit was not executed
*/
-static int v4l2_handle_event(V4L2Context *ctx)
+static int v4l2_handle_dyn_res_change(V4L2Context *ctx)
{
V4L2m2mContext *s = ctx_to_m2mctx(ctx);
struct v4l2_format cap_fmt = s->capture.format;
- struct v4l2_event evt = { 0 };
int ret;
- ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt);
- if (ret < 0) {
- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n",
ctx->name);
- return 0;
- }
-
- if (evt.type == V4L2_EVENT_EOS) {
- ctx->done = 1;
- return 0;
- }
-
- if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
- return 0;
+ cap_fmt.type = s->capture.type;
ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
if (ret) {
@@ -201,11 +188,13 @@ static int v4l2_handle_event(V4L2Context *ctx)
}
if (v4l2_resolution_changed(&s->capture, &cap_fmt)) {
+ s->capture.format.fmt.pix_mp.pixelformat =
cap_fmt.fmt.pix_mp.pixelformat;
s->capture.height = v4l2_get_height(&cap_fmt);
s->capture.width = v4l2_get_width(&cap_fmt);
s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
} else {
v4l2_start_decode(ctx);
+ ctx->pending_res_change = 0;
return 0;
}
@@ -222,10 +211,41 @@ static int v4l2_handle_event(V4L2Context *ctx)
return AVERROR(EINVAL);
}
+ ctx->pending_res_change = 0;
/* reinit executed */
return 1;
}
+/**
+ * capture resolution change event and end of stream event
+ * returns 1 or negative if it failed
+ * returns 0 if nothing went wrong
+ */
+static int v4l2_handle_event(V4L2Context *ctx)
+{
+ V4L2m2mContext *s = ctx_to_m2mctx(ctx);
+ struct v4l2_event evt = { 0 };
+ int ret;
+
+ ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt);
+ if (ret < 0) {
+ av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n",
ctx->name);
+ return errno;
+ }
+
+ if (evt.type == V4L2_EVENT_EOS) {
+ ctx->done = 1;
+ return 0;
+ }
+
+ if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
+ return AVERROR(EINVAL);
+
+ ctx->pending_res_change = 1;
+
+ return 0;
+}
+
static int v4l2_stop_decode(V4L2Context *ctx)
{
struct v4l2_decoder_cmd cmd = {
@@ -342,16 +362,19 @@ start:
/* 1. handle resolution changes */
if (pfd.revents & POLLPRI) {
ret = v4l2_handle_event(ctx);
- if (ret < 0) {
- /* if re-init failed, abort */
- ctx->done = 1;
- return NULL;
- }
if (ret) {
- /* if re-init was successful drop the buffer (if there was
one)
- * since we had to reconfigure capture (unmap all buffers)
- */
+ /* if event handler failed, abort */
+ ctx->done = 1;
return NULL;
+ } else if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
+ if (!ctx->streamon)
+ ret = v4l2_handle_dyn_res_change(ctx);
+ if (ret == 1)
+ return NULL;
+ } else {
+ /* Poll the device again, we want the buffer with the flag
+ * that answer to the event */
+ return v4l2_dequeue_v4l2buf(ctx, timeout);
}
}
@@ -391,17 +414,23 @@ dequeue:
return NULL;
}
- if (ctx_to_m2mctx(ctx)->draining &&
!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
+ if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ?
buf.m.planes[0].bytesused : buf.bytesused;
+
+#ifdef V4L2_BUF_FLAG_LAST
+ if (buf.flags & V4L2_BUF_FLAG_LAST) {
+ if (ctx_to_m2mctx(ctx)->draining)
+ ctx->done = 1;
+ if (ctx->pending_res_change)
+ ret = v4l2_handle_dyn_res_change(ctx);
+ }
+#endif
if (bytesused == 0) {
- ctx->done = 1;
+ if (ctx_to_m2mctx(ctx)->draining)
+ ctx->done = 1;
return NULL;
}
-#ifdef V4L2_BUF_FLAG_LAST
- if (buf.flags & V4L2_BUF_FLAG_LAST)
- ctx->done = 1;
-#endif
}
avbuf = &ctx->buffers[buf.index];
diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
index 6f7460c89a..b30457c5ad 100644
--- a/libavcodec/v4l2_context.h
+++ b/libavcodec/v4l2_context.h
@@ -87,6 +87,12 @@ typedef struct V4L2Context {
*/
int streamon;
+ /**
+ * Pending resolution change event to handle. Only context for CAPTURE
+ * queue could set this flag.
+ */
+ int pending_res_change;
+
/**
* Either no more buffers available or an unrecoverable error was
notified
* by the V4L2 kernel driver: once set the context has to be exited.
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 4944d08511..3c38fde700 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -40,6 +40,7 @@ static int v4l2_try_start(AVCodecContext *avctx)
V4L2Context *const capture = &s->capture;
V4L2Context *const output = &s->output;
struct v4l2_selection selection = { 0 };
+ AVFrame frame;
int ret;
/* 1. start the output process */
@@ -54,15 +55,16 @@ static int v4l2_try_start(AVCodecContext *avctx)
if (capture->streamon)
return 0;
- /* 2. get the capture format */
- capture->format.type = capture->type;
- ret = ioctl(s->fd, VIDIOC_G_FMT, &capture->format);
+ /* TODO wait event here */
+ ret = ff_v4l2_context_dequeue_frame(capture, &frame, 10);
if (ret) {
- av_log(avctx, AV_LOG_WARNING, "VIDIOC_G_FMT ioctl\n");
- return ret;
+ if (ret == AVERROR(EAGAIN))
+ ret = 0;
+ else
+ return ret;
}
- /* 2.1 update the AVCodecContext */
+ /* 2 update the AVCodecContext */
avctx->pix_fmt =
ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat,
AV_CODEC_ID_RAWVIDEO);
capture->av_pix_fmt = avctx->pix_fmt;
-- 2.17.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".