Quoting Martin Storsjö (2014-11-04 15:38:11)
> 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.
> ---
>  libavformat/movenc.c | 33 ++++++++++++++++++++++++++++++++-
>  libavformat/movenc.h |  2 ++
>  2 files changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 80a44cf..7d37b15 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 e905627..8349a18 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)
> -- 
> 1.9.3 (Apple Git-50)
> 

Don't know much about mov, but looks sane enough from what I can tell.
Perhaps Yusuke has an opinion. Otherwise feel free to push.

-- 
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to