diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 7133cf4e4e..e0c0cdd335 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -3297,6 +3297,46 @@ static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov, return 0; } +static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks) +{ + int i; + for (i = 0; i < mov->nb_streams; i++) { + MOVTrack *track = &mov->tracks[i]; + MOVFragmentInfo *info; + if ((tracks >= 0 && i != tracks) || !track->entry) + continue; + track->nb_frag_info++; + if (track->nb_frag_info >= track->frag_info_capacity) { + unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT; + if (av_reallocp_array(&track->frag_info, + new_capacity, + sizeof(*track->frag_info))) + return AVERROR(ENOMEM); + track->frag_info_capacity = new_capacity; + } + info = &track->frag_info[track->nb_frag_info - 1]; + info->offset = avio_tell(pb); + // Try to recreate the original pts for the first packet + // from the fields we have stored + info->time = track->start_dts + track->frag_start + + track->cluster[0].cts; + // If the pts is less than zero, we will have trimmed + // away parts of the media track using an edit list, + // and the corresponding start presentation time is zero. + if (info->time < 0) + info->time = 0; + info->duration = track->start_dts + track->track_duration - + track->cluster[0].dts; + info->tfrf_offset = 0; + mov_write_tfrf_tags(pb, mov, track); + // If writing all tracks, we currently only add a tfra entry for + // the first track (that actually has data to be written). + if (tracks < 0) + break; + } + return 0; +} + static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -3327,7 +3367,11 @@ static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov, if (mov->ism_lookahead) { int i, size = 16 + 4 + 1 + 16 * mov->ism_lookahead; - track->tfrf_offset = avio_tell(pb); + if (track->nb_frag_info > 0) { + MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1]; + if (!info->tfrf_offset) + info->tfrf_offset = avio_tell(pb); + } avio_wb32(pb, 8 + size); ffio_wfourcc(pb, "free"); for (i = 0; i < size; i++) @@ -3370,6 +3414,10 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) return ret; mov_write_moof_tag_internal(avio_buf, mov, tracks, 0); moof_size = ffio_close_null_buf(avio_buf); + + if ((ret = mov_add_tfra_entries(pb, mov, tracks)) < 0) + return ret; + return mov_write_moof_tag_internal(pb, mov, tracks, moof_size); } @@ -3729,36 +3777,9 @@ static int mov_flush_fragment(AVFormatContext *s) } if (write_moof) { - MOVFragmentInfo *info; avio_flush(s->pb); - track->nb_frag_info++; - if (track->nb_frag_info >= track->frag_info_capacity) { - unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT; - if (av_reallocp_array(&track->frag_info, - new_capacity, - sizeof(*track->frag_info))) - return AVERROR(ENOMEM); - track->frag_info_capacity = new_capacity; - } - info = &track->frag_info[track->nb_frag_info - 1]; - info->offset = avio_tell(s->pb); - info->time = track->frag_start; - if (track->entry) { - // Try to recreate the original pts for the first packet - // from the fields we have stored - info->time = track->start_dts + track->frag_start + - track->cluster[0].cts; - // If the pts is less than zero, we will have trimmed - // away parts of the media track using an edit list, - // and the corresponding start presentation time is zero. - if (info->time < 0) - info->time = 0; - } - info->duration = duration; - mov_write_tfrf_tags(s->pb, mov, track); mov_write_moof_tag(s->pb, mov, moof_tracks); - info->tfrf_offset = track->tfrf_offset; mov->fragments++; avio_wb32(s->pb, mdat_size + 8); diff --git a/libavformat/movenc.h b/libavformat/movenc.h index 89230ac231..502572a73b 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -128,7 +128,6 @@ typedef struct MOVTrack { AVIOContext *mdat_buf; int64_t data_offset; int64_t frag_start; - int64_t tfrf_offset; int nb_frag_info; MOVFragmentInfo *frag_info;