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