From b40cfcfffb659138ed341badd6b76b02df4190b1 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 10 Dec 2014 16:55:44 +0100 Subject: [PATCH] qtdemux: Update duration when we get more information When dealing with fragmented files, we will get more accurate duration information via the mfra and moof atoms. In order for playback to not stop at the initial duration (from the moov atom), we need to check and update the various duration variables when we find more information. Fixes playback of fragmented files in pull mode --- gst/isomp4/qtdemux.c | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index f6db80f5c6..c46e7c2a06 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -308,6 +308,7 @@ struct _QtDemuxStream /* quicktime segments */ guint32 n_segments; QtDemuxSegment *segments; + gboolean dummy_segment; guint32 from_sample; guint32 to_sample; @@ -2447,13 +2448,60 @@ qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream, return TRUE; } +/* This method should be called whenever a more accurate duration might + * have been found. It will update all relevant variables if/where needed + */ +static void +check_update_duration (GstQTDemux * qtdemux, GstClockTime duration) +{ + guint i; + guint64 movdur; + GstClockTime prevdur; + + movdur = gst_util_uint64_scale (duration, qtdemux->timescale, GST_SECOND); + + if (movdur > qtdemux->duration) { + GST_DEBUG_OBJECT (qtdemux, "Updating total duration to %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration)); + prevdur = + gst_util_uint64_scale (qtdemux->duration, GST_SECOND, + qtdemux->timescale); + qtdemux->duration = movdur; + if (qtdemux->segment.duration == prevdur) { + /* If the current segment has duration/stop identical to previous duration + * update them also (because they were set at that point in time with + * the wrong duration */ + qtdemux->segment.duration = duration; + qtdemux->segment.stop = duration; + } + } + for (i = 0; i < qtdemux->n_streams; i++) { + QtDemuxStream *stream = qtdemux->streams[i]; + if (stream) { + movdur = gst_util_uint64_scale (duration, stream->timescale, GST_SECOND); + if (movdur > stream->duration) { + GST_DEBUG_OBJECT (qtdemux, + "Updating stream #%d duration to %" GST_TIME_FORMAT, i, + GST_TIME_ARGS (duration)); + stream->duration = movdur; + if (stream->dummy_segment) { + /* Update all dummy values to new duration */ + stream->segments[0].stop_time = duration; + stream->segments[0].duration = duration; + stream->segments[0].media_stop = duration; + } + } + } + } +} + static gboolean qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size, guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length, gint64 * base_offset, gint64 * running_offset, gint64 decode_ts) { - GstClockTime gst_ts; + GstClockTime gst_ts = GST_CLOCK_TIME_NONE; guint64 timestamp; gint32 data_offset = 0; guint32 flags = 0, first_flags = 0, samples_count = 0; @@ -2614,6 +2662,7 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, " (extends previous samples)", GST_TIME_ARGS (gst_ts)); } } + sample = stream->samples + stream->n_samples; for (i = 0; i < samples_count; i++) { guint32 dur, size, sflags, ct; @@ -2662,6 +2711,10 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, sample++; } + /* Update total duration if needed */ + check_update_duration (qtdemux, gst_util_uint64_scale (timestamp, GST_SECOND, + stream->timescale)); + stream->n_samples += samples_count; if (stream->pending_seek != NULL) @@ -3027,6 +3080,8 @@ qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node) #endif } + check_update_duration (qtdemux, time); + return TRUE; /* ERRORS */ @@ -7160,6 +7215,7 @@ done: GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT, GST_TIME_ARGS (stream_duration)); stream->n_segments = 1; + stream->dummy_segment = TRUE; } GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);