From 6e48a3ec28aa2a9617c234d33ea495db5cf8c7e7 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 12 May 2022 02:51:00 +1000 Subject: [PATCH] adaptivedemux2: Improve reverse playback buffering. In reverse playback, store the lowest running time in each GOP as the input_time for buffering purposes. That means we end up storing at least a complete GOP before declaring buffering 100% Part-of: --- .../adaptivedemux2/gstadaptivedemux-track.c | 58 ++++++++++++++----- .../ext/adaptivedemux2/gstadaptivedemux.h | 1 + 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-track.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-track.c index 497123a46a..9d6c96776b 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-track.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux-track.c @@ -45,7 +45,7 @@ gst_adaptive_demux_track_flush (GstAdaptiveDemuxTrack * track) gst_event_store_flush (&track->sticky_events); gst_segment_init (&track->input_segment, GST_FORMAT_TIME); - track->input_time = 0; + track->lowest_input_time = track->input_time = 0; track->input_segment_seqnum = GST_SEQNUM_INVALID; gst_segment_init (&track->output_segment, GST_FORMAT_TIME); @@ -235,14 +235,15 @@ handle_event: gst_event_copy_segment (event, &track->output_segment); if (!GST_CLOCK_STIME_IS_VALID (track->output_time)) { - if (track->output_segment.rate > 0.0) + if (track->output_segment.rate > 0.0) { track->output_time = my_segment_to_running_time (&track->output_segment, track->output_segment.start); - else + } else { track->output_time = my_segment_to_running_time (&track->output_segment, track->output_segment.stop); + } } if (track->update_next_segment) { @@ -430,7 +431,7 @@ my_segment_to_running_time (GstSegment * segment, GstClockTime val) static void track_queue_data_locked (GstAdaptiveDemux * demux, GstAdaptiveDemuxTrack * track, GstMiniObject * object, gsize size, - GstClockTime timestamp, GstClockTime duration) + GstClockTime timestamp, GstClockTime duration, gboolean is_discont) { TrackQueueItem item; @@ -449,24 +450,44 @@ track_queue_data_locked (GstAdaptiveDemux * demux, /* Update segment position (include duration if valid) */ track->input_segment.position = timestamp; + if (GST_CLOCK_TIME_IS_VALID (duration)) { - /* In backward playback, each buffer is played - * 'backward', so the segment position should - * only include duration in forward playback */ if (track->input_segment.rate > 0.0) { + /* Forward playback, add duration onto our position and update + * the input time to match */ track->input_segment.position += duration; - input_time = my_segment_to_running_time (&track->input_segment, + item.runningtime_end = input_time = + my_segment_to_running_time (&track->input_segment, track->input_segment.position); } else { - /* Otherwise, the end of the buffer has the smaller running time */ + /* Otherwise, the end of the buffer has the smaller running time and + * we need to change the item.runningtime, but input_time and runningtime_end + * are already set to the larger running time */ item.runningtime = my_segment_to_running_time (&track->input_segment, timestamp + duration); } } /* Update track input time and level */ - if (input_time > track->input_time) - track->input_time = input_time; + if (track->input_segment.rate > 0.0) { + if (input_time > track->input_time) { + track->input_time = input_time; + } + } else { + /* In reverse playback, we track input time differently, to do buffering + * across the reversed GOPs. Each GOP arrives in reverse order, with + * running time moving backward, then jumping forward at the start of + * each GOP. At each point, we want the input time to be the lowest + * running time of the previous GOP. Therefore, we track input times + * into a different variable, and transfer it across when a discont buffer + * arrives */ + if (is_discont) { + track->input_time = track->lowest_input_time; + track->lowest_input_time = input_time; + } else if (input_time < track->lowest_input_time) { + track->lowest_input_time = input_time; + } + } /* Store the maximum running time we've seen as * this item's "buffering running time" */ @@ -489,6 +510,12 @@ track_queue_data_locked (GstAdaptiveDemux * demux, track->stream_id, GST_STIME_ARGS (track->input_time), GST_STIME_ARGS (track->output_time), GST_TIME_ARGS (track->level_time)); } + + GST_LOG_OBJECT (demux, + "track %s item running_time :%" GST_STIME_FORMAT " end :%" + GST_STIME_FORMAT, track->stream_id, GST_STIME_ARGS (item.runningtime), + GST_STIME_ARGS (item.runningtime_end)); + track->level_bytes += size; gst_queue_array_push_tail_struct (track->queue, &item); @@ -554,11 +581,12 @@ _track_sink_chain_function (GstPad * pad, GstObject * parent, "Inserting gap for %" GST_TIME_FORMAT " vs %" GST_TIME_FORMAT, GST_TIME_ARGS (ts), GST_TIME_ARGS (track->input_segment.position)); track_queue_data_locked (demux, track, (GstMiniObject *) gap, 0, - track->input_segment.position, duration); + track->input_segment.position, duration, FALSE); } track_queue_data_locked (demux, track, (GstMiniObject *) buffer, - gst_buffer_get_size (buffer), ts, GST_BUFFER_DURATION (buffer)); + gst_buffer_get_size (buffer), ts, GST_BUFFER_DURATION (buffer), + GST_BUFFER_IS_DISCONT (buffer)); /* Recalculate buffering */ demux_update_buffering_locked (demux); @@ -577,6 +605,7 @@ _track_sink_event_function (GstPad * pad, GstObject * parent, GstEvent * event) GstClockTime timestamp = GST_CLOCK_TIME_NONE; GstClockTime duration = GST_CLOCK_TIME_NONE; gboolean drop = FALSE; + gboolean is_discont = FALSE; GST_DEBUG_OBJECT (pad, "event %" GST_PTR_FORMAT, event); @@ -667,6 +696,7 @@ _track_sink_event_function (GstPad * pad, GstObject * parent, GstEvent * event) GST_DEBUG_OBJECT (pad, "track %s stored segment %" GST_SEGMENT_FORMAT, track->stream_id, &track->input_segment); timestamp = track->input_segment.position; + is_discont = TRUE; break; } @@ -686,7 +716,7 @@ _track_sink_event_function (GstPad * pad, GstObject * parent, GstEvent * event) } track_queue_data_locked (demux, track, (GstMiniObject *) event, 0, - timestamp, duration); + timestamp, duration, is_discont); /* Recalculate buffering */ demux_update_buffering_locked (demux); diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h index ceeaa22a00..9a118ededf 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/gstadaptivedemux.h @@ -208,6 +208,7 @@ struct _GstAdaptiveDemuxTrack /* Input segment and time (in running time) */ GstSegment input_segment; GstClockTimeDiff input_time; + GstClockTimeDiff lowest_input_time; guint64 input_segment_seqnum; /* ================= */