This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 260f5a47a5cdf24c359f9979efd3d151985bc2b6
Author:     Zhao Zhili <[email protected]>
AuthorDate: Thu Dec 18 20:33:19 2025 +0800
Commit:     Zhao Zhili <[email protected]>
CommitDate: Tue Dec 23 03:20:34 2025 +0000

    avformat/rawvideodec: add stride option to skip line padding
    
    Some tools like v4l2-ctl dump data without skip padding. If the
    padding size is not an integer multiple of the number of pixel
    bytes, we cannot handle it by using a larger width, e.g.,, for
    RGB24 image with 32 bytes padding in each line.
---
 doc/demuxers.texi                 | 12 +++++
 libavformat/rawvideodec.c         | 99 ++++++++++++++++++++++++++++++++++++---
 libavformat/version.h             |  2 +-
 tests/fate/demux.mak              |  6 +++
 tests/ref/fate/rawvideo-rgb-demux |  7 +++
 tests/ref/fate/rawvideo-yuv-demux |  8 ++++
 6 files changed, 127 insertions(+), 7 deletions(-)

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 3de9992976..c1dda7f1eb 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1035,6 +1035,11 @@ Set input video frame rate. Default value is 25.
 @item pixel_format
 Set the input video pixel format. Default value is @code{yuv420p}.
 
+@item stride
+Set frame line size in bytes, only required if there are extra padding.
+For multiplane formats, @option{stride} is a list of line size for each
+plane.
+
 @item video_size
 Set the input video size. This value must be specified explicitly.
 @end table
@@ -1047,6 +1052,13 @@ the command:
 ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 
input.raw
 @end example
 
+Read a rawvideo with @command{ffplay}, assuming a pixel format of 
@code{yuv420p},
+a video size of @code{1080x1920}, has 8 bytes of padding in each line of Y 
plane,
+and 4 bytes of padding with UV plane,
+@example
+ffplay -f rawvideo -pixel_format yuv420p -video_size 1080x1920 -stride 
1088,544,544 input.raw
+@end example
+
 @anchor{rcwtdec}
 @section rcwt
 
diff --git a/libavformat/rawvideodec.c b/libavformat/rawvideodec.c
index 1fde1124a5..67aedabe8c 100644
--- a/libavformat/rawvideodec.c
+++ b/libavformat/rawvideodec.c
@@ -21,6 +21,8 @@
 
 #include "config_components.h"
 
+#include <stdbool.h>
+
 #include "libavutil/imgutils.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/pixdesc.h"
@@ -34,6 +36,18 @@ typedef struct RawVideoDemuxerContext {
     int width, height;        /**< Integers describing video size, set by a 
private option. */
     enum AVPixelFormat pix_fmt;
     AVRational framerate;     /**< AVRational describing framerate, set by a 
private option. */
+
+    bool has_padding;
+    /* We could derive linesize[1 to N] from linesize[0] for multiplane 
formats,
+     * but having users explicitly specify linesize for each plane can reduce
+     * unexpected results and support more use cases.
+     */
+    int *linesize;
+    unsigned nb_linesize;
+    // with padding
+    size_t frame_size;
+    // linesize without padding
+    int raw_bytes[4];
 } RawVideoDemuxerContext;
 
 // v210 frame width is padded to multiples of 48
@@ -63,6 +77,37 @@ static int rawvideo_read_header(AVFormatContext *ctx)
     st->codecpar->width  = s->width;
     st->codecpar->height = s->height;
 
+    if (s->nb_linesize) {
+        int n = av_pix_fmt_count_planes(pix_fmt);
+        if (s->nb_linesize != n) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid number of stride %u, "
+                   "pixel format has %d plane\n",
+                   s->nb_linesize, n);
+            return AVERROR(EINVAL);
+        }
+
+        ret = av_image_fill_linesizes(s->raw_bytes, pix_fmt, s->width);
+        if (ret < 0)
+            return ret;
+
+        size_t linesize[4] = {0};
+        for (int i = 0; i < n; i++) {
+            if (s->linesize[i] < s->raw_bytes[i]) {
+                av_log(ctx, AV_LOG_ERROR, "Invalid stride %u of plane %d, "
+                       "minimum required size is %d for width %d\n",
+                       s->linesize[i], i, s->raw_bytes[i], s->width);
+                return AVERROR(EINVAL);
+            }
+            if (s->linesize[i] > s->raw_bytes[i])
+                s->has_padding = true;
+            linesize[i] = s->linesize[i];
+        }
+
+        size_t plane_size[4] = {0};
+        av_image_fill_plane_sizes(plane_size, pix_fmt, s->height, linesize);
+        s->frame_size = plane_size[0] + plane_size[1] + plane_size[2] + 
plane_size[3];
+    }
+
     if (ffifmt(ctx->iformat)->raw_codec_id == AV_CODEC_ID_BITPACKED) {
         unsigned int pgroup; /* size of the pixel group in bytes */
         unsigned int xinc;
@@ -110,24 +155,66 @@ static int rawvideo_read_header(AVFormatContext *ctx)
 }
 
 
