From: sohamukute via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: sohamukute <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] fate: add tests for h261_parser and yuv4mpegenc, extend file test (PR #22237)
Date: Sat, 21 Feb 2026 05:31:50 -0000
Message-ID: <177165191131.25.15704043415661500015@29965ddac10e> (raw)
PR #22237 opened by sohamukute
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22237
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22237.patch
libavutil/tests/file.c: add error path coverage for av_file_map()
with nonexistent files and non-zero log_offset.
libavcodec/tests/h261_parser.c: test the h261 parser with a flush
call, garbage input, mid-buffer PSC, split input across two calls,
and both QCIF and CIF source formats.
libavformat/tests/yuv4mpegenc.c: test the yuv4mpegpipe muxer with
various pixel formats (yuv420p/422p/444p/411p/gray8/yuvj*), square
and non-square SAR, unknown SAR, interlaced and progressive field
order, limited and full color range, and an unsupported pixel format
that must be rejected.
Coverage results (measured with gcov on Linux x86_64):
libavutil/file.c:
Lines: 8.8% -> 64.7% (remaining uncovered: Windows-only code paths)
Branches: 8.3% -> 100%
libavcodec/h261_parser.c:
Lines: 21.9% -> 96.9%
Branches: 5.0% -> 100%
libavformat/yuv4mpegenc.c:
Lines: 32.2% -> 47.9%
Branches: 30.0% -> 77.1%
Note: yuv4mpegenc line coverage is limited by non-standard pixel
formats requiring -strict -1 and the wrapped avframe write path.
Branch coverage improved from 30% to 77%. Tested on Linux x86_64.
Signed-off-by: Soham Kute <officialsohamkute@gmail.com>
From fd605c7b0f8c8cbb1a107f94b218c60cd6aee3a9 Mon Sep 17 00:00:00 2001
From: Soham Kute <officialsohamkute@gmail.com>
Date: Sat, 21 Feb 2026 10:50:12 +0530
Subject: [PATCH] fate: add coverage tests for file, h261_parser and
yuv4mpegenc
Extend and add self-tests to improve branch and line coverage:
- libavutil/tests/file.c: extend existing test to cover av_file_map()
error paths (nonexistent file, non-zero log_offset branch).
Lines: 8.8% -> 64.7%, Branches: 8.3% -> 100%
- libavcodec/tests/h261_parser.c: new test covering flush call (size=0),
garbage input with no PSC, PSC at mid-buffer, split PSC across two
calls, and QCIF/CIF source format detection branches.
Lines: 21.9% -> 96.9%, Branches: 5.0% -> 100%
- libavformat/tests/yuv4mpegenc.c: new test covering pixel format
variants (YUV420P/422P/444P/411P/GRAY8/YUVJ*), SAR branches
(square/non-square/unknown), interlacing (progressive/TFF/BFF),
color range (MPEG/JPEG/unspecified), write_packet path via raw
frame, and unsupported format rejection.
Lines: 32.2% -> 47.9%, Branches: 30.0% -> 77.1%
Signed-off-by: Soham Kute <officialsohamkute@gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/tests/h261_parser.c | 125 +++++++++++++++++++++++++
libavformat/Makefile | 1 +
libavformat/tests/yuv4mpegenc.c | 160 ++++++++++++++++++++++++++++++++
libavutil/tests/file.c | 18 +++-
tests/fate/libavcodec.mak | 5 +
tests/fate/libavformat.mak | 5 +
tests/fate/libavutil.mak | 5 +
8 files changed, 317 insertions(+), 3 deletions(-)
create mode 100644 libavcodec/tests/h261_parser.c
create mode 100644 libavformat/tests/yuv4mpegenc.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 50ac7d712b..0d0917dd57 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1379,6 +1379,7 @@ TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman
TESTPROGS-$(HAVE_MMX) += motion
TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate
TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels
+TESTPROGS-$(CONFIG_H261_DECODER) += h261_parser
TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels
TESTPROGS-$(CONFIG_RANGECODER) += rangecoder
TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc
diff --git a/libavcodec/tests/h261_parser.c b/libavcodec/tests/h261_parser.c
new file mode 100644
index 0000000000..93b14d6d4c
--- /dev/null
+++ b/libavcodec/tests/h261_parser.c
@@ -0,0 +1,125 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/log.h"
+
+/*
+ * H.261 Picture Start Code (PSC): 20 zero bits followed by 1 bit.
+ * Byte layout: 0x00 0x01 0x00 ...
+ * Next bits: temporal_ref(5), split_screen(1), camera(1), freeze(1),
+ * source_format(1): 0=QCIF, 1=CIF
+ */
+
+/* Minimal CIF frame: source_format bit = 1 */
+static const uint8_t cif_frame[] = {
+ 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* Minimal QCIF frame: source_format bit = 0 */
+static const uint8_t qcif_frame[] = {
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* Garbage with no PSC */
+static const uint8_t garbage[] = {
+ 0xff, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78,
+};
+
+/* PSC not at offset 0 */
+static const uint8_t psc_mid[] = {
+ 0xff, 0xab,
+ 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+};
+
+int main(void)
+{
+ AVCodecParserContext *parser;
+ AVCodecContext *avctx;
+ uint8_t *out;
+ int out_size, ret;
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ parser = av_parser_init(AV_CODEC_ID_H261);
+ if (!parser)
+ return 0; /* skip if not compiled in */
+
+ /* A codec-independent context — no decoder required */
+ avctx = avcodec_alloc_context3(NULL);
+ if (!avctx) {
+ av_parser_close(parser);
+ return 1;
+ }
+
+ /* flush (buf_size == 0) */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ NULL, 0, AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ /* garbage — no PSC */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ garbage, sizeof(garbage),
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ /* valid CIF frame */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ cif_frame, sizeof(cif_frame),
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ /* valid QCIF frame */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ qcif_frame, sizeof(qcif_frame),
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ /* PSC not at start of buffer */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ psc_mid, sizeof(psc_mid),
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ /* split input across two calls */
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ cif_frame, 1,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ ret = av_parser_parse2(parser, avctx, &out, &out_size,
+ cif_frame + 1, sizeof(cif_frame) - 1,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+ if (ret < 0)
+ goto fail;
+
+ av_parser_close(parser);
+ avcodec_free_context(&avctx);
+ return 0;
+
+fail:
+ av_parser_close(parser);
+ avcodec_free_context(&avctx);
+ return 1;
+}
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 5b8564bf54..e49fb4a445 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -781,6 +781,7 @@ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer
TESTPROGS-$(CONFIG_FIFO_MUXER) += $(FIFO-MUXER-TESTPROGS-yes)
TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
TESTPROGS-$(CONFIG_MOV_MUXER) += movenc
+TESTPROGS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpegenc
TESTPROGS-$(CONFIG_NETWORK) += noproxy
TESTPROGS-$(CONFIG_SRTP) += srtp
TESTPROGS-$(CONFIG_IMF_DEMUXER) += imf
diff --git a/libavformat/tests/yuv4mpegenc.c b/libavformat/tests/yuv4mpegenc.c
new file mode 100644
index 0000000000..75128648f8
--- /dev/null
+++ b/libavformat/tests/yuv4mpegenc.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+#include "libavcodec/codec_par.h"
+#include "libavcodec/packet.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/pixfmt.h"
+
+static int mux_once(enum AVPixelFormat pix_fmt,
+ AVRational sar, enum AVFieldOrder field_order,
+ enum AVColorRange color_range,
+ int expect_fail)
+{
+ AVFormatContext *oc = NULL;
+ AVStream *st;
+ uint8_t *buf = NULL;
+ int ret;
+
+ ret = avformat_alloc_output_context2(&oc, NULL, "yuv4mpegpipe", NULL);
+ if (ret < 0)
+ return ret;
+
+ st = avformat_new_stream(oc, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codecpar->format = pix_fmt;
+ st->codecpar->width = 16;
+ st->codecpar->height = 16;
+ st->codecpar->field_order = field_order;
+ st->codecpar->color_range = color_range;
+
+ st->sample_aspect_ratio = sar;
+ st->time_base = (AVRational){ 1, 25 };
+ st->avg_frame_rate = (AVRational){ 25, 1 };
+
+ ret = avio_open_dyn_buf(&oc->pb);
+ if (ret < 0)
+ goto end;
+
+ ret = avformat_write_header(oc, NULL);
+ if (ret < 0) {
+ avio_close_dyn_buf(oc->pb, &buf);
+ oc->pb = NULL;
+ av_free(buf);
+ goto end;
+ }
+
+ /* Exercise write_packet with a valid raw YUV420P frame */
+ if (pix_fmt == AV_PIX_FMT_YUV420P) {
+ AVPacket *pkt = av_packet_alloc();
+ if (pkt) {
+ /* YUV420P 16x16: Y=256, U=64, V=64 = 384 bytes */
+ if (av_new_packet(pkt, 384) == 0) {
+ pkt->stream_index = 0;
+ pkt->pts = pkt->dts = 0;
+ pkt->duration = 1;
+ av_write_frame(oc, pkt);
+ }
+ av_packet_free(&pkt);
+ }
+ }
+
+ av_write_trailer(oc);
+ avio_close_dyn_buf(oc->pb, &buf);
+ oc->pb = NULL;
+ av_free(buf);
+
+end:
+ if (oc->pb) {
+ avio_close_dyn_buf(oc->pb, &buf);
+ av_free(buf);
+ oc->pb = NULL;
+ }
+ avformat_free_context(oc);
+
+ if (expect_fail)
+ return (ret < 0) ? 0 : AVERROR(EINVAL);
+ return ret;
+}
+
+int main(void)
+{
+ int ret;
+ const AVRational sar11 = { 1, 1 };
+ const AVRational sar43 = { 4, 3 };
+ const AVRational sar01 = { 0, 1 };
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 1;
+
+ ret = mux_once(AV_PIX_FMT_YUV422P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 2;
+
+ ret = mux_once(AV_PIX_FMT_YUV444P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 3;
+
+ ret = mux_once(AV_PIX_FMT_GRAY8, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 4;
+
+ ret = mux_once(AV_PIX_FMT_YUV411P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 5;
+
+ ret = mux_once(AV_PIX_FMT_YUVJ420P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 6;
+
+ ret = mux_once(AV_PIX_FMT_YUVJ422P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 7;
+
+ ret = mux_once(AV_PIX_FMT_YUVJ444P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 8;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar43, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 9;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar01, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 10;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar11, AV_FIELD_TT, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 11;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar11, AV_FIELD_BB, AVCOL_RANGE_UNSPECIFIED, 0);
+ if (ret < 0) return 12;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_MPEG, 0);
+ if (ret < 0) return 13;
+
+ ret = mux_once(AV_PIX_FMT_YUV420P, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_JPEG, 0);
+ if (ret < 0) return 14;
+
+ /* unsupported pixel format must fail */
+ ret = mux_once(AV_PIX_FMT_RGB24, sar11, AV_FIELD_PROGRESSIVE, AVCOL_RANGE_UNSPECIFIED, 1);
+ if (ret < 0) return 15;
+
+ return 0;
+}
diff --git a/libavutil/tests/file.c b/libavutil/tests/file.c
index 0b151de9a1..ede337646d 100644
--- a/libavutil/tests/file.c
+++ b/libavutil/tests/file.c
@@ -18,15 +18,27 @@
#include "libavutil/file.c"
-int main(void)
+int main(int argc, char **argv)
{
+ const char *path = argc > 1 ? argv[1] : "file.c";
uint8_t *buf;
size_t size;
- if (av_file_map("file.c", &buf, &size, 0, NULL) < 0)
- return 1;
+ if (av_file_map(path, &buf, &size, 0, NULL) < 0)
+ return 1;
buf[0] = 's';
printf("%s", buf);
av_file_unmap(buf, size);
+
+ if (av_file_map("no_such_file_xyz", &buf, &size, 0, NULL) >= 0) {
+ av_file_unmap(buf, size);
+ return 2;
+ }
+
+ if (av_file_map("no_such_file_xyz", &buf, &size, 1, NULL) >= 0) {
+ av_file_unmap(buf, size);
+ return 3;
+ }
+
return 0;
}
diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index e2d616e307..426bbe976c 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -116,3 +116,8 @@ fate-libavcodec-htmlsubtitles: CMD = run libavcodec/tests/htmlsubtitles$(EXESUF)
FATE-$(CONFIG_AVCODEC) += $(FATE_LIBAVCODEC-yes)
fate-libavcodec: $(FATE_LIBAVCODEC-yes)
+
+FATE_LIBAVCODEC-$(CONFIG_H261_DECODER) += fate-h261-parser
+fate-h261-parser: libavcodec/tests/h261_parser$(EXESUF)
+fate-h261-parser: CMD = run libavcodec/tests/h261_parser$(EXESUF)
+fate-h261-parser: CMP = null
diff --git a/tests/fate/libavformat.mak b/tests/fate/libavformat.mak
index 3b3a8a1177..a0349ac762 100644
--- a/tests/fate/libavformat.mak
+++ b/tests/fate/libavformat.mak
@@ -34,3 +34,8 @@ fate-seek_utils: CMP = null
FATE_LIBAVFORMAT += $(FATE_LIBAVFORMAT-yes)
FATE-$(CONFIG_AVFORMAT) += $(FATE_LIBAVFORMAT)
fate-libavformat: $(FATE_LIBAVFORMAT)
+
+FATE_LIBAVFORMAT-$(CONFIG_YUV4MPEGPIPE_MUXER) += fate-yuv4mpegenc
+fate-yuv4mpegenc: libavformat/tests/yuv4mpegenc$(EXESUF)
+fate-yuv4mpegenc: CMD = run libavformat/tests/yuv4mpegenc$(EXESUF)
+fate-yuv4mpegenc: CMP = null
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index 6bf03b2438..18b3257853 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -182,3 +182,8 @@ fate-uuid: CMP = null
FATE_LIBAVUTIL += $(FATE_LIBAVUTIL-yes)
FATE-$(CONFIG_AVUTIL) += $(FATE_LIBAVUTIL)
fate-libavutil: $(FATE_LIBAVUTIL)
+
+FATE_LIBAVUTIL += fate-file
+fate-file: libavutil/tests/file$(EXESUF)
+fate-file: CMD = run libavutil/tests/file$(EXESUF) libavutil/tests/file.c
+fate-file: CMP = null
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
reply other threads:[~2026-02-21 5:50 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=177165191131.25.15704043415661500015@29965ddac10e \
--to=ffmpeg-devel@ffmpeg.org \
--cc=code@ffmpeg.org \
/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