From 30db53939b976f231d5b1071223620db7cc3ad58 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Tue, 29 Oct 2024 11:32:48 +0100 Subject: [PATCH] fix(MSS): Fix playback of some MSS streams (#7517) fix(DASH): Fix playback of some DASH with multiple period (#7516) With this change, closeSegmentIndex() of stream removed of a period are defered in StreamingEngine.onUpdate_() Fixes #7517 --- lib/dash/dash_parser.js | 10 ++++++++ lib/media/segment_index.js | 13 +++++++++++ lib/media/streaming_engine.js | 22 ++++++++++++++++++ lib/player.js | 2 ++ lib/util/periods.js | 43 +++++++++++++++++++++++++++++++++-- 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index ba0ba0772a..a92b57062a 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -1491,6 +1491,16 @@ shaka.dash.DashParser = class { } } + /** + * Handles deferred releases of old SegmentIndexes + * content type from a previous update. + */ + handleDeferredCloseSegmentIndexes() { + if (this.periodCombiner_) { + this.periodCombiner_.handleDeferredCloseSegmentIndexes_(); + } + } + /** * Clean StreamMap Object to remove reference of deleted Stream Object * @private diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 2142aeab28..9cf8d5acd2 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -308,6 +308,19 @@ shaka.media.SegmentIndex = class { this.numEvicted_ += diff; } + /** + * Removes all SegmentReferences that end before the given time. + * + * @param {number} time The time in seconds. + * @export + */ + evictAll() { + if (this.references.length) { + this.numEvicted_ += this.references.length; + this.references = []; + } + } + /** * Drops references that start after windowEnd, or end before windowStart, diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 38056b0314..a8e82fe5b8 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -148,6 +148,13 @@ shaka.media.StreamingEngine = class { /** @private {?shaka.media.StreamingEngine.MediaState_} */ this.lastTextMediaStateBeforeUnload_ = null; + + /** + * Defered closedSegmentIndex of the periodCombiner. + * + * @private {function} + */ + this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; } /** @override */ @@ -182,6 +189,7 @@ shaka.media.StreamingEngine = class { this.playerInterface_ = null; this.manifest_ = null; this.config_ = null; + this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; } /** @@ -269,6 +277,14 @@ shaka.media.StreamingEngine = class { } } + /** + * Provide function for releases of old SegmentIndexes of the PeriodCombiner + * @param {function} extraDeferredCloseSegmentIndexes + */ + setExtraDeferredCloseSegmentIndexesFunction(deferredCloseSegmentIndexesFunction) + { + this.periodCombinerDeferredCloseSegmentIndexesFunction_ = deferredCloseSegmentIndexesFunction; + } /** * Applies a playback range. This will only affect non-live content. @@ -1255,6 +1271,12 @@ shaka.media.StreamingEngine = class { } return; } + + if (this.periodCombinerDeferredCloseSegmentIndexesFunction_) + { + this.periodCombinerDeferredCloseSegmentIndexesFunction_(); + } + } // Update the MediaState. diff --git a/lib/player.js b/lib/player.js index 9544582b67..166b38f5a4 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2570,6 +2570,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.streamingEngine_ = this.createStreamingEngine(); this.streamingEngine_.configure(this.config_.streaming); + if (this.parser_.handleDeferredCloseSegmentIndexes) + this.streamingEngine_.setExtraDeferredCloseSegmentIndexesFunction(this.parser_.handleDeferredCloseSegmentIndexes) // Set the load mode to "loaded with media source" as late as possible so // that public methods won't try to access internal components until diff --git a/lib/util/periods.js b/lib/util/periods.js index 2055e944c8..24503ac779 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -56,6 +56,14 @@ shaka.util.PeriodCombiner = class { * @private {!Set.} */ this.usedPeriodIds_ = new Set(); + + /** + * Retains a reference to the function used to close SegmentIndex objects + * for streams which were switched away from during an ongoing update_() + * just after the period removal. + * @private {!Map.} + */ + this.deferredCloseSegmentIndex_ = new Map(); } /** @override */ @@ -69,6 +77,7 @@ shaka.util.PeriodCombiner = class { stream.segmentIndex.release(); } } + this.handleDeferredCloseSegmentIndexes_(); this.audioStreams_ = []; this.videoStreams_ = []; @@ -110,6 +119,21 @@ shaka.util.PeriodCombiner = class { return this.imageStreams_; } + + /** + * Handles deferred releases of old SegmentIndexes + * content type from a previous update. + * @private + */ + handleDeferredCloseSegmentIndexes_() { + for (const [key, value] of this.deferredCloseSegmentIndex_.entries()) { + const streamId = /** @type {string} */ (key); + const closeSegmentIndex = /** @type {!function()} */ (value); + closeSegmentIndex(); + this.deferredCloseSegmentIndex_.delete(streamId); + } + } + /** * Deletes a stream from matchedStreams because it is no longer needed * @@ -154,9 +178,24 @@ shaka.util.PeriodCombiner = class { }); } } - if (stream.segmentIndex) { - stream.closeSegmentIndex(); + + if (stream.segmentIndex && !this.deferredCloseSegmentIndex_.has(stream.id)) { + const originalcloseSegmentIndex = stream.closeSegmentIndex; + stream.closeSegmentIndex = () => { + if(stream.segmentIndex) + { + /** + * as the closure of the segmentIndex is defered + * update the number of evicted references in case or + * than 2 of more period are removed. + */ + stream.segmentIndex.evictAll(); + } + originalcloseSegmentIndex(); + } + this.deferredCloseSegmentIndex_.set(stream.id, stream.closeSegmentIndex); } + this.usedPeriodIds_.delete(periodId); }