aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2014-11-04 16:28:48 +0200
committerMartin Storsjö <martin@martin.st>2014-11-07 12:11:46 +0200
commit1d8a0c1b43e58332a3a15c67d4adc161713cade8 (patch)
tree0ae9f768a10ecf7f8fdd1b1ebc891fe845cb2115
parent897d5c3a4296f3da80b8699d1487328ca2de8e55 (diff)
downloadffmpeg-1d8a0c1b43e58332a3a15c67d4adc161713cade8.tar.gz
movenc: Allow to request not to use edit lists
In this case, shift tracks to start from zero instead (potentially stretching the first sample in tracks that start later than the first one). Some software does not support edit lists at all, the adobe flash player seems to be one of these. This results in AV sync errors when edit lists are used to adjust AV sync. Some players, such as QuickTime, don't respect the duration for audio packets, so if an audio track starts later than the video track and the first audio sample gets a duration longer than the actual amount of data in it, the result will be out of sync. Based on patches by Michael Niedermayer. Signed-off-by: Martin Storsjö <martin@martin.st>
-rw-r--r--libavformat/movenc.c33
-rw-r--r--libavformat/movenc.h2
2 files changed, 34 insertions, 1 deletions
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index c6c683fe33..7a0d9f1150 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -68,6 +68,7 @@ static const AVOption options[] = {
{ "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
+ { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ NULL },
};
@@ -1773,7 +1774,11 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS ||
(track->entry && track->cluster[0].dts) ||
is_clcp_track(track)) {
- mov_write_edts_tag(pb, mov, track); // PSP Movies require edts box
+ if (mov->use_editlist)
+ mov_write_edts_tag(pb, mov, track); // PSP Movies require edts box
+ else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
+ av_log(mov->fc, AV_LOG_WARNING,
+ "Not writing any edit list even though one would have been required\n");
}
if (track->tref_tag)
mov_write_tref_tag(pb, track);
@@ -3148,6 +3153,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
* of this packet to be what the previous packets duration implies. */
trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
}
+ if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
+ s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
+ /* Not using edit lists and shifting the first track to start from zero.
+ * If the other streams start from a later timestamp, we won't be able
+ * to signal the difference in starting time without an edit list.
+ * Thus move the timestamp for this first sample to 0, increasing
+ * its duration instead. */
+ trk->cluster[trk->entry].dts = trk->start_dts = 0;
+ }
if (trk->start_dts == AV_NOPTS_VALUE) {
trk->start_dts = pkt->dts;
if (pkt->dts && mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
@@ -3462,6 +3476,23 @@ static int mov_write_header(AVFormatContext *s)
}
}
+ if (mov->use_editlist < 0) {
+ mov->use_editlist = 1;
+ if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
+ // If we can avoid needing an edit list by shifting the
+ // tracks, prefer that over (trying to) write edit lists
+ // in fragmented output.
+ if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
+ s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
+ mov->use_editlist = 0;
+ }
+ }
+ if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && mov->use_editlist)
+ av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov\n");
+
+ if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO)
+ s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
+
/* Non-seekable output is ok if using fragmentation. If ism_lookahead
* is enabled, we don't support non-seekable output at all. */
if (!s->pb->seekable &&
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index e9056275ef..8349a18c1d 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -166,6 +166,8 @@ typedef struct MOVMuxContext {
int per_stream_grouping;
AVFormatContext *fc;
+
+ int use_editlist;
} MOVMuxContext;
#define FF_MOV_FLAG_RTP_HINT (1 << 0)