summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2016-04-20 23:10:37 +0300
committerMartin Storsjö <martin@martin.st>2016-05-18 10:37:03 +0300
commite1eb0fc960163402bbb4e630185790488f7d28ed (patch)
tree6e27920fd573abb1428ccd0b6fa4e74ab9603165 /libavformat
parentfd4957d9c67996e7d218fd36b4168c9cb85f9ea7 (diff)
movenc: Use packets in interleaving queues for the duration at the end of fragments
As long as caller only writes packets using av_interleaved_write_frame with no manual flushing, this should allow us to always have accurate durations at the end of fragments, since there should be at least one queued packet in each stream (except for the stream where the current packet is being written, but if the muxer itself does the cutting of fragments, it also has info about the next packet for that stream). Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/avformat.h4
-rw-r--r--libavformat/internal.h10
-rw-r--r--libavformat/movenc.c22
-rw-r--r--libavformat/movenc.h1
-rw-r--r--libavformat/mux.c11
-rw-r--r--libavformat/version.h2
6 files changed, 49 insertions, 1 deletions
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.
* <br>
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, \