PR #25226 opened by rajeshgk URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25226 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25226.patch
Add six RTP packet-size boundary cases covering MPEG video, MP2, and PCM S16BE. Verify header-time rejection for MPEG payloads and packet-time rejection for PCM samples. Check that accepted media packets respect the configured packet-size limit. Provide a header-only mode for safe baseline comparison with older RTP muxers. Depends on the RTP packet-size security fix in FFmpeg PR #25222. The full PCM regression requires that fix to avoid a legacy nonterminating packetization loop. # Summary of changes Briefly describe what this PR does and why. <!-- If this PR requires new FATE test samples, attach them to the PR and list their target paths below (relative to the fate-suite root). Attached filenames must match the sample's filename: ```fate-samples # e.g. vorbis/new-sample.ogg ``` --> >From c4f1113a3e68d8515d76460f9beccff7ef95b66c Mon Sep 17 00:00:00 2001 From: Rajesh Gopinath Kumar <[email protected]> Date: Mon, 19 Oct 2026 15:52:54 -0500 Subject: [PATCH] fate: add RTP packet-size boundary regression tests Add six RTP packet-size boundary cases covering MPEG video, MP2, and PCM S16BE. Verify header-time rejection for MPEG payloads and packet-time rejection for PCM samples. Check that accepted media packets respect the configured packet-size limit. Provide a header-only mode for safe baseline comparison with older RTP muxers. Depends on the RTP packet-size security fix in FFmpeg PR #25222. The full PCM regression requires that fix to avoid a legacy nonterminating packetization loop. --- libavformat/Makefile | 1 + libavformat/tests/rtpenc_packetsize.c | 209 ++++++++++++++++++++++++++ tests/fate/libavformat.mak | 4 + tests/ref/fate/rtpenc-packetsize | 7 + 4 files changed, 221 insertions(+) create mode 100644 libavformat/tests/rtpenc_packetsize.c create mode 100644 tests/ref/fate/rtpenc-packetsize diff --git a/libavformat/Makefile b/libavformat/Makefile index 7c17892c22f..8c357d5d885 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -792,6 +792,7 @@ TESTPROGS = id3v2 \ url \ seek_utils TESTPROGS-$(CONFIG_RTPDEC) += rtpdec +TESTPROGS-$(CONFIG_RTP_MUXER) += rtpenc_packetsize # async \ FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer diff --git a/libavformat/tests/rtpenc_packetsize.c b/libavformat/tests/rtpenc_packetsize.c new file mode 100644 index 00000000000..f7e122c7b7e --- /dev/null +++ b/libavformat/tests/rtpenc_packetsize.c @@ -0,0 +1,209 @@ +/* + * RTP packet-size boundary regression tests. + * + * 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. + */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include "libavformat/avformat.h" +#include "libavutil/error.h" +#include "libavutil/mem.h" + +typedef struct Output { + int max_packet_size; + int packets; + int rtcp_packets; + int oversized; +} Output; + +static int write_packet(void *opaque, const uint8_t *buf, int size) +{ + Output *out = opaque; + + /* + * RTCP sender reports are independent control packets. + * The RTP media packet-size limit does not apply to them. + */ + if (size >= 8 && + (buf[0] >> 6) == 2 && + buf[1] == 200 && + ((buf[2] << 8) | buf[3]) == 6) { + out->rtcp_packets++; + return size; + } + + if (size > out->max_packet_size) + out->oversized++; + + out->packets++; + return size; +} + +static int run_case(enum AVCodecID codec_id, int packet_size, + int should_accept) +{ + AVFormatContext *fmt = NULL; + AVIOContext *avio = NULL; + AVStream *st; + Output output = { 0 }; + uint8_t *buffer = NULL; + AVPacket *pkt = NULL; + int ret; + int result = 1; + int header_written = 0; + int header_ret; + int packet_written = 0; + + output.max_packet_size = packet_size; + + ret = avformat_alloc_output_context2(&fmt, NULL, "rtp", NULL); + if (ret < 0 || !fmt) + goto end; + + st = avformat_new_stream(fmt, NULL); + if (!st) + goto end; + + st->codecpar->codec_id = codec_id; + + if (codec_id == AV_CODEC_ID_PCM_S16BE || + codec_id == AV_CODEC_ID_MP2) { + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->sample_rate = 44100; + st->codecpar->ch_layout.nb_channels = 1; + } else { + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->width = 64; + st->codecpar->height = 64; + } + + buffer = av_malloc(4096); + if (!buffer) + goto end; + + avio = avio_alloc_context(buffer, 4096, 1, &output, + NULL, write_packet, NULL); + if (!avio) + goto end; + buffer = NULL; + + avio->max_packet_size = packet_size; + fmt->pb = avio; + fmt->flags |= AVFMT_FLAG_CUSTOM_IO; + fmt->packet_size = packet_size; + + ret = avformat_write_header(fmt, NULL); + header_ret = ret; + if (ret >= 0) + header_written = 1; + + /* + * MPEG video and audio must reject undersized RTP packets at header + * initialization. Avoid writing those invalid packets because older + * implementations can enter nonterminating packetization loops. + * + * PCM sample alignment is checked during packet writing, so PCM + * rejection cases must still exercise av_write_frame(). + */ + if (ret >= 0 && + (should_accept || codec_id == AV_CODEC_ID_PCM_S16BE)) { + pkt = av_packet_alloc(); + if (!pkt) + goto end; + + ret = av_new_packet(pkt, 128); + if (ret < 0) + goto end; + + memset(pkt->data, 0x55, pkt->size); + pkt->stream_index = 0; + pkt->pts = 0; + pkt->dts = 0; + pkt->duration = 1; + + packet_written = 1; + ret = av_write_frame(fmt, pkt); + } + + if (avio) + avio_flush(avio); + + if (should_accept) { + result = ret < 0 || + !packet_written || + output.oversized != 0 || + output.packets == 0; + } else if (codec_id == AV_CODEC_ID_PCM_S16BE) { + result = header_ret < 0 || + !packet_written || + ret >= 0 || + output.oversized != 0; + } else { + result = header_ret >= 0 || + packet_written || + output.oversized != 0; + } + + printf("%-12s size=%-3d expected=%s result=%s\n", + avcodec_get_name(codec_id), + packet_size, + should_accept ? "accept" : "reject", + result ? "FAIL" : "PASS"); + +end: + if (header_written && ret >= 0) + av_write_trailer(fmt); + + av_packet_free(&pkt); + + if (fmt) + fmt->pb = NULL; + + if (avio) + avio_context_free(&avio); + + av_free(buffer); + avformat_free_context(fmt); + + return result; +} + +int main(int argc, char **argv) +{ + int failures = 0; + int header_only = argc == 2 && + !strcmp(argv[1], "--header-only"); + + if (argc > 1 && !header_only) { + fprintf(stderr, "Usage: %s [--header-only]\n", argv[0]); + return 2; + } + + failures += run_case(AV_CODEC_ID_MPEG1VIDEO, 16, 0); + failures += run_case(AV_CODEC_ID_MPEG1VIDEO, 17, 1); + failures += run_case(AV_CODEC_ID_MP2, 16, 0); + failures += run_case(AV_CODEC_ID_MP2, 17, 1); + + /* + * PCM rejection occurs during packet writing. Older RTP muxers + * can enter a nonterminating loop when the payload cannot fit + * a complete sample. Skip PCM in header-only baseline mode. + */ + if (!header_only) { + failures += run_case(AV_CODEC_ID_PCM_S16BE, 13, 0); + failures += run_case(AV_CODEC_ID_PCM_S16BE, 14, 1); + } + + printf("RTP packet-size regression: %s\n", + failures ? "FAIL" : "PASS"); + + return failures ? 1 : 0; +} diff --git a/tests/fate/libavformat.mak b/tests/fate/libavformat.mak index 45878891fd9..0fa8332187d 100644 --- a/tests/fate/libavformat.mak +++ b/tests/fate/libavformat.mak @@ -52,6 +52,10 @@ FATE_LIBAVFORMAT-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += fate-rtmpdh fate-rtmpdh: libavformat/tests/rtmpdh$(EXESUF) fate-rtmpdh: CMD = run libavformat/tests/rtmpdh$(EXESUF) +FATE_LIBAVFORMAT-$(CONFIG_RTP_MUXER) += fate-rtpenc-packetsize +fate-rtpenc-packetsize: libavformat/tests/rtpenc_packetsize$(EXESUF) +fate-rtpenc-packetsize: CMD = run libavformat/tests/rtpenc_packetsize$(EXESUF) + FATE_LIBAVFORMAT-$(CONFIG_RTPDEC) += fate-rtpdec fate-rtpdec: libavformat/tests/rtpdec$(EXESUF) fate-rtpdec: CMD = run libavformat/tests/rtpdec$(EXESUF) diff --git a/tests/ref/fate/rtpenc-packetsize b/tests/ref/fate/rtpenc-packetsize new file mode 100644 index 00000000000..d6a9160b24c --- /dev/null +++ b/tests/ref/fate/rtpenc-packetsize @@ -0,0 +1,7 @@ +mpeg1video size=16 expected=reject result=PASS +mpeg1video size=17 expected=accept result=PASS +mp2 size=16 expected=reject result=PASS +mp2 size=17 expected=accept result=PASS +pcm_s16be size=13 expected=reject result=PASS +pcm_s16be size=14 expected=accept result=PASS +RTP packet-size regression: PASS -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
