Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Hsia-Jun Li <Randy.Li@synaptics.com>
To: ffmpeg-devel@ffmpeg.org
Cc: jramirez@baylibre.com
Subject: [FFmpeg-devel] [PATCH] avcodec/v4l2_m2m_dec: resolve resolution change
Date: Fri, 30 Jun 2023 11:04:07 +0800
Message-ID: <5d1fc70a-675a-0d18-87be-e6e00a8fc607@synaptics.com> (raw)

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

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-request@ffmpeg.org with subject "unsubscribe".

                 reply	other threads:[~2023-06-30  3:04 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5d1fc70a-675a-0d18-87be-e6e00a8fc607@synaptics.com \
    --to=randy.li@synaptics.com \
    --cc=ffmpeg-devel@ffmpeg.org \
    --cc=jramirez@baylibre.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git