diff mbox series

[FFmpeg-devel] avcodec/v4l2_m2m_dec: resolve resolution change

Message ID 5d1fc70a-675a-0d18-87be-e6e00a8fc607@synaptics.com
State New
Headers show
Series [FFmpeg-devel] avcodec/v4l2_m2m_dec: resolve resolution change | expand

Checks

Context Check Description
andriy/configure_x86 warning Failed to apply patch
yinshiyou/configure_loongarch64 warning Failed to apply patch

Commit Message

Hsia-Jun Li June 30, 2023, 3:04 a.m. UTC
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.li@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(-)

      capture->av_pix_fmt = avctx->pix_fmt;

-- 2.17.1
diff mbox series

Patch

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