diff --git a/libavformat/avformat.h b/libavformat/avformat.h index f66c39b1c1..4eb11404ca 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -2427,6 +2427,10 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt); * increasing dts. Callers doing their own interleaving should call * av_write_frame() instead of this function. * + * Using this function instead of av_write_frame() can give muxers advance + * knowledge of future packets, improving e.g. the behaviour of the mp4 + * muxer for VFR content in fragmenting mode. + * * @param s media file handle * @param pkt The packet containing the data to be written. *
diff --git a/libavformat/internal.h b/libavformat/internal.h index 99015271b6..6b7f677950 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -620,4 +620,14 @@ int ff_get_packet_palette(AVFormatContext *s, AVPacket *pkt, int ret, uint32_t * */ int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf); +/** + * Find the next packet in the interleaving queue for the given stream. + * The packet is not removed from the interleaving queue, but only + * a pointer to it is returned. + * + * @return a pointer to the next packet, or NULL if no packet is queued + * for this stream. + */ +const AVPacket *ff_interleaved_peek(AVFormatContext *s, int stream); + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 4e5f65f24b..0a7983658e 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -4241,6 +4241,25 @@ static int mov_flush_fragment(AVFormatContext *s, int force) if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) return 0; + // Try to fill in the duration of the last packet in each stream + // from queued packets in the interleave queues. If the flushing + // of fragments was triggered automatically by an AVPacket, we + // already have reliable info for the end of that track, but other + // tracks may need to be filled in. + for (i = 0; i < s->nb_streams; i++) { + MOVTrack *track = &mov->tracks[i]; + if (!track->end_reliable) { + AVPacket *next = ff_interleaved_peek(s, i); + if (next) { + track->track_duration = next->dts - track->start_dts; + if (next->pts != AV_NOPTS_VALUE) + track->end_pts = next->pts; + else + track->end_pts = next->dts; + } + } + } + for (i = 0; i < mov->nb_streams; i++) { MOVTrack *track = &mov->tracks[i]; if (track->entry <= 1) @@ -4316,6 +4335,7 @@ static int mov_flush_fragment(AVFormatContext *s, int force) mov->tracks[i].track_duration - mov->tracks[i].cluster[0].dts; mov->tracks[i].entry = 0; + mov->tracks[i].end_reliable = 0; } avio_flush(s->pb); return 0; @@ -4395,6 +4415,7 @@ static int mov_flush_fragment(AVFormatContext *s, int force) track->frag_start += duration; track->entry = 0; track->entries_flushed = 0; + track->end_reliable = 0; if (!mov->frag_interleave) { if (!track->mdat_buf) continue; @@ -4760,6 +4781,7 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) trk->end_pts = pkt->pts; else trk->end_pts = pkt->dts; + trk->end_reliable = 1; mov_auto_flush_fragment(s, 0); } } diff --git a/libavformat/movenc.h b/libavformat/movenc.h index 1090085a5a..c4fded89bb 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -115,6 +115,7 @@ typedef struct MOVTrack { int64_t start_dts; int64_t start_cts; int64_t end_pts; + int end_reliable; int hint_track; ///< the track that hints this track, -1 if no hint track is set int src_track; ///< the track that this hint (or tmcd) track describes diff --git a/libavformat/mux.c b/libavformat/mux.c index 8488043006..10b2750e3f 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -1041,6 +1041,17 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, } } +const AVPacket *ff_interleaved_peek(AVFormatContext *s, int stream) +{ + AVPacketList *pktl = s->internal->packet_buffer; + while (pktl) { + if (pktl->pkt.stream_index == stream) + return &pktl->pkt; + pktl = pktl->next; + } + return NULL; +} + /** * Interleave an AVPacket correctly so it can be muxed. * @param out the interleaved packet will be output here diff --git a/libavformat/version.h b/libavformat/version.h index 543afbb166..544d4363eb 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -33,7 +33,7 @@ // Also please add any ticket numbers that you belive might be affected here #define LIBAVFORMAT_VERSION_MAJOR 57 #define LIBAVFORMAT_VERSION_MINOR 40 -#define LIBAVFORMAT_VERSION_MICRO 100 +#define LIBAVFORMAT_VERSION_MICRO 101 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \