shaka-player 3.2.1 → 3.2.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/AUTHORS +3 -0
- package/CHANGELOG.md +57 -0
- package/CONTRIBUTORS +3 -0
- package/build/generateExterns.js +1 -1
- package/demo/common/assets.js +1 -1
- package/demo/index.html +1 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +1 -1
- package/dist/demo.compiled.js +1 -1
- package/dist/deps.js +1 -1
- package/dist/locales.js +37 -37
- package/dist/receiver.compiled.debug.js +1 -1
- package/dist/receiver.compiled.js +1 -1
- 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 +1 -1
- package/dist/shaka-player.compiled.debug.js +188 -181
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +1 -1
- package/dist/shaka-player.compiled.js +795 -790
- package/dist/shaka-player.compiled.map +3 -3
- 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 +3 -3
- package/dist/shaka-player.ui.debug.js +217 -210
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +3 -3
- package/dist/shaka-player.ui.js +945 -940
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/ui.md +5 -5
- package/karma.conf.js +1 -0
- package/lib/ads/client_side_ad_manager.js +46 -86
- package/lib/ads/server_side_ad_manager.js +7 -10
- package/lib/cast/cast_proxy.js +3 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/dash/dash_parser.js +93 -2
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +30 -17
- package/lib/media/drm_engine.js +7 -0
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/streaming_engine.js +2 -1
- package/lib/net/networking_engine.js +2 -1
- package/lib/player.js +26 -25
- package/lib/polyfill/media_capabilities.js +7 -1
- package/lib/polyfill/mediasource.js +6 -0
- package/lib/polyfill/orientation.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +4 -4
- package/lib/polyfill/patchedmediakeys_ms.js +4 -4
- package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +5 -0
- package/lib/text/ui_text_displayer.js +85 -37
- package/lib/util/fake_event.js +53 -7
- package/lib/util/periods.js +4 -1
- package/lib/util/platform.js +13 -1
- package/lib/util/stream_utils.js +13 -0
- package/package.json +1 -1
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/dash/dash_parser_manifest_unit.js +187 -1
- package/test/hls/hls_parser_unit.js +5 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_unit.js +44 -0
- package/test/player_integration.js +38 -0
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/util/fake_ad_manager.js +1 -1
- package/test/text/ttml_text_parser_unit.js +9 -0
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/util/stream_utils_unit.js +35 -0
- package/ui/cast_button.js +2 -3
- package/ui/controls.js +4 -6
- package/ui/less/containers.less +3 -7
- package/ui/locales/ru.json +6 -6
- package/ui/localization.js +28 -51
- package/ui/pip_button.js +2 -3
|
@@ -167,9 +167,14 @@ shaka.text.UITextDisplayer = class {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// Remove the cues out of the time range.
|
|
170
|
+
const oldNumCues = this.cues_.length;
|
|
170
171
|
this.cues_ = this.cues_.filter(
|
|
171
172
|
(cue) => cue.startTime < start || cue.endTime >= end);
|
|
172
|
-
this
|
|
173
|
+
// If anything was actually removed in this process, force the captions to
|
|
174
|
+
// update. This makes sure that the currently-displayed cues will stop
|
|
175
|
+
// displaying if removed (say, due to the user changing languages).
|
|
176
|
+
const forceUpdate = oldNumCues > this.cues_.length;
|
|
177
|
+
this.updateCaptions_(forceUpdate);
|
|
173
178
|
|
|
174
179
|
return true;
|
|
175
180
|
}
|
|
@@ -192,13 +197,13 @@ shaka.text.UITextDisplayer = class {
|
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
/**
|
|
195
|
-
* @param {!Array.<!shaka.
|
|
200
|
+
* @param {!Array.<!shaka.extern.Cue>} cues
|
|
196
201
|
* @param {!HTMLElement} container
|
|
197
202
|
* @param {number} currentTime
|
|
198
|
-
* @param {
|
|
203
|
+
* @param {!Array.<!shaka.extern.Cue>} parents
|
|
199
204
|
* @private
|
|
200
205
|
*/
|
|
201
|
-
updateCuesRecursive_(cues, container, currentTime,
|
|
206
|
+
updateCuesRecursive_(cues, container, currentTime, parents) {
|
|
202
207
|
// Set to true if the cues have changed in some way, which will require
|
|
203
208
|
// DOM changes. E.g. if a cue was added or removed.
|
|
204
209
|
let updateDOM = false;
|
|
@@ -214,10 +219,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
214
219
|
* The cues whose corresponding elements should be in the DOM.
|
|
215
220
|
* Some of these might be new, some might have been displayed beforehand.
|
|
216
221
|
* These will only be added if updateDOM is true.
|
|
217
|
-
* @type {!Array.<!shaka.
|
|
222
|
+
* @type {!Array.<!shaka.extern.Cue>}
|
|
218
223
|
*/
|
|
219
224
|
const toPlant = [];
|
|
220
225
|
for (const cue of cues) {
|
|
226
|
+
parents.push(cue);
|
|
227
|
+
|
|
221
228
|
let cueRegistry = this.currentCuesMap_.get(cue);
|
|
222
229
|
const shouldBeDisplayed =
|
|
223
230
|
cue.startTime <= currentTime && cue.endTime > currentTime;
|
|
@@ -241,7 +248,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
241
248
|
toPlant.push(cue);
|
|
242
249
|
if (!cueRegistry) {
|
|
243
250
|
// The cue has to be made!
|
|
244
|
-
this.createCue_(cue,
|
|
251
|
+
this.createCue_(cue, parents);
|
|
245
252
|
cueRegistry = this.currentCuesMap_.get(cue);
|
|
246
253
|
wrapper = cueRegistry.wrapper;
|
|
247
254
|
updateDOM = true;
|
|
@@ -255,8 +262,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
255
262
|
// guaranteed that the children will neither need to be added nor removed.
|
|
256
263
|
if (cue.nestedCues.length > 0 && wrapper) {
|
|
257
264
|
this.updateCuesRecursive_(
|
|
258
|
-
cue.nestedCues, wrapper, currentTime,
|
|
265
|
+
cue.nestedCues, wrapper, currentTime, parents);
|
|
259
266
|
}
|
|
267
|
+
|
|
268
|
+
const topCue = parents.pop();
|
|
269
|
+
goog.asserts.assert(topCue == cue, 'Parent cues should be kept in order');
|
|
260
270
|
}
|
|
261
271
|
if (updateDOM) {
|
|
262
272
|
for (const cueElement of toUproot) {
|
|
@@ -304,7 +314,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
304
314
|
|
|
305
315
|
// Update the cues.
|
|
306
316
|
this.updateCuesRecursive_(
|
|
307
|
-
this.cues_, this.textContainer_, currentTime,
|
|
317
|
+
this.cues_, this.textContainer_, currentTime, /* parents= */ []);
|
|
308
318
|
|
|
309
319
|
if (goog.DEBUG) {
|
|
310
320
|
// Previously, we had an issue (#2076) where cues sometimes were not
|
|
@@ -327,10 +337,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
327
337
|
* Creates the object for a cue.
|
|
328
338
|
*
|
|
329
339
|
* @param {!shaka.extern.Cue} cue
|
|
330
|
-
* @param {
|
|
340
|
+
* @param {!Array.<!shaka.extern.Cue>} parents
|
|
331
341
|
* @private
|
|
332
342
|
*/
|
|
333
|
-
createCue_(cue,
|
|
343
|
+
createCue_(cue, parents) {
|
|
344
|
+
const isNested = parents.length > 1;
|
|
334
345
|
let type = isNested ? 'span' : 'div';
|
|
335
346
|
if (cue.lineBreak || cue.spacer) {
|
|
336
347
|
if (cue.spacer) {
|
|
@@ -344,7 +355,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
344
355
|
// Nested cues are inline elements. Top-level cues are block elements.
|
|
345
356
|
const cueElement = shaka.util.Dom.createHTMLElement(type);
|
|
346
357
|
if (type != 'br') {
|
|
347
|
-
this.setCaptionStyles_(cueElement, cue,
|
|
358
|
+
this.setCaptionStyles_(cueElement, cue, parents);
|
|
348
359
|
}
|
|
349
360
|
|
|
350
361
|
let wrapper = cueElement;
|
|
@@ -363,13 +374,16 @@ shaka.text.UITextDisplayer = class {
|
|
|
363
374
|
/**
|
|
364
375
|
* @param {!HTMLElement} cueElement
|
|
365
376
|
* @param {!shaka.extern.Cue} cue
|
|
366
|
-
* @param {
|
|
377
|
+
* @param {!Array.<!shaka.extern.Cue>} parents
|
|
367
378
|
* @private
|
|
368
379
|
*/
|
|
369
|
-
setCaptionStyles_(cueElement, cue,
|
|
380
|
+
setCaptionStyles_(cueElement, cue, parents) {
|
|
370
381
|
const Cue = shaka.text.Cue;
|
|
371
|
-
|
|
382
|
+
const inherit =
|
|
383
|
+
(cb) => shaka.text.UITextDisplayer.inheritProperty_(parents, cb);
|
|
384
|
+
const style = cueElement.style;
|
|
372
385
|
const isLeaf = cue.nestedCues.length == 0;
|
|
386
|
+
const isNested = parents.length > 1;
|
|
373
387
|
|
|
374
388
|
// TODO: wrapLine is not yet supported. Lines always wrap.
|
|
375
389
|
|
|
@@ -388,16 +402,6 @@ shaka.text.UITextDisplayer = class {
|
|
|
388
402
|
const nonBreakingSpace = '\xa0';
|
|
389
403
|
return nonBreakingSpace.repeat(match.length);
|
|
390
404
|
});
|
|
391
|
-
if (isNested) {
|
|
392
|
-
cueElement.textContent = text;
|
|
393
|
-
} else if (text.length) {
|
|
394
|
-
// If a top-level cue has text, move to a <span> so the background is
|
|
395
|
-
// styled correctly.
|
|
396
|
-
const span = shaka.util.Dom.createHTMLElement('span');
|
|
397
|
-
span.textContent = text;
|
|
398
|
-
cueElement.appendChild(span);
|
|
399
|
-
style = span.style;
|
|
400
|
-
}
|
|
401
405
|
|
|
402
406
|
style.backgroundColor = cue.backgroundColor;
|
|
403
407
|
style.border = cue.border;
|
|
@@ -406,20 +410,40 @@ shaka.text.UITextDisplayer = class {
|
|
|
406
410
|
style.opacity = cue.opacity;
|
|
407
411
|
style.paddingLeft = shaka.text.UITextDisplayer.convertLengthValue_(
|
|
408
412
|
cue.linePadding, cue, this.videoContainer_);
|
|
409
|
-
style.paddingRight =
|
|
410
|
-
|
|
413
|
+
style.paddingRight =
|
|
414
|
+
shaka.text.UITextDisplayer.convertLengthValue_(
|
|
415
|
+
cue.linePadding, cue, this.videoContainer_);
|
|
411
416
|
|
|
412
417
|
if (cue.backgroundImage) {
|
|
413
418
|
style.backgroundImage = 'url(\'' + cue.backgroundImage + '\')';
|
|
414
419
|
style.backgroundRepeat = 'no-repeat';
|
|
415
420
|
style.backgroundSize = 'contain';
|
|
416
421
|
style.backgroundPosition = 'center';
|
|
422
|
+
} else {
|
|
423
|
+
// If we have both text and nested cues, then style everything; otherwise
|
|
424
|
+
// place the text in its own <span> so the background doesn't fill the
|
|
425
|
+
// whole region.
|
|
426
|
+
let elem;
|
|
427
|
+
if (cue.nestedCues.length) {
|
|
428
|
+
elem = cueElement;
|
|
429
|
+
} else {
|
|
430
|
+
elem = shaka.util.Dom.createHTMLElement('span');
|
|
431
|
+
cueElement.appendChild(elem);
|
|
432
|
+
}
|
|
417
433
|
|
|
418
|
-
if (cue.
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
434
|
+
if (cue.border) {
|
|
435
|
+
elem.style.border = cue.border;
|
|
436
|
+
}
|
|
437
|
+
const bgColor = inherit((c) => c.backgroundColor);
|
|
438
|
+
if (bgColor) {
|
|
439
|
+
elem.style.backgroundColor = bgColor;
|
|
440
|
+
} else if (text) {
|
|
441
|
+
// If there is no background, default to a semi-transparent black.
|
|
442
|
+
// Only do this for the text itself.
|
|
443
|
+
elem.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
|
|
444
|
+
}
|
|
445
|
+
if (text) {
|
|
446
|
+
elem.textContent = text;
|
|
423
447
|
}
|
|
424
448
|
}
|
|
425
449
|
|
|
@@ -472,20 +496,28 @@ shaka.text.UITextDisplayer = class {
|
|
|
472
496
|
// TODO: Implement lineAlignment of 'CENTER'.
|
|
473
497
|
if (cue.line) {
|
|
474
498
|
if (cue.lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
|
|
499
|
+
// When setting absolute positioning, you need to set x/y/width/height
|
|
500
|
+
// so the element is positioned correctly. Set these as default and
|
|
501
|
+
// other settings will override them.
|
|
475
502
|
style.position = 'absolute';
|
|
503
|
+
style.left = '0';
|
|
504
|
+
style.top = '0';
|
|
476
505
|
if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
|
|
506
|
+
style.width = '100%';
|
|
477
507
|
if (cue.lineAlign == Cue.lineAlign.START) {
|
|
478
508
|
style.top = cue.line + '%';
|
|
479
509
|
} else if (cue.lineAlign == Cue.lineAlign.END) {
|
|
480
510
|
style.bottom = cue.line + '%';
|
|
481
511
|
}
|
|
482
512
|
} else if (cue.writingMode == Cue.writingMode.VERTICAL_LEFT_TO_RIGHT) {
|
|
513
|
+
style.height = '100%';
|
|
483
514
|
if (cue.lineAlign == Cue.lineAlign.START) {
|
|
484
515
|
style.left = cue.line + '%';
|
|
485
516
|
} else if (cue.lineAlign == Cue.lineAlign.END) {
|
|
486
517
|
style.right = cue.line + '%';
|
|
487
518
|
}
|
|
488
519
|
} else {
|
|
520
|
+
style.height = '100%';
|
|
489
521
|
if (cue.lineAlign == Cue.lineAlign.START) {
|
|
490
522
|
style.right = cue.line + '%';
|
|
491
523
|
} else if (cue.lineAlign == Cue.lineAlign.END) {
|
|
@@ -493,12 +525,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
493
525
|
}
|
|
494
526
|
}
|
|
495
527
|
}
|
|
496
|
-
} else if (cue.region && cue.region.id
|
|
497
|
-
((!isNested && !isLeaf) || (cue.backgroundImage))) {
|
|
498
|
-
// In text-base cues, regions are only applied to block container
|
|
499
|
-
// (!isNested && !isLeaf).
|
|
500
|
-
// In bitmap-based cues, region settings are used to specify the size and
|
|
501
|
-
// position of the backgroundImage.
|
|
528
|
+
} else if (cue.region && cue.region.id) {
|
|
502
529
|
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
503
530
|
const heightUnit = cue.region.heightUnits == percentageUnit ? '%' : 'px';
|
|
504
531
|
const widthUnit = cue.region.widthUnits == percentageUnit ? '%' : 'px';
|
|
@@ -631,4 +658,25 @@ shaka.text.UITextDisplayer = class {
|
|
|
631
658
|
|
|
632
659
|
return (containerHeight * value / cue.cellResolution.rows) + 'px';
|
|
633
660
|
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Inherits a property from the parent Cue elements. If the value is falsy,
|
|
664
|
+
* it is assumed to be inherited from the parent. This returns null if the
|
|
665
|
+
* value isn't found.
|
|
666
|
+
*
|
|
667
|
+
* @param {!Array.<!shaka.extern.Cue>} parents
|
|
668
|
+
* @param {function(!shaka.extern.Cue):?T} cb
|
|
669
|
+
* @return {?T}
|
|
670
|
+
* @template T
|
|
671
|
+
* @private
|
|
672
|
+
*/
|
|
673
|
+
static inheritProperty_(parents, cb) {
|
|
674
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
675
|
+
const val = cb(parents[i]);
|
|
676
|
+
if (val || val === 0) {
|
|
677
|
+
return val;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
634
682
|
};
|
package/lib/util/fake_event.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.FakeEvent');
|
|
8
8
|
|
|
9
|
+
goog.require('goog.asserts');
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @summary Create an Event work-alike object based on the provided dictionary.
|
|
@@ -16,18 +18,62 @@ goog.provide('shaka.util.FakeEvent');
|
|
|
16
18
|
*/
|
|
17
19
|
shaka.util.FakeEvent = class {
|
|
18
20
|
/**
|
|
19
|
-
* @param {
|
|
20
|
-
* @
|
|
21
|
+
* @param {!Event} event
|
|
22
|
+
* @return {!shaka.util.FakeEvent}
|
|
21
23
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
for (const key in
|
|
25
|
-
Object.defineProperty(
|
|
26
|
-
value:
|
|
24
|
+
static fromRealEvent(event) {
|
|
25
|
+
const fakeEvent = new shaka.util.FakeEvent(event.type);
|
|
26
|
+
for (const key in event) {
|
|
27
|
+
Object.defineProperty(fakeEvent, key, {
|
|
28
|
+
value: event[key],
|
|
27
29
|
writable: true,
|
|
28
30
|
enumerable: true,
|
|
29
31
|
});
|
|
30
32
|
}
|
|
33
|
+
return fakeEvent;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Allows us to tell the compiler that the dictionary "map" is actually a
|
|
38
|
+
* generic object, for backwards compatibility.
|
|
39
|
+
* @param {!Map.<string, Object>} dict
|
|
40
|
+
* @return {!Object}
|
|
41
|
+
* @suppress {invalidCasts}
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
static recastDictAsObject_(dict) {
|
|
45
|
+
goog.asserts.assert(!(dict instanceof Map), 'dict should not be a map');
|
|
46
|
+
return /** @type {!Object} */ (dict);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} type
|
|
51
|
+
* @param {Map.<string, Object>=} dict
|
|
52
|
+
*/
|
|
53
|
+
constructor(type, dict) {
|
|
54
|
+
if (dict) {
|
|
55
|
+
if (dict instanceof Map) {
|
|
56
|
+
// Take properties from dict if present.
|
|
57
|
+
for (const key of dict.keys()) {
|
|
58
|
+
Object.defineProperty(this, key, {
|
|
59
|
+
value: dict.get(key),
|
|
60
|
+
writable: true,
|
|
61
|
+
enumerable: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// For backwards compatibility with external apps that may make use of
|
|
66
|
+
// this public constructor, this should still accept generic objects.
|
|
67
|
+
const obj = shaka.util.FakeEvent.recastDictAsObject_(dict);
|
|
68
|
+
for (const key in obj) {
|
|
69
|
+
Object.defineProperty(this, key, {
|
|
70
|
+
value: obj[key],
|
|
71
|
+
writable: true,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
31
77
|
|
|
32
78
|
// The properties below cannot be set by the dict. They are all provided
|
|
33
79
|
// for compatibility with native events.
|
package/lib/util/periods.js
CHANGED
|
@@ -80,7 +80,10 @@ shaka.util.PeriodCombiner = class {
|
|
|
80
80
|
|
|
81
81
|
/** @return {!Array.<shaka.extern.Stream>} */
|
|
82
82
|
getTextStreams() {
|
|
83
|
-
|
|
83
|
+
// Return a copy of the array because makeTextStreamsForClosedCaptions
|
|
84
|
+
// may make changes to the contents of the array. Those changes should not
|
|
85
|
+
// propagate back to the PeriodCombiner.
|
|
86
|
+
return this.textStreams_.slice();
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
/** @return {!Array.<shaka.extern.Stream>} */
|
package/lib/util/platform.js
CHANGED
|
@@ -163,7 +163,6 @@ shaka.util.Platform = class {
|
|
|
163
163
|
!shaka.util.Platform.isEdge();
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
167
166
|
/**
|
|
168
167
|
* Check if the current platform is from Apple.
|
|
169
168
|
*
|
|
@@ -179,6 +178,19 @@ shaka.util.Platform = class {
|
|
|
179
178
|
&& !shaka.util.Platform.isTizen();
|
|
180
179
|
}
|
|
181
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Check if the current platform is Playstation 5.
|
|
183
|
+
*
|
|
184
|
+
* Returns true on Playstation 5 browsers.
|
|
185
|
+
*
|
|
186
|
+
* Returns false for Playstation 5 browsers
|
|
187
|
+
*
|
|
188
|
+
* @return {boolean}
|
|
189
|
+
*/
|
|
190
|
+
static isPS5() {
|
|
191
|
+
return shaka.util.Platform.userAgentContains_('PlayStation 5');
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
/**
|
|
183
195
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
184
196
|
*
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -547,6 +547,19 @@ shaka.util.StreamUtils = class {
|
|
|
547
547
|
// framerate must be greater than 0, otherwise the config is invalid.
|
|
548
548
|
framerate: video.frameRate || 1,
|
|
549
549
|
};
|
|
550
|
+
if (video.hdr) {
|
|
551
|
+
switch (video.hdr) {
|
|
552
|
+
case 'SDR':
|
|
553
|
+
mediaDecodingConfig.video.transferFunction = 'srgb';
|
|
554
|
+
break;
|
|
555
|
+
case 'PQ':
|
|
556
|
+
mediaDecodingConfig.video.transferFunction = 'pq';
|
|
557
|
+
break;
|
|
558
|
+
case 'HLG':
|
|
559
|
+
mediaDecodingConfig.video.transferFunction = 'hlg';
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
550
563
|
}
|
|
551
564
|
if (audio) {
|
|
552
565
|
// Some Tizen devices seem to misreport AC-3 support, but correctly
|
package/package.json
CHANGED
|
@@ -297,7 +297,8 @@ describe('CastProxy', () => {
|
|
|
297
297
|
'timeupdate', Util.spyFunc(proxyListener));
|
|
298
298
|
|
|
299
299
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
300
|
-
const fakeEvent = new FakeEvent(
|
|
300
|
+
const fakeEvent = new FakeEvent(
|
|
301
|
+
'timeupdate', (new Map()).set('detail', 8675309));
|
|
301
302
|
mockVideo.on['timeupdate'](fakeEvent);
|
|
302
303
|
expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
|
|
303
304
|
type: 'timeupdate',
|
|
@@ -315,7 +316,8 @@ describe('CastProxy', () => {
|
|
|
315
316
|
mockSender.hasRemoteProperties.and.returnValue(true);
|
|
316
317
|
|
|
317
318
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
318
|
-
const fakeEvent = new FakeEvent(
|
|
319
|
+
const fakeEvent = new FakeEvent(
|
|
320
|
+
'timeupdate', (new Map()).set('detail', 8675309));
|
|
319
321
|
mockVideo.on['timeupdate'](fakeEvent);
|
|
320
322
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
321
323
|
});
|
|
@@ -332,7 +334,8 @@ describe('CastProxy', () => {
|
|
|
332
334
|
mockSender.hasRemoteProperties.and.returnValue(true);
|
|
333
335
|
|
|
334
336
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
335
|
-
const fakeEvent = new FakeEvent(
|
|
337
|
+
const fakeEvent = new FakeEvent(
|
|
338
|
+
'timeupdate', (new Map()).set('detail', 8675309));
|
|
336
339
|
mockSender.onRemoteEvent('video', fakeEvent);
|
|
337
340
|
expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
|
|
338
341
|
type: 'timeupdate',
|
|
@@ -446,7 +449,8 @@ describe('CastProxy', () => {
|
|
|
446
449
|
'buffering', Util.spyFunc(proxyListener));
|
|
447
450
|
|
|
448
451
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
449
|
-
const fakeEvent = new FakeEvent(
|
|
452
|
+
const fakeEvent = new FakeEvent(
|
|
453
|
+
'buffering', (new Map()).set('detail', 8675309));
|
|
450
454
|
mockPlayer.listeners['buffering'](fakeEvent);
|
|
451
455
|
expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
|
|
452
456
|
type: 'buffering',
|
|
@@ -464,7 +468,8 @@ describe('CastProxy', () => {
|
|
|
464
468
|
mockSender.hasRemoteProperties.and.returnValue(true);
|
|
465
469
|
|
|
466
470
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
467
|
-
const fakeEvent = new FakeEvent(
|
|
471
|
+
const fakeEvent = new FakeEvent(
|
|
472
|
+
'buffering', (new Map()).set('detail', 8675309));
|
|
468
473
|
mockPlayer.listeners['buffering'](fakeEvent);
|
|
469
474
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
470
475
|
});
|
|
@@ -481,7 +486,8 @@ describe('CastProxy', () => {
|
|
|
481
486
|
mockSender.hasRemoteProperties.and.returnValue(true);
|
|
482
487
|
|
|
483
488
|
expect(proxyListener).not.toHaveBeenCalled();
|
|
484
|
-
const fakeEvent = new FakeEvent(
|
|
489
|
+
const fakeEvent = new FakeEvent(
|
|
490
|
+
'buffering', (new Map()).set('detail', 8675309));
|
|
485
491
|
mockSender.onRemoteEvent('player', fakeEvent);
|
|
486
492
|
expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
|
|
487
493
|
type: 'buffering',
|
|
@@ -123,7 +123,7 @@ describe('CastUtils', () => {
|
|
|
123
123
|
expect(typeof deserialized).toBe('object');
|
|
124
124
|
|
|
125
125
|
// The object can be used to construct a FakeEvent.
|
|
126
|
-
const fakeEvent =
|
|
126
|
+
const fakeEvent = FakeEvent.fromRealEvent(deserialized);
|
|
127
127
|
|
|
128
128
|
// The fake event has the same type and properties as the original.
|
|
129
129
|
const asObj = /** @type {!Object} */ (fakeEvent);
|