From 727966c1a57ac215a32d9af4864649b7853c2499 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Tue, 29 Oct 2024 12:02:49 +0100 Subject: [PATCH 1/8] fix(DASH): Fix playback of some DASH with multiple period (#7516) With this change, closeSegmentIndex() of all streams of a removed period are defered in StreamingEngine.onUpdate_() Fixes #7516 --- 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 +++++++- some-changes.patch | 188 ++++++++++++++++++++++++++++++++++ 6 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 some-changes.patch diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 3071c3ce20..5a72b8dc78 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 eca072ed05..522b5f2af1 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -147,6 +147,13 @@ shaka.media.StreamingEngine = class { /** @private {?shaka.media.StreamingEngine.MediaState_} */ this.lastTextMediaStateBeforeUnload_ = null; + + /** + * Defered closedSegmentIndex of the periodCombiner. + * + * @private {function} + */ + this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; } /** @override */ @@ -181,6 +188,7 @@ shaka.media.StreamingEngine = class { this.playerInterface_ = null; this.manifest_ = null; this.config_ = null; + this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; } /** @@ -268,6 +276,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. @@ -1254,6 +1270,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 6af6b80732..1bd1294b49 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2578,6 +2578,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); } diff --git a/some-changes.patch b/some-changes.patch new file mode 100644 index 0000000000..7d65322e74 --- /dev/null +++ b/some-changes.patch @@ -0,0 +1,188 @@ +diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js +index ba0ba0772..a92b57062 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 2142aeab2..9cf8d5acd 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 38056b031..a8e82fe5b 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 27d8042f3..3b0173a0c 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 2055e944c..24503ac77 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); + } + From 7e7724f6d37cd12af63fe04d4725d51c8837d918 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 30 Oct 2024 17:07:31 +0100 Subject: [PATCH 2/8] add shaka.util.CloseSegmentIndexRegister Provide an interface between StreamEngine and ManifestParser to defer the call of closeStreamIndex durring the update of segments instead the update of the manifest. Fix eslint / jsdoc --- build/types/core | 1 + externs/shaka/manifest_parser.js | 7 +++++ lib/dash/dash_parser.js | 15 ++++++++++- lib/dash/segment_template.js | 11 ++++++++ lib/hls/hls_parser.js | 5 ++++ lib/media/segment_index.js | 2 -- lib/media/streaming_engine.js | 33 +++++++++-------------- lib/mss/mss_parser.js | 6 +++++ lib/offline/offline_manifest_parser.js | 5 ++++ lib/player.js | 4 +-- lib/util/periods.js | 37 +++++++++++--------------- lib/util/segment_index.js | 36 +++++++++++++++++++++++++ test/offline/storage_integration.js | 5 ++++ test/test/util/simple_fakes.js | 7 +++++ test/test/util/test_scheme.js | 5 ++++ 15 files changed, 131 insertions(+), 48 deletions(-) create mode 100644 lib/util/segment_index.js diff --git a/build/types/core b/build/types/core index 23d04a5c8f..5989b765bf 100644 --- a/build/types/core +++ b/build/types/core @@ -114,6 +114,7 @@ +../../lib/util/public_promise.js +../../lib/util/state_history.js +../../lib/util/stats.js ++../../lib/util/segment_index.js +../../lib/util/stream_utils.js +../../lib/util/string_utils.js +../../lib/util/switch_history.js diff --git a/externs/shaka/manifest_parser.js b/externs/shaka/manifest_parser.js index 6eaa98d1e7..ff66b61dbf 100644 --- a/externs/shaka/manifest_parser.js +++ b/externs/shaka/manifest_parser.js @@ -120,6 +120,13 @@ shaka.extern.ManifestParser = class { * @exportDoc */ setMediaElement(mediaElement) {} + + /** + * provide CloseSegmentIndexRegister + * @param {shaka.util.CloseSegmentIndexRegister} register + * @exportDoc + */ + setCloseSegmentIndexRegister(register) {} }; diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 5a72b8dc78..0dc14d3f29 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -230,6 +230,18 @@ shaka.dash.DashParser = class { } } + /** + * @override + * @exportInterface + */ + setCloseSegmentIndexRegister(register) { + const parser = this; + const closeSegmentIndexes = () => { + parser.handleDeferredCloseSegmentIndexes(); + }; + register.add(closeSegmentIndexes); + } + /** * @override * @exportInterface @@ -1494,10 +1506,11 @@ shaka.dash.DashParser = class { /** * Handles deferred releases of old SegmentIndexes * content type from a previous update. + * @export */ handleDeferredCloseSegmentIndexes() { if (this.periodCombiner_) { - this.periodCombiner_.handleDeferredCloseSegmentIndexes_(); + this.periodCombiner_.handleDeferredCloseSegmentIndexes(); } } diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index f1cd9fde82..ee5fd68a22 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -837,6 +837,17 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { } } + /** + * @override + */ + evictAll() { + if (this.templateInfo_ && this.templateInfo_.timeline.length) { + this.numEvicted_ += this.templateInfo_.timeline.length; + this.templateInfo_.timeline = []; + } + this.references = []; + } + /** * Merge new template info * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 3834cc560f..5681b410a5 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -311,6 +311,11 @@ shaka.hls.HlsParser = class { } } + /** @override */ + setCloseSegmentIndexRegister(register) { + // No-op + } + /** * @override * @exportInterface diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 9cf8d5acd2..c42b5bc426 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -310,8 +310,6 @@ shaka.media.SegmentIndex = class { /** * Removes all SegmentReferences that end before the given time. - * - * @param {number} time The time in seconds. * @export */ evictAll() { diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 522b5f2af1..4c43123359 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -33,7 +33,7 @@ goog.require('shaka.util.MimeUtils'); goog.require('shaka.util.Mp4BoxParsers'); goog.require('shaka.util.Mp4Parser'); goog.require('shaka.util.Networking'); - +goog.require('shaka.util.CloseSegmentIndexRegister'); /** * @summary Creates a Streaming Engine. @@ -149,11 +149,10 @@ shaka.media.StreamingEngine = class { this.lastTextMediaStateBeforeUnload_ = null; /** - * Defered closedSegmentIndex of the periodCombiner. - * - * @private {function} + * @private {shaka.util.CloseSegmentIndexRegister} */ - this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; + this.closeSegmentIndexRegister_ = + new shaka.util.CloseSegmentIndexRegister(); } /** @override */ @@ -188,7 +187,7 @@ shaka.media.StreamingEngine = class { this.playerInterface_ = null; this.manifest_ = null; this.config_ = null; - this.periodCombinerDeferredCloseSegmentIndexesFunction_ = null; + this.closeSegmentIndexRegister_ = null; } /** @@ -276,15 +275,6 @@ 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. * @@ -545,8 +535,15 @@ shaka.media.StreamingEngine = class { this.deferredCloseSegmentIndex_.delete(streamId); } } + this.closeSegmentIndexRegister_.closeSegmentIndexes(); } + /** + * @return {shaka.util.CloseSegmentIndexRegister} + */ + getCloseSegmentIndexRegister() { + return this.closeSegmentIndexRegister_; + } /** * Switches to the given Stream. |stream| may be from any Variant. @@ -1270,12 +1267,6 @@ shaka.media.StreamingEngine = class { } return; } - - if (this.periodCombinerDeferredCloseSegmentIndexesFunction_) - { - this.periodCombinerDeferredCloseSegmentIndexesFunction_(); - } - } // Update the MediaState. diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index f8be5fc390..78aaa339c5 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -103,6 +103,12 @@ shaka.mss.MssParser = class { } } + /** + * @override + * @exportInterface + */ + setCloseSegmentIndexRegister(register) {} + /** * @override * @exportInterface diff --git a/lib/offline/offline_manifest_parser.js b/lib/offline/offline_manifest_parser.js index d318e9bc86..94958ad64e 100644 --- a/lib/offline/offline_manifest_parser.js +++ b/lib/offline/offline_manifest_parser.js @@ -31,6 +31,11 @@ shaka.offline.OfflineManifestParser = class { // No-op } + /** @override */ + setCloseSegmentIndexRegister(register) { + // No-op + } + /** @override */ async start(uriString, playerInterface) { /** @type {shaka.offline.OfflineUri} */ diff --git a/lib/player.js b/lib/player.js index 1bd1294b49..80ffe7e979 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2578,8 +2578,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) + this.parser_.setCloseSegmentIndexRegister( + this.streamingEngine_.getCloseSegmentIndexRegister()); // 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 24503ac779..71a974bfab 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -59,9 +59,10 @@ shaka.util.PeriodCombiner = class { /** * Retains a reference to the function used to close SegmentIndex objects - * for streams which were switched away from during an ongoing update_() + * for streams which were switched away from during an ongoing update_() * just after the period removal. - * @private {!Map.} + * + * @private {!Map.} */ this.deferredCloseSegmentIndex_ = new Map(); } @@ -77,8 +78,7 @@ shaka.util.PeriodCombiner = class { stream.segmentIndex.release(); } } - this.handleDeferredCloseSegmentIndexes_(); - + this.handleDeferredCloseSegmentIndexes(); this.audioStreams_ = []; this.videoStreams_ = []; this.textStreams_ = []; @@ -123,12 +123,12 @@ shaka.util.PeriodCombiner = class { /** * Handles deferred releases of old SegmentIndexes * content type from a previous update. - * @private + * @export */ - handleDeferredCloseSegmentIndexes_() { + handleDeferredCloseSegmentIndexes() { for (const [key, value] of this.deferredCloseSegmentIndex_.entries()) { - const streamId = /** @type {string} */ (key); - const closeSegmentIndex = /** @type {!function()} */ (value); + const streamId = /** @type {number} */ (key); + const closeSegmentIndex = /** @type {function()} */ (value); closeSegmentIndex(); this.deferredCloseSegmentIndex_.delete(streamId); } @@ -178,22 +178,15 @@ shaka.util.PeriodCombiner = class { }); } } - - 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. - */ + if (stream.segmentIndex && + !this.deferredCloseSegmentIndex_.has(stream.id)) { + const deferedCloseSegmentIndex = () => { + if (stream.segmentIndex) { stream.segmentIndex.evictAll(); + stream.closeSegmentIndex(); } - originalcloseSegmentIndex(); - } - this.deferredCloseSegmentIndex_.set(stream.id, stream.closeSegmentIndex); + }; + this.deferredCloseSegmentIndex_.set(stream.id, deferedCloseSegmentIndex); } this.usedPeriodIds_.delete(periodId); diff --git a/lib/util/segment_index.js b/lib/util/segment_index.js new file mode 100644 index 0000000000..6a79a22b4d --- /dev/null +++ b/lib/util/segment_index.js @@ -0,0 +1,36 @@ +goog.provide('shaka.util.CloseSegmentIndexRegister'); + +/** + * @summary a register which provides an interface + * to close shaka.media.SegmentIndex + * @export + */ +shaka.util.CloseSegmentIndexRegister = class { + /** */ + constructor() { + /** @private {!Array.} */ + this.register_ = []; + } + + /** + * add function which closes shaka.media.SegmentIndex + * from the stream + * @param {Function} closeSegmentIndexFunction + */ + add(closeSegmentIndexFunction) { + if (closeSegmentIndexFunction) { + this.register_.push(closeSegmentIndexFunction); + } + } + + /** + * close shaka.media.SegmentIndex from register + */ + closeSegmentIndexes() { + for (const closeSegmentIndexFunction of this.register_) { + if (closeSegmentIndexFunction) { + closeSegmentIndexFunction(); + } + } + } +}; diff --git a/test/offline/storage_integration.js b/test/offline/storage_integration.js index a1ddad3381..1e09644c5a 100644 --- a/test/offline/storage_integration.js +++ b/test/offline/storage_integration.js @@ -1734,6 +1734,11 @@ filterDescribe('Storage', storageSupport, () => { /** @override */ configure(params) {} + /** @override */ + setCloseSegmentIndexRegister(register) { + // No-op + } + /** @override */ start(uri, player) { return Promise.resolve(this.map_[uri]); diff --git a/test/test/util/simple_fakes.js b/test/test/util/simple_fakes.js index 46a12b1e33..a59e9afcae 100644 --- a/test/test/util/simple_fakes.js +++ b/test/test/util/simple_fakes.js @@ -120,6 +120,10 @@ shaka.test.FakeStreamingEngine = class { jasmine.createSpy('switchTextStream').and.callFake((textStream) => { activeText = textStream; }); + + /** @type {!jasmine.Spy} */ + this.getCloseSegmentIndexRegister = + jasmine.createSpy('getCloseSegmentIndexRegister'); } }; @@ -149,6 +153,9 @@ shaka.test.FakeManifestParser = class { /** @type {!jasmine.Spy} */ this.onExpirationUpdated = jasmine.createSpy('onExpirationUpdated'); + + /** @type {!jasmine.Spy} */ + this.setCloseSegmentIndexRegister = jasmine.createSpy('setCloseSegmentIndexRegister'); } }; diff --git a/test/test/util/test_scheme.js b/test/test/util/test_scheme.js index 572f8c2359..f0894649b4 100644 --- a/test/test/util/test_scheme.js +++ b/test/test/util/test_scheme.js @@ -754,6 +754,11 @@ shaka.test.TestScheme.ManifestParser = class { return new shaka.test.TestScheme.ManifestParser(); } + /** @override */ + setCloseSegmentIndexRegister(register) { + // No-op + } + /** @override */ start(uri, playerInterface) { const re = /^test:([^/]+)$/; From 2828459c1709fcd407d50baecfbbe56bb3d02c81 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 30 Oct 2024 17:12:04 +0100 Subject: [PATCH 3/8] fix eslint --- test/test/util/simple_fakes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test/util/simple_fakes.js b/test/test/util/simple_fakes.js index a59e9afcae..cf7c845cb5 100644 --- a/test/test/util/simple_fakes.js +++ b/test/test/util/simple_fakes.js @@ -155,7 +155,8 @@ shaka.test.FakeManifestParser = class { this.onExpirationUpdated = jasmine.createSpy('onExpirationUpdated'); /** @type {!jasmine.Spy} */ - this.setCloseSegmentIndexRegister = jasmine.createSpy('setCloseSegmentIndexRegister'); + this.setCloseSegmentIndexRegister = + jasmine.createSpy('setCloseSegmentIndexRegister'); } }; From 117525edb4590f3354e64215c0a2478b424fde77 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 30 Oct 2024 18:01:41 +0100 Subject: [PATCH 4/8] remove patch from previous version --- some-changes.patch | 188 --------------------------------------------- 1 file changed, 188 deletions(-) delete mode 100644 some-changes.patch diff --git a/some-changes.patch b/some-changes.patch deleted file mode 100644 index 7d65322e74..0000000000 --- a/some-changes.patch +++ /dev/null @@ -1,188 +0,0 @@ -diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js -index ba0ba0772..a92b57062 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 2142aeab2..9cf8d5acd 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 38056b031..a8e82fe5b 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 27d8042f3..3b0173a0c 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 2055e944c..24503ac77 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); - } - From 12879f51299defb7aba42cee40e227eefe734b95 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Thu, 31 Oct 2024 09:59:25 +0100 Subject: [PATCH 5/8] Style nit: indent +2 --- test/offline/storage_integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/offline/storage_integration.js b/test/offline/storage_integration.js index 1e09644c5a..4ec1b7e987 100644 --- a/test/offline/storage_integration.js +++ b/test/offline/storage_integration.js @@ -1736,7 +1736,7 @@ filterDescribe('Storage', storageSupport, () => { /** @override */ setCloseSegmentIndexRegister(register) { - // No-op + // No-op } /** @override */ From 834d71e27dca865c34c88ff878be646735951fca Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 13 Nov 2024 16:19:14 +0100 Subject: [PATCH 6/8] Add player interface to close segmentIndex from manifest extend shaka.extern.ManifestParser.PlayerInterface to provide the function closeSegmentIndex. SegmentIndexex are closed only if not part of an active stream. --- build/types/core | 1 - externs/shaka/manifest_parser.js | 14 ++--- lib/dash/dash_parser.js | 26 +-------- lib/dash/segment_template.js | 11 ---- lib/hls/hls_parser.js | 5 -- lib/media/segment_index.js | 12 ---- lib/media/streaming_engine.js | 53 ++++++++++++------ lib/mss/mss_parser.js | 6 -- lib/offline/offline_manifest_parser.js | 5 -- lib/offline/storage.js | 1 + lib/player.js | 9 ++- lib/util/periods.js | 56 ++++++++----------- lib/util/segment_index.js | 36 ------------ .../dash_parser_content_protection_unit.js | 1 + test/dash/dash_parser_live_unit.js | 1 + test/dash/dash_parser_manifest_unit.js | 1 + test/dash/dash_parser_patch_unit.js | 1 + test/dash/dash_parser_segment_base_unit.js | 1 + test/dash/dash_parser_segment_list_unit.js | 1 + .../dash/dash_parser_segment_template_unit.js | 1 + test/hls/hls_live_unit.js | 1 + test/hls/hls_parser_unit.js | 1 + test/media/streaming_engine_integration.js | 2 + test/media/streaming_engine_unit.js | 2 + test/mss/mss_parser_unit.js | 1 + test/offline/storage_integration.js | 5 -- test/test/util/dash_parser_util.js | 2 + test/test/util/mss_parser_util.js | 2 + test/test/util/simple_fakes.js | 8 --- test/test/util/test_scheme.js | 5 -- test/util/content_steering_manager_unit.js | 1 + 31 files changed, 95 insertions(+), 177 deletions(-) delete mode 100644 lib/util/segment_index.js diff --git a/build/types/core b/build/types/core index 5989b765bf..23d04a5c8f 100644 --- a/build/types/core +++ b/build/types/core @@ -114,7 +114,6 @@ +../../lib/util/public_promise.js +../../lib/util/state_history.js +../../lib/util/stats.js -+../../lib/util/segment_index.js +../../lib/util/stream_utils.js +../../lib/util/string_utils.js +../../lib/util/switch_history.js diff --git a/externs/shaka/manifest_parser.js b/externs/shaka/manifest_parser.js index ff66b61dbf..f2b8b4d45a 100644 --- a/externs/shaka/manifest_parser.js +++ b/externs/shaka/manifest_parser.js @@ -120,13 +120,6 @@ shaka.extern.ManifestParser = class { * @exportDoc */ setMediaElement(mediaElement) {} - - /** - * provide CloseSegmentIndexRegister - * @param {shaka.util.CloseSegmentIndexRegister} register - * @exportDoc - */ - setCloseSegmentIndexRegister(register) {} }; @@ -147,8 +140,9 @@ shaka.extern.ManifestParser = class { * getBandwidthEstimate: function():number, * onMetadata: function(string, number, ?number, * !Array.), - * disableStream: function(!shaka.extern.Stream), - * addFont: function(string, string) +* closeSegmentIndex: function(shaka.extern.Stream, function()), +* disableStream: function(!shaka.extern.Stream), +* addFont: function(string, string) * }} * * @description @@ -193,6 +187,8 @@ shaka.extern.ManifestParser = class { * @property {function(!shaka.extern.Stream)} disableStream * Called to temporarily disable a stream i.e. disabling all variant * containing said stream. + * @property {function(!shaka.extern.Stream, function())} closeSegmentIndex + * Called to close a segment index. * @property {function(string, string)} addFont * Called when a new font needs to be added. * @exportDoc diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index 0dc14d3f29..bb0ec502d2 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -230,18 +230,6 @@ shaka.dash.DashParser = class { } } - /** - * @override - * @exportInterface - */ - setCloseSegmentIndexRegister(register) { - const parser = this; - const closeSegmentIndexes = () => { - parser.handleDeferredCloseSegmentIndexes(); - }; - register.add(closeSegmentIndexes); - } - /** * @override * @exportInterface @@ -251,6 +239,9 @@ shaka.dash.DashParser = class { this.lowLatencyMode_ = playerInterface.isLowLatencyMode(); this.manifestUris_ = [uri]; this.playerInterface_ = playerInterface; + if (this.periodCombiner_) { + this.periodCombiner_.setPlayerInterface(this.playerInterface_); + } const updateDelay = await this.requestManifest_(); @@ -1503,17 +1494,6 @@ shaka.dash.DashParser = class { } } - /** - * Handles deferred releases of old SegmentIndexes - * content type from a previous update. - * @export - */ - handleDeferredCloseSegmentIndexes() { - if (this.periodCombiner_) { - this.periodCombiner_.handleDeferredCloseSegmentIndexes(); - } - } - /** * Clean StreamMap Object to remove reference of deleted Stream Object * @private diff --git a/lib/dash/segment_template.js b/lib/dash/segment_template.js index ee5fd68a22..f1cd9fde82 100644 --- a/lib/dash/segment_template.js +++ b/lib/dash/segment_template.js @@ -837,17 +837,6 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex { } } - /** - * @override - */ - evictAll() { - if (this.templateInfo_ && this.templateInfo_.timeline.length) { - this.numEvicted_ += this.templateInfo_.timeline.length; - this.templateInfo_.timeline = []; - } - this.references = []; - } - /** * Merge new template info * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 5681b410a5..3834cc560f 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -311,11 +311,6 @@ shaka.hls.HlsParser = class { } } - /** @override */ - setCloseSegmentIndexRegister(register) { - // No-op - } - /** * @override * @exportInterface diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index c42b5bc426..05588fbff3 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -308,18 +308,6 @@ shaka.media.SegmentIndex = class { this.numEvicted_ += diff; } - /** - * Removes all SegmentReferences that end before the given time. - * @export - */ - evictAll() { - if (this.references.length) { - this.numEvicted_ += this.references.length; - this.references = []; - } - } - - /** * Drops references that start after windowEnd, or end before windowStart, * and contracts the last reference so that it ends at windowEnd. diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index 4c43123359..a468dbf19b 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -33,7 +33,6 @@ goog.require('shaka.util.MimeUtils'); goog.require('shaka.util.Mp4BoxParsers'); goog.require('shaka.util.Mp4Parser'); goog.require('shaka.util.Networking'); -goog.require('shaka.util.CloseSegmentIndexRegister'); /** * @summary Creates a Streaming Engine. @@ -147,12 +146,6 @@ shaka.media.StreamingEngine = class { /** @private {?shaka.media.StreamingEngine.MediaState_} */ this.lastTextMediaStateBeforeUnload_ = null; - - /** - * @private {shaka.util.CloseSegmentIndexRegister} - */ - this.closeSegmentIndexRegister_ = - new shaka.util.CloseSegmentIndexRegister(); } /** @override */ @@ -187,7 +180,6 @@ shaka.media.StreamingEngine = class { this.playerInterface_ = null; this.manifest_ = null; this.config_ = null; - this.closeSegmentIndexRegister_ = null; } /** @@ -519,6 +511,32 @@ shaka.media.StreamingEngine = class { } } + /** + * closeSegmentIndex if the stream is not active + * @param {shaka.extern.Stream} stream + * @param {function()} closeSegmentIndex + */ + closeSegmentIndex(stream, closeSegmentIndex) { + const type = /** @type {!shaka.util.ManifestParserUtils.ContentType} */ + (stream.type); + const mediaState = this.mediaStates_.get(type); + if (mediaState) { + /** + * Closes the segmentIndex only if the stream is not active. + * If the stream is active the eviction will be peformed + * by the next onUpdate_(). + */ + const matchedStreams = mediaState.stream.matchedStreams; + const found = matchedStreams.find((match) => match.id === stream.id); + if (!found) { + closeSegmentIndex(); + } + } else { + // type of stream not active + closeSegmentIndex(); + } + } + /** * Handles deferred releases of old SegmentIndexes for the mediaState's @@ -535,14 +553,6 @@ shaka.media.StreamingEngine = class { this.deferredCloseSegmentIndex_.delete(streamId); } } - this.closeSegmentIndexRegister_.closeSegmentIndexes(); - } - - /** - * @return {shaka.util.CloseSegmentIndexRegister} - */ - getCloseSegmentIndexRegister() { - return this.closeSegmentIndexRegister_; } /** @@ -2840,6 +2850,17 @@ shaka.media.StreamingEngine = class { static logPrefix_(mediaState) { return '(' + mediaState.type + ':' + mediaState.stream.id + ')'; } + + /** + * @param {shaka.util.ManifestParserUtils.ContentType} type + * @param {number} id + * @return {string} A log prefix of the form [$CONTENT_TYPE:$STREAM_ID], e.g., + * "[audio:5]" or "[video:10]". + * @private + */ + static logExtPrefix_(type, id) { + return '[' + type + ':' + id.toString() + ']'; + } }; diff --git a/lib/mss/mss_parser.js b/lib/mss/mss_parser.js index 78aaa339c5..f8be5fc390 100644 --- a/lib/mss/mss_parser.js +++ b/lib/mss/mss_parser.js @@ -103,12 +103,6 @@ shaka.mss.MssParser = class { } } - /** - * @override - * @exportInterface - */ - setCloseSegmentIndexRegister(register) {} - /** * @override * @exportInterface diff --git a/lib/offline/offline_manifest_parser.js b/lib/offline/offline_manifest_parser.js index 94958ad64e..d318e9bc86 100644 --- a/lib/offline/offline_manifest_parser.js +++ b/lib/offline/offline_manifest_parser.js @@ -31,11 +31,6 @@ shaka.offline.OfflineManifestParser = class { // No-op } - /** @override */ - setCloseSegmentIndexRegister(register) { - // No-op - } - /** @override */ async start(uriString, playerInterface) { /** @type {shaka.offline.OfflineUri} */ diff --git a/lib/offline/storage.js b/lib/offline/storage.js index e73a30822e..9285f9c977 100644 --- a/lib/offline/storage.js +++ b/lib/offline/storage.js @@ -1217,6 +1217,7 @@ shaka.offline.Storage = class { onManifestUpdated: () => {}, getBandwidthEstimate: () => config.abr.defaultBandwidthEstimate, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/lib/player.js b/lib/player.js index 80ffe7e979..e489765f72 100644 --- a/lib/player.js +++ b/lib/player.js @@ -2169,6 +2169,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget { }); } }, + closeSegmentIndex: (stream, closeSegmentIndex) => { + if (this.streamingEngine_) { + this.streamingEngine_.closeSegmentIndex(stream, closeSegmentIndex); + } else { + closeSegmentIndex(); + } + }, disableStream: (stream) => this.disableStream( stream, this.config_.streaming.maxDisabledTime), addFont: (name, url) => this.addFont(name, url), @@ -2578,8 +2585,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget { this.streamingEngine_ = this.createStreamingEngine(); this.streamingEngine_.configure(this.config_.streaming); - this.parser_.setCloseSegmentIndexRegister( - this.streamingEngine_.getCloseSegmentIndexRegister()); // 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 71a974bfab..4a6f540872 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -48,6 +48,9 @@ shaka.util.PeriodCombiner = class { /** @private {boolean} */ this.useStreamOnce_ = false; + /** @private {?shaka.extern.ManifestParser.PlayerInterface} */ + this.playerInterface_ = null; + /** * The IDs of the periods we have already used to generate streams. * This helps us identify the periods which have been added when a live @@ -56,15 +59,6 @@ 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 */ @@ -78,7 +72,6 @@ shaka.util.PeriodCombiner = class { stream.segmentIndex.release(); } } - this.handleDeferredCloseSegmentIndexes(); this.audioStreams_ = []; this.videoStreams_ = []; this.textStreams_ = []; @@ -89,6 +82,15 @@ shaka.util.PeriodCombiner = class { this.usedPeriodIds_.clear(); } + /** + * @param {?shaka.extern.ManifestParser.PlayerInterface} playerInterface + * + * @export + */ + setPlayerInterface(playerInterface) { + this.playerInterface_ = playerInterface; + } + /** * @return {!Array.} * @@ -119,21 +121,6 @@ shaka.util.PeriodCombiner = class { return this.imageStreams_; } - - /** - * Handles deferred releases of old SegmentIndexes - * content type from a previous update. - * @export - */ - handleDeferredCloseSegmentIndexes() { - for (const [key, value] of this.deferredCloseSegmentIndex_.entries()) { - const streamId = /** @type {number} */ (key); - const closeSegmentIndex = /** @type {function()} */ (value); - closeSegmentIndex(); - this.deferredCloseSegmentIndex_.delete(streamId); - } - } - /** * Deletes a stream from matchedStreams because it is no longer needed * @@ -178,15 +165,18 @@ shaka.util.PeriodCombiner = class { }); } } - if (stream.segmentIndex && - !this.deferredCloseSegmentIndex_.has(stream.id)) { - const deferedCloseSegmentIndex = () => { - if (stream.segmentIndex) { - stream.segmentIndex.evictAll(); + if (stream.segmentIndex) { + if (this.playerInterface_) { + const closeSegmentIndex = () => { stream.closeSegmentIndex(); - } - }; - this.deferredCloseSegmentIndex_.set(stream.id, deferedCloseSegmentIndex); + }; + + this.playerInterface_.closeSegmentIndex( + stream, + closeSegmentIndex); + } else { + stream.closeSegmentIndex(); + } } this.usedPeriodIds_.delete(periodId); diff --git a/lib/util/segment_index.js b/lib/util/segment_index.js deleted file mode 100644 index 6a79a22b4d..0000000000 --- a/lib/util/segment_index.js +++ /dev/null @@ -1,36 +0,0 @@ -goog.provide('shaka.util.CloseSegmentIndexRegister'); - -/** - * @summary a register which provides an interface - * to close shaka.media.SegmentIndex - * @export - */ -shaka.util.CloseSegmentIndexRegister = class { - /** */ - constructor() { - /** @private {!Array.} */ - this.register_ = []; - } - - /** - * add function which closes shaka.media.SegmentIndex - * from the stream - * @param {Function} closeSegmentIndexFunction - */ - add(closeSegmentIndexFunction) { - if (closeSegmentIndexFunction) { - this.register_.push(closeSegmentIndexFunction); - } - } - - /** - * close shaka.media.SegmentIndex from register - */ - closeSegmentIndexes() { - for (const closeSegmentIndexFunction of this.register_) { - if (closeSegmentIndexFunction) { - closeSegmentIndexFunction(); - } - } - } -}; diff --git a/test/dash/dash_parser_content_protection_unit.js b/test/dash/dash_parser_content_protection_unit.js index 1a390b8027..4ec124ec7e 100644 --- a/test/dash/dash_parser_content_protection_unit.js +++ b/test/dash/dash_parser_content_protection_unit.js @@ -47,6 +47,7 @@ describe('DashParser ContentProtection', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js index 5a3f691a84..c849349f6b 100644 --- a/test/dash/dash_parser_live_unit.js +++ b/test/dash/dash_parser_live_unit.js @@ -39,6 +39,7 @@ describe('DashParser Live', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 74bfb04732..43fdabb450 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -60,6 +60,7 @@ describe('DashParser Manifest', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: shaka.test.Util.spyFunc(addFontSpy), }; diff --git a/test/dash/dash_parser_patch_unit.js b/test/dash/dash_parser_patch_unit.js index 70e7b54c23..6ff8d1c231 100644 --- a/test/dash/dash_parser_patch_unit.js +++ b/test/dash/dash_parser_patch_unit.js @@ -50,6 +50,7 @@ describe('DashParser Patch', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/dash/dash_parser_segment_base_unit.js b/test/dash/dash_parser_segment_base_unit.js index 2295722289..cdbff25593 100644 --- a/test/dash/dash_parser_segment_base_unit.js +++ b/test/dash/dash_parser_segment_base_unit.js @@ -43,6 +43,7 @@ describe('DashParser SegmentBase', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/dash/dash_parser_segment_list_unit.js b/test/dash/dash_parser_segment_list_unit.js index a212426623..f9bea13d63 100644 --- a/test/dash/dash_parser_segment_list_unit.js +++ b/test/dash/dash_parser_segment_list_unit.js @@ -353,6 +353,7 @@ describe('DashParser SegmentList', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/dash/dash_parser_segment_template_unit.js b/test/dash/dash_parser_segment_template_unit.js index 169de3246a..f7d1c7023b 100644 --- a/test/dash/dash_parser_segment_template_unit.js +++ b/test/dash/dash_parser_segment_template_unit.js @@ -52,6 +52,7 @@ describe('DashParser SegmentTemplate', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js index 5c117bfab3..fab21bc732 100644 --- a/test/hls/hls_live_unit.js +++ b/test/hls/hls_live_unit.js @@ -82,6 +82,7 @@ describe('HlsParser live', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index 5f1f8fb62d..bcd90296da 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -96,6 +96,7 @@ describe('HlsParser', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: shaka.test.Util.spyFunc(onMetadataSpy), + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/media/streaming_engine_integration.js b/test/media/streaming_engine_integration.js index 9f47541b27..5f76ce5178 100644 --- a/test/media/streaming_engine_integration.js +++ b/test/media/streaming_engine_integration.js @@ -271,6 +271,8 @@ describe('StreamingEngine', () => { onSegmentAppended: () => playhead.notifyOfBufferingChange(), onInitSegmentAppended: () => {}, beforeAppendSegment: () => Promise.resolve(), + onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream, time) => false, }; streamingEngine = new shaka.media.StreamingEngine( diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index b129ad92e0..a336c54766 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -467,6 +467,8 @@ describe('StreamingEngine', () => { onSegmentAppended: Util.spyFunc(onSegmentAppended), onInitSegmentAppended: () => {}, beforeAppendSegment: Util.spyFunc(beforeAppendSegment), + onMetadata: Util.spyFunc(onMetadata), + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: Util.spyFunc(disableStream), }; streamingEngine = new shaka.media.StreamingEngine( diff --git a/test/mss/mss_parser_unit.js b/test/mss/mss_parser_unit.js index 071bba0d1a..b6c19573ec 100644 --- a/test/mss/mss_parser_unit.js +++ b/test/mss/mss_parser_unit.js @@ -82,6 +82,7 @@ describe('MssParser Manifest', () => { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/offline/storage_integration.js b/test/offline/storage_integration.js index 4ec1b7e987..a1ddad3381 100644 --- a/test/offline/storage_integration.js +++ b/test/offline/storage_integration.js @@ -1734,11 +1734,6 @@ filterDescribe('Storage', storageSupport, () => { /** @override */ configure(params) {} - /** @override */ - setCloseSegmentIndexRegister(register) { - // No-op - } - /** @override */ start(uri, player) { return Promise.resolve(this.map_[uri]); diff --git a/test/test/util/dash_parser_util.js b/test/test/util/dash_parser_util.js index c047e92617..0202c2fb81 100644 --- a/test/test/util/dash_parser_util.js +++ b/test/test/util/dash_parser_util.js @@ -48,6 +48,7 @@ shaka.test.Dash = class { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; @@ -98,6 +99,7 @@ shaka.test.Dash = class { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/test/util/mss_parser_util.js b/test/test/util/mss_parser_util.js index 13e88b780f..bf228a53da 100644 --- a/test/test/util/mss_parser_util.js +++ b/test/test/util/mss_parser_util.js @@ -48,6 +48,7 @@ shaka.test.Mss = class { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; @@ -89,6 +90,7 @@ shaka.test.Mss = class { onManifestUpdated: () => {}, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; diff --git a/test/test/util/simple_fakes.js b/test/test/util/simple_fakes.js index cf7c845cb5..46a12b1e33 100644 --- a/test/test/util/simple_fakes.js +++ b/test/test/util/simple_fakes.js @@ -120,10 +120,6 @@ shaka.test.FakeStreamingEngine = class { jasmine.createSpy('switchTextStream').and.callFake((textStream) => { activeText = textStream; }); - - /** @type {!jasmine.Spy} */ - this.getCloseSegmentIndexRegister = - jasmine.createSpy('getCloseSegmentIndexRegister'); } }; @@ -153,10 +149,6 @@ shaka.test.FakeManifestParser = class { /** @type {!jasmine.Spy} */ this.onExpirationUpdated = jasmine.createSpy('onExpirationUpdated'); - - /** @type {!jasmine.Spy} */ - this.setCloseSegmentIndexRegister = - jasmine.createSpy('setCloseSegmentIndexRegister'); } }; diff --git a/test/test/util/test_scheme.js b/test/test/util/test_scheme.js index f0894649b4..572f8c2359 100644 --- a/test/test/util/test_scheme.js +++ b/test/test/util/test_scheme.js @@ -754,11 +754,6 @@ shaka.test.TestScheme.ManifestParser = class { return new shaka.test.TestScheme.ManifestParser(); } - /** @override */ - setCloseSegmentIndexRegister(register) { - // No-op - } - /** @override */ start(uri, playerInterface) { const re = /^test:([^/]+)$/; diff --git a/test/util/content_steering_manager_unit.js b/test/util/content_steering_manager_unit.js index a3a0760517..6bf7e52498 100644 --- a/test/util/content_steering_manager_unit.js +++ b/test/util/content_steering_manager_unit.js @@ -30,6 +30,7 @@ describe('ContentSteeringManager', () => { onManifestUpdated: fail, getBandwidthEstimate: () => 1e6, onMetadata: () => {}, + closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: (stream) => {}, addFont: (name, url) => {}, }; From 697c17e3fa89b0c839f82ebbc45884bbb3ae93e7 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 13 Nov 2024 16:59:32 +0100 Subject: [PATCH 7/8] PR review restore empty lines initialy removed by eslint --fix remove logExtPrefix_ --- externs/shaka/manifest_parser.js | 6 +++--- lib/media/segment_index.js | 1 + lib/media/streaming_engine.js | 14 +++----------- lib/util/periods.js | 1 + 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/externs/shaka/manifest_parser.js b/externs/shaka/manifest_parser.js index f2b8b4d45a..22ec3d6ffe 100644 --- a/externs/shaka/manifest_parser.js +++ b/externs/shaka/manifest_parser.js @@ -140,9 +140,9 @@ shaka.extern.ManifestParser = class { * getBandwidthEstimate: function():number, * onMetadata: function(string, number, ?number, * !Array.), -* closeSegmentIndex: function(shaka.extern.Stream, function()), -* disableStream: function(!shaka.extern.Stream), -* addFont: function(string, string) + * closeSegmentIndex: function(shaka.extern.Stream, function()), + * disableStream: function(!shaka.extern.Stream), + * addFont: function(string, string) * }} * * @description diff --git a/lib/media/segment_index.js b/lib/media/segment_index.js index 05588fbff3..2142aeab28 100644 --- a/lib/media/segment_index.js +++ b/lib/media/segment_index.js @@ -308,6 +308,7 @@ shaka.media.SegmentIndex = class { this.numEvicted_ += diff; } + /** * Drops references that start after windowEnd, or end before windowStart, * and contracts the last reference so that it ends at windowEnd. diff --git a/lib/media/streaming_engine.js b/lib/media/streaming_engine.js index a468dbf19b..196c0af21b 100644 --- a/lib/media/streaming_engine.js +++ b/lib/media/streaming_engine.js @@ -34,6 +34,7 @@ goog.require('shaka.util.Mp4BoxParsers'); goog.require('shaka.util.Mp4Parser'); goog.require('shaka.util.Networking'); + /** * @summary Creates a Streaming Engine. * The StreamingEngine is responsible for setting up the Manifest's Streams @@ -267,6 +268,7 @@ shaka.media.StreamingEngine = class { } } + /** * Applies a playback range. This will only affect non-live content. * @@ -555,6 +557,7 @@ shaka.media.StreamingEngine = class { } } + /** * Switches to the given Stream. |stream| may be from any Variant. * @@ -2850,17 +2853,6 @@ shaka.media.StreamingEngine = class { static logPrefix_(mediaState) { return '(' + mediaState.type + ':' + mediaState.stream.id + ')'; } - - /** - * @param {shaka.util.ManifestParserUtils.ContentType} type - * @param {number} id - * @return {string} A log prefix of the form [$CONTENT_TYPE:$STREAM_ID], e.g., - * "[audio:5]" or "[video:10]". - * @private - */ - static logExtPrefix_(type, id) { - return '[' + type + ':' + id.toString() + ']'; - } }; diff --git a/lib/util/periods.js b/lib/util/periods.js index 4a6f540872..bc6acb76fd 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -72,6 +72,7 @@ shaka.util.PeriodCombiner = class { stream.segmentIndex.release(); } } + this.audioStreams_ = []; this.videoStreams_ = []; this.textStreams_ = []; From d022d36699434a2e154ecff17cc5ad12eee6d145 Mon Sep 17 00:00:00 2001 From: Nicolas Cocaign Date: Wed, 13 Nov 2024 17:21:32 +0100 Subject: [PATCH 8/8] fix rebase --- test/media/streaming_engine_unit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/media/streaming_engine_unit.js b/test/media/streaming_engine_unit.js index a336c54766..f8b86a8f53 100644 --- a/test/media/streaming_engine_unit.js +++ b/test/media/streaming_engine_unit.js @@ -467,7 +467,6 @@ describe('StreamingEngine', () => { onSegmentAppended: Util.spyFunc(onSegmentAppended), onInitSegmentAppended: () => {}, beforeAppendSegment: Util.spyFunc(beforeAppendSegment), - onMetadata: Util.spyFunc(onMetadata), closeSegmentIndex: (stream, closeSegmentIndex) => {}, disableStream: Util.spyFunc(disableStream), };