Commit 67a29123 authored by Martin Storsjö's avatar Martin Storsjö

movenc: Don't assume that fragment durations in pts is equal to duration in dts

For strict CFR, they should be pretty much equal, but if the stream
is VFR, there can be a sometimes significant difference.

Calculate the pts duration separately, used in sidx atoms and for
tfrf/tfxd boxes in smooth streaming ismv files.

Also make sure to reduce the duration of sidx entries according to
edit lists.
Signed-off-by: 's avatarMartin Storsjö <martin@martin.st>
parent 5c337353
...@@ -2544,8 +2544,8 @@ static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track) ...@@ -2544,8 +2544,8 @@ static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb24(pb, 0); avio_wb24(pb, 0);
avio_wb64(pb, track->start_dts + track->frag_start + avio_wb64(pb, track->start_dts + track->frag_start +
track->cluster[0].cts); track->cluster[0].cts);
avio_wb64(pb, track->start_dts + track->track_duration - avio_wb64(pb, track->end_pts -
track->cluster[0].dts); (track->cluster[0].dts + track->cluster[0].cts));
return update_size(pb, pos); return update_size(pb, pos);
} }
...@@ -2625,13 +2625,15 @@ static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks, ...@@ -2625,13 +2625,15 @@ static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
// from the fields we have stored // from the fields we have stored
info->time = track->start_dts + track->frag_start + info->time = track->start_dts + track->frag_start +
track->cluster[0].cts; track->cluster[0].cts;
info->duration = track->end_pts -
(track->cluster[0].dts + track->cluster[0].cts);
// If the pts is less than zero, we will have trimmed // If the pts is less than zero, we will have trimmed
// away parts of the media track using an edit list, // away parts of the media track using an edit list,
// and the corresponding start presentation time is zero. // and the corresponding start presentation time is zero.
if (info->time < 0) if (info->time < 0) {
info->duration += info->time;
info->time = 0; info->time = 0;
info->duration = track->start_dts + track->track_duration - }
track->cluster[0].dts;
info->tfrf_offset = 0; info->tfrf_offset = 0;
mov_write_tfrf_tags(pb, mov, track); mov_write_tfrf_tags(pb, mov, track);
} }
...@@ -2724,13 +2726,15 @@ static int mov_write_sidx_tag(AVIOContext *pb, ...@@ -2724,13 +2726,15 @@ static int mov_write_sidx_tag(AVIOContext *pb,
entries = 1; entries = 1;
presentation_time = track->start_dts + track->frag_start + presentation_time = track->start_dts + track->frag_start +
track->cluster[0].cts; track->cluster[0].cts;
duration = track->start_dts + track->track_duration - duration = track->end_pts -
track->cluster[0].dts; (track->cluster[0].dts + track->cluster[0].cts);
starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE; starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
// pts<0 should be cut away using edts // pts<0 should be cut away using edts
if (presentation_time < 0) if (presentation_time < 0) {
duration += presentation_time;
presentation_time = 0; presentation_time = 0;
}
} else { } else {
entries = track->nb_frag_info; entries = track->nb_frag_info;
presentation_time = track->frag_info[0].time; presentation_time = track->frag_info[0].time;
...@@ -3172,6 +3176,7 @@ static int mov_flush_fragment(AVFormatContext *s) ...@@ -3172,6 +3176,7 @@ static int mov_flush_fragment(AVFormatContext *s)
// to be too long), but probably the best we can do - having a zero // to be too long), but probably the best we can do - having a zero
// duration is bad as well. // duration is bad as well.
track->track_duration += get_cluster_duration(track, track->entry - 2); track->track_duration += get_cluster_duration(track, track->entry - 2);
track->end_pts += get_cluster_duration(track, track->entry - 2);
if (!mov->missing_duration_warned) { if (!mov->missing_duration_warned) {
av_log(s, AV_LOG_WARNING, av_log(s, AV_LOG_WARNING,
"Estimating the duration of the last packet in a " "Estimating the duration of the last packet in a "
...@@ -3459,12 +3464,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -3459,12 +3464,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
* be the same in all fragments. */ * be the same in all fragments. */
if ((mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_FASTSTART)) || if ((mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_FASTSTART)) ||
mov->mode == MODE_ISM) mov->mode == MODE_ISM)
pkt->pts = pkt->dts + trk->start_cts; pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
} else { } else {
/* New fragment, but discontinuous from previous fragments. /* New fragment, but discontinuous from previous fragments.
* Pretend the duration sum of the earlier fragments is * Pretend the duration sum of the earlier fragments is
* pkt->dts - trk->start_dts. */ * pkt->dts - trk->start_dts. */
trk->frag_start = pkt->dts - trk->start_dts; trk->frag_start = pkt->dts - trk->start_dts;
trk->end_pts = AV_NOPTS_VALUE;
trk->frag_discont = 0; trk->frag_discont = 0;
} }
} }
...@@ -3504,6 +3510,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -3504,6 +3510,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
trk->cluster[trk->entry].flags = 0; trk->cluster[trk->entry].flags = 0;
if (trk->start_cts == AV_NOPTS_VALUE) if (trk->start_cts == AV_NOPTS_VALUE)
trk->start_cts = pkt->pts - pkt->dts; trk->start_cts = pkt->pts - pkt->dts;
if (trk->end_pts == AV_NOPTS_VALUE)
trk->end_pts = trk->cluster[trk->entry].dts +
trk->cluster[trk->entry].cts + pkt->duration;
else
trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
trk->cluster[trk->entry].cts +
pkt->duration);
if (enc->codec_id == AV_CODEC_ID_VC1) { if (enc->codec_id == AV_CODEC_ID_VC1) {
mov_parse_vc1_frame(pkt, trk); mov_parse_vc1_frame(pkt, trk);
...@@ -3570,6 +3583,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -3570,6 +3583,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
// duration, but only helps for this particular track, not // duration, but only helps for this particular track, not
// for the other ones that are flushed at the same time. // for the other ones that are flushed at the same time.
trk->track_duration = pkt->dts - trk->start_dts; trk->track_duration = pkt->dts - trk->start_dts;
trk->end_pts = pkt->pts;
mov_auto_flush_fragment(s); mov_auto_flush_fragment(s);
} }
} }
...@@ -3905,6 +3919,7 @@ static int mov_write_header(AVFormatContext *s) ...@@ -3905,6 +3919,7 @@ static int mov_write_header(AVFormatContext *s)
track->hint_track = -1; track->hint_track = -1;
track->start_dts = AV_NOPTS_VALUE; track->start_dts = AV_NOPTS_VALUE;
track->start_cts = AV_NOPTS_VALUE; track->start_cts = AV_NOPTS_VALUE;
track->end_pts = AV_NOPTS_VALUE;
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') || if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') || track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
......
...@@ -105,6 +105,7 @@ typedef struct MOVTrack { ...@@ -105,6 +105,7 @@ typedef struct MOVTrack {
int tref_id; ///< trackID of the referenced track int tref_id; ///< trackID of the referenced track
int64_t start_dts; int64_t start_dts;
int64_t start_cts; int64_t start_cts;
int64_t end_pts;
int hint_track; ///< the track that hints this track, -1 if no hint track is set int hint_track; ///< the track that hints this track, -1 if no hint track is set
int src_track; ///< the track that this hint track describes int src_track; ///< the track that this hint track describes
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment