shaka-player 3.1.0 → 3.1.4
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 +8 -2
- package/CHANGELOG.md +209 -0
- package/CONTRIBUTORS +10 -3
- package/README.md +3 -0
- package/build/apps.py +2 -2
- package/build/check.py +2 -2
- package/build/conformance.textproto +0 -9
- package/build/generateExterns.js +1 -1
- package/build/misspellings.txt +1 -0
- package/build/shakaBuildHelpers.py +6 -5
- package/build/subprocessWindowsPatch.py +103 -0
- package/demo/common/asset.js +11 -0
- package/demo/common/assets.js +1 -1
- package/demo/common/message_ids.js +5 -0
- package/demo/config.js +2 -1
- package/demo/custom.js +84 -3
- package/demo/demo.less +13 -1
- package/demo/demo_utils.js +1 -0
- package/demo/input.js +31 -12
- package/demo/input_container.js +24 -1
- package/demo/locales/en.json +6 -1
- package/demo/locales/source.json +20 -0
- package/demo/main.js +5 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +99 -91
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +99 -91
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +9 -9
- package/dist/locales.js +36 -34
- package/dist/receiver.compiled.debug.js +74 -70
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +74 -70
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +165 -9
- package/dist/shaka-player.compiled.debug.d.ts +165 -9
- package/dist/shaka-player.compiled.debug.externs.js +179 -11
- package/dist/shaka-player.compiled.debug.js +367 -339
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +179 -11
- package/dist/shaka-player.compiled.js +818 -807
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +165 -9
- package/dist/shaka-player.ui.debug.d.ts +165 -9
- package/dist/shaka-player.ui.debug.externs.js +181 -13
- package/dist/shaka-player.ui.debug.js +459 -429
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +181 -13
- package/dist/shaka-player.ui.js +973 -961
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/faq.md +25 -0
- package/docs/tutorials/index.json +2 -2
- package/docs/tutorials/upgrade-v3.md +38 -0
- package/docs/tutorials/upgrade.md +3 -3
- package/externs/ima.js +4 -0
- package/externs/media_capabilities.js +16 -0
- package/externs/shaka/ads.js +2 -0
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/player.js +6 -0
- package/karma.conf.js +1 -0
- package/lib/abr/simple_abr_manager.js +1 -1
- package/lib/ads/ad_manager.js +29 -11
- package/lib/ads/client_side_ad_manager.js +76 -86
- package/lib/ads/server_side_ad_manager.js +26 -11
- 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/cea/sei_processor.js +24 -17
- package/lib/dash/dash_parser.js +107 -4
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +45 -15
- package/lib/dependencies/all.js +15 -15
- package/lib/hls/hls_parser.js +46 -18
- package/lib/media/closed_caption_parser.js +3 -1
- package/lib/media/content_workarounds.js +18 -0
- package/lib/media/drm_engine.js +20 -1
- package/lib/media/gap_jumping_controller.js +8 -4
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/playhead.js +1 -1
- package/lib/media/presentation_timeline.js +3 -1
- package/lib/media/segment_index.js +38 -12
- package/lib/media/segment_reference.js +8 -0
- package/lib/media/streaming_engine.js +30 -21
- package/lib/net/http_fetch_plugin.js +2 -2
- package/lib/net/networking_engine.js +3 -2
- package/lib/offline/storage.js +4 -0
- package/lib/player.js +113 -56
- package/lib/polyfill/encryption_scheme.js +2 -0
- package/lib/polyfill/fullscreen.js +2 -0
- package/lib/polyfill/mathround.js +2 -0
- package/lib/polyfill/media_capabilities.js +62 -23
- package/lib/polyfill/mediasource.js +8 -0
- package/lib/polyfill/orientation.js +3 -1
- package/lib/polyfill/patchedmediakeys_apple.js +6 -4
- package/lib/polyfill/patchedmediakeys_ms.js +6 -4
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +6 -4
- package/lib/polyfill/pip_webkit.js +2 -0
- package/lib/polyfill/storage_estimate.js +2 -0
- package/lib/polyfill/video_play_promise.js +2 -0
- package/lib/polyfill/videoplaybackquality.js +2 -0
- package/lib/polyfill/vttcue.js +2 -0
- package/lib/text/cue.js +11 -0
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +52 -30
- package/lib/text/ui_text_displayer.js +255 -82
- package/lib/text/vtt_text_parser.js +4 -2
- package/lib/util/error.js +1 -4
- package/lib/util/fake_event.js +53 -7
- package/lib/util/mime_utils.js +33 -0
- package/lib/util/mp4_box_parsers.js +1 -1
- package/lib/util/mp4_parser.js +14 -0
- package/lib/util/networking.js +1 -1
- package/lib/util/periods.js +132 -37
- package/lib/util/platform.js +13 -1
- package/lib/util/stream_utils.js +46 -7
- package/package.json +3 -3
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_receiver_integration.js +1 -1
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/cea/mp4_cea_parser_unit.js +26 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +187 -1
- package/test/dash/dash_parser_segment_template_unit.js +3 -3
- package/test/demo/demo_unit.js +0 -1
- package/test/hls/hls_parser_unit.js +45 -1
- package/test/media/closed_caption_parser_unit.js +20 -0
- package/test/media/drm_engine_unit.js +59 -3
- package/test/media/playhead_unit.js +27 -1
- package/test/media/presentation_timeline_unit.js +19 -0
- package/test/media/segment_index_unit.js +76 -3
- package/test/media/streaming_engine_unit.js +3 -3
- package/test/player_integration.js +38 -0
- package/test/player_unit.js +125 -6
- 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/assets/empty_caption_video_init.mp4 +0 -0
- package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
- package/test/test/util/fake_ad_manager.js +4 -1
- package/test/test/util/simple_fakes.js +5 -3
- package/test/test/util/waiter.js +36 -2
- package/test/text/ttml_text_parser_unit.js +55 -0
- package/test/text/ui_text_displayer_unit.js +95 -18
- package/test/text/vtt_text_parser_unit.js +17 -1
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +52 -1
- package/test/ui/ui_unit.js +4 -0
- package/test/util/mp4_box_parsers_unit.js +28 -0
- package/test/util/periods_unit.js +190 -2
- package/test/util/stream_utils_unit.js +56 -5
- package/ui/airplay_button.js +5 -0
- package/ui/big_play_button.js +10 -0
- package/ui/cast_button.js +2 -3
- package/ui/controls.js +9 -7
- package/ui/less/containers.less +10 -5
- package/ui/locales/en.json +1 -0
- package/ui/locales/ru.json +6 -6
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +28 -51
- package/ui/pip_button.js +2 -3
- package/ui/play_button.js +10 -10
- package/ui/small_play_button.js +12 -0
- package/ui/ui.js +1 -1
- package/docs/tutorials/upgrade-v2-4.md +0 -481
|
@@ -39,6 +39,7 @@ describe('PeriodCombiner', () => {
|
|
|
39
39
|
makeAudioStream('en', /* channels= */ 2),
|
|
40
40
|
],
|
|
41
41
|
textStreams: [],
|
|
42
|
+
imageStreams: [],
|
|
42
43
|
},
|
|
43
44
|
{
|
|
44
45
|
id: 'ad',
|
|
@@ -49,6 +50,7 @@ describe('PeriodCombiner', () => {
|
|
|
49
50
|
makeAudioStream('en', /* channels= */ 2),
|
|
50
51
|
],
|
|
51
52
|
textStreams: [],
|
|
53
|
+
imageStreams: [],
|
|
52
54
|
},
|
|
53
55
|
];
|
|
54
56
|
|
|
@@ -117,6 +119,7 @@ describe('PeriodCombiner', () => {
|
|
|
117
119
|
makeAudioStream('en', /* channels= */ 2),
|
|
118
120
|
],
|
|
119
121
|
textStreams: [],
|
|
122
|
+
imageStreams: [],
|
|
120
123
|
},
|
|
121
124
|
{
|
|
122
125
|
id: 'main',
|
|
@@ -130,6 +133,7 @@ describe('PeriodCombiner', () => {
|
|
|
130
133
|
makeAudioStream('en', /* channels= */ 2),
|
|
131
134
|
],
|
|
132
135
|
textStreams: [],
|
|
136
|
+
imageStreams: [],
|
|
133
137
|
},
|
|
134
138
|
];
|
|
135
139
|
|
|
@@ -194,6 +198,7 @@ describe('PeriodCombiner', () => {
|
|
|
194
198
|
makeAudioStream('en'),
|
|
195
199
|
],
|
|
196
200
|
textStreams: [],
|
|
201
|
+
imageStreams: [],
|
|
197
202
|
},
|
|
198
203
|
{
|
|
199
204
|
id: '2',
|
|
@@ -204,6 +209,7 @@ describe('PeriodCombiner', () => {
|
|
|
204
209
|
makeAudioStream('en'),
|
|
205
210
|
],
|
|
206
211
|
textStreams: [],
|
|
212
|
+
imageStreams: [],
|
|
207
213
|
},
|
|
208
214
|
];
|
|
209
215
|
|
|
@@ -242,6 +248,7 @@ describe('PeriodCombiner', () => {
|
|
|
242
248
|
makeAudioStream('en'),
|
|
243
249
|
],
|
|
244
250
|
textStreams: [],
|
|
251
|
+
imageStreams: [],
|
|
245
252
|
},
|
|
246
253
|
{
|
|
247
254
|
id: '2',
|
|
@@ -252,6 +259,7 @@ describe('PeriodCombiner', () => {
|
|
|
252
259
|
makeAudioStream('en'),
|
|
253
260
|
],
|
|
254
261
|
textStreams: [],
|
|
262
|
+
imageStreams: [],
|
|
255
263
|
},
|
|
256
264
|
];
|
|
257
265
|
|
|
@@ -289,6 +297,7 @@ describe('PeriodCombiner', () => {
|
|
|
289
297
|
makeAudioStream('fr', /* channels= */ 2, /* primary= */ false),
|
|
290
298
|
],
|
|
291
299
|
textStreams: [],
|
|
300
|
+
imageStreams: [],
|
|
292
301
|
},
|
|
293
302
|
{
|
|
294
303
|
id: 'ad',
|
|
@@ -299,6 +308,7 @@ describe('PeriodCombiner', () => {
|
|
|
299
308
|
makeAudioStream('en'),
|
|
300
309
|
],
|
|
301
310
|
textStreams: [],
|
|
311
|
+
imageStreams: [],
|
|
302
312
|
},
|
|
303
313
|
{
|
|
304
314
|
id: 'show2',
|
|
@@ -311,6 +321,7 @@ describe('PeriodCombiner', () => {
|
|
|
311
321
|
makeAudioStream('fr', /* channels= */ 2, /* primary= */ true),
|
|
312
322
|
],
|
|
313
323
|
textStreams: [],
|
|
324
|
+
imageStreams: [],
|
|
314
325
|
},
|
|
315
326
|
];
|
|
316
327
|
|
|
@@ -361,6 +372,7 @@ describe('PeriodCombiner', () => {
|
|
|
361
372
|
makeAudioStream('es'),
|
|
362
373
|
],
|
|
363
374
|
textStreams: [],
|
|
375
|
+
imageStreams: [],
|
|
364
376
|
},
|
|
365
377
|
{
|
|
366
378
|
id: 'show2',
|
|
@@ -371,6 +383,7 @@ describe('PeriodCombiner', () => {
|
|
|
371
383
|
makeAudioStream('en'),
|
|
372
384
|
],
|
|
373
385
|
textStreams: [],
|
|
386
|
+
imageStreams: [],
|
|
374
387
|
},
|
|
375
388
|
];
|
|
376
389
|
|
|
@@ -411,6 +424,7 @@ describe('PeriodCombiner', () => {
|
|
|
411
424
|
makeAudioStream('en'),
|
|
412
425
|
],
|
|
413
426
|
textStreams: [],
|
|
427
|
+
imageStreams: [],
|
|
414
428
|
},
|
|
415
429
|
];
|
|
416
430
|
|
|
@@ -429,7 +443,6 @@ describe('PeriodCombiner', () => {
|
|
|
429
443
|
expect(highBandwidth.video.originalId).toBe('480');
|
|
430
444
|
});
|
|
431
445
|
|
|
432
|
-
|
|
433
446
|
it('Filters out duplicate streams', async () => {
|
|
434
447
|
// v1 and v3 are duplicates
|
|
435
448
|
const v1 = makeVideoStream(1280);
|
|
@@ -496,6 +509,16 @@ describe('PeriodCombiner', () => {
|
|
|
496
509
|
t3.originalId = 't3';
|
|
497
510
|
t3.roles = ['role1'];
|
|
498
511
|
|
|
512
|
+
// i1 and i3 are duplicates.
|
|
513
|
+
const i1 = makeImageStream(240);
|
|
514
|
+
i1.originalId = 'i1';
|
|
515
|
+
|
|
516
|
+
const i2 = makeImageStream(480);
|
|
517
|
+
i2.originalId = 'i2';
|
|
518
|
+
|
|
519
|
+
const i3 = makeImageStream(240);
|
|
520
|
+
i3.originalId = 'i3';
|
|
521
|
+
|
|
499
522
|
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
500
523
|
const periods = [
|
|
501
524
|
{
|
|
@@ -517,6 +540,11 @@ describe('PeriodCombiner', () => {
|
|
|
517
540
|
t2,
|
|
518
541
|
t3,
|
|
519
542
|
],
|
|
543
|
+
imageStreams: [
|
|
544
|
+
i1,
|
|
545
|
+
i2,
|
|
546
|
+
i3,
|
|
547
|
+
],
|
|
520
548
|
},
|
|
521
549
|
];
|
|
522
550
|
|
|
@@ -544,9 +572,61 @@ describe('PeriodCombiner', () => {
|
|
|
544
572
|
for (const id of textIds) {
|
|
545
573
|
expect(id).not.toBe('t3');
|
|
546
574
|
}
|
|
575
|
+
|
|
576
|
+
const imageStreams = combiner.getImageStreams();
|
|
577
|
+
expect(imageStreams.length).toBe(2);
|
|
578
|
+
|
|
579
|
+
// i3 should've been filtered out
|
|
580
|
+
const imageIds = imageStreams.map((i) => i.originalId);
|
|
581
|
+
for (const id of imageIds) {
|
|
582
|
+
expect(id).not.toBe('i3');
|
|
583
|
+
}
|
|
547
584
|
});
|
|
548
585
|
|
|
549
|
-
|
|
586
|
+
// Regression test for #3383, where we failed on multi-period content with
|
|
587
|
+
// multiple image streams per period.
|
|
588
|
+
it('Can handle multiple image streams', async () => {
|
|
589
|
+
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
590
|
+
const periods = [
|
|
591
|
+
{
|
|
592
|
+
id: '1',
|
|
593
|
+
videoStreams: [
|
|
594
|
+
makeVideoStream(1280),
|
|
595
|
+
],
|
|
596
|
+
audioStreams: [],
|
|
597
|
+
textStreams: [],
|
|
598
|
+
imageStreams: [
|
|
599
|
+
makeImageStream(240),
|
|
600
|
+
makeImageStream(480),
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
id: '2',
|
|
605
|
+
videoStreams: [
|
|
606
|
+
makeVideoStream(1280),
|
|
607
|
+
],
|
|
608
|
+
audioStreams: [],
|
|
609
|
+
textStreams: [],
|
|
610
|
+
imageStreams: [
|
|
611
|
+
makeImageStream(240),
|
|
612
|
+
makeImageStream(480),
|
|
613
|
+
],
|
|
614
|
+
},
|
|
615
|
+
];
|
|
616
|
+
|
|
617
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ true);
|
|
618
|
+
|
|
619
|
+
const imageStreams = combiner.getImageStreams();
|
|
620
|
+
expect(imageStreams.length).toBe(2);
|
|
621
|
+
|
|
622
|
+
const imageIds = imageStreams.map((i) => i.originalId);
|
|
623
|
+
expect(imageIds).toEqual([
|
|
624
|
+
'240,240',
|
|
625
|
+
'480,480',
|
|
626
|
+
]);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it('handles text track gaps', async () => {
|
|
550
630
|
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
551
631
|
const periods = [
|
|
552
632
|
{
|
|
@@ -560,6 +640,7 @@ describe('PeriodCombiner', () => {
|
|
|
560
640
|
textStreams: [
|
|
561
641
|
makeTextStream('en'),
|
|
562
642
|
],
|
|
643
|
+
imageStreams: [],
|
|
563
644
|
},
|
|
564
645
|
{
|
|
565
646
|
id: '2',
|
|
@@ -572,6 +653,7 @@ describe('PeriodCombiner', () => {
|
|
|
572
653
|
textStreams: [
|
|
573
654
|
/* No text streams */
|
|
574
655
|
],
|
|
656
|
+
imageStreams: [],
|
|
575
657
|
},
|
|
576
658
|
{
|
|
577
659
|
id: '3',
|
|
@@ -585,6 +667,7 @@ describe('PeriodCombiner', () => {
|
|
|
585
667
|
makeTextStream('en'),
|
|
586
668
|
makeTextStream('es'),
|
|
587
669
|
],
|
|
670
|
+
imageStreams: [],
|
|
588
671
|
},
|
|
589
672
|
];
|
|
590
673
|
|
|
@@ -608,6 +691,70 @@ describe('PeriodCombiner', () => {
|
|
|
608
691
|
expect(english.originalId).toBe('en,,en');
|
|
609
692
|
});
|
|
610
693
|
|
|
694
|
+
it('handles image track gaps', async () => {
|
|
695
|
+
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
696
|
+
const periods = [
|
|
697
|
+
{
|
|
698
|
+
id: '1',
|
|
699
|
+
videoStreams: [
|
|
700
|
+
makeVideoStream(1080),
|
|
701
|
+
],
|
|
702
|
+
audioStreams: [
|
|
703
|
+
makeAudioStream('en'),
|
|
704
|
+
],
|
|
705
|
+
textStreams: [],
|
|
706
|
+
imageStreams: [
|
|
707
|
+
makeImageStream(240),
|
|
708
|
+
],
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
id: '2',
|
|
712
|
+
videoStreams: [
|
|
713
|
+
makeVideoStream(1080),
|
|
714
|
+
],
|
|
715
|
+
audioStreams: [
|
|
716
|
+
makeAudioStream('en'),
|
|
717
|
+
],
|
|
718
|
+
textStreams: [],
|
|
719
|
+
imageStreams: [
|
|
720
|
+
/* No image streams in this period */
|
|
721
|
+
],
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
id: '3',
|
|
725
|
+
videoStreams: [
|
|
726
|
+
makeVideoStream(1080),
|
|
727
|
+
],
|
|
728
|
+
audioStreams: [
|
|
729
|
+
makeAudioStream('en'),
|
|
730
|
+
],
|
|
731
|
+
textStreams: [],
|
|
732
|
+
imageStreams: [
|
|
733
|
+
makeImageStream(240),
|
|
734
|
+
makeImageStream(480),
|
|
735
|
+
],
|
|
736
|
+
},
|
|
737
|
+
];
|
|
738
|
+
|
|
739
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ false);
|
|
740
|
+
const imageStreams = combiner.getImageStreams();
|
|
741
|
+
expect(imageStreams).toEqual(jasmine.arrayWithExactContents([
|
|
742
|
+
jasmine.objectContaining({
|
|
743
|
+
height: 240,
|
|
744
|
+
}),
|
|
745
|
+
jasmine.objectContaining({
|
|
746
|
+
height: 480,
|
|
747
|
+
}),
|
|
748
|
+
]));
|
|
749
|
+
|
|
750
|
+
// We can use the originalId field to see what each track is composed of.
|
|
751
|
+
|
|
752
|
+
const i240 = imageStreams.find((s) => s.height == 240);
|
|
753
|
+
const i480 = imageStreams.find((s) => s.height == 480);
|
|
754
|
+
expect(i240.originalId).toBe('240,,240');
|
|
755
|
+
expect(i480.originalId).toBe('240,,480');
|
|
756
|
+
});
|
|
757
|
+
|
|
611
758
|
it('Disjoint audio channels', async () => {
|
|
612
759
|
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
613
760
|
const periods = [
|
|
@@ -620,6 +767,7 @@ describe('PeriodCombiner', () => {
|
|
|
620
767
|
makeAudioStream('en', /* channels= */ 6),
|
|
621
768
|
],
|
|
622
769
|
textStreams: [],
|
|
770
|
+
imageStreams: [],
|
|
623
771
|
},
|
|
624
772
|
{
|
|
625
773
|
id: '2',
|
|
@@ -630,6 +778,7 @@ describe('PeriodCombiner', () => {
|
|
|
630
778
|
makeAudioStream('en', /* channels= */ 2),
|
|
631
779
|
],
|
|
632
780
|
textStreams: [],
|
|
781
|
+
imageStreams: [],
|
|
633
782
|
},
|
|
634
783
|
];
|
|
635
784
|
|
|
@@ -666,6 +815,7 @@ describe('PeriodCombiner', () => {
|
|
|
666
815
|
makeAudioStreamWithSampleRate(48000),
|
|
667
816
|
],
|
|
668
817
|
textStreams: [],
|
|
818
|
+
imageStreams: [],
|
|
669
819
|
},
|
|
670
820
|
{
|
|
671
821
|
id: '2',
|
|
@@ -676,6 +826,7 @@ describe('PeriodCombiner', () => {
|
|
|
676
826
|
makeAudioStreamWithSampleRate(44100),
|
|
677
827
|
],
|
|
678
828
|
textStreams: [],
|
|
829
|
+
imageStreams: [],
|
|
679
830
|
},
|
|
680
831
|
];
|
|
681
832
|
|
|
@@ -712,6 +863,7 @@ describe('PeriodCombiner', () => {
|
|
|
712
863
|
makeAudioStreamWithSampleRate(44100),
|
|
713
864
|
],
|
|
714
865
|
textStreams: [],
|
|
866
|
+
imageStreams: [],
|
|
715
867
|
},
|
|
716
868
|
{
|
|
717
869
|
id: '2',
|
|
@@ -722,6 +874,7 @@ describe('PeriodCombiner', () => {
|
|
|
722
874
|
makeAudioStreamWithSampleRate(48000),
|
|
723
875
|
],
|
|
724
876
|
textStreams: [],
|
|
877
|
+
imageStreams: [],
|
|
725
878
|
},
|
|
726
879
|
];
|
|
727
880
|
|
|
@@ -752,6 +905,7 @@ describe('PeriodCombiner', () => {
|
|
|
752
905
|
],
|
|
753
906
|
audioStreams: [],
|
|
754
907
|
textStreams: [],
|
|
908
|
+
imageStreams: [],
|
|
755
909
|
},
|
|
756
910
|
{
|
|
757
911
|
id: '2',
|
|
@@ -761,6 +915,7 @@ describe('PeriodCombiner', () => {
|
|
|
761
915
|
],
|
|
762
916
|
audioStreams: [],
|
|
763
917
|
textStreams: [],
|
|
918
|
+
imageStreams: [],
|
|
764
919
|
},
|
|
765
920
|
];
|
|
766
921
|
|
|
@@ -805,6 +960,7 @@ describe('PeriodCombiner', () => {
|
|
|
805
960
|
stream2,
|
|
806
961
|
],
|
|
807
962
|
textStreams: [],
|
|
963
|
+
imageStreams: [],
|
|
808
964
|
},
|
|
809
965
|
{
|
|
810
966
|
id: '1',
|
|
@@ -816,6 +972,7 @@ describe('PeriodCombiner', () => {
|
|
|
816
972
|
stream4,
|
|
817
973
|
],
|
|
818
974
|
textStreams: [],
|
|
975
|
+
imageStreams: [],
|
|
819
976
|
},
|
|
820
977
|
];
|
|
821
978
|
|
|
@@ -864,6 +1021,7 @@ describe('PeriodCombiner', () => {
|
|
|
864
1021
|
stream2,
|
|
865
1022
|
],
|
|
866
1023
|
textStreams: [],
|
|
1024
|
+
imageStreams: [],
|
|
867
1025
|
},
|
|
868
1026
|
{
|
|
869
1027
|
id: '2',
|
|
@@ -875,6 +1033,7 @@ describe('PeriodCombiner', () => {
|
|
|
875
1033
|
stream4,
|
|
876
1034
|
],
|
|
877
1035
|
textStreams: [],
|
|
1036
|
+
imageStreams: [],
|
|
878
1037
|
},
|
|
879
1038
|
];
|
|
880
1039
|
|
|
@@ -999,24 +1158,28 @@ describe('PeriodCombiner', () => {
|
|
|
999
1158
|
videoStreams: [v1, v2, v3, v4, v5],
|
|
1000
1159
|
audioStreams: [],
|
|
1001
1160
|
textStreams: [],
|
|
1161
|
+
imageStreams: [],
|
|
1002
1162
|
},
|
|
1003
1163
|
{
|
|
1004
1164
|
id: '2',
|
|
1005
1165
|
videoStreams: [v6, v7, v8, v9, v10],
|
|
1006
1166
|
audioStreams: [],
|
|
1007
1167
|
textStreams: [],
|
|
1168
|
+
imageStreams: [],
|
|
1008
1169
|
},
|
|
1009
1170
|
{
|
|
1010
1171
|
id: '3',
|
|
1011
1172
|
videoStreams: [v11, v12, v13, v14, v15],
|
|
1012
1173
|
audioStreams: [],
|
|
1013
1174
|
textStreams: [],
|
|
1175
|
+
imageStreams: [],
|
|
1014
1176
|
},
|
|
1015
1177
|
{
|
|
1016
1178
|
id: '4',
|
|
1017
1179
|
videoStreams: [v16, v17, v18, v19, v20],
|
|
1018
1180
|
audioStreams: [],
|
|
1019
1181
|
textStreams: [],
|
|
1182
|
+
imageStreams: [],
|
|
1020
1183
|
},
|
|
1021
1184
|
{
|
|
1022
1185
|
id: '5',
|
|
@@ -1024,6 +1187,7 @@ describe('PeriodCombiner', () => {
|
|
|
1024
1187
|
videoStreams: [v1, v2, v3, v4, v5],
|
|
1025
1188
|
audioStreams: [],
|
|
1026
1189
|
textStreams: [],
|
|
1190
|
+
imageStreams: [],
|
|
1027
1191
|
},
|
|
1028
1192
|
{
|
|
1029
1193
|
id: '6',
|
|
@@ -1031,6 +1195,7 @@ describe('PeriodCombiner', () => {
|
|
|
1031
1195
|
videoStreams: [v6, v7, v8, v9, v10],
|
|
1032
1196
|
audioStreams: [],
|
|
1033
1197
|
textStreams: [],
|
|
1198
|
+
imageStreams: [],
|
|
1034
1199
|
},
|
|
1035
1200
|
{
|
|
1036
1201
|
id: '7',
|
|
@@ -1038,6 +1203,7 @@ describe('PeriodCombiner', () => {
|
|
|
1038
1203
|
videoStreams: [v11, v12, v13, v14, v15],
|
|
1039
1204
|
audioStreams: [],
|
|
1040
1205
|
textStreams: [],
|
|
1206
|
+
imageStreams: [],
|
|
1041
1207
|
},
|
|
1042
1208
|
{
|
|
1043
1209
|
id: '8',
|
|
@@ -1045,6 +1211,7 @@ describe('PeriodCombiner', () => {
|
|
|
1045
1211
|
videoStreams: [v16, v17, v18, v19, v20],
|
|
1046
1212
|
audioStreams: [],
|
|
1047
1213
|
textStreams: [],
|
|
1214
|
+
imageStreams: [],
|
|
1048
1215
|
},
|
|
1049
1216
|
// Adding the 1st period again since it was the one that used to
|
|
1050
1217
|
// cause trouble when repeated.
|
|
@@ -1054,6 +1221,7 @@ describe('PeriodCombiner', () => {
|
|
|
1054
1221
|
videoStreams: [v1, v2, v3, v4, v5],
|
|
1055
1222
|
audioStreams: [],
|
|
1056
1223
|
textStreams: [],
|
|
1224
|
+
imageStreams: [],
|
|
1057
1225
|
},
|
|
1058
1226
|
];
|
|
1059
1227
|
|
|
@@ -1181,6 +1349,26 @@ describe('PeriodCombiner', () => {
|
|
|
1181
1349
|
return streamGenerator.build_();
|
|
1182
1350
|
}
|
|
1183
1351
|
|
|
1352
|
+
/**
|
|
1353
|
+
* @param {number} height
|
|
1354
|
+
* @return {shaka.extern.Stream}
|
|
1355
|
+
* @suppress {accessControls}
|
|
1356
|
+
*/
|
|
1357
|
+
function makeImageStream(height) {
|
|
1358
|
+
const width = height * 4 / 3;
|
|
1359
|
+
const streamGenerator = new shaka.test.ManifestGenerator.Stream(
|
|
1360
|
+
/* manifest= */ null,
|
|
1361
|
+
/* isPartial= */ false,
|
|
1362
|
+
/* id= */ nextId++,
|
|
1363
|
+
/* type= */ shaka.util.ManifestParserUtils.ContentType.IMAGE,
|
|
1364
|
+
/* lang= */ 'und');
|
|
1365
|
+
streamGenerator.size(width, height);
|
|
1366
|
+
streamGenerator.originalId = height.toString();
|
|
1367
|
+
streamGenerator.mime('image/jpeg');
|
|
1368
|
+
streamGenerator.tilesLayout = '1x1';
|
|
1369
|
+
return streamGenerator.build_();
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1184
1372
|
/**
|
|
1185
1373
|
* @param {number} height
|
|
1186
1374
|
* @param {string} language
|
|
@@ -16,14 +16,14 @@ describe('StreamUtils', () => {
|
|
|
16
16
|
/** @type {!jasmine.Spy} */
|
|
17
17
|
let decodingInfoSpy;
|
|
18
18
|
|
|
19
|
-
const originalDecodingInfo =
|
|
19
|
+
const originalDecodingInfo = window.shakaMediaCapabilities.decodingInfo;
|
|
20
20
|
|
|
21
21
|
beforeEach(() => {
|
|
22
22
|
decodingInfoSpy = jasmine.createSpy('decodingInfo');
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
afterEach(() => {
|
|
26
|
-
|
|
26
|
+
window.shakaMediaCapabilities.decodingInfo = originalDecodingInfo;
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
describe('filterStreamsByLanguageAndRole', () => {
|
|
@@ -488,14 +488,30 @@ describe('StreamUtils', () => {
|
|
|
488
488
|
});
|
|
489
489
|
|
|
490
490
|
await StreamUtils.getDecodingInfosForVariants(manifest.variants,
|
|
491
|
-
/* usePersistentLicenses= */false);
|
|
491
|
+
/* usePersistentLicenses= */false, /* srcEquals= */ false);
|
|
492
|
+
expect(manifest.variants.length).toBeTruthy();
|
|
493
|
+
expect(manifest.variants[0].decodingInfos.length).toBe(1);
|
|
494
|
+
expect(manifest.variants[0].decodingInfos[0].supported).toBeTruthy();
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('for srcEquals content', async () => {
|
|
498
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
499
|
+
manifest.addVariant(0, (variant) => {
|
|
500
|
+
variant.addVideo(1, (stream) => {
|
|
501
|
+
stream.mime('video/mp4', 'avc1.4d400d');
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
await StreamUtils.getDecodingInfosForVariants(manifest.variants,
|
|
507
|
+
/* usePersistentLicenses= */false, /* srcEquals= */ true);
|
|
492
508
|
expect(manifest.variants.length).toBeTruthy();
|
|
493
509
|
expect(manifest.variants[0].decodingInfos.length).toBe(1);
|
|
494
510
|
expect(manifest.variants[0].decodingInfos[0].supported).toBeTruthy();
|
|
495
511
|
});
|
|
496
512
|
|
|
497
513
|
it('handles decodingInfo exception', async () => {
|
|
498
|
-
|
|
514
|
+
window.shakaMediaCapabilities.decodingInfo =
|
|
499
515
|
shaka.test.Util.spyFunc(decodingInfoSpy);
|
|
500
516
|
// If decodingInfo() fails, setDecodingInfo should finish without throwing
|
|
501
517
|
// an exception, and the variant should have no decodingInfo result.
|
|
@@ -517,10 +533,45 @@ describe('StreamUtils', () => {
|
|
|
517
533
|
});
|
|
518
534
|
|
|
519
535
|
await StreamUtils.getDecodingInfosForVariants(manifest.variants,
|
|
520
|
-
/* usePersistentLicenses= */false);
|
|
536
|
+
/* usePersistentLicenses= */false, /* srcEquals= */ false);
|
|
521
537
|
expect(manifest.variants.length).toBe(1);
|
|
522
538
|
expect(manifest.variants[0].decodingInfos.length).toBe(0);
|
|
523
539
|
});
|
|
540
|
+
|
|
541
|
+
it('includes transferFunction in config when hdr', async () => {
|
|
542
|
+
window.shakaMediaCapabilities.decodingInfo =
|
|
543
|
+
shaka.test.Util.spyFunc(decodingInfoSpy);
|
|
544
|
+
|
|
545
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
546
|
+
manifest.addVariant(0, (variant) => {
|
|
547
|
+
variant.addVideo(0, (stream) => {
|
|
548
|
+
stream.mime('video/mp4', 'avc1.640028');
|
|
549
|
+
stream.hdr = 'SDR';
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
manifest.addVariant(1, (variant) => {
|
|
553
|
+
variant.addVideo(1, (stream) => {
|
|
554
|
+
stream.mime('video/mp4', 'hvc1.2.4.L150.90');
|
|
555
|
+
stream.hdr = 'PQ';
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
manifest.addVariant(2, (variant) => {
|
|
559
|
+
variant.addVideo(2, (stream) => {
|
|
560
|
+
stream.mime('video/mp4', 'hvc1.2.4.L153.B0');
|
|
561
|
+
stream.hdr = 'HLG';
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
await StreamUtils.getDecodingInfosForVariants(manifest.variants,
|
|
567
|
+
/* usePersistentLicenses= */ false, /* srcEquals= */ false);
|
|
568
|
+
expect(decodingInfoSpy.calls.argsFor(0)[0].video.transferFunction)
|
|
569
|
+
.toBe('srgb');
|
|
570
|
+
expect(decodingInfoSpy.calls.argsFor(1)[0].video.transferFunction)
|
|
571
|
+
.toBe('pq');
|
|
572
|
+
expect(decodingInfoSpy.calls.argsFor(2)[0].video.transferFunction)
|
|
573
|
+
.toBe('hlg');
|
|
574
|
+
});
|
|
524
575
|
});
|
|
525
576
|
|
|
526
577
|
describe('filterManifest', () => {
|
package/ui/airplay_button.js
CHANGED
|
@@ -44,6 +44,11 @@ shaka.ui.AirPlayButton = class extends shaka.ui.Element {
|
|
|
44
44
|
this.airplayIcon_.textContent = shaka.ui.Enums.MaterialDesignIcons.AIRPLAY;
|
|
45
45
|
this.airplayButton_.appendChild(this.airplayIcon_);
|
|
46
46
|
|
|
47
|
+
// Don't show the button if AirPlay is not supported.
|
|
48
|
+
if (!window.WebKitPlaybackTargetAvailabilityEvent) {
|
|
49
|
+
this.airplayButton_.classList.add('shaka-hidden');
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
const label = shaka.util.Dom.createHTMLElement('label');
|
|
48
53
|
label.classList.add('shaka-overflow-button-label');
|
|
49
54
|
label.classList.add('shaka-overflow-menu-only');
|
package/ui/big_play_button.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
goog.provide('shaka.ui.BigPlayButton');
|
|
9
9
|
|
|
10
|
+
goog.require('shaka.ui.Locales');
|
|
10
11
|
goog.require('shaka.ui.PlayButton');
|
|
11
12
|
goog.requireType('shaka.ui.Controls');
|
|
12
13
|
|
|
@@ -40,4 +41,13 @@ shaka.ui.BigPlayButton = class extends shaka.ui.PlayButton {
|
|
|
40
41
|
this.button.setAttribute('icon', 'pause');
|
|
41
42
|
}
|
|
42
43
|
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/** @override */
|
|
47
|
+
updateAriaLabel() {
|
|
48
|
+
const LocIds = shaka.ui.Locales.Ids;
|
|
49
|
+
const label = this.isPaused() ? LocIds.PLAY : LocIds.PAUSE;
|
|
50
|
+
|
|
51
|
+
this.button.ariaLabel = this.localization.resolve(label);
|
|
52
|
+
}
|
|
43
53
|
};
|
package/ui/cast_button.js
CHANGED
|
@@ -102,9 +102,8 @@ shaka.ui.CastButton = class extends shaka.ui.Element {
|
|
|
102
102
|
} catch (error) {
|
|
103
103
|
this.castButton_.disabled = false;
|
|
104
104
|
if (error.code != shaka.util.Error.Code.CAST_CANCELED_BY_USER) {
|
|
105
|
-
this.controls.dispatchEvent(new shaka.util.FakeEvent(
|
|
106
|
-
|
|
107
|
-
}));
|
|
105
|
+
this.controls.dispatchEvent(new shaka.util.FakeEvent(
|
|
106
|
+
'error', (new Map()).set('detail', error)));
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
109
|
}
|
package/ui/controls.js
CHANGED
|
@@ -198,6 +198,10 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
198
198
|
* @export
|
|
199
199
|
*/
|
|
200
200
|
async destroy() {
|
|
201
|
+
if (document.pictureInPictureElement == this.localVideo_) {
|
|
202
|
+
await document.exitPictureInPicture();
|
|
203
|
+
}
|
|
204
|
+
|
|
201
205
|
if (this.eventManager_) {
|
|
202
206
|
this.eventManager_.release();
|
|
203
207
|
this.eventManager_ = null;
|
|
@@ -569,9 +573,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
569
573
|
}
|
|
570
574
|
}
|
|
571
575
|
} catch (error) {
|
|
572
|
-
this.dispatchEvent(new shaka.util.FakeEvent(
|
|
573
|
-
|
|
574
|
-
}));
|
|
576
|
+
this.dispatchEvent(new shaka.util.FakeEvent(
|
|
577
|
+
'error', (new Map()).set('detail', error)));
|
|
575
578
|
}
|
|
576
579
|
}
|
|
577
580
|
}
|
|
@@ -687,7 +690,7 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
687
690
|
});
|
|
688
691
|
|
|
689
692
|
this.eventManager_.listen(this.controlsContainer_, 'dblclick', () => {
|
|
690
|
-
if (this.config_.doubleClickForFullscreen) {
|
|
693
|
+
if (this.config_.doubleClickForFullscreen && document.fullscreenEnabled) {
|
|
691
694
|
this.toggleFullScreen();
|
|
692
695
|
}
|
|
693
696
|
});
|
|
@@ -1158,9 +1161,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
|
|
|
1158
1161
|
/** @private */
|
|
1159
1162
|
onCastStatusChange_() {
|
|
1160
1163
|
const isCasting = this.castProxy_.isCasting();
|
|
1161
|
-
this.dispatchEvent(new shaka.util.FakeEvent(
|
|
1162
|
-
|
|
1163
|
-
}));
|
|
1164
|
+
this.dispatchEvent(new shaka.util.FakeEvent(
|
|
1165
|
+
'caststatuschanged', (new Map()).set('newStatus', isCasting)));
|
|
1164
1166
|
|
|
1165
1167
|
if (isCasting) {
|
|
1166
1168
|
this.controlsContainer_.setAttribute('casting', 'true');
|
package/ui/less/containers.less
CHANGED
|
@@ -157,6 +157,9 @@
|
|
|
157
157
|
/* 32px tall controls. */
|
|
158
158
|
height: 32px;
|
|
159
159
|
|
|
160
|
+
/* Consistent alignment of buttons. */
|
|
161
|
+
line-height: 0.5;
|
|
162
|
+
|
|
160
163
|
/* Consistent margins (external) and padding (internal) between controls. */
|
|
161
164
|
.bottom-panels-elements-margin();
|
|
162
165
|
|
|
@@ -226,11 +229,13 @@
|
|
|
226
229
|
transition-delay: 500ms;
|
|
227
230
|
|
|
228
231
|
/* These are defaults which are overridden by JS or cue styles. */
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
font-size: 20px;
|
|
233
|
+
line-height: 1.4; // relative to font size.
|
|
234
|
+
color: rgb(255, 255, 255);
|
|
235
|
+
|
|
236
|
+
span.shaka-text-wrapper {
|
|
237
|
+
display: inline;
|
|
238
|
+
background: none;
|
|
234
239
|
}
|
|
235
240
|
}
|
|
236
241
|
|