diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 7d026b66d5..fbdfba4fb1 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1720,6 +1720,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 4760ba89ff..bbdfd2f719 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -441,4 +441,14 @@ static inline int ff_rename(const char *oldpath, const char *newpath) */ void ff_format_io_close(AVFormatContext *s, AVIOContext **pb); +/** + * 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 d8022dcd5c..ae754e13e3 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -3188,6 +3188,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) @@ -3267,6 +3286,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; @@ -3346,6 +3366,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; @@ -3650,6 +3671,7 @@ static int mov_write_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 fccf1f3b34..6c922fb5df 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -106,6 +106,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 track describes diff --git a/libavformat/mux.c b/libavformat/mux.c index 49fe65cf98..c41c477ab4 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -614,6 +614,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 b2a1e054bf..1e1105fe5c 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 57 #define LIBAVFORMAT_VERSION_MINOR 7 -#define LIBAVFORMAT_VERSION_MICRO 0 +#define LIBAVFORMAT_VERSION_MICRO 1 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \