shaka-player 4.13.1 → 4.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTORS +1 -0
- package/dist/deps.js +1 -1
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +353 -345
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1413 -1408
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +350 -342
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1630 -1624
- package/dist/shaka-player.ui.map +3 -3
- package/eslint.config.mjs +14 -1
- package/lib/cast/cast_proxy.js +48 -10
- package/lib/debug/log.js +16 -17
- package/lib/hls/hls_parser.js +27 -1
- package/lib/media/media_source_engine.js +124 -120
- package/lib/media/preload_manager.js +10 -5
- package/lib/media/region_observer.js +9 -8
- package/lib/media/region_timeline.js +10 -8
- package/lib/media/streaming_engine.js +25 -9
- package/lib/player.js +87 -38
- package/lib/text/cue.js +6 -2
- package/lib/text/ui_text_displayer.js +25 -4
- package/lib/util/platform.js +24 -3
- package/lib/util/stream_utils.js +13 -0
- package/package.json +1 -1
- package/project-words.txt +1 -0
- package/ui/ad_statistics_button.js +2 -0
- package/ui/statistics_button.js +3 -1
|
@@ -73,23 +73,21 @@ shaka.media.MediaSourceEngine = class {
|
|
|
73
73
|
this.textDisplayer_ = textDisplayer;
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* @private {!
|
|
77
|
-
* SourceBuffer>}
|
|
76
|
+
* @private {!Map<shaka.util.ManifestParserUtils.ContentType, SourceBuffer>}
|
|
78
77
|
*/
|
|
79
|
-
this.sourceBuffers_ =
|
|
78
|
+
this.sourceBuffers_ = new Map();
|
|
80
79
|
|
|
81
80
|
/**
|
|
82
|
-
* @private {!
|
|
83
|
-
* string>}
|
|
81
|
+
* @private {!Map<shaka.util.ManifestParserUtils.ContentType, string>}
|
|
84
82
|
*/
|
|
85
|
-
this.sourceBufferTypes_ =
|
|
83
|
+
this.sourceBufferTypes_ = new Map();
|
|
86
84
|
|
|
87
85
|
|
|
88
86
|
/**
|
|
89
|
-
* @private {!
|
|
87
|
+
* @private {!Map<shaka.util.ManifestParserUtils.ContentType,
|
|
90
88
|
* boolean>}
|
|
91
89
|
*/
|
|
92
|
-
this.expectedEncryption_ =
|
|
90
|
+
this.expectedEncryption_ = new Map();
|
|
93
91
|
|
|
94
92
|
/** @private {shaka.text.TextEngine} */
|
|
95
93
|
this.textEngine_ = null;
|
|
@@ -101,16 +99,17 @@ shaka.media.MediaSourceEngine = class {
|
|
|
101
99
|
this.lcevcDec_ = lcevcDec || null;
|
|
102
100
|
|
|
103
101
|
/**
|
|
104
|
-
* @private {!
|
|
105
|
-
* !Array<shaka.media.MediaSourceEngine.Operation>>}
|
|
102
|
+
* @private {!Map<string, !Array<shaka.media.MediaSourceEngine.Operation>>}
|
|
106
103
|
*/
|
|
107
|
-
this.queues_ =
|
|
104
|
+
this.queues_ = new Map();
|
|
108
105
|
|
|
109
106
|
/** @private {shaka.util.EventManager} */
|
|
110
107
|
this.eventManager_ = new shaka.util.EventManager();
|
|
111
108
|
|
|
112
|
-
/**
|
|
113
|
-
|
|
109
|
+
/**
|
|
110
|
+
* @private {!Map<shaka.util.ManifestParserUtils.ContentType,
|
|
111
|
+
!shaka.extern.Transmuxer>} */
|
|
112
|
+
this.transmuxers_ = new Map();
|
|
114
113
|
|
|
115
114
|
/** @private {?shaka.media.IClosedCaptionParser} */
|
|
116
115
|
this.captionParser_ = null;
|
|
@@ -171,10 +170,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
171
170
|
this.lastDuration_ = null;
|
|
172
171
|
|
|
173
172
|
/**
|
|
174
|
-
* @private {!
|
|
173
|
+
* @private {!Map<shaka.util.ManifestParserUtils.ContentType,
|
|
175
174
|
* !shaka.util.TsParser>}
|
|
176
175
|
*/
|
|
177
|
-
this.tsParsers_ =
|
|
176
|
+
this.tsParsers_ = new Map();
|
|
178
177
|
|
|
179
178
|
/** @private {?number} */
|
|
180
179
|
this.firstVideoTimestamp_ = null;
|
|
@@ -456,13 +455,14 @@ shaka.media.MediaSourceEngine = class {
|
|
|
456
455
|
|
|
457
456
|
const cleanup = [];
|
|
458
457
|
|
|
459
|
-
for (const
|
|
458
|
+
for (const [key, q] of this.queues_) {
|
|
460
459
|
// Make a local copy of the queue and the first item.
|
|
461
|
-
const q = this.queues_[contentType];
|
|
462
460
|
const inProgress = q[0];
|
|
463
461
|
|
|
462
|
+
const contentType = /** @type {string} */(key);
|
|
463
|
+
|
|
464
464
|
// Drop everything else out of the original queue.
|
|
465
|
-
this.queues_
|
|
465
|
+
this.queues_.set(contentType, q.slice(0, 1));
|
|
466
466
|
|
|
467
467
|
// We will wait for this item to complete/fail.
|
|
468
468
|
if (inProgress) {
|
|
@@ -481,8 +481,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
481
481
|
|
|
482
482
|
await Promise.all(cleanup);
|
|
483
483
|
|
|
484
|
-
for (const
|
|
485
|
-
|
|
484
|
+
for (const transmuxer of this.transmuxers_.values()) {
|
|
485
|
+
transmuxer.destroy();
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
if (this.eventManager_) {
|
|
@@ -507,22 +507,23 @@ shaka.media.MediaSourceEngine = class {
|
|
|
507
507
|
this.mediaSource_ = null;
|
|
508
508
|
this.textEngine_ = null;
|
|
509
509
|
this.textDisplayer_ = null;
|
|
510
|
-
this.sourceBuffers_
|
|
511
|
-
this.
|
|
510
|
+
this.sourceBuffers_.clear();
|
|
511
|
+
this.expectedEncryption_.clear();
|
|
512
|
+
this.transmuxers_.clear();
|
|
512
513
|
this.captionParser_ = null;
|
|
513
514
|
if (goog.DEBUG) {
|
|
514
|
-
for (const contentType
|
|
515
|
+
for (const [contentType, q] of this.queues_) {
|
|
515
516
|
goog.asserts.assert(
|
|
516
|
-
|
|
517
|
+
q.length == 0,
|
|
517
518
|
contentType + ' queue should be empty after destroy!');
|
|
518
519
|
}
|
|
519
520
|
}
|
|
520
|
-
this.queues_
|
|
521
|
+
this.queues_.clear();
|
|
521
522
|
|
|
522
523
|
// This object is owned by Player
|
|
523
524
|
this.lcevcDec_ = null;
|
|
524
525
|
|
|
525
|
-
this.tsParsers_
|
|
526
|
+
this.tsParsers_.clear();
|
|
526
527
|
this.playerInterface_ = null;
|
|
527
528
|
}
|
|
528
529
|
|
|
@@ -581,7 +582,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
581
582
|
this.manifestType_ == shaka.media.ManifestParser.HLS &&
|
|
582
583
|
!this.ignoreManifestTimestampsInSegmentsMode_;
|
|
583
584
|
|
|
584
|
-
this.tsParsers_
|
|
585
|
+
this.tsParsers_.clear();
|
|
585
586
|
this.firstVideoTimestamp_ = null;
|
|
586
587
|
this.firstVideoReferenceStartTime_ = null;
|
|
587
588
|
this.firstAudioTimestamp_ = null;
|
|
@@ -593,10 +594,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
593
594
|
// eslint-disable-next-line no-await-in-loop
|
|
594
595
|
await this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
595
596
|
if (this.needSplitMuxedContent_) {
|
|
596
|
-
this.queues_
|
|
597
|
-
this.queues_
|
|
597
|
+
this.queues_.set(ContentType.AUDIO, []);
|
|
598
|
+
this.queues_.set(ContentType.VIDEO, []);
|
|
598
599
|
} else {
|
|
599
|
-
this.queues_
|
|
600
|
+
this.queues_.set(contentType, []);
|
|
600
601
|
}
|
|
601
602
|
}
|
|
602
603
|
const audio = streamsByType.get(ContentType.AUDIO);
|
|
@@ -656,7 +657,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
656
657
|
.findTransmuxer(mimeTypeWithAllCodecs);
|
|
657
658
|
if (transmuxerPlugin) {
|
|
658
659
|
const transmuxer = transmuxerPlugin();
|
|
659
|
-
this.transmuxers_
|
|
660
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
660
661
|
mimeType =
|
|
661
662
|
transmuxer.convertCodecs(contentType, mimeTypeWithAllCodecs);
|
|
662
663
|
}
|
|
@@ -691,9 +692,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
691
692
|
this.eventManager_.listen(
|
|
692
693
|
sourceBuffer, 'updateend',
|
|
693
694
|
() => this.onUpdateEnd_(contentType));
|
|
694
|
-
this.sourceBuffers_
|
|
695
|
-
this.sourceBufferTypes_
|
|
696
|
-
this.expectedEncryption_
|
|
695
|
+
this.sourceBuffers_.set(contentType, sourceBuffer);
|
|
696
|
+
this.sourceBufferTypes_.set(contentType, mimeType);
|
|
697
|
+
this.expectedEncryption_.set(contentType, !!stream.drmInfos.length);
|
|
697
698
|
}
|
|
698
699
|
}
|
|
699
700
|
|
|
@@ -767,7 +768,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
767
768
|
* @return {?number} The timestamp in seconds, or null if nothing is buffered.
|
|
768
769
|
*/
|
|
769
770
|
bufferStart(contentType) {
|
|
770
|
-
if (!
|
|
771
|
+
if (!this.sourceBuffers_.size) {
|
|
771
772
|
return null;
|
|
772
773
|
}
|
|
773
774
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -785,7 +786,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
785
786
|
* @return {?number} The timestamp in seconds, or null if nothing is buffered.
|
|
786
787
|
*/
|
|
787
788
|
bufferEnd(contentType) {
|
|
788
|
-
if (!
|
|
789
|
+
if (!this.sourceBuffers_.size) {
|
|
789
790
|
return null;
|
|
790
791
|
}
|
|
791
792
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -872,9 +873,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
872
873
|
return null;
|
|
873
874
|
}
|
|
874
875
|
try {
|
|
875
|
-
return this.sourceBuffers_
|
|
876
|
+
return this.sourceBuffers_.get(contentType).buffered;
|
|
876
877
|
} catch (exception) {
|
|
877
|
-
if (
|
|
878
|
+
if (this.sourceBuffers_.has(contentType)) {
|
|
878
879
|
// Note: previous MediaSource errors may cause access to |buffered| to
|
|
879
880
|
// throw.
|
|
880
881
|
shaka.log.error('failed to get buffered range for ' + contentType,
|
|
@@ -973,12 +974,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
973
974
|
}
|
|
974
975
|
} else if (!mimeType.includes('/mp4') && !mimeType.includes('/webm') &&
|
|
975
976
|
shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
976
|
-
if (!this.tsParsers_
|
|
977
|
-
this.tsParsers_
|
|
977
|
+
if (!this.tsParsers_.has(contentType)) {
|
|
978
|
+
this.tsParsers_.set(contentType, new shaka.util.TsParser());
|
|
978
979
|
} else {
|
|
979
|
-
this.tsParsers_
|
|
980
|
+
this.tsParsers_.get(contentType).clearData();
|
|
980
981
|
}
|
|
981
|
-
const tsParser = this.tsParsers_
|
|
982
|
+
const tsParser = this.tsParsers_.get(contentType).parse(uint8ArrayData);
|
|
982
983
|
const startTime = tsParser.getStartTime(contentType);
|
|
983
984
|
if (startTime != null) {
|
|
984
985
|
timestamp = startTime;
|
|
@@ -1203,16 +1204,16 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1203
1204
|
return;
|
|
1204
1205
|
}
|
|
1205
1206
|
|
|
1206
|
-
if (!this.sourceBuffers_
|
|
1207
|
+
if (!this.sourceBuffers_.has(contentType)) {
|
|
1207
1208
|
shaka.log.warning('Attempted to restore a non-existent source buffer');
|
|
1208
1209
|
return;
|
|
1209
1210
|
}
|
|
1210
1211
|
|
|
1211
|
-
let timestampOffset = this.sourceBuffers_
|
|
1212
|
+
let timestampOffset = this.sourceBuffers_.get(contentType).timestampOffset;
|
|
1212
1213
|
|
|
1213
|
-
let mimeType = this.sourceBufferTypes_
|
|
1214
|
-
if (this.transmuxers_
|
|
1215
|
-
mimeType = this.transmuxers_
|
|
1214
|
+
let mimeType = this.sourceBufferTypes_.get(contentType);
|
|
1215
|
+
if (this.transmuxers_.has(contentType)) {
|
|
1216
|
+
mimeType = this.transmuxers_.get(contentType).getOriginalMimeType();
|
|
1216
1217
|
}
|
|
1217
1218
|
if (reference) {
|
|
1218
1219
|
const {timestamp, metadata} = this.getTimestampAndDispatchMetadata(
|
|
@@ -1256,7 +1257,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1256
1257
|
// adjust TimestampOffset relative to 0 because segments do not have
|
|
1257
1258
|
// any timestamp information.
|
|
1258
1259
|
if (!this.sequenceMode_ &&
|
|
1259
|
-
RAW_FORMATS.includes(this.sourceBufferTypes_
|
|
1260
|
+
RAW_FORMATS.includes(this.sourceBufferTypes_.get(contentType))) {
|
|
1260
1261
|
realTimestamp = 0;
|
|
1261
1262
|
}
|
|
1262
1263
|
const calculatedTimestampOffset = reference.startTime - realTimestamp;
|
|
@@ -1282,7 +1283,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1282
1283
|
// Prefer video for this when available.
|
|
1283
1284
|
const isBestSourceBufferForTimestamps =
|
|
1284
1285
|
contentType == ContentType.VIDEO ||
|
|
1285
|
-
!(ContentType.VIDEO
|
|
1286
|
+
!(this.sourceBuffers_.has(ContentType.VIDEO));
|
|
1286
1287
|
if (isBestSourceBufferForTimestamps) {
|
|
1287
1288
|
this.textSequenceModeOffset_.resolve(timestampOffset);
|
|
1288
1289
|
}
|
|
@@ -1317,8 +1318,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1317
1318
|
}
|
|
1318
1319
|
}
|
|
1319
1320
|
|
|
1320
|
-
if (this.transmuxers_
|
|
1321
|
-
data = await this.transmuxers_
|
|
1321
|
+
if (this.transmuxers_.has(contentType)) {
|
|
1322
|
+
data = await this.transmuxers_.get(contentType).transmux(
|
|
1322
1323
|
data, stream, reference, this.mediaSource_.duration, contentType);
|
|
1323
1324
|
}
|
|
1324
1325
|
|
|
@@ -1337,7 +1338,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1337
1338
|
if (this.manifestType_ == shaka.media.ManifestParser.HLS &&
|
|
1338
1339
|
!this.needSplitMuxedContent_ &&
|
|
1339
1340
|
contentType == ContentType.AUDIO &&
|
|
1340
|
-
this.sourceBuffers_
|
|
1341
|
+
this.sourceBuffers_.has(ContentType.VIDEO)) {
|
|
1341
1342
|
const compensation = await this.audioCompensation_;
|
|
1342
1343
|
// Only apply compensation if the difference is greater than 100ms
|
|
1343
1344
|
if (Math.abs(compensation) > 0.1) {
|
|
@@ -1692,13 +1693,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1692
1693
|
// have to insert a dummy operation into the beginning of each queue,
|
|
1693
1694
|
// which the 'updateend' handler will remove.
|
|
1694
1695
|
if (duration < this.mediaSource_.duration) {
|
|
1695
|
-
for (const contentType
|
|
1696
|
+
for (const contentType of this.sourceBuffers_.keys()) {
|
|
1696
1697
|
const dummyOperation = {
|
|
1697
1698
|
start: () => {},
|
|
1698
1699
|
p: new shaka.util.PublicPromise(),
|
|
1699
1700
|
uri: null,
|
|
1700
1701
|
};
|
|
1701
|
-
this.queues_
|
|
1702
|
+
this.queues_.get(contentType).unshift(dummyOperation);
|
|
1702
1703
|
}
|
|
1703
1704
|
}
|
|
1704
1705
|
|
|
@@ -1771,7 +1772,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1771
1772
|
}
|
|
1772
1773
|
|
|
1773
1774
|
// This will trigger an 'updateend' event.
|
|
1774
|
-
this.sourceBuffers_
|
|
1775
|
+
this.sourceBuffers_.get(contentType).appendBuffer(data);
|
|
1775
1776
|
}
|
|
1776
1777
|
|
|
1777
1778
|
/**
|
|
@@ -1790,7 +1791,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1790
1791
|
}
|
|
1791
1792
|
|
|
1792
1793
|
// This will trigger an 'updateend' event.
|
|
1793
|
-
this.sourceBuffers_
|
|
1794
|
+
this.sourceBuffers_.get(contentType).remove(startTime, endTime);
|
|
1794
1795
|
}
|
|
1795
1796
|
|
|
1796
1797
|
/**
|
|
@@ -1801,18 +1802,18 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1801
1802
|
* @private
|
|
1802
1803
|
*/
|
|
1803
1804
|
abort_(contentType) {
|
|
1805
|
+
const sourceBuffer = this.sourceBuffers_.get(contentType);
|
|
1804
1806
|
// Save the append window, which is reset on abort().
|
|
1805
|
-
const appendWindowStart =
|
|
1806
|
-
|
|
1807
|
-
const appendWindowEnd = this.sourceBuffers_[contentType].appendWindowEnd;
|
|
1807
|
+
const appendWindowStart = sourceBuffer.appendWindowStart;
|
|
1808
|
+
const appendWindowEnd = sourceBuffer.appendWindowEnd;
|
|
1808
1809
|
|
|
1809
1810
|
// This will not trigger an 'updateend' event, since nothing is happening.
|
|
1810
1811
|
// This is only to reset MSE internals, not to abort an actual operation.
|
|
1811
|
-
|
|
1812
|
+
sourceBuffer.abort();
|
|
1812
1813
|
|
|
1813
1814
|
// Restore the append window.
|
|
1814
|
-
|
|
1815
|
-
|
|
1815
|
+
sourceBuffer.appendWindowStart = appendWindowStart;
|
|
1816
|
+
sourceBuffer.appendWindowEnd = appendWindowEnd;
|
|
1816
1817
|
|
|
1817
1818
|
// Fake an 'updateend' event to resolve the operation.
|
|
1818
1819
|
this.onUpdateEnd_(contentType);
|
|
@@ -1854,7 +1855,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1854
1855
|
timestampOffset += 0.001;
|
|
1855
1856
|
}
|
|
1856
1857
|
|
|
1857
|
-
this.sourceBuffers_
|
|
1858
|
+
this.sourceBuffers_.get(contentType).timestampOffset = timestampOffset;
|
|
1858
1859
|
|
|
1859
1860
|
// Fake an 'updateend' event to resolve the operation.
|
|
1860
1861
|
this.onUpdateEnd_(contentType);
|
|
@@ -1868,12 +1869,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1868
1869
|
* @private
|
|
1869
1870
|
*/
|
|
1870
1871
|
setAppendWindow_(contentType, appendWindowStart, appendWindowEnd) {
|
|
1872
|
+
const sourceBuffer = this.sourceBuffers_.get(contentType);
|
|
1871
1873
|
// You can't set start > end, so first set start to 0, then set the new
|
|
1872
1874
|
// end, then set the new start. That way, there are no intermediate
|
|
1873
1875
|
// states which are invalid.
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1876
|
+
sourceBuffer.appendWindowStart = 0;
|
|
1877
|
+
sourceBuffer.appendWindowEnd = appendWindowEnd;
|
|
1878
|
+
sourceBuffer.appendWindowStart = appendWindowStart;
|
|
1877
1879
|
|
|
1878
1880
|
// Fake an 'updateend' event to resolve the operation.
|
|
1879
1881
|
this.onUpdateEnd_(contentType);
|
|
@@ -1884,9 +1886,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1884
1886
|
* @private
|
|
1885
1887
|
*/
|
|
1886
1888
|
onError_(contentType) {
|
|
1887
|
-
const operation = this.queues_
|
|
1889
|
+
const operation = this.queues_.get(contentType)[0];
|
|
1888
1890
|
goog.asserts.assert(operation, 'Spurious error event!');
|
|
1889
|
-
goog.asserts.assert(!this.sourceBuffers_
|
|
1891
|
+
goog.asserts.assert(!this.sourceBuffers_.get(contentType).updating,
|
|
1890
1892
|
'SourceBuffer should not be updating on error!');
|
|
1891
1893
|
const code = this.video_.error ? this.video_.error.code : 0;
|
|
1892
1894
|
operation.p.reject(new shaka.util.Error(
|
|
@@ -1909,12 +1911,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1909
1911
|
if (this.reloadingMediaSource_) {
|
|
1910
1912
|
return;
|
|
1911
1913
|
}
|
|
1912
|
-
const operation = this.queues_
|
|
1914
|
+
const operation = this.queues_.get(contentType)[0];
|
|
1913
1915
|
goog.asserts.assert(operation, 'Spurious updateend event!');
|
|
1914
1916
|
if (!operation) {
|
|
1915
1917
|
return;
|
|
1916
1918
|
}
|
|
1917
|
-
goog.asserts.assert(!this.sourceBuffers_
|
|
1919
|
+
goog.asserts.assert(!this.sourceBuffers_.get(contentType).updating,
|
|
1918
1920
|
'SourceBuffer should not be updating on updateend!');
|
|
1919
1921
|
operation.p.resolve();
|
|
1920
1922
|
this.popFromQueue_(contentType);
|
|
@@ -1936,9 +1938,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1936
1938
|
p: new shaka.util.PublicPromise(),
|
|
1937
1939
|
uri,
|
|
1938
1940
|
};
|
|
1939
|
-
this.queues_
|
|
1941
|
+
this.queues_.get(contentType).push(operation);
|
|
1940
1942
|
|
|
1941
|
-
if (this.queues_
|
|
1943
|
+
if (this.queues_.get(contentType).length == 1) {
|
|
1942
1944
|
this.startOperation_(contentType);
|
|
1943
1945
|
}
|
|
1944
1946
|
return operation.p;
|
|
@@ -1958,7 +1960,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1958
1960
|
/** @type {!Array<!shaka.util.PublicPromise>} */
|
|
1959
1961
|
const allWaiters = [];
|
|
1960
1962
|
/** @type {!Array<!shaka.util.ManifestParserUtils.ContentType>} */
|
|
1961
|
-
const contentTypes =
|
|
1963
|
+
const contentTypes = Array.from(this.sourceBuffers_.keys());
|
|
1962
1964
|
|
|
1963
1965
|
// Enqueue a 'wait' operation onto each queue.
|
|
1964
1966
|
// This operation signals its readiness when it starts.
|
|
@@ -1971,10 +1973,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1971
1973
|
uri: null,
|
|
1972
1974
|
};
|
|
1973
1975
|
|
|
1974
|
-
this.queues_
|
|
1976
|
+
const queue = this.queues_.get(contentType);
|
|
1977
|
+
|
|
1978
|
+
queue.push(operation);
|
|
1975
1979
|
allWaiters.push(ready);
|
|
1976
1980
|
|
|
1977
|
-
if (
|
|
1981
|
+
if (queue.length == 1) {
|
|
1978
1982
|
operation.start();
|
|
1979
1983
|
}
|
|
1980
1984
|
}
|
|
@@ -1994,14 +1998,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1994
1998
|
// are wiped in destroy.
|
|
1995
1999
|
if (goog.DEBUG) {
|
|
1996
2000
|
for (const contentType of contentTypes) {
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2001
|
+
const queue = this.queues_.get(contentType);
|
|
2002
|
+
if (queue.length) {
|
|
2003
|
+
goog.asserts.assert(queue.length == 1,
|
|
2000
2004
|
'Should be at most one item in queue!');
|
|
2001
|
-
goog.asserts.assert(
|
|
2002
|
-
allWaiters.includes(this.queues_[contentType][0].p),
|
|
2005
|
+
goog.asserts.assert(allWaiters.includes(queue[0].p),
|
|
2003
2006
|
'The item in queue should be one of our waiters!');
|
|
2004
|
-
|
|
2007
|
+
queue.shift();
|
|
2005
2008
|
}
|
|
2006
2009
|
}
|
|
2007
2010
|
}
|
|
@@ -2012,7 +2015,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2012
2015
|
// If we did it correctly, nothing is updating.
|
|
2013
2016
|
for (const contentType of contentTypes) {
|
|
2014
2017
|
goog.asserts.assert(
|
|
2015
|
-
this.sourceBuffers_
|
|
2018
|
+
this.sourceBuffers_.get(contentType).updating == false,
|
|
2016
2019
|
'SourceBuffers should not be updating after a blocking op!');
|
|
2017
2020
|
}
|
|
2018
2021
|
}
|
|
@@ -2042,9 +2045,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2042
2045
|
* @private
|
|
2043
2046
|
*/
|
|
2044
2047
|
popFromQueue_(contentType) {
|
|
2045
|
-
goog.asserts.assert(this.queues_
|
|
2048
|
+
goog.asserts.assert(this.queues_.has(contentType), 'Queue should exist');
|
|
2046
2049
|
// Remove the in-progress operation, which is now complete.
|
|
2047
|
-
this.queues_
|
|
2050
|
+
this.queues_.get(contentType).shift();
|
|
2048
2051
|
this.startOperation_(contentType);
|
|
2049
2052
|
}
|
|
2050
2053
|
|
|
@@ -2055,7 +2058,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2055
2058
|
*/
|
|
2056
2059
|
startOperation_(contentType) {
|
|
2057
2060
|
// Retrieve the next operation, if any, from the queue and start it.
|
|
2058
|
-
const next = this.queues_
|
|
2061
|
+
const next = this.queues_.get(contentType)[0];
|
|
2059
2062
|
if (next) {
|
|
2060
2063
|
try {
|
|
2061
2064
|
next.start();
|
|
@@ -2123,7 +2126,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2123
2126
|
const Platform = shaka.util.Platform;
|
|
2124
2127
|
|
|
2125
2128
|
const isInitSegment = startTime == null;
|
|
2126
|
-
const encryptionExpected = this.expectedEncryption_
|
|
2129
|
+
const encryptionExpected = this.expectedEncryption_.get(contentType);
|
|
2127
2130
|
const keySystem = this.playerInterface_.getKeySystem();
|
|
2128
2131
|
|
|
2129
2132
|
// If:
|
|
@@ -2141,7 +2144,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2141
2144
|
encryptionExpected &&
|
|
2142
2145
|
Platform.requiresEncryptionInfoInAllInitSegments(keySystem) &&
|
|
2143
2146
|
shaka.util.MimeUtils.getContainerType(
|
|
2144
|
-
this.sourceBufferTypes_
|
|
2147
|
+
this.sourceBufferTypes_.get(contentType)) == 'mp4') {
|
|
2145
2148
|
shaka.log.debug('Forcing fake encryption information in init segment.');
|
|
2146
2149
|
segment = shaka.media.ContentWorkarounds.fakeEncryption(segment, uri);
|
|
2147
2150
|
}
|
|
@@ -2149,7 +2152,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2149
2152
|
if (isInitSegment &&
|
|
2150
2153
|
Platform.requiresEC3InitSegments() &&
|
|
2151
2154
|
shaka.util.MimeUtils.getContainerType(
|
|
2152
|
-
this.sourceBufferTypes_
|
|
2155
|
+
this.sourceBufferTypes_.get(contentType)) == 'mp4') {
|
|
2153
2156
|
shaka.log.debug('Forcing fake EC-3 information in init segment.');
|
|
2154
2157
|
segment = shaka.media.ContentWorkarounds.fakeEC3(segment);
|
|
2155
2158
|
}
|
|
@@ -2171,19 +2174,20 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2171
2174
|
shaka.log.debug(`Change not supported for ${contentType}`);
|
|
2172
2175
|
return;
|
|
2173
2176
|
}
|
|
2177
|
+
const sourceBuffer = this.sourceBufferTypes_.get(contentType);
|
|
2174
2178
|
shaka.log.debug(
|
|
2175
|
-
`Change Type: ${
|
|
2179
|
+
`Change Type: ${sourceBuffer} -> ${mimeType}`);
|
|
2176
2180
|
if (shaka.media.Capabilities.isChangeTypeSupported()) {
|
|
2177
|
-
if (this.transmuxers_
|
|
2178
|
-
this.transmuxers_
|
|
2179
|
-
|
|
2181
|
+
if (this.transmuxers_.has(contentType)) {
|
|
2182
|
+
this.transmuxers_.get(contentType).destroy();
|
|
2183
|
+
this.transmuxers_.delete(contentType);
|
|
2180
2184
|
}
|
|
2181
2185
|
if (transmuxer) {
|
|
2182
|
-
this.transmuxers_
|
|
2186
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
2183
2187
|
}
|
|
2184
2188
|
const type = this.addExtraFeaturesToMimeType_(mimeType);
|
|
2185
|
-
this.sourceBuffers_
|
|
2186
|
-
this.sourceBufferTypes_
|
|
2189
|
+
this.sourceBuffers_.get(contentType).changeType(type);
|
|
2190
|
+
this.sourceBufferTypes_.set(contentType, mimeType);
|
|
2187
2191
|
} else {
|
|
2188
2192
|
shaka.log.debug('Change Type not supported');
|
|
2189
2193
|
}
|
|
@@ -2237,19 +2241,18 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2237
2241
|
try {
|
|
2238
2242
|
this.eventManager_.removeAll();
|
|
2239
2243
|
|
|
2240
|
-
for (const
|
|
2241
|
-
|
|
2244
|
+
for (const transmuxer of this.transmuxers_.values()) {
|
|
2245
|
+
transmuxer.destroy();
|
|
2242
2246
|
}
|
|
2243
|
-
for (const
|
|
2244
|
-
const sourceBuffer = this.sourceBuffers_[contentType];
|
|
2247
|
+
for (const sourceBuffer of this.sourceBuffers_.values()) {
|
|
2245
2248
|
try {
|
|
2246
2249
|
this.mediaSource_.removeSourceBuffer(sourceBuffer);
|
|
2247
2250
|
} catch (e) {
|
|
2248
2251
|
shaka.log.debug('Exception on removeSourceBuffer', e);
|
|
2249
2252
|
}
|
|
2250
2253
|
}
|
|
2251
|
-
this.transmuxers_
|
|
2252
|
-
this.sourceBuffers_
|
|
2254
|
+
this.transmuxers_.clear();
|
|
2255
|
+
this.sourceBuffers_.clear();
|
|
2253
2256
|
|
|
2254
2257
|
const previousDuration = this.mediaSource_.duration;
|
|
2255
2258
|
this.mediaSourceOpen_ = new shaka.util.PublicPromise();
|
|
@@ -2288,8 +2291,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2288
2291
|
if (audio && audio.isAudioMuxedInVideo) {
|
|
2289
2292
|
this.needSplitMuxedContent_ = true;
|
|
2290
2293
|
}
|
|
2291
|
-
if (this.needSplitMuxedContent_ && !this.queues_
|
|
2292
|
-
this.queues_
|
|
2294
|
+
if (this.needSplitMuxedContent_ && !this.queues_.has(ContentType.AUDIO)) {
|
|
2295
|
+
this.queues_.set(ContentType.AUDIO, []);
|
|
2293
2296
|
}
|
|
2294
2297
|
|
|
2295
2298
|
// Fake a seek to catchup the playhead.
|
|
@@ -2408,9 +2411,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2408
2411
|
}
|
|
2409
2412
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2410
2413
|
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2411
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2414
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(contentType)));
|
|
2412
2415
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2413
|
-
this.sourceBufferTypes_
|
|
2416
|
+
this.sourceBufferTypes_.get(contentType));
|
|
2414
2417
|
|
|
2415
2418
|
const realInfo = this.getRealInfo_(contentType, mimeType, codecs);
|
|
2416
2419
|
const transmuxer = realInfo.transmuxer;
|
|
@@ -2424,9 +2427,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2424
2427
|
const muxedRealInfo =
|
|
2425
2428
|
this.getRealInfo_(ContentType.AUDIO, mimeType, codecs);
|
|
2426
2429
|
const muxedCurrentCodec = MimeUtils.getNormalizedCodec(
|
|
2427
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2430
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(ContentType.AUDIO)));
|
|
2428
2431
|
const muxedCurrentBasicType = MimeUtils.getBasicType(
|
|
2429
|
-
this.sourceBufferTypes_
|
|
2432
|
+
this.sourceBufferTypes_.get(ContentType.AUDIO));
|
|
2430
2433
|
muxedContentCheck = muxedCurrentCodec == muxedRealInfo.codec &&
|
|
2431
2434
|
muxedCurrentBasicType == muxedRealInfo.basicType;
|
|
2432
2435
|
if (muxedRealInfo.transmuxer) {
|
|
@@ -2437,18 +2440,19 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2437
2440
|
// Current/new codecs base and basic type match then no need to switch
|
|
2438
2441
|
if (currentCodec === newCodec && currentBasicType === newBasicType &&
|
|
2439
2442
|
muxedContentCheck) {
|
|
2440
|
-
if (this.transmuxers_
|
|
2441
|
-
this.transmuxers_
|
|
2442
|
-
|
|
2443
|
-
} else if (!this.transmuxers_
|
|
2444
|
-
this.transmuxers_
|
|
2443
|
+
if (this.transmuxers_.has(contentType) && !transmuxer) {
|
|
2444
|
+
this.transmuxers_.get(contentType).destroy();
|
|
2445
|
+
this.transmuxers_.delete(contentType);
|
|
2446
|
+
} else if (!this.transmuxers_.has(contentType) && transmuxer) {
|
|
2447
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
2445
2448
|
} else if (transmuxer) {
|
|
2446
2449
|
// Compare if the transmuxer is different
|
|
2447
|
-
if (this.transmuxers_
|
|
2448
|
-
this.transmuxers_
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
this.transmuxers_
|
|
2450
|
+
if (this.transmuxers_.has(contentType) &&
|
|
2451
|
+
this.transmuxers_.get(contentType).transmux !=
|
|
2452
|
+
transmuxer.transmux) {
|
|
2453
|
+
this.transmuxers_.get(contentType).destroy();
|
|
2454
|
+
this.transmuxers_.delete(contentType);
|
|
2455
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
2452
2456
|
} else {
|
|
2453
2457
|
transmuxer.destroy();
|
|
2454
2458
|
}
|
|
@@ -2458,7 +2462,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2458
2462
|
|
|
2459
2463
|
let allowChangeType = true;
|
|
2460
2464
|
if (this.needSplitMuxedContent_ || (transmuxerMuxed &&
|
|
2461
|
-
transmuxer && !this.transmuxers_
|
|
2465
|
+
transmuxer && !this.transmuxers_.has(contentType))) {
|
|
2462
2466
|
allowChangeType = false;
|
|
2463
2467
|
}
|
|
2464
2468
|
|
|
@@ -2490,9 +2494,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2490
2494
|
}
|
|
2491
2495
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2492
2496
|
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2493
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2497
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(contentType)));
|
|
2494
2498
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2495
|
-
this.sourceBufferTypes_
|
|
2499
|
+
this.sourceBufferTypes_.get(contentType));
|
|
2496
2500
|
|
|
2497
2501
|
let newMimeType = shaka.util.MimeUtils.getFullType(refMimeType, refCodecs);
|
|
2498
2502
|
let needTransmux = this.config_.forceTransmux;
|