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