shaka-player 4.13.0 → 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 +4 -4
- package/dist/locales.js +36 -36
- package/dist/shaka-player.compiled.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.externs.js +2 -9
- package/dist/shaka-player.compiled.debug.js +491 -478
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +2 -9
- package/dist/shaka-player.compiled.js +1455 -1443
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +1 -1
- package/dist/shaka-player.ui.debug.d.ts +1 -1
- package/dist/shaka-player.ui.debug.externs.js +2 -9
- package/dist/shaka-player.ui.debug.js +544 -530
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +2 -9
- package/dist/shaka-player.ui.js +1627 -1613
- package/dist/shaka-player.ui.map +4 -4
- package/eslint.config.mjs +14 -1
- package/lib/cast/cast_proxy.js +50 -12
- package/lib/cast/cast_receiver.js +6 -9
- package/lib/cast/cast_sender.js +14 -11
- package/lib/cast/cast_utils.js +43 -46
- package/lib/cea/mp4_cea_parser.js +23 -23
- package/lib/dash/content_protection.js +1 -1
- package/lib/dash/dash_parser.js +39 -29
- package/lib/dash/mpd_utils.js +8 -9
- package/lib/dash/segment_list.js +2 -2
- package/lib/dash/segment_template.js +9 -9
- package/lib/debug/log.js +16 -17
- package/lib/hls/hls_parser.js +122 -99
- package/lib/media/closed_caption_parser.js +5 -5
- package/lib/media/content_workarounds.js +78 -0
- package/lib/media/example_based_criteria.js +4 -3
- package/lib/media/manifest_parser.js +8 -12
- package/lib/media/media_source_engine.js +136 -119
- 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/mss/mss_parser.js +6 -7
- package/lib/net/http_plugin_utils.js +1 -1
- package/lib/net/networking_engine.js +7 -7
- package/lib/net/networking_utils.js +38 -39
- package/lib/offline/stream_bandwidth_estimator.js +8 -8
- package/lib/player.js +98 -47
- package/lib/polyfill/media_capabilities.js +8 -9
- package/lib/text/cue.js +6 -2
- package/lib/text/text_engine.js +7 -7
- package/lib/text/ttml_text_parser.js +14 -16
- package/lib/text/ui_text_displayer.js +25 -4
- package/lib/transmuxer/ac3_transmuxer.js +6 -1
- package/lib/transmuxer/transmuxer_engine.js +6 -6
- package/lib/util/manifest_parser_utils.js +7 -8
- package/lib/util/mp4_generator.js +23 -8
- package/lib/util/mp4_parser.js +10 -10
- package/lib/util/multi_map.js +22 -20
- package/lib/util/platform.js +40 -9
- package/lib/util/player_configuration.js +1 -1
- package/lib/util/stream_utils.js +35 -17
- package/package.json +2 -2
- package/project-words.txt +1 -0
- package/third_party/closure-uri/uri.js +13 -13
- package/ui/ad_statistics_button.js +17 -16
- package/ui/audio_language_selection.js +6 -1
- package/ui/statistics_button.js +36 -35
|
@@ -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);
|
|
@@ -622,6 +623,11 @@ shaka.media.MediaSourceEngine = class {
|
|
|
622
623
|
stream, contentType),
|
|
623
624
|
'Type negotiation should happen before MediaSourceEngine.init!');
|
|
624
625
|
|
|
626
|
+
if (contentType == ContentType.AUDIO && codecs) {
|
|
627
|
+
codecs = shaka.util.StreamUtils.getCorrectAudioCodecs(
|
|
628
|
+
codecs, stream.mimeType);
|
|
629
|
+
}
|
|
630
|
+
|
|
625
631
|
let mimeType = shaka.util.MimeUtils.getFullType(
|
|
626
632
|
stream.mimeType, codecs);
|
|
627
633
|
if (contentType == ContentType.TEXT) {
|
|
@@ -651,7 +657,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
651
657
|
.findTransmuxer(mimeTypeWithAllCodecs);
|
|
652
658
|
if (transmuxerPlugin) {
|
|
653
659
|
const transmuxer = transmuxerPlugin();
|
|
654
|
-
this.transmuxers_
|
|
660
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
655
661
|
mimeType =
|
|
656
662
|
transmuxer.convertCodecs(contentType, mimeTypeWithAllCodecs);
|
|
657
663
|
}
|
|
@@ -686,9 +692,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
686
692
|
this.eventManager_.listen(
|
|
687
693
|
sourceBuffer, 'updateend',
|
|
688
694
|
() => this.onUpdateEnd_(contentType));
|
|
689
|
-
this.sourceBuffers_
|
|
690
|
-
this.sourceBufferTypes_
|
|
691
|
-
this.expectedEncryption_
|
|
695
|
+
this.sourceBuffers_.set(contentType, sourceBuffer);
|
|
696
|
+
this.sourceBufferTypes_.set(contentType, mimeType);
|
|
697
|
+
this.expectedEncryption_.set(contentType, !!stream.drmInfos.length);
|
|
692
698
|
}
|
|
693
699
|
}
|
|
694
700
|
|
|
@@ -762,7 +768,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
762
768
|
* @return {?number} The timestamp in seconds, or null if nothing is buffered.
|
|
763
769
|
*/
|
|
764
770
|
bufferStart(contentType) {
|
|
765
|
-
if (!
|
|
771
|
+
if (!this.sourceBuffers_.size) {
|
|
766
772
|
return null;
|
|
767
773
|
}
|
|
768
774
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -780,7 +786,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
780
786
|
* @return {?number} The timestamp in seconds, or null if nothing is buffered.
|
|
781
787
|
*/
|
|
782
788
|
bufferEnd(contentType) {
|
|
783
|
-
if (!
|
|
789
|
+
if (!this.sourceBuffers_.size) {
|
|
784
790
|
return null;
|
|
785
791
|
}
|
|
786
792
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -867,9 +873,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
867
873
|
return null;
|
|
868
874
|
}
|
|
869
875
|
try {
|
|
870
|
-
return this.sourceBuffers_
|
|
876
|
+
return this.sourceBuffers_.get(contentType).buffered;
|
|
871
877
|
} catch (exception) {
|
|
872
|
-
if (
|
|
878
|
+
if (this.sourceBuffers_.has(contentType)) {
|
|
873
879
|
// Note: previous MediaSource errors may cause access to |buffered| to
|
|
874
880
|
// throw.
|
|
875
881
|
shaka.log.error('failed to get buffered range for ' + contentType,
|
|
@@ -968,12 +974,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
968
974
|
}
|
|
969
975
|
} else if (!mimeType.includes('/mp4') && !mimeType.includes('/webm') &&
|
|
970
976
|
shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
971
|
-
if (!this.tsParsers_
|
|
972
|
-
this.tsParsers_
|
|
977
|
+
if (!this.tsParsers_.has(contentType)) {
|
|
978
|
+
this.tsParsers_.set(contentType, new shaka.util.TsParser());
|
|
973
979
|
} else {
|
|
974
|
-
this.tsParsers_
|
|
980
|
+
this.tsParsers_.get(contentType).clearData();
|
|
975
981
|
}
|
|
976
|
-
const tsParser = this.tsParsers_
|
|
982
|
+
const tsParser = this.tsParsers_.get(contentType).parse(uint8ArrayData);
|
|
977
983
|
const startTime = tsParser.getStartTime(contentType);
|
|
978
984
|
if (startTime != null) {
|
|
979
985
|
timestamp = startTime;
|
|
@@ -1198,16 +1204,16 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1198
1204
|
return;
|
|
1199
1205
|
}
|
|
1200
1206
|
|
|
1201
|
-
if (!this.sourceBuffers_
|
|
1207
|
+
if (!this.sourceBuffers_.has(contentType)) {
|
|
1202
1208
|
shaka.log.warning('Attempted to restore a non-existent source buffer');
|
|
1203
1209
|
return;
|
|
1204
1210
|
}
|
|
1205
1211
|
|
|
1206
|
-
let timestampOffset = this.sourceBuffers_
|
|
1212
|
+
let timestampOffset = this.sourceBuffers_.get(contentType).timestampOffset;
|
|
1207
1213
|
|
|
1208
|
-
let mimeType = this.sourceBufferTypes_
|
|
1209
|
-
if (this.transmuxers_
|
|
1210
|
-
mimeType = this.transmuxers_
|
|
1214
|
+
let mimeType = this.sourceBufferTypes_.get(contentType);
|
|
1215
|
+
if (this.transmuxers_.has(contentType)) {
|
|
1216
|
+
mimeType = this.transmuxers_.get(contentType).getOriginalMimeType();
|
|
1211
1217
|
}
|
|
1212
1218
|
if (reference) {
|
|
1213
1219
|
const {timestamp, metadata} = this.getTimestampAndDispatchMetadata(
|
|
@@ -1251,7 +1257,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1251
1257
|
// adjust TimestampOffset relative to 0 because segments do not have
|
|
1252
1258
|
// any timestamp information.
|
|
1253
1259
|
if (!this.sequenceMode_ &&
|
|
1254
|
-
RAW_FORMATS.includes(this.sourceBufferTypes_
|
|
1260
|
+
RAW_FORMATS.includes(this.sourceBufferTypes_.get(contentType))) {
|
|
1255
1261
|
realTimestamp = 0;
|
|
1256
1262
|
}
|
|
1257
1263
|
const calculatedTimestampOffset = reference.startTime - realTimestamp;
|
|
@@ -1277,7 +1283,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1277
1283
|
// Prefer video for this when available.
|
|
1278
1284
|
const isBestSourceBufferForTimestamps =
|
|
1279
1285
|
contentType == ContentType.VIDEO ||
|
|
1280
|
-
!(ContentType.VIDEO
|
|
1286
|
+
!(this.sourceBuffers_.has(ContentType.VIDEO));
|
|
1281
1287
|
if (isBestSourceBufferForTimestamps) {
|
|
1282
1288
|
this.textSequenceModeOffset_.resolve(timestampOffset);
|
|
1283
1289
|
}
|
|
@@ -1312,8 +1318,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1312
1318
|
}
|
|
1313
1319
|
}
|
|
1314
1320
|
|
|
1315
|
-
if (this.transmuxers_
|
|
1316
|
-
data = await this.transmuxers_
|
|
1321
|
+
if (this.transmuxers_.has(contentType)) {
|
|
1322
|
+
data = await this.transmuxers_.get(contentType).transmux(
|
|
1317
1323
|
data, stream, reference, this.mediaSource_.duration, contentType);
|
|
1318
1324
|
}
|
|
1319
1325
|
|
|
@@ -1332,7 +1338,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1332
1338
|
if (this.manifestType_ == shaka.media.ManifestParser.HLS &&
|
|
1333
1339
|
!this.needSplitMuxedContent_ &&
|
|
1334
1340
|
contentType == ContentType.AUDIO &&
|
|
1335
|
-
this.sourceBuffers_
|
|
1341
|
+
this.sourceBuffers_.has(ContentType.VIDEO)) {
|
|
1336
1342
|
const compensation = await this.audioCompensation_;
|
|
1337
1343
|
// Only apply compensation if the difference is greater than 100ms
|
|
1338
1344
|
if (Math.abs(compensation) > 0.1) {
|
|
@@ -1687,13 +1693,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1687
1693
|
// have to insert a dummy operation into the beginning of each queue,
|
|
1688
1694
|
// which the 'updateend' handler will remove.
|
|
1689
1695
|
if (duration < this.mediaSource_.duration) {
|
|
1690
|
-
for (const contentType
|
|
1696
|
+
for (const contentType of this.sourceBuffers_.keys()) {
|
|
1691
1697
|
const dummyOperation = {
|
|
1692
1698
|
start: () => {},
|
|
1693
1699
|
p: new shaka.util.PublicPromise(),
|
|
1694
1700
|
uri: null,
|
|
1695
1701
|
};
|
|
1696
|
-
this.queues_
|
|
1702
|
+
this.queues_.get(contentType).unshift(dummyOperation);
|
|
1697
1703
|
}
|
|
1698
1704
|
}
|
|
1699
1705
|
|
|
@@ -1766,7 +1772,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1766
1772
|
}
|
|
1767
1773
|
|
|
1768
1774
|
// This will trigger an 'updateend' event.
|
|
1769
|
-
this.sourceBuffers_
|
|
1775
|
+
this.sourceBuffers_.get(contentType).appendBuffer(data);
|
|
1770
1776
|
}
|
|
1771
1777
|
|
|
1772
1778
|
/**
|
|
@@ -1785,7 +1791,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1785
1791
|
}
|
|
1786
1792
|
|
|
1787
1793
|
// This will trigger an 'updateend' event.
|
|
1788
|
-
this.sourceBuffers_
|
|
1794
|
+
this.sourceBuffers_.get(contentType).remove(startTime, endTime);
|
|
1789
1795
|
}
|
|
1790
1796
|
|
|
1791
1797
|
/**
|
|
@@ -1796,18 +1802,18 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1796
1802
|
* @private
|
|
1797
1803
|
*/
|
|
1798
1804
|
abort_(contentType) {
|
|
1805
|
+
const sourceBuffer = this.sourceBuffers_.get(contentType);
|
|
1799
1806
|
// Save the append window, which is reset on abort().
|
|
1800
|
-
const appendWindowStart =
|
|
1801
|
-
|
|
1802
|
-
const appendWindowEnd = this.sourceBuffers_[contentType].appendWindowEnd;
|
|
1807
|
+
const appendWindowStart = sourceBuffer.appendWindowStart;
|
|
1808
|
+
const appendWindowEnd = sourceBuffer.appendWindowEnd;
|
|
1803
1809
|
|
|
1804
1810
|
// This will not trigger an 'updateend' event, since nothing is happening.
|
|
1805
1811
|
// This is only to reset MSE internals, not to abort an actual operation.
|
|
1806
|
-
|
|
1812
|
+
sourceBuffer.abort();
|
|
1807
1813
|
|
|
1808
1814
|
// Restore the append window.
|
|
1809
|
-
|
|
1810
|
-
|
|
1815
|
+
sourceBuffer.appendWindowStart = appendWindowStart;
|
|
1816
|
+
sourceBuffer.appendWindowEnd = appendWindowEnd;
|
|
1811
1817
|
|
|
1812
1818
|
// Fake an 'updateend' event to resolve the operation.
|
|
1813
1819
|
this.onUpdateEnd_(contentType);
|
|
@@ -1849,7 +1855,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1849
1855
|
timestampOffset += 0.001;
|
|
1850
1856
|
}
|
|
1851
1857
|
|
|
1852
|
-
this.sourceBuffers_
|
|
1858
|
+
this.sourceBuffers_.get(contentType).timestampOffset = timestampOffset;
|
|
1853
1859
|
|
|
1854
1860
|
// Fake an 'updateend' event to resolve the operation.
|
|
1855
1861
|
this.onUpdateEnd_(contentType);
|
|
@@ -1863,12 +1869,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1863
1869
|
* @private
|
|
1864
1870
|
*/
|
|
1865
1871
|
setAppendWindow_(contentType, appendWindowStart, appendWindowEnd) {
|
|
1872
|
+
const sourceBuffer = this.sourceBuffers_.get(contentType);
|
|
1866
1873
|
// You can't set start > end, so first set start to 0, then set the new
|
|
1867
1874
|
// end, then set the new start. That way, there are no intermediate
|
|
1868
1875
|
// states which are invalid.
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1876
|
+
sourceBuffer.appendWindowStart = 0;
|
|
1877
|
+
sourceBuffer.appendWindowEnd = appendWindowEnd;
|
|
1878
|
+
sourceBuffer.appendWindowStart = appendWindowStart;
|
|
1872
1879
|
|
|
1873
1880
|
// Fake an 'updateend' event to resolve the operation.
|
|
1874
1881
|
this.onUpdateEnd_(contentType);
|
|
@@ -1879,9 +1886,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1879
1886
|
* @private
|
|
1880
1887
|
*/
|
|
1881
1888
|
onError_(contentType) {
|
|
1882
|
-
const operation = this.queues_
|
|
1889
|
+
const operation = this.queues_.get(contentType)[0];
|
|
1883
1890
|
goog.asserts.assert(operation, 'Spurious error event!');
|
|
1884
|
-
goog.asserts.assert(!this.sourceBuffers_
|
|
1891
|
+
goog.asserts.assert(!this.sourceBuffers_.get(contentType).updating,
|
|
1885
1892
|
'SourceBuffer should not be updating on error!');
|
|
1886
1893
|
const code = this.video_.error ? this.video_.error.code : 0;
|
|
1887
1894
|
operation.p.reject(new shaka.util.Error(
|
|
@@ -1904,12 +1911,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1904
1911
|
if (this.reloadingMediaSource_) {
|
|
1905
1912
|
return;
|
|
1906
1913
|
}
|
|
1907
|
-
const operation = this.queues_
|
|
1914
|
+
const operation = this.queues_.get(contentType)[0];
|
|
1908
1915
|
goog.asserts.assert(operation, 'Spurious updateend event!');
|
|
1909
1916
|
if (!operation) {
|
|
1910
1917
|
return;
|
|
1911
1918
|
}
|
|
1912
|
-
goog.asserts.assert(!this.sourceBuffers_
|
|
1919
|
+
goog.asserts.assert(!this.sourceBuffers_.get(contentType).updating,
|
|
1913
1920
|
'SourceBuffer should not be updating on updateend!');
|
|
1914
1921
|
operation.p.resolve();
|
|
1915
1922
|
this.popFromQueue_(contentType);
|
|
@@ -1931,9 +1938,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1931
1938
|
p: new shaka.util.PublicPromise(),
|
|
1932
1939
|
uri,
|
|
1933
1940
|
};
|
|
1934
|
-
this.queues_
|
|
1941
|
+
this.queues_.get(contentType).push(operation);
|
|
1935
1942
|
|
|
1936
|
-
if (this.queues_
|
|
1943
|
+
if (this.queues_.get(contentType).length == 1) {
|
|
1937
1944
|
this.startOperation_(contentType);
|
|
1938
1945
|
}
|
|
1939
1946
|
return operation.p;
|
|
@@ -1953,7 +1960,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1953
1960
|
/** @type {!Array<!shaka.util.PublicPromise>} */
|
|
1954
1961
|
const allWaiters = [];
|
|
1955
1962
|
/** @type {!Array<!shaka.util.ManifestParserUtils.ContentType>} */
|
|
1956
|
-
const contentTypes =
|
|
1963
|
+
const contentTypes = Array.from(this.sourceBuffers_.keys());
|
|
1957
1964
|
|
|
1958
1965
|
// Enqueue a 'wait' operation onto each queue.
|
|
1959
1966
|
// This operation signals its readiness when it starts.
|
|
@@ -1966,10 +1973,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1966
1973
|
uri: null,
|
|
1967
1974
|
};
|
|
1968
1975
|
|
|
1969
|
-
this.queues_
|
|
1976
|
+
const queue = this.queues_.get(contentType);
|
|
1977
|
+
|
|
1978
|
+
queue.push(operation);
|
|
1970
1979
|
allWaiters.push(ready);
|
|
1971
1980
|
|
|
1972
|
-
if (
|
|
1981
|
+
if (queue.length == 1) {
|
|
1973
1982
|
operation.start();
|
|
1974
1983
|
}
|
|
1975
1984
|
}
|
|
@@ -1989,14 +1998,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1989
1998
|
// are wiped in destroy.
|
|
1990
1999
|
if (goog.DEBUG) {
|
|
1991
2000
|
for (const contentType of contentTypes) {
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2001
|
+
const queue = this.queues_.get(contentType);
|
|
2002
|
+
if (queue.length) {
|
|
2003
|
+
goog.asserts.assert(queue.length == 1,
|
|
1995
2004
|
'Should be at most one item in queue!');
|
|
1996
|
-
goog.asserts.assert(
|
|
1997
|
-
allWaiters.includes(this.queues_[contentType][0].p),
|
|
2005
|
+
goog.asserts.assert(allWaiters.includes(queue[0].p),
|
|
1998
2006
|
'The item in queue should be one of our waiters!');
|
|
1999
|
-
|
|
2007
|
+
queue.shift();
|
|
2000
2008
|
}
|
|
2001
2009
|
}
|
|
2002
2010
|
}
|
|
@@ -2007,7 +2015,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2007
2015
|
// If we did it correctly, nothing is updating.
|
|
2008
2016
|
for (const contentType of contentTypes) {
|
|
2009
2017
|
goog.asserts.assert(
|
|
2010
|
-
this.sourceBuffers_
|
|
2018
|
+
this.sourceBuffers_.get(contentType).updating == false,
|
|
2011
2019
|
'SourceBuffers should not be updating after a blocking op!');
|
|
2012
2020
|
}
|
|
2013
2021
|
}
|
|
@@ -2037,9 +2045,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2037
2045
|
* @private
|
|
2038
2046
|
*/
|
|
2039
2047
|
popFromQueue_(contentType) {
|
|
2040
|
-
goog.asserts.assert(this.queues_
|
|
2048
|
+
goog.asserts.assert(this.queues_.has(contentType), 'Queue should exist');
|
|
2041
2049
|
// Remove the in-progress operation, which is now complete.
|
|
2042
|
-
this.queues_
|
|
2050
|
+
this.queues_.get(contentType).shift();
|
|
2043
2051
|
this.startOperation_(contentType);
|
|
2044
2052
|
}
|
|
2045
2053
|
|
|
@@ -2050,7 +2058,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2050
2058
|
*/
|
|
2051
2059
|
startOperation_(contentType) {
|
|
2052
2060
|
// Retrieve the next operation, if any, from the queue and start it.
|
|
2053
|
-
const next = this.queues_
|
|
2061
|
+
const next = this.queues_.get(contentType)[0];
|
|
2054
2062
|
if (next) {
|
|
2055
2063
|
try {
|
|
2056
2064
|
next.start();
|
|
@@ -2118,7 +2126,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2118
2126
|
const Platform = shaka.util.Platform;
|
|
2119
2127
|
|
|
2120
2128
|
const isInitSegment = startTime == null;
|
|
2121
|
-
const encryptionExpected = this.expectedEncryption_
|
|
2129
|
+
const encryptionExpected = this.expectedEncryption_.get(contentType);
|
|
2122
2130
|
const keySystem = this.playerInterface_.getKeySystem();
|
|
2123
2131
|
|
|
2124
2132
|
// If:
|
|
@@ -2136,11 +2144,19 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2136
2144
|
encryptionExpected &&
|
|
2137
2145
|
Platform.requiresEncryptionInfoInAllInitSegments(keySystem) &&
|
|
2138
2146
|
shaka.util.MimeUtils.getContainerType(
|
|
2139
|
-
this.sourceBufferTypes_
|
|
2147
|
+
this.sourceBufferTypes_.get(contentType)) == 'mp4') {
|
|
2140
2148
|
shaka.log.debug('Forcing fake encryption information in init segment.');
|
|
2141
2149
|
segment = shaka.media.ContentWorkarounds.fakeEncryption(segment, uri);
|
|
2142
2150
|
}
|
|
2143
2151
|
|
|
2152
|
+
if (isInitSegment &&
|
|
2153
|
+
Platform.requiresEC3InitSegments() &&
|
|
2154
|
+
shaka.util.MimeUtils.getContainerType(
|
|
2155
|
+
this.sourceBufferTypes_.get(contentType)) == 'mp4') {
|
|
2156
|
+
shaka.log.debug('Forcing fake EC-3 information in init segment.');
|
|
2157
|
+
segment = shaka.media.ContentWorkarounds.fakeEC3(segment);
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2144
2160
|
return segment;
|
|
2145
2161
|
}
|
|
2146
2162
|
|
|
@@ -2158,19 +2174,20 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2158
2174
|
shaka.log.debug(`Change not supported for ${contentType}`);
|
|
2159
2175
|
return;
|
|
2160
2176
|
}
|
|
2177
|
+
const sourceBuffer = this.sourceBufferTypes_.get(contentType);
|
|
2161
2178
|
shaka.log.debug(
|
|
2162
|
-
`Change Type: ${
|
|
2179
|
+
`Change Type: ${sourceBuffer} -> ${mimeType}`);
|
|
2163
2180
|
if (shaka.media.Capabilities.isChangeTypeSupported()) {
|
|
2164
|
-
if (this.transmuxers_
|
|
2165
|
-
this.transmuxers_
|
|
2166
|
-
|
|
2181
|
+
if (this.transmuxers_.has(contentType)) {
|
|
2182
|
+
this.transmuxers_.get(contentType).destroy();
|
|
2183
|
+
this.transmuxers_.delete(contentType);
|
|
2167
2184
|
}
|
|
2168
2185
|
if (transmuxer) {
|
|
2169
|
-
this.transmuxers_
|
|
2186
|
+
this.transmuxers_.set(contentType, transmuxer);
|
|
2170
2187
|
}
|
|
2171
2188
|
const type = this.addExtraFeaturesToMimeType_(mimeType);
|
|
2172
|
-
this.sourceBuffers_
|
|
2173
|
-
this.sourceBufferTypes_
|
|
2189
|
+
this.sourceBuffers_.get(contentType).changeType(type);
|
|
2190
|
+
this.sourceBufferTypes_.set(contentType, mimeType);
|
|
2174
2191
|
} else {
|
|
2175
2192
|
shaka.log.debug('Change Type not supported');
|
|
2176
2193
|
}
|
|
@@ -2224,19 +2241,18 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2224
2241
|
try {
|
|
2225
2242
|
this.eventManager_.removeAll();
|
|
2226
2243
|
|
|
2227
|
-
for (const
|
|
2228
|
-
|
|
2244
|
+
for (const transmuxer of this.transmuxers_.values()) {
|
|
2245
|
+
transmuxer.destroy();
|
|
2229
2246
|
}
|
|
2230
|
-
for (const
|
|
2231
|
-
const sourceBuffer = this.sourceBuffers_[contentType];
|
|
2247
|
+
for (const sourceBuffer of this.sourceBuffers_.values()) {
|
|
2232
2248
|
try {
|
|
2233
2249
|
this.mediaSource_.removeSourceBuffer(sourceBuffer);
|
|
2234
2250
|
} catch (e) {
|
|
2235
2251
|
shaka.log.debug('Exception on removeSourceBuffer', e);
|
|
2236
2252
|
}
|
|
2237
2253
|
}
|
|
2238
|
-
this.transmuxers_
|
|
2239
|
-
this.sourceBuffers_
|
|
2254
|
+
this.transmuxers_.clear();
|
|
2255
|
+
this.sourceBuffers_.clear();
|
|
2240
2256
|
|
|
2241
2257
|
const previousDuration = this.mediaSource_.duration;
|
|
2242
2258
|
this.mediaSourceOpen_ = new shaka.util.PublicPromise();
|
|
@@ -2275,8 +2291,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2275
2291
|
if (audio && audio.isAudioMuxedInVideo) {
|
|
2276
2292
|
this.needSplitMuxedContent_ = true;
|
|
2277
2293
|
}
|
|
2278
|
-
if (this.needSplitMuxedContent_ && !this.queues_
|
|
2279
|
-
this.queues_
|
|
2294
|
+
if (this.needSplitMuxedContent_ && !this.queues_.has(ContentType.AUDIO)) {
|
|
2295
|
+
this.queues_.set(ContentType.AUDIO, []);
|
|
2280
2296
|
}
|
|
2281
2297
|
|
|
2282
2298
|
// Fake a seek to catchup the playhead.
|
|
@@ -2395,9 +2411,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2395
2411
|
}
|
|
2396
2412
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2397
2413
|
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2398
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2414
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(contentType)));
|
|
2399
2415
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2400
|
-
this.sourceBufferTypes_
|
|
2416
|
+
this.sourceBufferTypes_.get(contentType));
|
|
2401
2417
|
|
|
2402
2418
|
const realInfo = this.getRealInfo_(contentType, mimeType, codecs);
|
|
2403
2419
|
const transmuxer = realInfo.transmuxer;
|
|
@@ -2411,9 +2427,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2411
2427
|
const muxedRealInfo =
|
|
2412
2428
|
this.getRealInfo_(ContentType.AUDIO, mimeType, codecs);
|
|
2413
2429
|
const muxedCurrentCodec = MimeUtils.getNormalizedCodec(
|
|
2414
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2430
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(ContentType.AUDIO)));
|
|
2415
2431
|
const muxedCurrentBasicType = MimeUtils.getBasicType(
|
|
2416
|
-
this.sourceBufferTypes_
|
|
2432
|
+
this.sourceBufferTypes_.get(ContentType.AUDIO));
|
|
2417
2433
|
muxedContentCheck = muxedCurrentCodec == muxedRealInfo.codec &&
|
|
2418
2434
|
muxedCurrentBasicType == muxedRealInfo.basicType;
|
|
2419
2435
|
if (muxedRealInfo.transmuxer) {
|
|
@@ -2424,18 +2440,19 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2424
2440
|
// Current/new codecs base and basic type match then no need to switch
|
|
2425
2441
|
if (currentCodec === newCodec && currentBasicType === newBasicType &&
|
|
2426
2442
|
muxedContentCheck) {
|
|
2427
|
-
if (this.transmuxers_
|
|
2428
|
-
this.transmuxers_
|
|
2429
|
-
|
|
2430
|
-
} else if (!this.transmuxers_
|
|
2431
|
-
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);
|
|
2432
2448
|
} else if (transmuxer) {
|
|
2433
2449
|
// Compare if the transmuxer is different
|
|
2434
|
-
if (this.transmuxers_
|
|
2435
|
-
this.transmuxers_
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
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);
|
|
2439
2456
|
} else {
|
|
2440
2457
|
transmuxer.destroy();
|
|
2441
2458
|
}
|
|
@@ -2445,7 +2462,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2445
2462
|
|
|
2446
2463
|
let allowChangeType = true;
|
|
2447
2464
|
if (this.needSplitMuxedContent_ || (transmuxerMuxed &&
|
|
2448
|
-
transmuxer && !this.transmuxers_
|
|
2465
|
+
transmuxer && !this.transmuxers_.has(contentType))) {
|
|
2449
2466
|
allowChangeType = false;
|
|
2450
2467
|
}
|
|
2451
2468
|
|
|
@@ -2477,9 +2494,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2477
2494
|
}
|
|
2478
2495
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2479
2496
|
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2480
|
-
MimeUtils.getCodecs(this.sourceBufferTypes_
|
|
2497
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_.get(contentType)));
|
|
2481
2498
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2482
|
-
this.sourceBufferTypes_
|
|
2499
|
+
this.sourceBufferTypes_.get(contentType));
|
|
2483
2500
|
|
|
2484
2501
|
let newMimeType = shaka.util.MimeUtils.getFullType(refMimeType, refCodecs);
|
|
2485
2502
|
let needTransmux = this.config_.forceTransmux;
|