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
package/eslint.config.mjs
CHANGED
|
@@ -81,7 +81,6 @@ export default [
|
|
|
81
81
|
},
|
|
82
82
|
rules: {
|
|
83
83
|
// Things the compiler already takes care of, with more precision: {{{
|
|
84
|
-
'no-console': 'off',
|
|
85
84
|
'no-eq-null': 'off',
|
|
86
85
|
'no-eval': 'off',
|
|
87
86
|
'no-undef': 'off',
|
|
@@ -132,6 +131,7 @@ export default [
|
|
|
132
131
|
'guard-for-in': 'off',
|
|
133
132
|
'no-alert': 'error',
|
|
134
133
|
'no-caller': 'error',
|
|
134
|
+
'no-console': 'error',
|
|
135
135
|
'no-div-regex': 'error',
|
|
136
136
|
'no-extend-native': 'error', // May conflict with future polyfills
|
|
137
137
|
'no-extra-label': 'error',
|
|
@@ -340,4 +340,17 @@ export default [
|
|
|
340
340
|
'jsdoc/require-jsdoc': 'off',
|
|
341
341
|
},
|
|
342
342
|
},
|
|
343
|
+
{
|
|
344
|
+
files: [
|
|
345
|
+
'karma.conf.js',
|
|
346
|
+
'build/**/*.js',
|
|
347
|
+
'demo/**/*.js',
|
|
348
|
+
'lib/debug/asserts.js',
|
|
349
|
+
'lib/debug/log.js',
|
|
350
|
+
'test/**/**.js',
|
|
351
|
+
],
|
|
352
|
+
rules: {
|
|
353
|
+
'no-console': 'off',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
343
356
|
];
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -81,17 +81,21 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
81
81
|
this.compiledToExternNames_ = new Map();
|
|
82
82
|
|
|
83
83
|
/** @private {shaka.cast.CastSender} */
|
|
84
|
-
this.sender_ =
|
|
85
|
-
receiverAppId,
|
|
86
|
-
() => this.onCastStatusChanged_(),
|
|
87
|
-
() => this.onFirstCastStateUpdate_(),
|
|
88
|
-
(targetName, event) => this.onRemoteEvent_(targetName, event),
|
|
89
|
-
() => this.onResumeLocal_(),
|
|
90
|
-
() => this.getInitState_(),
|
|
91
|
-
androidReceiverCompatible);
|
|
92
|
-
|
|
84
|
+
this.sender_ = null;
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
if (window.chrome) {
|
|
87
|
+
this.sender_ = new shaka.cast.CastSender(
|
|
88
|
+
receiverAppId,
|
|
89
|
+
() => this.onCastStatusChanged_(),
|
|
90
|
+
() => this.onFirstCastStateUpdate_(),
|
|
91
|
+
(targetName, event) => this.onRemoteEvent_(targetName, event),
|
|
92
|
+
() => this.onResumeLocal_(),
|
|
93
|
+
() => this.getInitState_(),
|
|
94
|
+
androidReceiverCompatible);
|
|
95
|
+
this.init_();
|
|
96
|
+
} else {
|
|
97
|
+
this.initWithoutSender_();
|
|
98
|
+
}
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
/**
|
|
@@ -163,6 +167,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
163
167
|
* @export
|
|
164
168
|
*/
|
|
165
169
|
canCast() {
|
|
170
|
+
if (!this.sender_) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
166
173
|
return this.sender_.apiReady() && this.sender_.hasReceivers();
|
|
167
174
|
}
|
|
168
175
|
|
|
@@ -171,6 +178,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
171
178
|
* @export
|
|
172
179
|
*/
|
|
173
180
|
isCasting() {
|
|
181
|
+
if (!this.sender_) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
174
184
|
return this.sender_.isCasting();
|
|
175
185
|
}
|
|
176
186
|
|
|
@@ -179,6 +189,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
179
189
|
* @export
|
|
180
190
|
*/
|
|
181
191
|
receiverName() {
|
|
192
|
+
if (!this.sender_) {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
182
195
|
return this.sender_.receiverName();
|
|
183
196
|
}
|
|
184
197
|
|
|
@@ -188,6 +201,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
188
201
|
* @export
|
|
189
202
|
*/
|
|
190
203
|
async cast() {
|
|
204
|
+
if (!this.sender_) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
191
207
|
// TODO: transfer manually-selected tracks?
|
|
192
208
|
// TODO: transfer side-loaded text tracks?
|
|
193
209
|
|
|
@@ -208,6 +224,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
208
224
|
* @export
|
|
209
225
|
*/
|
|
210
226
|
setAppData(appData) {
|
|
227
|
+
if (!this.sender_) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
211
230
|
this.sender_.setAppData(appData);
|
|
212
231
|
}
|
|
213
232
|
|
|
@@ -216,6 +235,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
216
235
|
* @export
|
|
217
236
|
*/
|
|
218
237
|
suggestDisconnect() {
|
|
238
|
+
if (!this.sender_) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
219
241
|
this.sender_.showDisconnectDialog();
|
|
220
242
|
}
|
|
221
243
|
|
|
@@ -224,6 +246,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
224
246
|
* @export
|
|
225
247
|
*/
|
|
226
248
|
forceDisconnect() {
|
|
249
|
+
if (!this.sender_) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
227
252
|
this.sender_.forceDisconnect();
|
|
228
253
|
}
|
|
229
254
|
|
|
@@ -243,6 +268,10 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
243
268
|
this.receiverAppId_ = newAppId;
|
|
244
269
|
this.androidReceiverCompatible_ = newCastAndroidReceiver;
|
|
245
270
|
|
|
271
|
+
if (!this.sender_) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
246
275
|
// Destroy the old sender
|
|
247
276
|
this.sender_.forceDisconnect();
|
|
248
277
|
await this.sender_.destroy();
|
|
@@ -262,6 +291,15 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
262
291
|
this.sender_.init();
|
|
263
292
|
}
|
|
264
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Initialize the Proxies without Cast sender.
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
initWithoutSender_() {
|
|
299
|
+
this.videoProxy_ = /** @type {Object} */(this.localVideo_);
|
|
300
|
+
this.playerProxy_ = /** @type {Object} */(this.localPlayer_);
|
|
301
|
+
}
|
|
302
|
+
|
|
265
303
|
/**
|
|
266
304
|
* Initialize the Proxies and the Cast sender.
|
|
267
305
|
* @private
|
|
@@ -721,8 +759,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
721
759
|
// If we are casting, but the first update has not come in yet, use local
|
|
722
760
|
// getters, but not local methods.
|
|
723
761
|
if (this.sender_.isCasting() && !this.sender_.hasRemoteProperties()) {
|
|
724
|
-
if (shaka.cast.CastUtils.PlayerGetterMethods
|
|
725
|
-
shaka.cast.CastUtils.LargePlayerGetterMethods
|
|
762
|
+
if (shaka.cast.CastUtils.PlayerGetterMethods.has(name) ||
|
|
763
|
+
shaka.cast.CastUtils.LargePlayerGetterMethods.has(name)) {
|
|
726
764
|
const value = /** @type {Object} */(this.localPlayer_)[name];
|
|
727
765
|
goog.asserts.assert(typeof value == 'function',
|
|
728
766
|
'only methods on Player');
|
|
@@ -484,19 +484,17 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
484
484
|
if (this.player_.isLive()) {
|
|
485
485
|
const PlayerGetterMethodsThatRequireLive =
|
|
486
486
|
shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive;
|
|
487
|
-
|
|
488
|
-
const frequency = PlayerGetterMethodsThatRequireLive[name];
|
|
487
|
+
PlayerGetterMethodsThatRequireLive.forEach((frequency, name) => {
|
|
489
488
|
if (this.updateNumber_ % frequency == 0) {
|
|
490
489
|
update['player'][name] = /** @type {Object} */ (this.player_)[name]();
|
|
491
490
|
}
|
|
492
|
-
}
|
|
491
|
+
});
|
|
493
492
|
}
|
|
494
|
-
|
|
495
|
-
const frequency = shaka.cast.CastUtils.PlayerGetterMethods[name];
|
|
493
|
+
shaka.cast.CastUtils.PlayerGetterMethods.forEach((frequency, name) => {
|
|
496
494
|
if (this.updateNumber_ % frequency == 0) {
|
|
497
495
|
update['player'][name] = /** @type {Object} */ (this.player_)[name]();
|
|
498
496
|
}
|
|
499
|
-
}
|
|
497
|
+
});
|
|
500
498
|
|
|
501
499
|
// Volume attributes are tied to the system volume.
|
|
502
500
|
const manager = cast.receiver.CastReceiverManager.getInstance();
|
|
@@ -512,8 +510,7 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
512
510
|
}, this.shakaBus_);
|
|
513
511
|
|
|
514
512
|
// Getters with large outputs each get sent in their own update message.
|
|
515
|
-
|
|
516
|
-
const frequency = shaka.cast.CastUtils.LargePlayerGetterMethods[name];
|
|
513
|
+
shaka.cast.CastUtils.LargePlayerGetterMethods.forEach((frequency, name) => {
|
|
517
514
|
if (this.updateNumber_ % frequency == 0) {
|
|
518
515
|
const update = {'player': {}};
|
|
519
516
|
update['player'][name] = /** @type {Object} */ (this.player_)[name]();
|
|
@@ -523,7 +520,7 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
523
520
|
'update': update,
|
|
524
521
|
}, this.shakaBus_);
|
|
525
522
|
}
|
|
526
|
-
}
|
|
523
|
+
});
|
|
527
524
|
|
|
528
525
|
// Only start progressing the update number once data is loaded,
|
|
529
526
|
// just in case any of the "rarely changing" properties with less frequent
|
package/lib/cast/cast_sender.js
CHANGED
|
@@ -91,8 +91,8 @@ shaka.cast.CastSender = class {
|
|
|
91
91
|
/** @private {number} */
|
|
92
92
|
this.nextAsyncCallId_ = 0;
|
|
93
93
|
|
|
94
|
-
/** @private {
|
|
95
|
-
this.asyncCallPromises_ =
|
|
94
|
+
/** @private {Map<string, !shaka.util.PublicPromise>} */
|
|
95
|
+
this.asyncCallPromises_ = new Map();
|
|
96
96
|
|
|
97
97
|
/** @private {shaka.util.PublicPromise} */
|
|
98
98
|
this.castPromise_ = null;
|
|
@@ -350,7 +350,7 @@ shaka.cast.CastSender = class {
|
|
|
350
350
|
return (...args) => this.remoteCall_(targetName, property, ...args);
|
|
351
351
|
}
|
|
352
352
|
} else if (targetName == 'player') {
|
|
353
|
-
if (CastUtils.PlayerGetterMethodsThatRequireLive
|
|
353
|
+
if (CastUtils.PlayerGetterMethodsThatRequireLive.has(property)) {
|
|
354
354
|
const isLive = this.get('player', 'isLive')();
|
|
355
355
|
goog.asserts.assert(isLive,
|
|
356
356
|
property + ' should be called on a live stream!');
|
|
@@ -367,8 +367,8 @@ shaka.cast.CastSender = class {
|
|
|
367
367
|
return (...args) =>
|
|
368
368
|
this.remoteAsyncCall_(targetName, property, ...args);
|
|
369
369
|
}
|
|
370
|
-
if (CastUtils.PlayerGetterMethods
|
|
371
|
-
CastUtils.LargePlayerGetterMethods
|
|
370
|
+
if (CastUtils.PlayerGetterMethods.has(property) ||
|
|
371
|
+
CastUtils.LargePlayerGetterMethods.has(property)) {
|
|
372
372
|
return () => this.propertyGetter_(targetName, property);
|
|
373
373
|
}
|
|
374
374
|
}
|
|
@@ -491,7 +491,7 @@ shaka.cast.CastSender = class {
|
|
|
491
491
|
const p = new shaka.util.PublicPromise();
|
|
492
492
|
const id = this.nextAsyncCallId_.toString();
|
|
493
493
|
this.nextAsyncCallId_++;
|
|
494
|
-
this.asyncCallPromises_
|
|
494
|
+
this.asyncCallPromises_.set(id, p);
|
|
495
495
|
|
|
496
496
|
try {
|
|
497
497
|
this.sendMessage_({
|
|
@@ -618,9 +618,12 @@ shaka.cast.CastSender = class {
|
|
|
618
618
|
* @private
|
|
619
619
|
*/
|
|
620
620
|
rejectAllPromises_() {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
621
|
+
if (!this.asyncCallPromises_) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
for (const id of this.asyncCallPromises_.keys()) {
|
|
625
|
+
const p = this.asyncCallPromises_.get(id);
|
|
626
|
+
this.asyncCallPromises_.delete(id);
|
|
624
627
|
|
|
625
628
|
// Reject pending async operations as if they were interrupted.
|
|
626
629
|
// At the moment, load() is the only async operation we are worried about.
|
|
@@ -669,8 +672,8 @@ shaka.cast.CastSender = class {
|
|
|
669
672
|
case 'asyncComplete': {
|
|
670
673
|
const id = message['id'];
|
|
671
674
|
const error = message['error'];
|
|
672
|
-
const p = this.asyncCallPromises_
|
|
673
|
-
|
|
675
|
+
const p = this.asyncCallPromises_.get(id);
|
|
676
|
+
this.asyncCallPromises_.delete(id);
|
|
674
677
|
|
|
675
678
|
goog.asserts.assert(p, 'Unexpected async id');
|
|
676
679
|
if (!p) {
|
package/lib/cast/cast_utils.js
CHANGED
|
@@ -300,54 +300,52 @@ shaka.cast.CastUtils.VideoVoidMethods = [
|
|
|
300
300
|
* Player getter methods that are proxied while casting.
|
|
301
301
|
* The key is the method, the value is the frequency of updates.
|
|
302
302
|
* Frequency 1 translates to every update; frequency 2 to every 2 updates, etc.
|
|
303
|
-
* @const {!
|
|
303
|
+
* @const {!Map<string, number>}
|
|
304
304
|
*/
|
|
305
|
-
shaka.cast.CastUtils.PlayerGetterMethods =
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
};
|
|
305
|
+
shaka.cast.CastUtils.PlayerGetterMethods = new Map()
|
|
306
|
+
// NOTE: The 'drmInfo' property is not proxied, as it is very large.
|
|
307
|
+
.set('getAssetUri', 2)
|
|
308
|
+
.set('getAudioLanguages', 4)
|
|
309
|
+
.set('getAudioLanguagesAndRoles', 4)
|
|
310
|
+
.set('getBufferFullness', 1)
|
|
311
|
+
.set('getBufferedInfo', 2)
|
|
312
|
+
.set('getExpiration', 2)
|
|
313
|
+
.set('getKeyStatuses', 2)
|
|
314
|
+
// NOTE: The 'getManifest' property is not proxied, as it is very large.
|
|
315
|
+
// NOTE: The 'getManifestParserFactory' property is not proxied, as it would
|
|
316
|
+
// not serialize.
|
|
317
|
+
.set('getPlaybackRate', 2)
|
|
318
|
+
.set('getTextLanguages', 4)
|
|
319
|
+
.set('getTextLanguagesAndRoles', 4)
|
|
320
|
+
.set('getImageTracks', 2)
|
|
321
|
+
.set('getThumbnails', 2)
|
|
322
|
+
.set('isAudioOnly', 10)
|
|
323
|
+
.set('isBuffering', 1)
|
|
324
|
+
.set('isInProgress', 1)
|
|
325
|
+
.set('isLive', 10)
|
|
326
|
+
.set('isTextTrackVisible', 1)
|
|
327
|
+
.set('keySystem', 10)
|
|
328
|
+
.set('seekRange', 1)
|
|
329
|
+
.set('getLoadMode', 10)
|
|
330
|
+
.set('getManifestType', 10)
|
|
331
|
+
.set('isFullyLoaded', 1)
|
|
332
|
+
.set('isEnded', 1);
|
|
334
333
|
|
|
335
334
|
|
|
336
335
|
/**
|
|
337
336
|
* Player getter methods with data large enough to be sent in their own update
|
|
338
337
|
* messages, to reduce the size of each message. The format of this is
|
|
339
338
|
* identical to PlayerGetterMethods.
|
|
340
|
-
* @const {!
|
|
339
|
+
* @const {!Map<string, number>}
|
|
341
340
|
*/
|
|
342
|
-
shaka.cast.CastUtils.LargePlayerGetterMethods =
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
};
|
|
341
|
+
shaka.cast.CastUtils.LargePlayerGetterMethods = new Map()
|
|
342
|
+
// NOTE: The 'getSharedConfiguration' property is not proxied as it would
|
|
343
|
+
// not be possible to share a reference.
|
|
344
|
+
.set('getConfiguration', 4)
|
|
345
|
+
.set('getConfigurationForLowLatency', 4)
|
|
346
|
+
.set('getStats', 5)
|
|
347
|
+
.set('getTextTracks', 2)
|
|
348
|
+
.set('getVariantTracks', 2);
|
|
351
349
|
|
|
352
350
|
|
|
353
351
|
/**
|
|
@@ -355,13 +353,12 @@ shaka.cast.CastUtils.LargePlayerGetterMethods = {
|
|
|
355
353
|
* a livestream.
|
|
356
354
|
* The key is the method, the value is the frequency of updates.
|
|
357
355
|
* Frequency 1 translates to every update; frequency 2 to every 2 updates, etc.
|
|
358
|
-
* @const {!
|
|
356
|
+
* @const {!Map<string, number>}
|
|
359
357
|
*/
|
|
360
|
-
shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive =
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
};
|
|
358
|
+
shaka.cast.CastUtils.PlayerGetterMethodsThatRequireLive = new Map()
|
|
359
|
+
.set('getPlayheadTimeAsDate', 1)
|
|
360
|
+
.set('getPresentationStartTimeAsDate', 20)
|
|
361
|
+
.set('getSegmentAvailabilityDuration', 20);
|
|
365
362
|
|
|
366
363
|
|
|
367
364
|
/**
|
|
@@ -389,8 +389,9 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
389
389
|
* @private
|
|
390
390
|
*/
|
|
391
391
|
setBitstreamFormat_(codec) {
|
|
392
|
-
if (
|
|
393
|
-
this.bitstreamFormat_ =
|
|
392
|
+
if (shaka.cea.Mp4CeaParser.CodecBitstreamMap_.has(codec)) {
|
|
393
|
+
this.bitstreamFormat_ =
|
|
394
|
+
shaka.cea.Mp4CeaParser.CodecBitstreamMap_.get(codec);
|
|
394
395
|
}
|
|
395
396
|
}
|
|
396
397
|
};
|
|
@@ -403,27 +404,26 @@ shaka.cea.Mp4CeaParser.BitstreamFormat = {
|
|
|
403
404
|
H266: 3,
|
|
404
405
|
};
|
|
405
406
|
|
|
406
|
-
/** @private {
|
|
407
|
-
shaka.cea.Mp4CeaParser.CodecBitstreamMap_ =
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
};
|
|
407
|
+
/** @private {Map<string, shaka.cea.Mp4CeaParser.BitstreamFormat>} */
|
|
408
|
+
shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = new Map()
|
|
409
|
+
// AVC
|
|
410
|
+
.set('avc1', shaka.cea.Mp4CeaParser.BitstreamFormat.H264)
|
|
411
|
+
.set('avc3', shaka.cea.Mp4CeaParser.BitstreamFormat.H264)
|
|
412
|
+
// Dolby Vision based in AVC
|
|
413
|
+
.set('dvav', shaka.cea.Mp4CeaParser.BitstreamFormat.H264)
|
|
414
|
+
.set('dva1', shaka.cea.Mp4CeaParser.BitstreamFormat.H264)
|
|
415
|
+
// HEVC
|
|
416
|
+
.set('hev1', shaka.cea.Mp4CeaParser.BitstreamFormat.H265)
|
|
417
|
+
.set('hvc1', shaka.cea.Mp4CeaParser.BitstreamFormat.H265)
|
|
418
|
+
// Dolby Vision based in HEVC
|
|
419
|
+
.set('dvh1', shaka.cea.Mp4CeaParser.BitstreamFormat.H265)
|
|
420
|
+
.set('dvhe', shaka.cea.Mp4CeaParser.BitstreamFormat.H265)
|
|
421
|
+
// VVC
|
|
422
|
+
.set('vvc1', shaka.cea.Mp4CeaParser.BitstreamFormat.H266)
|
|
423
|
+
.set('vvi1', shaka.cea.Mp4CeaParser.BitstreamFormat.H266)
|
|
424
|
+
// Dolby Vision based in VVC
|
|
425
|
+
.set('dvc1', shaka.cea.Mp4CeaParser.BitstreamFormat.H266)
|
|
426
|
+
.set('dvi1', shaka.cea.Mp4CeaParser.BitstreamFormat.H266);
|
|
427
427
|
|
|
428
428
|
/**
|
|
429
429
|
* @typedef {{
|
|
@@ -203,7 +203,7 @@ shaka.dash.ContentProtection = class {
|
|
|
203
203
|
* @return {string}
|
|
204
204
|
*/
|
|
205
205
|
static getFairPlayLicenseUrl(element) {
|
|
206
|
-
if (shaka.util.Platform.isMediaKeysPolyfilled()) {
|
|
206
|
+
if (shaka.util.Platform.isMediaKeysPolyfilled('apple')) {
|
|
207
207
|
throw new shaka.util.Error(
|
|
208
208
|
shaka.util.Error.Severity.CRITICAL,
|
|
209
209
|
shaka.util.Error.Category.MANIFEST,
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -98,22 +98,22 @@ shaka.dash.DashParser = class {
|
|
|
98
98
|
* A map of IDs to Stream objects.
|
|
99
99
|
* ID: Period@id,Representation@id
|
|
100
100
|
* e.g.: '1,23'
|
|
101
|
-
* @private {!
|
|
101
|
+
* @private {!Map<string, !shaka.extern.Stream>}
|
|
102
102
|
*/
|
|
103
|
-
this.streamMap_ =
|
|
103
|
+
this.streamMap_ = new Map();
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* A map of Period IDs to Stream Map IDs.
|
|
107
107
|
* Use to have direct access to streamMap key.
|
|
108
|
-
* @private {!
|
|
108
|
+
* @private {!Map<string, !Array<string>>}
|
|
109
109
|
*/
|
|
110
|
-
this.indexStreamMap_ =
|
|
110
|
+
this.indexStreamMap_ = new Map();
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* A map of period ids to their durations
|
|
114
|
-
* @private {!
|
|
114
|
+
* @private {!Map<string, number>}
|
|
115
115
|
*/
|
|
116
|
-
this.periodDurations_ =
|
|
116
|
+
this.periodDurations_ = new Map();
|
|
117
117
|
|
|
118
118
|
/** @private {shaka.util.PeriodCombiner} */
|
|
119
119
|
this.periodCombiner_ = new shaka.util.PeriodCombiner();
|
|
@@ -265,7 +265,7 @@ shaka.dash.DashParser = class {
|
|
|
265
265
|
stop() {
|
|
266
266
|
// When the parser stops, release all segment indexes, which stops their
|
|
267
267
|
// timers, as well.
|
|
268
|
-
for (const stream of
|
|
268
|
+
for (const stream of this.streamMap_.values()) {
|
|
269
269
|
if (stream.segmentIndex) {
|
|
270
270
|
stream.segmentIndex.release();
|
|
271
271
|
}
|
|
@@ -279,8 +279,8 @@ shaka.dash.DashParser = class {
|
|
|
279
279
|
this.config_ = null;
|
|
280
280
|
this.manifestUris_ = [];
|
|
281
281
|
this.manifest_ = null;
|
|
282
|
-
this.streamMap_
|
|
283
|
-
this.indexStreamMap_
|
|
282
|
+
this.streamMap_.clear();
|
|
283
|
+
this.indexStreamMap_.clear();
|
|
284
284
|
this.contextCache_.clear();
|
|
285
285
|
this.manifestPatchContext_ = {
|
|
286
286
|
mpdId: '',
|
|
@@ -690,7 +690,7 @@ shaka.dash.DashParser = class {
|
|
|
690
690
|
// https://github.com/shaka-project/shaka-player/issues/3169#issuecomment-823580634
|
|
691
691
|
const availabilityStart =
|
|
692
692
|
presentationTimeline.getSegmentAvailabilityStart();
|
|
693
|
-
for (const stream of
|
|
693
|
+
for (const stream of this.streamMap_.values()) {
|
|
694
694
|
if (stream.segmentIndex) {
|
|
695
695
|
stream.segmentIndex.evict(availabilityStart);
|
|
696
696
|
}
|
|
@@ -1178,7 +1178,7 @@ shaka.dash.DashParser = class {
|
|
|
1178
1178
|
/** @type {shaka.dash.DashParser.Context} */
|
|
1179
1179
|
const context = this.contextCache_.get(contextId);
|
|
1180
1180
|
|
|
1181
|
-
const currentStream = this.streamMap_
|
|
1181
|
+
const currentStream = this.streamMap_.get(contextId);
|
|
1182
1182
|
goog.asserts.assert(currentStream, 'stream should exist');
|
|
1183
1183
|
|
|
1184
1184
|
if (currentStream.segmentIndex) {
|
|
@@ -1426,7 +1426,7 @@ shaka.dash.DashParser = class {
|
|
|
1426
1426
|
periods.push(period);
|
|
1427
1427
|
|
|
1428
1428
|
if (context.period.id && periodDuration) {
|
|
1429
|
-
this.periodDurations_
|
|
1429
|
+
this.periodDurations_.set(context.period.id, periodDuration);
|
|
1430
1430
|
}
|
|
1431
1431
|
|
|
1432
1432
|
if (periodDuration == null) {
|
|
@@ -1490,14 +1490,14 @@ shaka.dash.DashParser = class {
|
|
|
1490
1490
|
* @private
|
|
1491
1491
|
*/
|
|
1492
1492
|
cleanStreamMap_() {
|
|
1493
|
-
const oldPeriodIds =
|
|
1493
|
+
const oldPeriodIds = Array.from(this.indexStreamMap_.keys());
|
|
1494
1494
|
const diffPeriodsIDs = oldPeriodIds.filter((pId) => {
|
|
1495
1495
|
return !this.lastManifestUpdatePeriodIds_.includes(pId);
|
|
1496
1496
|
});
|
|
1497
1497
|
for (const pId of diffPeriodsIDs) {
|
|
1498
1498
|
let shouldDeleteIndex = true;
|
|
1499
|
-
for (const contextId of this.indexStreamMap_
|
|
1500
|
-
const stream = this.streamMap_
|
|
1499
|
+
for (const contextId of this.indexStreamMap_.get(pId)) {
|
|
1500
|
+
const stream = this.streamMap_.get(contextId);
|
|
1501
1501
|
if (!stream) {
|
|
1502
1502
|
continue;
|
|
1503
1503
|
}
|
|
@@ -1506,12 +1506,12 @@ shaka.dash.DashParser = class {
|
|
|
1506
1506
|
continue;
|
|
1507
1507
|
}
|
|
1508
1508
|
if (this.periodCombiner_) {
|
|
1509
|
-
this.periodCombiner_.deleteStream(
|
|
1509
|
+
this.periodCombiner_.deleteStream(stream, pId);
|
|
1510
1510
|
}
|
|
1511
|
-
|
|
1511
|
+
this.streamMap_.delete(contextId);
|
|
1512
1512
|
}
|
|
1513
1513
|
if (shouldDeleteIndex) {
|
|
1514
|
-
|
|
1514
|
+
this.indexStreamMap_.delete(pId);
|
|
1515
1515
|
}
|
|
1516
1516
|
}
|
|
1517
1517
|
}
|
|
@@ -1983,6 +1983,10 @@ shaka.dash.DashParser = class {
|
|
|
1983
1983
|
// Duplicate representations with their supplementalCodecs
|
|
1984
1984
|
const obj = shaka.util.ObjectUtils.cloneObject(rep);
|
|
1985
1985
|
obj.attributes['codecs'] = supplementalCodecs.split(' ').join(',');
|
|
1986
|
+
if (obj.attributes['id']) {
|
|
1987
|
+
obj.attributes['supplementalId'] =
|
|
1988
|
+
obj.attributes['id'] + '_supplementalCodecs';
|
|
1989
|
+
}
|
|
1986
1990
|
supplementalRepresentations.push(obj);
|
|
1987
1991
|
}
|
|
1988
1992
|
}
|
|
@@ -2048,8 +2052,9 @@ shaka.dash.DashParser = class {
|
|
|
2048
2052
|
}
|
|
2049
2053
|
|
|
2050
2054
|
const repIds = representations
|
|
2051
|
-
.map((node) => {
|
|
2052
|
-
|
|
2055
|
+
.map((node) => {
|
|
2056
|
+
return node.attributes['supplementalId'] || node.attributes['id'];
|
|
2057
|
+
}).filter(shaka.util.Functional.isNotNull);
|
|
2053
2058
|
|
|
2054
2059
|
return {
|
|
2055
2060
|
id: adaptationId,
|
|
@@ -2305,7 +2310,7 @@ shaka.dash.DashParser = class {
|
|
|
2305
2310
|
const codecs = context.representation.codecs;
|
|
2306
2311
|
// Detect the presence of Dolby Atmos audio content based on the codec and
|
|
2307
2312
|
// bandwidth. Bandwidth above 384 kbps is a good indicator of Atmos content.
|
|
2308
|
-
const isAtmos = codecs.includes('ec-3') && context.bandwidth
|
|
2313
|
+
const isAtmos = codecs.includes('ec-3') && context.bandwidth > 384000;
|
|
2309
2314
|
let spatialAudio = false;
|
|
2310
2315
|
if (hasJoc || isAtmos) {
|
|
2311
2316
|
spatialAudio = true;
|
|
@@ -2357,8 +2362,8 @@ shaka.dash.DashParser = class {
|
|
|
2357
2362
|
/** @type {shaka.extern.Stream} */
|
|
2358
2363
|
let stream;
|
|
2359
2364
|
|
|
2360
|
-
if (contextId && this.streamMap_
|
|
2361
|
-
stream = this.streamMap_
|
|
2365
|
+
if (contextId && this.streamMap_.has(contextId)) {
|
|
2366
|
+
stream = this.streamMap_.get(contextId);
|
|
2362
2367
|
} else {
|
|
2363
2368
|
stream = {
|
|
2364
2369
|
id: this.globalId_++,
|
|
@@ -2416,13 +2421,13 @@ shaka.dash.DashParser = class {
|
|
|
2416
2421
|
}
|
|
2417
2422
|
};
|
|
2418
2423
|
|
|
2419
|
-
if (contextId && context.dynamic && !this.streamMap_
|
|
2424
|
+
if (contextId && context.dynamic && !this.streamMap_.has(contextId)) {
|
|
2420
2425
|
const periodId = context.period.id || '';
|
|
2421
|
-
if (!this.indexStreamMap_
|
|
2422
|
-
this.indexStreamMap_
|
|
2426
|
+
if (!this.indexStreamMap_.has(periodId)) {
|
|
2427
|
+
this.indexStreamMap_.set(periodId, []);
|
|
2423
2428
|
}
|
|
2424
|
-
this.streamMap_
|
|
2425
|
-
this.indexStreamMap_
|
|
2429
|
+
this.streamMap_.set(contextId, stream);
|
|
2430
|
+
this.indexStreamMap_.get(periodId).push(contextId);
|
|
2426
2431
|
}
|
|
2427
2432
|
|
|
2428
2433
|
return stream;
|
|
@@ -2580,6 +2585,7 @@ shaka.dash.DashParser = class {
|
|
|
2580
2585
|
const evalDivision = TXml.evalDivision;
|
|
2581
2586
|
|
|
2582
2587
|
const id = elem.attributes['id'];
|
|
2588
|
+
const supplementalId = elem.attributes['supplementalId'];
|
|
2583
2589
|
const uriObjs = TXml.findChildren(elem, 'BaseURL');
|
|
2584
2590
|
let calculatedBaseUris;
|
|
2585
2591
|
let someLocationValid = false;
|
|
@@ -2694,7 +2700,8 @@ shaka.dash.DashParser = class {
|
|
|
2694
2700
|
frameRate: frameRate,
|
|
2695
2701
|
pixelAspectRatio: pixelAspectRatio,
|
|
2696
2702
|
emsgSchemeIdUris: emsgSchemeIdUris,
|
|
2697
|
-
id: id,
|
|
2703
|
+
id: supplementalId || id,
|
|
2704
|
+
originalId: id,
|
|
2698
2705
|
language: elem.attributes['lang'],
|
|
2699
2706
|
numChannels: numChannels,
|
|
2700
2707
|
audioSamplingRate: audioSamplingRate,
|
|
@@ -3243,6 +3250,7 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
3243
3250
|
* pixelAspectRatio: (string|undefined),
|
|
3244
3251
|
* emsgSchemeIdUris: !Array<string>,
|
|
3245
3252
|
* id: ?string,
|
|
3253
|
+
* originalId: ?string,
|
|
3246
3254
|
* position: (number|undefined),
|
|
3247
3255
|
* language: ?string,
|
|
3248
3256
|
* numChannels: ?number,
|
|
@@ -3284,6 +3292,8 @@ shaka.dash.DashParser.RequestSegmentCallback;
|
|
|
3284
3292
|
* emsg registered schemeIdUris.
|
|
3285
3293
|
* @property {?string} id
|
|
3286
3294
|
* The ID of the element.
|
|
3295
|
+
* @property {?string} originalId
|
|
3296
|
+
* The original ID of the element.
|
|
3287
3297
|
* @property {number|undefined} position
|
|
3288
3298
|
* Position of the element used for indexing in case of no id
|
|
3289
3299
|
* @property {?string} language
|