From c2424b1f35a1c6c06f1f9fe5f77a7157ed84e1cd Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Sun, 20 Dec 2020 00:45:42 +0200 Subject: movenc: Present durations in mvhd/tkhd/mdhd as they are after edits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the edit lists remove parts of the output timeline, or add a delay to it, this should be included in the mvhd/tkhd/mdhd durations, which should correspond to the edit lists. For tracks starting with pts < 0, the edit list trims out the segment before pts=0. For tracks starting with pts > 0, a delay element is added in the edit list, delaying the start of the track data. In both cases, the practical effect is that the post-edit output is as if the track had started with pts = 0. Thus calculate the range from pts=0 to end_pts, for the purposes of mvhd/tkhd/mdhd, unless edit lists explicitly are disabled. mov_write_edts_tag needs to operate on the actual pts duration of the track samples, not the duration that already takes the edit list effect into account. Signed-off-by: Martin Storsjö --- libavformat/movenc.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'libavformat') diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 18fa3f9b5e..372c04295d 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2904,21 +2904,50 @@ static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext return update_size(pb, pos); } -static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track) +static void get_pts_range(MOVMuxContext *mov, MOVTrack *track, + int64_t *start, int64_t *end) { if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) { // tmcd tracks gets track_duration set in mov_write_moov_tag from // another track's duration, while the end_pts may be left at zero. // Calculate the pts duration for that track instead. - return av_rescale(calc_pts_duration(mov, &mov->tracks[track->src_track]), - track->timescale, mov->tracks[track->src_track].timescale); + get_pts_range(mov, &mov->tracks[track->src_track], start, end); + *start = av_rescale(*start, track->timescale, + mov->tracks[track->src_track].timescale); + *end = av_rescale(*end, track->timescale, + mov->tracks[track->src_track].timescale); + return; } if (track->end_pts != AV_NOPTS_VALUE && track->start_dts != AV_NOPTS_VALUE && track->start_cts != AV_NOPTS_VALUE) { - return track->end_pts - (track->start_dts + track->start_cts); + *start = track->start_dts + track->start_cts; + *end = track->end_pts; + return; } - return track->track_duration; + *start = 0; + *end = track->track_duration; +} + +static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track) +{ + int64_t start, end; + get_pts_range(mov, track, &start, &end); + return end - start; +} + +// Calculate the actual duration of the track, after edits. +// If it starts with a pts < 0, that is removed by the edit list. +// If it starts with a pts > 0, the edit list adds a delay before that. +// Thus, with edit lists enabled, the post-edit output of the file is +// starting with pts=0. +static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track) +{ + int64_t start, end; + get_pts_range(mov, track, &start, &end); + if (mov->use_editlist != 0) + start = 0; + return end - start; } static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov, @@ -3145,7 +3174,7 @@ static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { - int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track), + int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track), MOV_TIMESCALE, track->timescale, AV_ROUND_UP); int version = duration < INT32_MAX ? 0 : 1; -- cgit v1.2.3