PR #24887 opened by BobEntwhistle
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24887
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24887.patch
# Summary of changes
Include the colour space in the comparison, and rename the helper since
it no longer looks only at the resolution.
#Description
v4l2_handle_event() only reinitialises the capture queue when the width
or height reported by VIDIOC_G_FMT differs from the cached format. A
driver may, however, raise V4L2_EVENT_SOURCE_CHANGE for a format change
that leaves the resolution untouched, and the V4L2 stateful decoder
interface requires the client to perform the drain/restart sequence
whenever that event is signalled. Taking the else branch leaves the
capture queue in the drained state the driver put it in, so no further
buffers are ever dequeued and decoding stalls indefinitely.
This is reproducible with bcm2835-codec on a Raspberry Pi 4. Any H.264
stream whose SPS VUI contains a colour description causes the firmware
to report a colour space, which raises MMAL_EVENT_FORMAT_CHANGED. The
driver then marks the capture queue as drained and queues
V4L2_EVENT_SOURCE_CHANGE, but the dimensions are unchanged, so no reinit
happens and h264_v4l2m2m returns no frames at all:
ffmpeg -f lavfi -i testsrc=size=720x480:rate=25:duration=5 \
-c:v libx264 -pix_fmt yuv420p nocolour.mp4
ffmpeg -f lavfi -i testsrc=size=720x480:rate=25:duration=5 \
-c:v libx264 -pix_fmt yuv420p -colorspace smpte170m \
-color_primaries smpte170m -color_trc bt709 colour.mp4
ffmpeg -c:v h264_v4l2m2m -i nocolour.mp4 -f null - # decodes
ffmpeg -c:v h264_v4l2m2m -i colour.mp4 -f null - # hangs, no output
Tested on a Raspberry Pi 4b.
>From 0ef498699e05543e4e86ac95bc141538e57e7090 Mon Sep 17 00:00:00 2001
From: Bob Entwhistle <[email protected]>
Date: Sun, 4 Oct 2026 11:54:31 -0500
Subject: [PATCH] avcodec/v4l2_context: reinit capture queue on any format
change
v4l2_handle_event() only reinitialises the capture queue when the width
or height reported by VIDIOC_G_FMT differs from the cached format. A
driver may, however, raise V4L2_EVENT_SOURCE_CHANGE for a format change
that leaves the resolution untouched, and the V4L2 stateful decoder
interface requires the client to perform the drain/restart sequence
whenever that event is signalled. Taking the else branch leaves the
capture queue in the drained state the driver put it in, so no further
buffers are ever dequeued and decoding stalls indefinitely.
This is reproducible with bcm2835-codec on a Raspberry Pi 4. Any H.264
stream whose SPS VUI contains a colour description causes the firmware
to report a colour space, which raises MMAL_EVENT_FORMAT_CHANGED. The
driver then marks the capture queue as drained and queues
V4L2_EVENT_SOURCE_CHANGE, but the dimensions are unchanged, so no reinit
happens and h264_v4l2m2m returns no frames at all:
ffmpeg -f lavfi -i testsrc=size=720x480:rate=25:duration=5 \
-c:v libx264 -pix_fmt yuv420p nocolour.mp4
ffmpeg -f lavfi -i testsrc=size=720x480:rate=25:duration=5 \
-c:v libx264 -pix_fmt yuv420p -colorspace smpte170m \
-color_primaries smpte170m -color_trc bt709 colour.mp4
ffmpeg -c:v h264_v4l2m2m -i nocolour.mp4 -f null - # decodes
ffmpeg -c:v h264_v4l2m2m -i colour.mp4 -f null - # hangs, no output
Include the colour space in the comparison, and rename the helper since
it no longer looks only at the resolution.
Signed-off-by: Bob Entwhistle <[email protected]>
---
libavcodec/v4l2_context.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index be1df3785b..05b9e45b35 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -82,15 +82,17 @@ static AVRational v4l2_get_sar(V4L2Context *ctx)
return sar;
}
-static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct
v4l2_format *fmt2)
+static inline unsigned int v4l2_format_changed(V4L2Context *ctx, struct
v4l2_format *fmt2)
{
struct v4l2_format *fmt1 = &ctx->format;
int ret = V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ?
fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width ||
- fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height
+ fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height ||
+ fmt1->fmt.pix_mp.colorspace != fmt2->fmt.pix_mp.colorspace
:
fmt1->fmt.pix.width != fmt2->fmt.pix.width ||
- fmt1->fmt.pix.height != fmt2->fmt.pix.height;
+ fmt1->fmt.pix.height != fmt2->fmt.pix.height ||
+ fmt1->fmt.pix.colorspace != fmt2->fmt.pix.colorspace;
if (ret)
av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n",
@@ -201,7 +203,7 @@ static int v4l2_handle_event(V4L2Context *ctx)
return 0;
}
- if (v4l2_resolution_changed(&s->capture, &cap_fmt)) {
+ if (v4l2_format_changed(&s->capture, &cap_fmt)) {
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);
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]