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".

Reply via email to