On Sat, Nov 22, 2014 at 1:55 PM, Martin Storsjö <[email protected]> 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
> [email protected]
> https://lists.libav.org/mailman/listinfo/libav-devel
>
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel