PR #24976 opened by gnattu URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24976 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24976.patch
When inserting A53 closed caption SEI, the encoder appends the caption payload to an existing SEI NAL unit produced by VideoToolbox, if any. This requires parsing that NAL unit, and the parser does not account for emulation prevention bytes. When the SEI emitted by VideoToolbox contains them, as its user_data_unregistered message can, parsing fails with AVERROR_INVALIDDATA, which previously was not fatal but now causes encoding to fail. The merging is not needed in the first place. H.264 allows an access unit to contain multiple SEI NAL units and only requires that they precede the primary coded picture (ITU-T H.264, 7.4.1.2.3). The encoder already writes the caption SEI as its own NAL unit before the first slice when VideoToolbox emits no SEI, so use that path unconditionally and remove the merging logic. Existing SEI NAL units are passed through unchanged, with the caption SEI placed after them. This keeps any buffering period SEI message first in the first SEI NAL unit, as 7.4.1.2.3 requires. Signed-off-by: gnattu <[email protected]> # 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 0df2759fd9ad3fc06f38a4eb755871b2de388011 Mon Sep 17 00:00:00 2001 From: gnattu <[email protected]> Date: Sat, 10 Oct 2026 00:24:45 +0800 Subject: [PATCH] avcodec/videotoolboxenc: remove caption SEI merging When inserting A53 closed caption SEI, the encoder appends the caption payload to an existing SEI NAL unit produced by VideoToolbox, if any. This requires parsing that NAL unit, and the parser does not account for emulation prevention bytes. When the SEI emitted by VideoToolbox contains them, as its user_data_unregistered message can, parsing fails with AVERROR_INVALIDDATA, which previously was not fatal but now causes encoding to fail. The merging is not needed in the first place. H.264 allows an access unit to contain multiple SEI NAL units and only requires that they precede the primary coded picture (ITU-T H.264, 7.4.1.2.3). The encoder already writes the caption SEI as its own NAL unit before the first slice when VideoToolbox emits no SEI, so use that path unconditionally and remove the merging logic. Existing SEI NAL units are passed through unchanged, with the caption SEI placed after them. This keeps any buffering period SEI message first in the first SEI NAL unit, as 7.4.1.2.3 requires. Signed-off-by: gnattu <[email protected]> --- libavcodec/videotoolboxenc.c | 88 ------------------------------------ 1 file changed, 88 deletions(-) diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index d01a091728..0ff5484e39 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -1851,64 +1851,6 @@ static int is_post_sei_nal_type(int nal_type){ nal_type != H264_NAL_AUD; } -/* - * Finds the sei message start/size of type find_sei_type. - * If more than one of that type exists, the last one is returned. - */ -static int find_sei_end(AVCodecContext *avctx, - uint8_t *nal_data, - size_t nal_size, - uint8_t **sei_end) -{ - int nal_type; - size_t sei_payload_size = 0; - uint8_t *nal_start = nal_data; - *sei_end = NULL; - - if (!nal_size) - return 0; - - nal_type = *nal_data & 0x1F; - if (nal_type != H264_NAL_SEI) - return 0; - - nal_data++; - nal_size--; - - if (nal_data[nal_size - 1] == 0x80) - nal_size--; - - while (nal_size > 0 && *nal_data > 0) { - do{ - nal_data++; - nal_size--; - } while (nal_size > 0 && *nal_data == 0xFF); - - if (!nal_size) { - av_log(avctx, AV_LOG_ERROR, "Unexpected end of SEI NAL Unit parsing type.\n"); - return AVERROR_INVALIDDATA; - } - - do{ - sei_payload_size += *nal_data; - nal_data++; - nal_size--; - } while (nal_size > 0 && *nal_data == 0xFF); - - if (nal_size < sei_payload_size) { - av_log(avctx, AV_LOG_ERROR, "Unexpected end of SEI NAL Unit parsing size.\n"); - return AVERROR_INVALIDDATA; - } - - nal_data += sei_payload_size; - nal_size -= sei_payload_size; - } - - *sei_end = nal_data; - - return nal_data - nal_start + 1; -} - /** * Copies the data inserting emulation prevention bytes as needed. * Existing data in the destination can be taken into account by providing @@ -2098,7 +2040,6 @@ static int copy_replace_length_codes( } if (sei && !wrote_sei && is_post_sei_nal_type(nal_type)) { - //No SEI NAL unit - insert. int wrote_bytes; memcpy(dst_data, start_code, sizeof(start_code)); @@ -2155,35 +2096,6 @@ static int copy_replace_length_codes( return AVERROR_EXTERNAL; } - if (sei && !wrote_sei && nal_type == H264_NAL_SEI) { - //Found SEI NAL unit - append. - int wrote_bytes; - int old_sei_length; - int extra_bytes; - uint8_t *new_sei; - old_sei_length = find_sei_end(avctx, dst_box, box_len, &new_sei); - if (old_sei_length < 0) - return old_sei_length; - - wrote_bytes = write_sei(sei, - SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, - new_sei, - remaining_dst_size - old_sei_length); - if (wrote_bytes < 0) - return wrote_bytes; - - if (new_sei + wrote_bytes >= dst_data + remaining_dst_size) - return AVERROR_BUFFER_TOO_SMALL; - - new_sei[wrote_bytes++] = 0x80; - extra_bytes = wrote_bytes - (dst_box + box_len - new_sei); - - dst_data += extra_bytes; - remaining_dst_size -= extra_bytes; - - wrote_sei = 1; - } - src_offset += curr_src_len; dst_data += curr_dst_len; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
