avcodec/bsf/extract_extradata: write correct length start codes for h26x

The specification for H.26{4,5,6} states that start codes may be three or four
bytes long long except for the first NALU in an AU, and for NALUs of parameter
set types, which must be four bytes long.
This is checked by ff_cbs_h2645_unit_requires_zero_byte(), which is made
available outside of CBS for this change.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2026-03-15 19:20:06 -03:00
parent 6bc257e292
commit d1431d3f50
12 changed files with 39 additions and 34 deletions
+8 -3
View File
@@ -181,6 +181,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
int extradata_size = 0, filtered_size = 0;
const int *extradata_nal_types;
size_t nb_extradata_nal_types;
int filtered_nb_nals = 0;
int i, has_sps = 0, has_vps = 0, ret = 0;
if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
@@ -202,7 +203,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
H2645NAL *nal = &s->h2645_pkt.nals[i];
if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
extradata_size += nal->raw_size + 3;
extradata_size += nal->raw_size + 4;
if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
if (nal->type == VVC_SPS_NUT) has_sps = 1;
if (nal->type == VVC_VPS_NUT) has_vps = 1;
@@ -213,7 +214,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
if (nal->type == H264_NAL_SPS) has_sps = 1;
}
} else if (s->remove) {
filtered_size += nal->raw_size + 3;
filtered_size += nal->raw_size + 3 +
ff_h2645_unit_requires_zero_byte(ctx->par_in->codec_id, nal->type, filtered_nb_nals++);
}
}
@@ -246,13 +248,16 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
if (s->remove)
bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size);
filtered_nb_nals = 0;
for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
H2645NAL *nal = &s->h2645_pkt.nals[i];
if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
nal->type)) {
bytestream2_put_be24u(&pb_extradata, 1); //startcode
bytestream2_put_be32u(&pb_extradata, 1); //startcode
bytestream2_put_bufferu(&pb_extradata, nal->raw_data, nal->raw_size);
} else if (s->remove) {
if (ff_h2645_unit_requires_zero_byte(ctx->par_in->codec_id, nal->type, filtered_nb_nals++))
bytestream2_put_byteu(&pb_filtered_data, 0); // zero_byte
bytestream2_put_be24u(&pb_filtered_data, 1); // startcode
bytestream2_put_bufferu(&pb_filtered_data, nal->raw_data, nal->raw_size);
}
+1 -19
View File
@@ -320,24 +320,6 @@ int ff_cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
return 0;
}
int ff_cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id,
CodedBitstreamUnitType type,
int nal_unit_index)
{
// Section B.1.2 in H.264, section B.2.2 in H.265, H.266.
if (nal_unit_index == 0) {
// Assume that this is the first NAL unit in an access unit.
return 1;
}
if (codec_id == AV_CODEC_ID_H264)
return type == H264_NAL_SPS || type == H264_NAL_PPS;
if (codec_id == AV_CODEC_ID_HEVC)
return type == HEVC_NAL_VPS || type == HEVC_NAL_SPS || type == HEVC_NAL_PPS;
if (codec_id == AV_CODEC_ID_VVC)
return type >= VVC_OPI_NUT && type <= VVC_SUFFIX_APS_NUT;
return 0;
}
int ff_cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag)
{
@@ -372,7 +354,7 @@ int ff_cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx,
frag->data_bit_padding = unit->data_bit_padding;
}
if (ff_cbs_h2645_unit_requires_zero_byte(ctx->codec->codec_id, unit->type, i)) {
if (ff_h2645_unit_requires_zero_byte(ctx->codec->codec_id, unit->type, i)) {
// zero_byte
data[dp++] = 0;
}
-4
View File
@@ -63,10 +63,6 @@ int ff_cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
struct PutBitContext *pbc, const uint8_t *data,
size_t data_size, int data_bit_start);
int ff_cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id,
CodedBitstreamUnitType type,
int nal_unit_index);
int ff_cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx,
CodedBitstreamFragment *frag);
+18
View File
@@ -664,6 +664,24 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
return 0;
}
int ff_h2645_unit_requires_zero_byte(enum AVCodecID codec_id,
unsigned int type,
int nal_unit_index)
{
// Section B.1.2 in H.264, section B.2.2 in H.265, H.266.
if (nal_unit_index == 0) {
// Assume that this is the first NAL unit in an access unit.
return 1;
}
if (codec_id == AV_CODEC_ID_H264)
return type == H264_NAL_SPS || type == H264_NAL_PPS;
if (codec_id == AV_CODEC_ID_HEVC)
return type == HEVC_NAL_VPS || type == HEVC_NAL_SPS || type == HEVC_NAL_PPS;
if (codec_id == AV_CODEC_ID_VVC)
return type >= VVC_OPI_NUT && type <= VVC_SUFFIX_APS_NUT;
return 0;
}
void ff_h2645_packet_uninit(H2645Packet *pkt)
{
int i;
+4
View File
@@ -123,6 +123,10 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
*/
void ff_h2645_packet_uninit(H2645Packet *pkt);
int ff_h2645_unit_requires_zero_byte(enum AVCodecID codec_id,
unsigned int type,
int nal_unit_index);
static inline int get_nalsize(int nal_length_size, const uint8_t *buf,
int buf_size, int *buf_index, void *logctx)
{
+2 -2
View File
@@ -1,5 +1,5 @@
0920978f3f8196413c43f0033b55a5b6 *tests/data/fate/copy-trac2211-avi.avi
1777956 tests/data/fate/copy-trac2211-avi.avi
ab1e2b88e25a8a65b0010ce9dc761f97 *tests/data/fate/copy-trac2211-avi.avi
1777958 tests/data/fate/copy-trac2211-avi.avi
#tb 0: 1/14
#media_type 0: video
#codec_id 0: rawvideo
+1 -1
View File
@@ -1,6 +1,6 @@
b6ff5910928ad0b2a7eec481dcc41594 *tests/data/fate/h264_mp4toannexb_ticket2991.h264
1985815 tests/data/fate/h264_mp4toannexb_ticket2991.h264
#extradata 0: 47, 0x3a590d55
#extradata 0: 49, 0x459b0d55
#tb 0: 1/1200000
#media_type 0: video
#codec_id 0: h264
+1 -1
View File
@@ -1,6 +1,6 @@
edddeef7901b2bd8d55625b8105b579f *tests/data/fate/h264_mp4toannexb_ticket5927.h264
595583 tests/data/fate/h264_mp4toannexb_ticket5927.h264
#extradata 0: 33, 0x84e308f7
#extradata 0: 35, 0x8c0208f7
#tb 0: 1/1200000
#media_type 0: video
#codec_id 0: h264
+1 -1
View File
@@ -1,6 +1,6 @@
edddeef7901b2bd8d55625b8105b579f *tests/data/fate/h264_mp4toannexb_ticket5927_2.h264
595583 tests/data/fate/h264_mp4toannexb_ticket5927_2.h264
#extradata 0: 33, 0x84e308f7
#extradata 0: 35, 0x8c0208f7
#tb 0: 1/1200000
#media_type 0: video
#codec_id 0: h264
+1 -1
View File
@@ -1,4 +1,4 @@
#extradata 0: 88, 0x61e61071
#extradata 0: 91, 0x721f1071
#tb 0: 1/1000
#media_type 0: video
#codec_id 0: hevc
+1 -1
View File
@@ -1,4 +1,4 @@
#extradata 0: 50, 0x4f1b0df9
#extradata 0: 52, 0x5a8b0df9
#tb 0: 1/90000
#media_type 0: video
#codec_id 0: h264
+1 -1
View File
@@ -72,5 +72,5 @@ packet|codec_type=video|stream_index=0|pts=546000|pts_time=6.066667|dts=546000|d
packet|codec_type=video|stream_index=0|pts=552000|pts_time=6.133333|dts=552000|dts_time=6.133333|duration=6000|duration_time=0.066667|size=16|pos=15604|flags=___|data_hash=CRC32:cca62b67|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224
packet|codec_type=video|stream_index=0|pts=558000|pts_time=6.200000|dts=558000|dts_time=6.200000|duration=6000|duration_time=0.066667|size=16|pos=15792|flags=___|data_hash=CRC32:27b943ef|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224
packet|codec_type=video|stream_index=0|pts=564000|pts_time=6.266667|dts=564000|dts_time=6.266667|duration=6000|duration_time=0.066667|size=16|pos=16356|flags=___|data_hash=CRC32:f7116111|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224
stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|mime_codec_string=avc1.42c00a|width=82|height=144|coded_width=82|coded_height=144|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=35|extradata_hash=CRC32:e62cae27|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|mime_codec_string=avc1.42c00a|width=82|height=144|coded_width=82|coded_height=144|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=37|extradata_hash=CRC32:1d7ffe93|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0
format|filename=h264small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=4.933333|size=16544|bit_rate=26828|probe_score=50