1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-04 22:03:09 +02:00

avformat/movenc: allow storing more than one extradata buffer per track

This is in preparation for a following change

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2025-07-27 18:10:37 -03:00
parent eefa6de7d5
commit 306448756b
2 changed files with 147 additions and 124 deletions

View File

@ -654,8 +654,8 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
*/ */
static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
{ {
avio_write(pb, track->par->extradata, track->par->extradata_size); avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
return track->par->extradata_size; return track->extradata_size[track->last_stsd_index];
} }
static int mov_write_enda_tag(AVIOContext *pb) static int mov_write_enda_tag(AVIOContext *pb)
@ -749,7 +749,8 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
{ {
struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track); struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
int64_t pos = avio_tell(pb); int64_t pos = avio_tell(pb);
int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0; int decoder_specific_info_len = track->extradata_size[track->last_stsd_index] ?
5 + track->extradata_size[track->last_stsd_index] : 0;
avio_wb32(pb, 0); // size avio_wb32(pb, 0); // size
ffio_wfourcc(pb, "esds"); ffio_wfourcc(pb, "esds");
@ -784,10 +785,11 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
avio_wb32(pb, bit_rates.avg_bit_rate); avio_wb32(pb, bit_rates.avg_bit_rate);
if (track->vos_len) { if (track->extradata_size[track->last_stsd_index]) {
// DecoderSpecific info descriptor // DecoderSpecific info descriptor
put_descr(pb, 0x05, track->vos_len); put_descr(pb, 0x05, track->extradata_size[track->last_stsd_index]);
avio_write(pb, track->vos_data, track->vos_len); avio_write(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index]);
} }
// SL descriptor // SL descriptor
@ -844,13 +846,13 @@ static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
avio_wb24(pb, 0); /* flags */ avio_wb24(pb, 0); /* flags */
/* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */ /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
if (track->par->extradata_size != FLAC_STREAMINFO_SIZE) if (track->extradata_size[track->last_stsd_index] != FLAC_STREAMINFO_SIZE)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
/* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */ /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */ avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
avio_wb24(pb, track->par->extradata_size); /* Length */ avio_wb24(pb, track->extradata_size[track->last_stsd_index]); /* Length */
avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */ avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]); /* BlockData[Length] */
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -862,28 +864,28 @@ static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "dOps"); ffio_wfourcc(pb, "dOps");
avio_w8(pb, 0); /* Version */ avio_w8(pb, 0); /* Version */
if (track->par->extradata_size < 19) { if (track->extradata_size[track->last_stsd_index] < 19) {
av_log(s, AV_LOG_ERROR, "invalid extradata size\n"); av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
/* extradata contains an Ogg OpusHead, other than byte-ordering and /* extradata contains an Ogg OpusHead, other than byte-ordering and
OpusHead's preceeding magic/version, OpusSpecificBox is currently OpusHead's preceeding magic/version, OpusSpecificBox is currently
identical. */ identical. */
channels = AV_RB8(track->par->extradata + 9); channels = AV_RB8(track->extradata[track->last_stsd_index] + 9);
channel_map = AV_RB8(track->par->extradata + 18); channel_map = AV_RB8(track->extradata[track->last_stsd_index] + 18);
avio_w8(pb, channels); /* OuputChannelCount */ avio_w8(pb, channels); /* OuputChannelCount */
avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 10)); /* PreSkip */
avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */ avio_wb32(pb, AV_RL32(track->extradata[track->last_stsd_index] + 12)); /* InputSampleRate */
avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */ avio_wb16(pb, AV_RL16(track->extradata[track->last_stsd_index] + 16)); /* OutputGain */
avio_w8(pb, channel_map); /* ChannelMappingFamily */ avio_w8(pb, channel_map); /* ChannelMappingFamily */
/* Write the rest of the header out without byte-swapping. */ /* Write the rest of the header out without byte-swapping. */
if (channel_map) { if (channel_map) {
if (track->par->extradata_size < 21 + channels) { if (track->extradata_size[track->last_stsd_index] < 21 + channels) {
av_log(s, AV_LOG_ERROR, "invalid extradata size\n"); av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */ avio_write(pb, track->extradata[track->last_stsd_index] + 19, 2 + channels); /* ChannelMappingTable */
} }
return update_size(pb, pos); return update_size(pb, pos);
@ -896,23 +898,23 @@ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "dmlp"); ffio_wfourcc(pb, "dmlp");
if (track->vos_len < 20) { if (track->extradata_size[track->last_stsd_index] < 20) {
av_log(s, AV_LOG_ERROR, av_log(s, AV_LOG_ERROR,
"Cannot write moov atom before TrueHD packets." "Cannot write moov atom before TrueHD packets."
" Set the delay_moov flag to fix this.\n"); " Set the delay_moov flag to fix this.\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
length = (AV_RB16(track->vos_data) & 0xFFF) * 2; length = (AV_RB16(track->extradata[track->last_stsd_index]) & 0xFFF) * 2;
if (length < 20 || length > track->vos_len) if (length < 20 || length > track->extradata_size[track->last_stsd_index])
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
// Only TrueHD is supported // Only TrueHD is supported
if (AV_RB32(track->vos_data + 4) != 0xF8726FBA) if (AV_RB32(track->extradata[track->last_stsd_index] + 4) != 0xF8726FBA)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */ avio_wb32(pb, AV_RB32(track->extradata[track->last_stsd_index] + 8)); /* format_info */
avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */ avio_wb16(pb, AV_RB16(track->extradata[track->last_stsd_index] + 18) << 1); /* peak_data_rate */
avio_wb32(pb, 0); /* reserved */ avio_wb32(pb, 0); /* reserved */
return update_size(pb, pos); return update_size(pb, pos);
@ -1078,7 +1080,8 @@ static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf) static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
{ {
uint8_t *unescaped; uint8_t *unescaped;
const uint8_t *start, *next, *end = track->vos_data + track->vos_len; const uint8_t *start, *next, *end = track->extradata[track->last_stsd_index] +
track->extradata_size[track->last_stsd_index];
int unescaped_size, seq_found = 0; int unescaped_size, seq_found = 0;
int level = 0, interlace = 0; int level = 0, interlace = 0;
int packet_seq = track->vc1_info.packet_seq; int packet_seq = track->vc1_info.packet_seq;
@ -1095,10 +1098,10 @@ static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
"dvc1 atom. Set the delay_moov flag to fix this.\n"); "dvc1 atom. Set the delay_moov flag to fix this.\n");
} }
unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE); unescaped = av_mallocz(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
if (!unescaped) if (!unescaped)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
start = find_next_marker(track->vos_data, end); start = find_next_marker(track->extradata[track->last_stsd_index], end);
for (next = start; next < end; start = next) { for (next = start; next < end; start = next) {
GetBitContext gb; GetBitContext gb;
int size; int size;
@ -1166,20 +1169,22 @@ static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
if ((ret = mov_write_dvc1_structs(track, buf)) < 0) if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
return ret; return ret;
avio_wb32(pb, track->vos_len + 8 + sizeof(buf)); avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8 + sizeof(buf));
ffio_wfourcc(pb, "dvc1"); ffio_wfourcc(pb, "dvc1");
avio_write(pb, buf, sizeof(buf)); avio_write(pb, buf, sizeof(buf));
avio_write(pb, track->vos_data, track->vos_len); avio_write(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index]);
return 0; return 0;
} }
static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
{ {
avio_wb32(pb, track->vos_len + 8); avio_wb32(pb, track->extradata_size[track->last_stsd_index] + 8);
ffio_wfourcc(pb, "glbl"); ffio_wfourcc(pb, "glbl");
avio_write(pb, track->vos_data, track->vos_len); avio_write(pb, track->extradata[track->last_stsd_index],
return 8 + track->vos_len; track->extradata_size[track->last_stsd_index]);
return 8 + track->extradata_size[track->last_stsd_index];
} }
/** /**
@ -1476,7 +1481,7 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = mov_write_pcmc_tag(s, pb, track); ret = mov_write_pcmc_tag(s, pb, track);
} else if (track->vos_len > 0) } else if (track->extradata_size[track->last_stsd_index] > 0)
ret = mov_write_glbl_tag(pb, track); ret = mov_write_glbl_tag(pb, track);
if (ret < 0) if (ret < 0)
@ -1523,7 +1528,8 @@ static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "av1C"); ffio_wfourcc(pb, "av1C");
ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF); ff_isom_write_av1c(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], track->mode != MODE_AVIF);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1533,7 +1539,8 @@ static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "avcC"); ffio_wfourcc(pb, "avcC");
ff_isom_write_avcc(pb, track->vos_data, track->vos_len); ff_isom_write_avcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index]);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1565,7 +1572,8 @@ static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
int64_t pos = avio_tell(pb); int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "av3c"); ffio_wfourcc(pb, "av3c");
mov_write_av3c(pb, track->vos_data, track->vos_len); mov_write_av3c(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index]);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1575,7 +1583,8 @@ static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "vpcC"); ffio_wfourcc(pb, "vpcC");
ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par); ff_isom_write_vpcc(s, pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], track->par);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1586,9 +1595,11 @@ static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "hvcC"); ffio_wfourcc(pb, "hvcC");
if (track->tag == MKTAG('h','v','c','1')) if (track->tag == MKTAG('h','v','c','1'))
ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1, s); ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 1, s);
else else
ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0, s); ff_isom_write_hvcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 0, s);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1600,9 +1611,11 @@ static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
avio_wb32(pb, 0); avio_wb32(pb, 0);
ffio_wfourcc(pb, "lhvC"); ffio_wfourcc(pb, "lhvC");
if (track->tag == MKTAG('h','v','c','1')) if (track->tag == MKTAG('h','v','c','1'))
ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1, s); ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 1, s);
else else
ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0, s); ret = ff_isom_write_lhvc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 0, s);
if (ret < 0) { if (ret < 0) {
avio_seek(pb, pos, SEEK_SET); avio_seek(pb, pos, SEEK_SET);
@ -1620,9 +1633,11 @@ static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "evcC"); ffio_wfourcc(pb, "evcC");
if (track->tag == MKTAG('e','v','c','1')) if (track->tag == MKTAG('e','v','c','1'))
ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1); ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 1);
else else
ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0); ff_isom_write_evcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 0);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1638,9 +1653,11 @@ static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
avio_wb24(pb, 0); /* flags */ avio_wb24(pb, 0); /* flags */
if (track->tag == MKTAG('v','v','c','1')) if (track->tag == MKTAG('v','v','c','1'))
ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1); ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 1);
else else
ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0); ff_isom_write_vvcc(pb, track->extradata[track->last_stsd_index],
track->extradata_size[track->last_stsd_index], 0);
return update_size(pb, pos); return update_size(pb, pos);
} }
@ -1666,11 +1683,11 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
int cid; int cid;
int display_width = track->par->width; int display_width = track->par->width;
if (track->vos_data && track->vos_len > 0x29) { if (track->extradata[track->last_stsd_index] && track->extradata_size[track->last_stsd_index] > 0x29) {
if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) { if (ff_dnxhd_parse_header_prefix(track->extradata[track->last_stsd_index]) != 0) {
/* looks like a DNxHD bit stream */ /* looks like a DNxHD bit stream */
interlaced = (track->vos_data[5] & 2); interlaced = (track->extradata[track->last_stsd_index][5] & 2);
cid = AV_RB32(track->vos_data + 0x28); cid = AV_RB32(track->extradata[track->last_stsd_index] + 0x28);
} else { } else {
av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n"); av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
return 0; return 0;
@ -1745,9 +1762,9 @@ static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
{ {
avio_wb32(pb, 12); avio_wb32(pb, 12);
ffio_wfourcc(pb, "DpxE"); ffio_wfourcc(pb, "DpxE");
if (track->par->extradata_size >= 12 && if (track->extradata_size[track->last_stsd_index] >= 12 &&
!memcmp(&track->par->extradata[4], "DpxE", 4)) { !memcmp(&track->extradata[track->last_stsd_index][4], "DpxE", 4)) {
avio_wb32(pb, track->par->extradata[11]); avio_wb32(pb, track->extradata[track->last_stsd_index][11]);
} else { } else {
avio_wb32(pb, 1); avio_wb32(pb, 1);
} }
@ -2158,8 +2175,8 @@ static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack
track->track_id); track->track_id);
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
} else if (track->par->extradata_size) } else if (track->extradata_size[track->last_stsd_index])
avio_write(pb, track->par->extradata, track->par->extradata_size); avio_write(pb, track->extradata[track->last_stsd_index], track->extradata_size[track->last_stsd_index]);
if (mov->write_btrt && if (mov->write_btrt &&
((ret = mov_write_btrt_tag(pb, track)) < 0)) ((ret = mov_write_btrt_tag(pb, track)) < 0))
@ -2788,7 +2805,7 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
mov_write_vpcc_tag(mov->fc, pb, track); mov_write_vpcc_tag(mov->fc, pb, track);
} else if (track->par->codec_id == AV_CODEC_ID_AV1) { } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
mov_write_av1c_tag(pb, track); mov_write_av1c_tag(pb, track);
} else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0) } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->extradata_size[track->last_stsd_index] > 0)
mov_write_dvc1_tag(pb, track); mov_write_dvc1_tag(pb, track);
else if (track->par->codec_id == AV_CODEC_ID_VP6F || else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
track->par->codec_id == AV_CODEC_ID_VP6A) { track->par->codec_id == AV_CODEC_ID_VP6A) {
@ -2799,7 +2816,7 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
mov_write_dpxe_tag(pb, track); mov_write_dpxe_tag(pb, track);
} else if (track->par->codec_id == AV_CODEC_ID_AVS3) { } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
mov_write_av3c_tag(pb, track); mov_write_av3c_tag(pb, track);
} else if (track->vos_len > 0) } else if (track->extradata_size[track->last_stsd_index] > 0)
mov_write_glbl_tag(pb, track); mov_write_glbl_tag(pb, track);
if (track->par->codec_id != AV_CODEC_ID_H264 && if (track->par->codec_id != AV_CODEC_ID_H264 &&
@ -3037,6 +3054,7 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext
ffio_wfourcc(pb, "stsd"); ffio_wfourcc(pb, "stsd");
avio_wb32(pb, 0); /* version & flags */ avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, 1); /* entry count */ avio_wb32(pb, 1); /* entry count */
if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
ret = mov_write_video_tag(s, pb, mov, track); ret = mov_write_video_tag(s, pb, mov, track);
else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
@ -5253,19 +5271,19 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) { if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
if (track->par->codec_id == AV_CODEC_ID_H264) { if (track->par->codec_id == AV_CODEC_ID_H264) {
uint8_t *ptr; uint8_t *ptr;
int size = track->par->extradata_size; int size = track->extradata_size[track->last_stsd_index];
if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr, if (!ff_avc_write_annexb_extradata(track->extradata[track->last_stsd_index], &ptr,
&size)) { &size)) {
param_write_hex(pb, "CodecPrivateData", param_write_hex(pb, "CodecPrivateData",
ptr ? ptr : track->par->extradata, ptr ? ptr : track->extradata[track->last_stsd_index],
size); size);
av_free(ptr); av_free(ptr);
} }
param_write_string(pb, "FourCC", "H264"); param_write_string(pb, "FourCC", "H264");
} else if (track->par->codec_id == AV_CODEC_ID_VC1) { } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
param_write_string(pb, "FourCC", "WVC1"); param_write_string(pb, "FourCC", "WVC1");
param_write_hex(pb, "CodecPrivateData", track->par->extradata, param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
track->par->extradata_size); track->extradata_size[track->last_stsd_index]);
} }
param_write_int(pb, "MaxWidth", track->par->width); param_write_int(pb, "MaxWidth", track->par->width);
param_write_int(pb, "MaxHeight", track->par->height); param_write_int(pb, "MaxHeight", track->par->height);
@ -5286,8 +5304,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
} else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) { } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
param_write_string(pb, "FourCC", "WMAP"); param_write_string(pb, "FourCC", "WMAP");
} }
param_write_hex(pb, "CodecPrivateData", track->par->extradata, param_write_hex(pb, "CodecPrivateData", track->extradata[track->last_stsd_index],
track->par->extradata_size); track->extradata_size[track->last_stsd_index]);
param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags, param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
track->par->codec_id)); track->par->codec_id));
param_write_int(pb, "Channels", track->par->ch_layout.nb_channels); param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
@ -6713,17 +6731,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} }
/* copy extradata if it exists */ /* copy extradata if it exists */
if (trk->vos_len == 0 && par->extradata_size > 0 && if (trk->extradata_size[0] == 0 && par->extradata_size > 0 &&
!TAG_IS_AVCI(trk->tag) && !TAG_IS_AVCI(trk->tag) &&
(par->codec_id != AV_CODEC_ID_DNXHD)) { (par->codec_id != AV_CODEC_ID_DNXHD)) {
trk->vos_len = par->extradata_size; trk->extradata[0] = av_memdup(par->extradata, par->extradata_size);
trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE); if (!trk->extradata[0]) {
if (!trk->vos_data) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto err; goto err;
} }
memcpy(trk->vos_data, par->extradata, trk->vos_len); trk->extradata_size[0] = par->extradata_size;
memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
} }
if ((par->codec_id == AV_CODEC_ID_DNXHD || if ((par->codec_id == AV_CODEC_ID_DNXHD ||
@ -6732,17 +6748,17 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
par->codec_id == AV_CODEC_ID_VVC || par->codec_id == AV_CODEC_ID_VVC ||
par->codec_id == AV_CODEC_ID_VP9 || par->codec_id == AV_CODEC_ID_VP9 ||
par->codec_id == AV_CODEC_ID_EVC || par->codec_id == AV_CODEC_ID_EVC ||
par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len && par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->extradata_size[0] &&
!TAG_IS_AVCI(trk->tag)) { !TAG_IS_AVCI(trk->tag)) {
/* copy frame to create needed atoms */ /* copy frame to create needed atoms */
trk->vos_len = size; trk->extradata_size[0] = size;
trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); trk->extradata[0] = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!trk->vos_data) { if (!trk->extradata[0]) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto err; goto err;
} }
memcpy(trk->vos_data, pkt->data, size); memcpy(trk->extradata[0], pkt->data, size);
memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
} }
if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
@ -6755,7 +6771,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} }
av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
} }
if (par->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) { if (par->codec_id == AV_CODEC_ID_H264 && trk->extradata_size[trk->last_stsd_index] > 0 &&
*(uint8_t *)trk->extradata[trk->last_stsd_index] != 1 && !TAG_IS_AVCI(trk->tag)) {
/* from x264 or from bytestream H.264 */ /* from x264 or from bytestream H.264 */
/* NAL reformatting needed */ /* NAL reformatting needed */
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) { if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
@ -6775,8 +6792,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
size = ff_nal_parse_units(pb, pkt->data, pkt->size); size = ff_nal_parse_units(pb, pkt->data, pkt->size);
} }
} }
} else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 && } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
(AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) { (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
/* extradata is Annex B, assume the bitstream is too and convert it */ /* extradata is Annex B, assume the bitstream is too and convert it */
int filter_ps = (trk->tag == MKTAG('h','v','c','1')); int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) { if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
@ -6796,8 +6813,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL); size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
} }
} }
} else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 && } else if (par->codec_id == AV_CODEC_ID_VVC && trk->extradata_size[trk->last_stsd_index] > 6 &&
(AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) { (AV_RB24(trk->extradata[trk->last_stsd_index]) == 1 || AV_RB32(trk->extradata[trk->last_stsd_index]) == 1)) {
/* extradata is Annex B, assume the bitstream is too and convert it */ /* extradata is Annex B, assume the bitstream is too and convert it */
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) { if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data, ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
@ -6854,11 +6871,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_write(s->pb, pkt->data, pkt->size); avio_write(s->pb, pkt->data, pkt->size);
} else { } else {
if (trk->cenc.aes_ctr) { if (trk->cenc.aes_ctr) {
if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) { uint8_t *extradata = trk->extradata[trk->last_stsd_index];
int nal_size_length = (par->extradata[4] & 0x3) + 1; int extradata_size = trk->extradata_size[trk->last_stsd_index];
if (par->codec_id == AV_CODEC_ID_H264 && extradata_size > 4) {
int nal_size_length = (extradata[4] & 0x3) + 1;
ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size); ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
} else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) { } else if(par->codec_id == AV_CODEC_ID_HEVC && extradata_size > 21) {
int nal_size_length = (par->extradata[21] & 0x3) + 1; int nal_size_length = (extradata[21] & 0x3) + 1;
ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size); ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
} else if(par->codec_id == AV_CODEC_ID_VVC) { } else if(par->codec_id == AV_CODEC_ID_VVC) {
ret = AVERROR_PATCHWELCOME; ret = AVERROR_PATCHWELCOME;
@ -7050,16 +7069,14 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
trk->par->codec_id == AV_CODEC_ID_FLAC) { trk->par->codec_id == AV_CODEC_ID_FLAC) {
size_t side_size; size_t side_size;
uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { /* Overwrite extradata only on flush packets or when no extradata was available during init */
void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE); if (side_size > 0 && (!pkt->size || !trk->extradata_size[trk->last_stsd_index])) {
void *newextra = av_memdup(side, side_size);
if (!newextra) if (!newextra)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
av_free(par->extradata); av_free(trk->extradata[trk->last_stsd_index]);
par->extradata = newextra; trk->extradata[trk->last_stsd_index] = newextra;
memcpy(par->extradata, side, side_size); trk->extradata_size[trk->last_stsd_index] = side_size;
par->extradata_size = side_size;
if (!pkt->size) // Flush packet
mov->need_rewrite_extradata = 1;
} }
} }
@ -7398,6 +7415,11 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
return ret; return ret;
memcpy(track->par->extradata, stub_header, sizeof(stub_header)); memcpy(track->par->extradata, stub_header, sizeof(stub_header));
track->extradata[0] = av_memdup(stub_header, sizeof(stub_header));
if (!track->extradata[0])
return AVERROR(ENOMEM);
track->extradata_size[0] = sizeof(stub_header);
pkt->stream_index = tracknum; pkt->stream_index = tracknum;
pkt->flags = AV_PKT_FLAG_KEY; pkt->flags = AV_PKT_FLAG_KEY;
@ -7569,8 +7591,9 @@ static void mov_free(AVFormatContext *s)
av_packet_free(&info->pkt); av_packet_free(&info->pkt);
av_freep(&track->eac3_priv); av_freep(&track->eac3_priv);
} }
if (track->vos_len) for (int j = 0; j < track->stsd_count; j++)
av_freep(&track->vos_data); av_freep(&track->extradata[j]);
av_freep(&track->extradata);
ff_mov_cenc_free(&track->cenc); ff_mov_cenc_free(&track->cenc);
ffio_free_dyn_buf(&track->mdat_buf); ffio_free_dyn_buf(&track->mdat_buf);
@ -7612,7 +7635,7 @@ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
int i, width = 720, height = 480; int i, width = 720, height = 480;
int have_palette = 0, have_size = 0; int have_palette = 0, have_size = 0;
uint32_t palette[16]; uint32_t palette[16];
char *cur = st->codecpar->extradata; char *cur = track->extradata[track->last_stsd_index];
while (cur && *cur) { while (cur && *cur) {
if (strncmp("palette:", cur, 8) == 0) { if (strncmp("palette:", cur, 8) == 0) {
@ -7641,14 +7664,14 @@ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
cur += strspn(cur, "\n\r"); cur += strspn(cur, "\n\r");
} }
if (have_palette) { if (have_palette) {
track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE); track->extradata[track->last_stsd_index] = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
if (!track->vos_data) if (!track->extradata[track->last_stsd_index])
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
AV_WB32(track->vos_data + i * 4, palette[i]); AV_WB32(track->extradata[track->last_stsd_index] + i * 4, palette[i]);
} }
memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE); memset(track->extradata[track->last_stsd_index] + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
track->vos_len = 16 * 4; track->extradata_size[track->last_stsd_index] = 16 * 4;
} }
st->codecpar->width = width; st->codecpar->width = width;
st->codecpar->height = track->height = height; st->codecpar->height = track->height = height;
@ -7963,6 +7986,16 @@ static int mov_init(AVFormatContext *s)
if (!mov->tracks) if (!mov->tracks)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
for (i = 0; i < mov->nb_tracks; i++) {
MOVTrack *track = &mov->tracks[i];
track->stsd_count = 1;
track->extradata = av_calloc(track->stsd_count, sizeof(*track->extradata));
track->extradata_size = av_calloc(track->stsd_count, sizeof(*track->extradata_size));
if (!track->extradata || !track->extradata_size)
return AVERROR(ENOMEM);
}
if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) { if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) { if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
mov->encryption_scheme = MOV_ENC_CENC_AES_CTR; mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
@ -8240,13 +8273,16 @@ static int mov_write_header(AVFormatContext *s)
if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE) if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
mov_create_dvd_sub_decoder_specific_info(track, st); mov_create_dvd_sub_decoder_specific_info(track, st);
else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) { else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
track->vos_len = st->codecpar->extradata_size; track->extradata_size[track->last_stsd_index] = st->codecpar->extradata_size;
track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE); track->extradata[track->last_stsd_index] =
if (!track->vos_data) { av_malloc(track->extradata_size[track->last_stsd_index] + AV_INPUT_BUFFER_PADDING_SIZE);
if (!track->extradata[track->last_stsd_index]) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
memcpy(track->vos_data, st->codecpar->extradata, track->vos_len); memcpy(track->extradata[track->last_stsd_index],
memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE); st->codecpar->extradata, track->extradata_size[track->last_stsd_index]);
memset(track->extradata[track->last_stsd_index] + track->extradata_size[track->last_stsd_index],
0, AV_INPUT_BUFFER_PADDING_SIZE);
} }
} }
@ -8467,22 +8503,6 @@ static int mov_write_trailer(AVFormatContext *s)
int i; int i;
int64_t moov_pos; int64_t moov_pos;
if (mov->need_rewrite_extradata) {
for (i = 0; i < mov->nb_streams; i++) {
MOVTrack *track = &mov->tracks[i];
AVCodecParameters *par = track->par;
track->vos_len = par->extradata_size;
av_freep(&track->vos_data);
track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
if (!track->vos_data)
return AVERROR(ENOMEM);
memcpy(track->vos_data, par->extradata, track->vos_len);
memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
mov->need_rewrite_extradata = 0;
}
/* /*
* Before actually writing the trailer, make sure that there are no * Before actually writing the trailer, make sure that there are no
* dangling subtitles, that need a terminating sample. * dangling subtitles, that need a terminating sample.

View File

@ -90,6 +90,13 @@ typedef struct MOVTrack {
uint64_t time; uint64_t time;
int64_t track_duration; int64_t track_duration;
int last_sample_is_subtitle_end; int last_sample_is_subtitle_end;
/* multiple stsd */
int stsd_count;
int last_stsd_index;
uint8_t **extradata;
int *extradata_size;
long sample_count; long sample_count;
long sample_size; long sample_size;
long chunkCount; long chunkCount;
@ -111,8 +118,6 @@ typedef struct MOVTrack {
int mono_as_fc; int mono_as_fc;
int multichannel_as_mono; int multichannel_as_mono;
int vos_len;
uint8_t *vos_data;
MOVIentry *cluster; MOVIentry *cluster;
MOVIentry *cluster_written; MOVIentry *cluster_written;
unsigned cluster_capacity; unsigned cluster_capacity;
@ -245,8 +250,6 @@ typedef struct MOVMuxContext {
uint8_t *encryption_kid; uint8_t *encryption_kid;
int encryption_kid_len; int encryption_kid_len;
int need_rewrite_extradata;
int use_stream_ids_as_track_ids; int use_stream_ids_as_track_ids;
int track_ids_ok; int track_ids_ok;
int write_btrt; int write_btrt;