PR #24583 opened by Forgejo_Fairy URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24583 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24583.patch
MXF output currently reserves only alignment padding after header metadata. Downstream systems that insert additional metadata may need more space to avoid relocating essence. Add `mxf_header_reserve` to the MXF, D-10, and OP-Atom muxers to reserve additional header KLV Fill. Addresses #23853. The option defaults to zero and rounds positive values up to a multiple of the 512-byte KAG. For example, `-mxf_header_reserve 65536` adds 65,536 bytes beyond the existing padding; it does not specify a total header partition size. Combine the reserve with the trailing Fill item and include it in `HeaderByteCount`. Retain four-byte BER lengths where sufficient and use nine-byte lengths for larger Fill items. Backpatch the header count before writing the reserve so that large reserves also work with non-seekable output. Documentation and four FATE tests cover ordinary MXF, D-10, OP-Atom, rounding, and a reserve above 16 MiB written to a pipe. All samples already exist in the FATE suite. Validation on Linux/AArch64: - Built with `--disable-autodetect --disable-doc --disable-debug`. - Passed `make -j8 fate-mxf SAMPLES=/opt/fate-suite` and the eight existing lavf MXF muxing tests: `mxf`, `mxf_d10`, `mxf_opatom`, `mxf_opatom_audio`, `mxf_dv25`, `mxf_dvcpro50`, `mxf_dvcpro100`, and `mxf_ffv1`. - Checked 64 reserve cases across variable-rate/constant-rate MXF, D-10, and video/audio OP-Atom, including MXF/D-10 pipe output. Values were 1, 511, 512, 513, 65536, 65537, 16777216, and 16777217. Verified header counts, Fill boundaries, partition/RIP offsets, and unchanged packet checksums. - Compared omitted/zero-option output byte-for-byte against unmodified master. - Verified rejection of -1 and 2147483648, and successful streaming of 2147483647 rounded to 2 GiB of additional Fill. Harmonic Omneon/Crispin interoperability remains for the reporter to validate. This change implements the configurable reserve; a separate broadcast-profile muxer is outside its scope. >From d884b92b8433e16e382a80e745ee3026e1bebf22 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 20 Sep 2026 12:51:34 +0000 Subject: [PATCH] avformat/mxfenc: add configurable header metadata reserve Add mxf_header_reserve to reserve additional KLV Fill after the header metadata for downstream metadata insertion. Round the requested space up to the KAG size and include it in HeaderByteCount. A zero default preserves the existing output. Combine the reserve with the existing trailing fill and use a longer BER length when it exceeds the four-byte encoding's capacity. Backpatch the header byte count before writing the potentially large reserve so that non-seekable output still works. Document the option and add FATE coverage for MXF, D-10, OP-Atom, and a large reserve written to a pipe. Existing FATE samples suffice. Addresses #23853. Assisted-by: Fairy --- doc/muxers.texi | 10 ++++++++++ libavformat/mxfenc.c | 24 ++++++++++++++++++++++-- tests/fate/mxf.mak | 14 ++++++++++++++ tests/ref/fate/mxf-d10-header-reserve | 11 +++++++++++ tests/ref/fate/mxf-header-reserve | 19 +++++++++++++++++++ tests/ref/fate/mxf-header-reserve-pipe | 1 + tests/ref/fate/mxf-opatom-header-reserve | 11 +++++++++++ 7 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/ref/fate/mxf-d10-header-reserve create mode 100644 tests/ref/fate/mxf-header-reserve create mode 100644 tests/ref/fate/mxf-header-reserve-pipe create mode 100644 tests/ref/fate/mxf-opatom-header-reserve diff --git a/doc/muxers.texi b/doc/muxers.texi index 95f7ea33a7..181715bff1 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -3348,6 +3348,16 @@ MXF muxer. The muxer options are: @table @option +@item mxf_header_reserve @var{bytes} +Reserve additional space after the header metadata for downstream metadata +insertion. The space is written as KLV Fill in the header partition and +included in its HeaderByteCount. The value specifies additional bytes of +KLV Fill, including any key and length overhead, and is rounded up to a +multiple of 512 bytes. It does not specify the total header partition size. +The default is 0, which preserves the existing alignment-only padding. +The range is 0 to 2147483647. This option is available for @code{mxf}, +@code{mxf_d10}, and @code{mxf_opatom}. + @item store_user_comments @var{bool} Set if user comments should be stored if available or never. IRT D-10 does not allow user comments. The default is thus to write them for diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 48043a7d47..03cbcecbc0 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -466,6 +466,7 @@ typedef struct MXFContext { int essence_container_count; AVRational time_base; int header_written; + int header_reserve; MXFIndexEntry *index_entries; unsigned edit_units_count; uint64_t timestamp; ///< timestamp, as year(16),month(8),day(8),hour(8),minutes(8),msec/4(8) @@ -2273,7 +2274,9 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, if (write_metadata) { // mark the start of the headermetadata and calculate metadata size int64_t pos, start; - unsigned header_byte_count; + uint64_t header_byte_count; + int64_t reserve = partition_offset ? 0 : + FFALIGN((int64_t)mxf->header_reserve, KAG_SIZE); mxf_write_klv_fill(s); start = avio_tell(s->pb); @@ -2281,12 +2284,27 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, mxf_write_klv_fill(s); mxf_write_header_metadata_sets(s); pos = avio_tell(s->pb); - header_byte_count = pos - start + klv_fill_size(pos); + header_byte_count = pos - start + klv_fill_size(pos) + reserve; // update header_byte_count avio_seek(pb, header_byte_count_offset, SEEK_SET); avio_wb64(pb, header_byte_count); avio_seek(pb, pos, SEEK_SET); + + if (reserve) { + /* Backpatch before writing the reserve, which may flush the + * buffer even on non-seekable outputs. */ + reserve += klv_fill_size(pos); + avio_write(pb, klv_fill_key, 16); + if (reserve - 20 <= 0xFFFFFF) { + reserve -= 20; + klv_encode_ber4_length(pb, reserve); + } else { + reserve -= 25; + klv_encode_ber9_length(pb, reserve); + } + ffio_fill(pb, 0, reserve); + } } if(key) @@ -3639,6 +3657,8 @@ static int mxf_check_bitstream(AVFormatContext *s, AVStream *st, const AVPacket } #define MXF_COMMON_OPTIONS \ + { "mxf_header_reserve", "Additional header KLV Fill size in bytes, rounded up to a multiple of 512",\ + offsetof(MXFContext, header_reserve), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},\ { "signal_standard", "Force/set Signal Standard",\ offsetof(MXFContext, signal_standard), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, .unit = "signal_standard"},\ { "bt601", "ITU-R BT.601 and BT.656, also SMPTE 125M (525 and 625 line interlaced)",\ diff --git a/tests/fate/mxf.mak b/tests/fate/mxf.mak index 10c310dd34..2d9eace3f5 100644 --- a/tests/fate/mxf.mak +++ b/tests/fate/mxf.mak @@ -58,6 +58,20 @@ fate-mxf-d10-user-comments: CMD = transcode mxf $(TARGET_SAMPLES)/mxf/Avid-00005 FATE_MXF-$(call DEMMUX, MXF, MXF_OPATOM, MPEGVIDEO_PARSER MPEG2VIDEO_DECODER) += fate-mxf-opatom-user-comments fate-mxf-opatom-user-comments: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -an -vcodec copy -metadata "comment_test=value" -fflags +bitexact -f mxf_opatom +# Exercise header rewriting, KAG rounding, and demuxing with reserved metadata space. +FATE_MXF-$(call REMUX, MXF, MPEGVIDEO_PARSER MPEG2VIDEO_DECODER) += fate-mxf-header-reserve +fate-mxf-header-reserve: CMD = transcode mxf $(TARGET_SAMPLES)/mxf/Sony-00001.mxf mxf "-c copy -t 0.12 -mxf_header_reserve 65536" "-c copy" + +# A reserve above 16 MiB needs a longer BER length and flushes the AVIO buffer. +FATE_MXF-$(call DEMMUX, MXF, MXF, MPEGVIDEO_PARSER MPEG2VIDEO_DECODER PIPE_PROTOCOL) += fate-mxf-header-reserve-pipe +fate-mxf-header-reserve-pipe: CMD = md5pipe -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -t 0.12 -mxf_header_reserve 16777217 -fflags +bitexact -f mxf + +FATE_MXF-$(call TRANSCODE, MPEG2VIDEO, MXF_D10 MXF, MPEGVIDEO_PARSER EXTRACT_EXTRADATA_BSF) += fate-mxf-d10-header-reserve +fate-mxf-d10-header-reserve: CMD = transcode mxf $(TARGET_SAMPLES)/mxf/Sony-00001.mxf mxf_d10 "-c:v mpeg2video -b:v 50000k -minrate:v 50000k -maxrate:v 50000k -bufsize:v 2000000 -rc_init_occupancy 2000000 -g 1 -an -t 0.12 -mxf_header_reserve 1" "-c copy" + +FATE_MXF-$(call REMUX, MXF_OPATOM MXF, MPEGVIDEO_PARSER MPEG2VIDEO_DECODER) += fate-mxf-opatom-header-reserve +fate-mxf-opatom-header-reserve: CMD = transcode mxf $(TARGET_SAMPLES)/mxf/Sony-00001.mxf mxf_opatom "-c copy -an -t 0.12 -mxf_header_reserve 65537" "-c copy" + FATE_SAMPLES_FFMPEG += $(FATE_MXF-yes) FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_MXF_FFMPEG_FFPROBE-yes) FATE_SAMPLES_FFPROBE += $(FATE_MXF_PROBE-yes) diff --git a/tests/ref/fate/mxf-d10-header-reserve b/tests/ref/fate/mxf-d10-header-reserve new file mode 100644 index 0000000000..626384c7dd --- /dev/null +++ b/tests/ref/fate/mxf-d10-header-reserve @@ -0,0 +1,11 @@ +733ad8e5047b7b79e691ba3fcdf1a77d *tests/data/fate/mxf-d10-header-reserve.mxf_d10 +759341 tests/data/fate/mxf-d10-header-reserve.mxf_d10 +#extradata 0: 34, 0x6cb90561 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: mpeg2video +#dimensions 0: 720x608 +#sar 0: 152/135 +0, -1, 0, 1, 250000, 0x8bb844b0 +0, 0, 1, 1, 250000, 0xbeae1f65 +0, 1, 2, 1, 250000, 0xd25c8555 diff --git a/tests/ref/fate/mxf-header-reserve b/tests/ref/fate/mxf-header-reserve new file mode 100644 index 0000000000..925007b73b --- /dev/null +++ b/tests/ref/fate/mxf-header-reserve @@ -0,0 +1,19 @@ +2150815593aca5ecd899e3b30e9874e2 *tests/data/fate/mxf-header-reserve.mxf +883257 tests/data/fate/mxf-header-reserve.mxf +#extradata 0: 22, 0x32ea0490 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: mpeg2video +#dimensions 0: 720x608 +#sar 0: 152/135 +#tb 1: 1/48000 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 48000 +#channel_layout_name 1: 7.1 +0, 0, 0, 1, 237628, 0xeff25579 +1, 0, 0, 1920, 30720, 0xa38d58ed +0, 1, 1, 1, 238066, 0xb2265f41 +1, 1920, 1920, 1920, 30720, 0x4f2a0ded +0, 2, 2, 1, 237723, 0x00d7cd24 +1, 3840, 3840, 1920, 30720, 0x2ee79ff8 diff --git a/tests/ref/fate/mxf-header-reserve-pipe b/tests/ref/fate/mxf-header-reserve-pipe new file mode 100644 index 0000000000..7e615d517d --- /dev/null +++ b/tests/ref/fate/mxf-header-reserve-pipe @@ -0,0 +1 @@ +d7ec7c962a493fe45b0b35dcdaaaffd0 diff --git a/tests/ref/fate/mxf-opatom-header-reserve b/tests/ref/fate/mxf-opatom-header-reserve new file mode 100644 index 0000000000..87c7823e39 --- /dev/null +++ b/tests/ref/fate/mxf-opatom-header-reserve @@ -0,0 +1,11 @@ +cd1900c0d97005a39b2ab8c65ac59eed *tests/data/fate/mxf-opatom-header-reserve.mxf_opatom +786489 tests/data/fate/mxf-opatom-header-reserve.mxf_opatom +#extradata 0: 22, 0x32ea0490 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: mpeg2video +#dimensions 0: 720x608 +#sar 0: 152/135 +0, 0, 0, 1, 237628, 0xeff25579 +0, 1, 1, 1, 238066, 0xb2265f41 +0, 2, 2, 1, 237723, 0x00d7cd24 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
