movenc: Write durations based on pts into mvhd/mdhd/tkhd/elst

Keep all the existing data fields as they are (there's lots and
lots of nontrivial calculation and heuristics based on them in
their current form), but derive the duration as the difference
between the pts of the first packet to the maximum pts+duration
(not necessarily the last packet); use this duration in any box
where the actual presentation duration is supposed to be.

Fixes: 8420

Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
Martin Storsjö 2019-12-14 01:00:20 +02:00
parent 3ea7057677
commit 3d894db700
1 changed files with 28 additions and 7 deletions

View File

@ -2761,10 +2761,28 @@ static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext
return update_size(pb, pos); return update_size(pb, pos);
} }
static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
{
if (track->tag == MKTAG('t','m','c','d')) {
// 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);
}
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);
}
return track->track_duration;
}
static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov, static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
MOVTrack *track) MOVTrack *track)
{ {
int version = track->track_duration < INT32_MAX ? 0 : 1; int64_t duration = calc_pts_duration(mov, track);
int version = duration < INT32_MAX ? 0 : 1;
if (track->mode == MODE_ISM) if (track->mode == MODE_ISM)
version = 1; version = 1;
@ -2786,7 +2804,7 @@ static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
else if (!track->entry) else if (!track->entry)
(version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0); (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
else else
(version == 1) ? avio_wb64(pb, track->track_duration) : avio_wb32(pb, track->track_duration); /* duration */ (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
avio_wb16(pb, track->language); /* language */ avio_wb16(pb, track->language); /* language */
avio_wb16(pb, 0); /* reserved (quality) */ avio_wb16(pb, 0); /* reserved (quality) */
@ -2836,8 +2854,9 @@ static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov, static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
MOVTrack *track, AVStream *st) MOVTrack *track, AVStream *st)
{ {
int64_t duration = av_rescale_rnd(track->track_duration, MOV_TIMESCALE, int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
track->timescale, AV_ROUND_UP); MOV_TIMESCALE, track->timescale,
AV_ROUND_UP);
int version = duration < INT32_MAX ? 0 : 1; int version = duration < INT32_MAX ? 0 : 1;
int flags = MOV_TKHD_FLAG_IN_MOVIE; int flags = MOV_TKHD_FLAG_IN_MOVIE;
int rotation = 0; int rotation = 0;
@ -2983,8 +3002,9 @@ static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov, static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
MOVTrack *track) MOVTrack *track)
{ {
int64_t duration = av_rescale_rnd(track->track_duration, MOV_TIMESCALE, int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
track->timescale, AV_ROUND_UP); MOV_TIMESCALE, track->timescale,
AV_ROUND_UP);
int version = duration < INT32_MAX ? 0 : 1; int version = duration < INT32_MAX ? 0 : 1;
int entry_size, entry_count, size; int entry_size, entry_count, size;
int64_t delay, start_ct = track->start_cts; int64_t delay, start_ct = track->start_cts;
@ -3270,7 +3290,8 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
for (i = 0; i < mov->nb_streams; i++) { for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) { if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
int64_t max_track_len_temp = av_rescale_rnd(mov->tracks[i].track_duration, int64_t max_track_len_temp = av_rescale_rnd(
calc_pts_duration(mov, &mov->tracks[i]),
MOV_TIMESCALE, MOV_TIMESCALE,
mov->tracks[i].timescale, mov->tracks[i].timescale,
AV_ROUND_UP); AV_ROUND_UP);