On Sat, Nov 22, 2014 at 1:55 PM, Martin Storsjö <mar...@martin.st> wrote:

> This allows creating a later mp4 fragment without sequentially
> writing the earlier ones before (when called from a segmenter).
>
> Normally when writing a fragmented mp4 file sequentially, the
> first timestamps of a fragment are adjusted to match the
> end of the previous fragment, to make sure the timestamp is the
> same, even if it is calculated as the sum of previous fragment
> durations. (And for the first packet in a file, the offset of
> the first packet is written using an edit list.)
>
> When writing an individual mp4 fragment discontinuously like this
> (with potentially writing the earlier fragments separately later),
> there's a risk of getting a gap in the timeline if the duration
> field of the last packet in the previous fragment doesn't match up
> with the start time of the next fragment.
>
> Using this requires setting -avoid_negative_ts make_non_negative
> (or -avoid_negative_ts 0).
>
Why is that? So make_zero won't work?
Also, maybe this is for another commit, but would it maybe be useful to
expose this as an option in dashenc.c as well?


> ---
>  libavformat/movenc.c | 34 ++++++++++++++++++++++++++++------
>  libavformat/movenc.h |  2 ++
>  2 files changed, 30 insertions(+), 6 deletions(-)
>
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 3ba1cc8..80531d0 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -60,6 +60,7 @@ static const AVOption options[] = {
>      { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST,
> {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX,
> AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
>      { "default_base_moof", "Set the default-base-is-moof flag in tfhd
> atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF},
> INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
>      { "dash", "Write DASH compatible fragmented MP4", 0,
> AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX,
> AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
> +    { "frag_discont", "Signal that the next fragment is discontinuous
> from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 =
> FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM,
> "movflags" },
>      FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
>      { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext,
> iods_skip), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
>      { "iods_audio_profile", "iods audio profile atom.",
> offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1},
> -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
> @@ -3282,11 +3283,19 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
>      trk->cluster[trk->entry].entries          = samples_in_chunk;
>      trk->cluster[trk->entry].dts              = pkt->dts;
>      if (!trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
> -        /* First packet of a new fragment. We already wrote the duration
> -         * of the last packet of the previous fragment based on
> track_duration,
> -         * which might not exactly match our dts. Therefore adjust the dts
> -         * of this packet to be what the previous packets duration
> implies. */
> -        trk->cluster[trk->entry].dts = trk->start_dts +
> trk->track_duration;
> +        if (!trk->frag_discont) {
> +            /* First packet of a new fragment. We already wrote the
> duration
> +             * of the last packet of the previous fragment based on
> track_duration,
> +             * which might not exactly match our dts. Therefore adjust
> the dts
> +             * of this packet to be what the previous packets duration
> implies. */
> +            trk->cluster[trk->entry].dts = trk->start_dts +
> trk->track_duration;
> +        } else {
> +            /* New fragment, but discontinuous from previous fragments.
> +             * Pretend the duration sum of the earlier fragments is
> +             * pkt->dts - trk->start_dts. */
> +            trk->frag_start = pkt->dts - trk->start_dts;
> +            trk->frag_discont = 0;
> +        }
>      }
>      if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE &&
> !mov->use_editlist &&
>          s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
> @@ -3299,7 +3308,13 @@ int ff_mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
>      }
>      if (trk->start_dts == AV_NOPTS_VALUE) {
>          trk->start_dts = pkt->dts;
> -        if (pkt->dts && mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
> +        if (trk->frag_discont) {
> +            /* Pretend the whole stream started at dts=0, with earlier
> framgents
> +             * already written, with a duration summing up to pkt->dts. */
> +            trk->frag_start   = pkt->dts;
> +            trk->start_dts    = 0;
> +            trk->frag_discont = 0;
> +        } else if (pkt->dts && mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
>              av_log(s, AV_LOG_WARNING,
>                     "Track %d starts with a nonzero dts %"PRId64". This "
>                     "currently isn't handled correctly in combination with
> "
> @@ -3357,6 +3372,13 @@ static int mov_write_packet(AVFormatContext *s,
> AVPacket *pkt)
>          if (!pkt->size)
>              return 0;             /* Discard 0 sized packets */
>
> +        if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
> +            int i;
> +            for (i = 0; i < s->nb_streams; i++)
> +                mov->tracks[i].frag_discont = 1;
> +            mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
> +        }
> +
>
Maybe I'm missing something, but are you not able to do this initialization
in mov_write_header? Then you wouldn't have to unset the flag either.


>          if (trk->entry)
>              frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
>
> s->streams[pkt->stream_index]->time_base,
> diff --git a/libavformat/movenc.h b/libavformat/movenc.h
> index 4483b69..c13a834 100644
> --- a/libavformat/movenc.h
> +++ b/libavformat/movenc.h
> @@ -121,6 +121,7 @@ typedef struct MOVTrack {
>      AVIOContext *mdat_buf;
>      int64_t     data_offset;
>      int64_t     frag_start;
> +    int         frag_discont;
>
>      int         nb_frag_info;
>      MOVFragmentInfo *frag_info;
> @@ -182,6 +183,7 @@ typedef struct MOVMuxContext {
>  #define FF_MOV_FLAG_DISABLE_CHPL          (1 <<  9)
>  #define FF_MOV_FLAG_DEFAULT_BASE_MOOF     (1 << 10)
>  #define FF_MOV_FLAG_DASH                  (1 << 11)
> +#define FF_MOV_FLAG_FRAG_DISCONT          (1 << 12)
>
>  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
>
> --
> 1.9.3 (Apple Git-50)
>
> _______________________________________________
> libav-devel mailing list
> libav-devel@libav.org
> https://lists.libav.org/mailman/listinfo/libav-devel
>
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to