From 1e6550f6235cabfbb975bd32fea803c5e2704342 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 25 Oct 2022 01:03:16 +1100 Subject: [PATCH] hlsdemux2: Resync stream time on partial segment boundaries When resyncing stream times in a playlist, support at any partial segment position, not just at full segment boundaries. Part-of: --- .../ext/adaptivedemux2/hls/gsthlsdemux.c | 42 +++++++++++++------ .../ext/adaptivedemux2/hls/m3u8.c | 29 +++++++++++++ .../ext/adaptivedemux2/hls/m3u8.h | 4 ++ 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c index d50a7fcd11..55b26b6294 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c @@ -1383,23 +1383,41 @@ gst_hlsdemux_handle_internal_time (GstHLSDemux * demux, GST_STIME_ARGS (real_stream_time), GST_STIME_ARGS (difference)); if (ABS (difference) > 10 * GST_MSECOND) { - /* FIXME: LL-HLS could recalculate stream times on parts. - * For now, only do it at the first part in a segment */ - if (!hls_stream->in_partial_segments || hls_stream->part_idx == 0) { - /* Update the value */ - GST_DEBUG_OBJECT (hls_stream, - "Updating current stream time to %" GST_STIME_FORMAT, - GST_STIME_ARGS (real_stream_time)); - current_segment->stream_time = real_stream_time; + GstClockTimeDiff wrong_position_threshold = + hls_stream->current_segment->duration / 2; + /* Update the value */ + GST_DEBUG_OBJECT (hls_stream, + "Updating current stream time to %" GST_STIME_FORMAT, + GST_STIME_ARGS (real_stream_time)); + + /* For LL-HLS, make sure to update and recalculate stream time from + * the right partial segment if playing one */ + if (hls_stream->in_partial_segments && hls_stream->part_idx != 0) { + if (current_segment->partial_segments + && hls_stream->part_idx < current_segment->partial_segments->len) { + GstM3U8PartialSegment *part = + g_ptr_array_index (current_segment->partial_segments, + hls_stream->part_idx); + part->stream_time = real_stream_time; + + gst_hls_media_playlist_recalculate_stream_time_from_part + (hls_stream->playlist, hls_stream->current_segment, + hls_stream->part_idx); + + /* When playing partial segments, the "Wrong position" threshold should be + * half the part duration */ + wrong_position_threshold = part->duration / 2; + } + } else { + /* Aligned to the start of the segment, update there */ + current_segment->stream_time = real_stream_time; gst_hls_media_playlist_recalculate_stream_time (hls_stream->playlist, hls_stream->current_segment); - gst_hls_media_playlist_dump (hls_stream->playlist); } + gst_hls_media_playlist_dump (hls_stream->playlist); - /* FIXME: When playing partial segments, the threshold should be - * half the part duration */ - if (ABS (difference) > (hls_stream->current_segment->duration / 2)) { + if (ABS (difference) > wrong_position_threshold) { GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) hls_stream; GstM3U8SeekResult seek_result; diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c index 87034de0d7..9f3ae055e0 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c @@ -1667,6 +1667,35 @@ gst_hls_media_playlist_recalculate_stream_time (GstHLSMediaPlaylist * playlist, } } +void +gst_hls_media_playlist_recalculate_stream_time_from_part (GstHLSMediaPlaylist * + playlist, GstM3U8MediaSegment * anchor, guint part_idx) +{ + g_assert (anchor->partial_segments != NULL + && part_idx < anchor->partial_segments->len); + + GstClockTimeDiff last_stream_time; + GstM3U8PartialSegment *part = + g_ptr_array_index (anchor->partial_segments, part_idx); + GstM3U8PartialSegment *cand, *prev; + gint iter; + + /* Work backward from the target partial segment, assigning stream times until + * we update the segment time itself, then recalculate all stream times */ + prev = part; + last_stream_time = part->stream_time; + for (iter = part_idx - 1; iter >= 0; iter--) { + cand = g_ptr_array_index (anchor->partial_segments, iter); + last_stream_time = cand->stream_time = prev->stream_time - cand->duration; + GST_DEBUG ("Backward partial segment iter %d %" GST_STIME_FORMAT, iter, + GST_STIME_ARGS (cand->stream_time)); + prev = cand; + } + anchor->stream_time = last_stream_time; + + gst_hls_media_playlist_recalculate_stream_time (playlist, anchor); +} + /* If a segment with the same URI, size, offset, SN and DSN is present in the * playlist, returns that one */ static GstM3U8MediaSegment * diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h index ad2ea78e1f..914eb8c44c 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h @@ -279,6 +279,10 @@ void gst_hls_media_playlist_recalculate_stream_time (GstHLSMediaPlaylist *playlist, GstM3U8MediaSegment *anchor); +void +gst_hls_media_playlist_recalculate_stream_time_from_part (GstHLSMediaPlaylist *playlist, + GstM3U8MediaSegment *anchor, guint part_idx); + GstM3U8MediaSegment * gst_hls_media_playlist_sync_to_segment (GstHLSMediaPlaylist * m3u8, GstM3U8MediaSegment * segment);