-static int rawvideo_read_packet(AVFormatContext *s, AVPacket *pkt)
+static int rawvideo_read_packet(AVFormatContext *ctx, AVPacket *pkt)
 {
     int ret;
+    RawVideoDemuxerContext *s = ctx->priv_data;
+
+    if (!s->has_padding) {
+        ret = av_get_packet(ctx->pb, pkt, ctx->packet_size);
+        if (ret < 0)
+            return ret;
+        pkt->pts = pkt->dts = pkt->pos / ctx->packet_size;
 
-    ret = av_get_packet(s->pb, pkt, s->packet_size);
-    pkt->pts = pkt->dts = pkt->pos / s->packet_size;
+        return 0;
+    }
 
-    pkt->stream_index = 0;
+    ret = av_new_packet(pkt, ctx->packet_size);
     if (ret < 0)
         return ret;
+
+    pkt->pos = avio_tell(ctx->pb);
+    pkt->pts = pkt->dts = pkt->pos / s->frame_size;
+
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->pix_fmt);
+    uint8_t *p = pkt->data;
+    for (int i = 0; i < s->nb_linesize; i++) {
+        int shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
+        int h = AV_CEIL_RSHIFT(s->height, shift);
+        int skip_bytes = s->linesize[i] - s->raw_bytes[i];
+
+        for (int j = 0; j < h; j++) {
+            ret = avio_read(ctx->pb, p, s->raw_bytes[i]);
+            if (ret != s->raw_bytes[i]) {
+                if (ret < 0 && ret != AVERROR_EOF)
+                    return ret;
+
+                if (ret == AVERROR_EOF && p == pkt->data)
+                    return AVERROR_EOF;
+
+                memset(p, 0, pkt->size - (p - pkt->data));
+                pkt->flags |= AV_PKT_FLAG_CORRUPT;
+
+                return 0;
+            }
+
+            p += s->raw_bytes[i];
+            avio_skip(ctx->pb, skip_bytes);
+        }
+    }
+
     return 0;
 }
 
 #define OFFSET(x) offsetof(RawVideoDemuxerContext, x)
 #define DEC AV_OPT_FLAG_DECODING_PARAM
 static const AVOption rawvideo_options[] = {
+    // Only supported by rawvideo demuxer
+    {"stride", "frame line size in bytes", OFFSET(linesize), AV_OPT_TYPE_INT | 
AV_OPT_TYPE_FLAG_ARRAY, {.arr = NULL}, 0, INT_MAX, DEC },
+#define BITPACKED_OPTION_OFFSET 1   // skip stride option
     /* pixel_format is not used by the v210 demuxers. */
     { "pixel_format", "set pixel format", OFFSET(pix_fmt), 
AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, AV_PIX_FMT_YUV420P, 
INT_MAX, DEC },
+#define V210_OPTION_OFFSET 2       // skip stride and pixel_format option
     { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, 
{.str = NULL}, 0, 0, DEC },
     { "framerate", "set frame rate", OFFSET(framerate), 
AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC },
     { NULL },
@@ -155,7 +242,7 @@ const FFInputFormat ff_rawvideo_demuxer = {
 static const AVClass bitpacked_demuxer_class = {
     .class_name = "bitpacked demuxer",
     .item_name  = av_default_item_name,
-    .option     = rawvideo_options,
+    .option     = &rawvideo_options[BITPACKED_OPTION_OFFSET],
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
@@ -176,7 +263,7 @@ const FFInputFormat ff_bitpacked_demuxer = {
 static const AVClass v210_demuxer_class = {
     .class_name = "v210(x) demuxer",
     .item_name  = av_default_item_name,
-    .option     = rawvideo_options + 1,
+    .option     = &rawvideo_options[V210_OPTION_OFFSET],
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
diff --git a/libavformat/version.h b/libavformat/version.h
index 35d796d318..392211f6b0 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@
 #include "version_major.h"
 
 #define LIBAVFORMAT_VERSION_MINOR   8
-#define LIBAVFORMAT_VERSION_MICRO 100
+#define LIBAVFORMAT_VERSION_MICRO 101
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak
index 5ad576608e..63b20cd458 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -136,6 +136,12 @@ fate-pva-demux: CMD = framecrc -idct simple -i 
$(TARGET_SAMPLES)/pva/PVA_test-pa
 FATE_SAMPLES_DEMUX-$(call CRC, QCP) += fate-qcp-demux
 fate-qcp-demux: CMD = crc -i $(TARGET_SAMPLES)/qcp/0036580847.QCP -c:a copy
 
+FATE_SAMPLES_DEMUX-$(call FRAMECRC, RAWVIDEO, RAWVIDEO) += 
fate-rawvideo-rgb-demux
+fate-rawvideo-rgb-demux: CMD = framecrc -f rawvideo -pixel_format rgb24 
-video_size 160x500 -stride 512 -i $(TARGET_SAMPLES)/hevc/two_first_slice.mp4
+
+FATE_SAMPLES_DEMUX-$(call FRAMECRC, RAWVIDEO, RAWVIDEO) += 
fate-rawvideo-yuv-demux
+fate-rawvideo-yuv-demux: CMD = framecrc -f rawvideo -pixel_format yuv420p 
-video_size 250x500 -stride 256,128,128 -i 
$(TARGET_SAMPLES)/hevc/two_first_slice.mp4
+
 FATE_SAMPLES_DEMUX-$(call FRAMECRC, R3D, JPEG2000 PCM_S32BE) += 
fate-redcode-demux
 fate-redcode-demux: CMD = framecrc -i $(TARGET_SAMPLES)/r3d/4MB-sample.r3d 
-c:v copy -c:a copy
 
diff --git a/tests/ref/fate/rawvideo-rgb-demux 
b/tests/ref/fate/rawvideo-rgb-demux
new file mode 100644
index 0000000000..5231b84a59
--- /dev/null
+++ b/tests/ref/fate/rawvideo-rgb-demux
@@ -0,0 +1,7 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 160x500
+#sar 0: 0/1
+0,          0,          0,        1,   240000, 0x184c16a4
+0,          1,          1,        1,   240000, 0xb28b58b2
diff --git a/tests/ref/fate/rawvideo-yuv-demux 
b/tests/ref/fate/rawvideo-yuv-demux
new file mode 100644
index 0000000000..40aab0378f
--- /dev/null
+++ b/tests/ref/fate/rawvideo-yuv-demux
@@ -0,0 +1,8 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 250x500
+#sar 0: 0/1
+0,          0,          0,        1,   187500, 0x16e17c12
+0,          1,          1,        1,   187500, 0xd36f0de2
+0,          2,          2,        1,   187500, 0x7bb2ca21

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to