shaka-player 4.5.0 → 4.6.0
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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/AUTHORS +2 -0
- package/CHANGELOG.md +98 -0
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +38 -32
- package/demo/common/asset.js +11 -17
- package/demo/common/assets.js +117 -11
- package/demo/config.js +28 -1
- package/demo/custom.js +52 -38
- package/demo/main.js +11 -3
- package/demo/search.js +7 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +133 -124
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +133 -124
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +20 -18
- package/dist/locales.js +35 -31
- package/dist/receiver.compiled.debug.js +58 -50
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +58 -50
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.externs.js +162 -77
- package/dist/shaka-player.compiled.debug.js +786 -736
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +162 -77
- package/dist/shaka-player.compiled.js +1154 -1121
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +491 -437
- package/dist/shaka-player.ui.debug.d.ts +491 -437
- package/dist/shaka-player.ui.debug.externs.js +167 -77
- package/dist/shaka-player.ui.debug.js +877 -811
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +167 -77
- package/dist/shaka-player.ui.js +1362 -1318
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +54 -0
- package/docs/tutorials/basic-usage.md +2 -1
- package/docs/tutorials/errors.md +2 -1
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +13 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/managedmediasource.js +24 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +21 -5
- package/externs/shaka/manifest_parser.js +17 -0
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +9 -2
- package/externs/shaka/player.js +53 -7
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/lib/abr/simple_abr_manager.js +25 -8
- package/lib/ads/media_tailor_ad_manager.js +14 -3
- package/lib/cast/cast_receiver.js +1 -1
- package/lib/cea/cea_decoder.js +28 -0
- package/lib/cea/dummy_caption_decoder.js +5 -0
- package/lib/dash/dash_parser.js +249 -83
- package/lib/dash/mpd_utils.js +52 -31
- package/lib/dash/segment_base.js +4 -5
- package/lib/dash/segment_list.js +5 -4
- package/lib/dash/segment_template.js +83 -26
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +761 -649
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/media/adaptation_set.js +20 -13
- package/lib/media/adaptation_set_criteria.js +70 -18
- package/lib/media/closed_caption_parser.js +13 -0
- package/lib/media/content_workarounds.js +6 -0
- package/lib/media/drm_engine.js +8 -13
- package/lib/media/manifest_parser.js +8 -113
- package/lib/media/media_source_capabilities.js +10 -3
- package/lib/media/media_source_engine.js +75 -21
- package/lib/media/play_rate_controller.js +8 -38
- package/lib/media/presentation_timeline.js +7 -1
- package/lib/media/quality_observer.js +1 -1
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +67 -1
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +41 -21
- package/lib/mss/mss_parser.js +18 -2
- package/lib/net/networking_engine.js +66 -12
- package/lib/net/networking_utils.js +95 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +2 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +11 -7
- package/lib/player.js +993 -1502
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/mp4_ttml_parser.js +2 -2
- package/lib/text/srt_text_parser.js +2 -2
- package/lib/text/stub_text_displayer.js +51 -0
- package/lib/text/text_engine.js +3 -2
- package/lib/text/ttml_text_parser.js +28 -5
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +7 -2
- package/lib/transmuxer/aac_transmuxer.js +1 -1
- package/lib/transmuxer/ac3_transmuxer.js +1 -1
- package/lib/transmuxer/ec3_transmuxer.js +1 -1
- package/lib/transmuxer/h264.js +5 -4
- package/lib/transmuxer/h265.js +5 -4
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +1 -1
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +33 -13
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +2 -6
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +5 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +2 -4
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +154 -179
- package/lib/util/platform.js +4 -3
- package/lib/util/player_configuration.js +35 -6
- package/lib/util/stream_utils.js +105 -98
- package/lib/util/ts_parser.js +124 -73
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +2 -2
- package/package.json +1 -1
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +0 -1
- package/test/abr/simple_abr_manager_unit.js +33 -33
- package/test/ads/ad_manager_unit.js +3 -2
- package/test/cast/cast_receiver_integration.js +3 -4
- package/test/cast/cast_utils_unit.js +2 -0
- package/test/cea/cea_decoder_unit.js +7 -0
- package/test/codec_switching/codec_switching_integration.js +2 -1
- package/test/dash/dash_parser_integration.js +2 -1
- package/test/dash/dash_parser_live_unit.js +0 -19
- package/test/dash/dash_parser_manifest_unit.js +494 -2
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/hls/hls_live_unit.js +12 -3
- package/test/hls/hls_parser_unit.js +377 -27
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +172 -21
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/content_workarounds_unit.js +1 -1
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +2 -1
- package/test/mss/mss_player_integration.js +3 -2
- package/test/net/networking_engine_unit.js +3 -3
- package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
- package/test/offline/manifest_convert_unit.js +9 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +21 -9
- package/test/player_external.js +4 -2
- package/test/player_integration.js +15 -4
- package/test/player_load_graph_integration.js +47 -151
- package/test/player_src_equals_external.js +1 -0
- package/test/player_src_equals_integration.js +71 -4
- package/test/player_unit.js +80 -27
- package/test/test/util/fake_media_source_engine.js +5 -0
- package/test/test/util/fake_networking_engine.js +9 -1
- package/test/test/util/fake_segment_prefetch.js +3 -0
- package/test/test/util/manifest_generator.js +4 -0
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +3 -0
- package/test/test/util/test_scheme.js +6 -0
- package/test/test/util/ui_utils.js +4 -3
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/srt_text_parser_unit.js +1 -1
- package/test/text/text_displayer_layout_unit.js +1 -1
- package/test/text/text_engine_unit.js +6 -0
- package/test/text/ttml_text_parser_unit.js +33 -2
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +33 -3
- package/test/ui/ad_ui_unit.js +2 -2
- package/test/ui/ui_customization_unit.js +17 -16
- package/test/ui/ui_integration.js +30 -20
- package/test/ui/ui_unit.js +25 -19
- package/test/util/buffer_utils_unit.js +1 -1
- package/test/util/content_steering_manager_unit.js +427 -0
- package/test/util/id3_utils_unit.js +52 -0
- package/test/util/stream_utils_unit.js +17 -113
- package/test/util/ts_parser_unit.js +3 -3
- package/third_party/closure-uri/uri.js +13 -1
- package/ui/audio_language_selection.js +9 -2
- package/ui/externs/ui.js +17 -2
- package/ui/language_utils.js +43 -8
- package/ui/less/range_elements.less +33 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/es-419.json +1 -0
- package/ui/locales/es.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +10 -0
- package/ui/remote_button.js +3 -1
- package/ui/resolution_selection.js +47 -10
- package/ui/seek_bar.js +296 -3
- package/ui/text_selection.js +2 -1
- package/ui/ui.js +6 -2
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -47
- package/lib/routing/walker.js +0 -587
- package/test/routing/walker_unit.js +0 -505
|
@@ -390,88 +390,6 @@ describe('StreamUtils', () => {
|
|
|
390
390
|
});
|
|
391
391
|
});
|
|
392
392
|
|
|
393
|
-
describe('filterVariantsByAudioChannelCount', () => {
|
|
394
|
-
it('chooses variants with preferred audio channels count', () => {
|
|
395
|
-
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
396
|
-
manifest.addVariant(0, (variant) => {
|
|
397
|
-
variant.addAudio(0, (stream) => {
|
|
398
|
-
stream.channelsCount = 2;
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
manifest.addVariant(1, (variant) => {
|
|
402
|
-
variant.addAudio(1, (stream) => {
|
|
403
|
-
stream.channelsCount = 6;
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
manifest.addVariant(2, (variant) => {
|
|
407
|
-
variant.addAudio(2, (stream) => {
|
|
408
|
-
stream.channelsCount = 2;
|
|
409
|
-
});
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
const chosen = StreamUtils.filterVariantsByAudioChannelCount(
|
|
414
|
-
manifest.variants, 2);
|
|
415
|
-
expect(chosen.length).toBe(2);
|
|
416
|
-
expect(chosen[0]).toBe(manifest.variants[0]);
|
|
417
|
-
expect(chosen[1]).toBe(manifest.variants[2]);
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it('chooses variants with largest audio channel count less than config' +
|
|
421
|
-
' when no exact audio channel count match is possible', () => {
|
|
422
|
-
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
423
|
-
manifest.addVariant(0, (variant) => {
|
|
424
|
-
variant.addAudio(0, (stream) => {
|
|
425
|
-
stream.channelsCount = 2;
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
manifest.addVariant(1, (variant) => {
|
|
429
|
-
variant.addAudio(1, (stream) => {
|
|
430
|
-
stream.channelsCount = 8;
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
manifest.addVariant(2, (variant) => {
|
|
434
|
-
variant.addAudio(2, (stream) => {
|
|
435
|
-
stream.channelsCount = 2;
|
|
436
|
-
});
|
|
437
|
-
});
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const chosen = StreamUtils.filterVariantsByAudioChannelCount(
|
|
441
|
-
manifest.variants, 6);
|
|
442
|
-
expect(chosen.length).toBe(2);
|
|
443
|
-
expect(chosen[0]).toBe(manifest.variants[0]);
|
|
444
|
-
expect(chosen[1]).toBe(manifest.variants[2]);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
it('chooses variants with fewest audio channels when none fit in the ' +
|
|
448
|
-
'config', () => {
|
|
449
|
-
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
450
|
-
manifest.addVariant(0, (variant) => {
|
|
451
|
-
variant.addAudio(0, (stream) => {
|
|
452
|
-
stream.channelsCount = 6;
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
manifest.addVariant(1, (variant) => {
|
|
456
|
-
variant.addAudio(1, (stream) => {
|
|
457
|
-
stream.channelsCount = 8;
|
|
458
|
-
});
|
|
459
|
-
});
|
|
460
|
-
manifest.addVariant(2, (variant) => {
|
|
461
|
-
variant.addAudio(2, (stream) => {
|
|
462
|
-
stream.channelsCount = 6;
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
const chosen = StreamUtils.filterVariantsByAudioChannelCount(
|
|
468
|
-
manifest.variants, 2);
|
|
469
|
-
expect(chosen.length).toBe(2);
|
|
470
|
-
expect(chosen[0]).toBe(manifest.variants[0]);
|
|
471
|
-
expect(chosen[1]).toBe(manifest.variants[2]);
|
|
472
|
-
});
|
|
473
|
-
});
|
|
474
|
-
|
|
475
393
|
describe('getDecodingInfosForVariants', () => {
|
|
476
394
|
it('for multiplexd content', async () => {
|
|
477
395
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
@@ -634,10 +552,7 @@ describe('StreamUtils', () => {
|
|
|
634
552
|
});
|
|
635
553
|
});
|
|
636
554
|
|
|
637
|
-
|
|
638
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
639
|
-
fakeDrmEngine, noVariant, manifest,
|
|
640
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
555
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
641
556
|
|
|
642
557
|
// Covers a regression in which we would remove streams with codecs.
|
|
643
558
|
// The last two streams should be removed because their full MIME types
|
|
@@ -672,10 +587,7 @@ describe('StreamUtils', () => {
|
|
|
672
587
|
});
|
|
673
588
|
});
|
|
674
589
|
|
|
675
|
-
|
|
676
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
677
|
-
fakeDrmEngine, noVariant, manifest,
|
|
678
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
590
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
679
591
|
|
|
680
592
|
// Covers a regression in which we would remove streams with codecs.
|
|
681
593
|
// The first 4 streams should be there because they are always supported.
|
|
@@ -714,9 +626,7 @@ describe('StreamUtils', () => {
|
|
|
714
626
|
shaka.util.StreamUtils.filterManifestByCurrentVariant =
|
|
715
627
|
shaka.test.Util.spyFunc(filterManifestByCurrentVariantSpy);
|
|
716
628
|
|
|
717
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
718
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest,
|
|
719
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
629
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
720
630
|
|
|
721
631
|
expect(filterManifestByCurrentVariantSpy).not.toHaveBeenCalled();
|
|
722
632
|
} finally {
|
|
@@ -738,9 +648,7 @@ describe('StreamUtils', () => {
|
|
|
738
648
|
});
|
|
739
649
|
});
|
|
740
650
|
|
|
741
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
742
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest,
|
|
743
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
651
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
744
652
|
|
|
745
653
|
// Covers a regression in which we would remove streams with codecs.
|
|
746
654
|
// The last two streams should be removed because their full MIME types
|
|
@@ -766,9 +674,7 @@ describe('StreamUtils', () => {
|
|
|
766
674
|
});
|
|
767
675
|
});
|
|
768
676
|
|
|
769
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
770
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest,
|
|
771
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
677
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
772
678
|
expect(manifest.variants.length).toBe(1);
|
|
773
679
|
});
|
|
774
680
|
|
|
@@ -784,9 +690,7 @@ describe('StreamUtils', () => {
|
|
|
784
690
|
});
|
|
785
691
|
});
|
|
786
692
|
|
|
787
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
788
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest,
|
|
789
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
693
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
790
694
|
|
|
791
695
|
expect(manifest.variants.length).toBe(1);
|
|
792
696
|
});
|
|
@@ -808,8 +712,7 @@ describe('StreamUtils', () => {
|
|
|
808
712
|
});
|
|
809
713
|
});
|
|
810
714
|
|
|
811
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
812
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest);
|
|
715
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
813
716
|
|
|
814
717
|
expect(manifest.variants.length).toBe(2);
|
|
815
718
|
});
|
|
@@ -831,8 +734,7 @@ describe('StreamUtils', () => {
|
|
|
831
734
|
});
|
|
832
735
|
});
|
|
833
736
|
|
|
834
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
835
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest);
|
|
737
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
836
738
|
|
|
837
739
|
expect(manifest.variants.length).toBe(2);
|
|
838
740
|
});
|
|
@@ -849,9 +751,7 @@ describe('StreamUtils', () => {
|
|
|
849
751
|
});
|
|
850
752
|
});
|
|
851
753
|
|
|
852
|
-
await shaka.util.StreamUtils.filterManifest(
|
|
853
|
-
fakeDrmEngine, /* currentVariant= */ null, manifest,
|
|
854
|
-
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
754
|
+
await shaka.util.StreamUtils.filterManifest(fakeDrmEngine, manifest);
|
|
855
755
|
|
|
856
756
|
expect(manifest.variants.length).toBe(1);
|
|
857
757
|
});
|
|
@@ -937,7 +837,6 @@ describe('StreamUtils', () => {
|
|
|
937
837
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
|
|
938
838
|
/* preferredVideoCodecs= */[],
|
|
939
839
|
/* preferredAudioCodecs= */[],
|
|
940
|
-
/* preferredAudioChannelCount= */2,
|
|
941
840
|
/* preferredDecodingAttributes= */[]);
|
|
942
841
|
|
|
943
842
|
expect(manifest.variants.length).toBe(2);
|
|
@@ -947,12 +846,17 @@ describe('StreamUtils', () => {
|
|
|
947
846
|
|
|
948
847
|
it('should filter variants by the best available bandwidth' +
|
|
949
848
|
' for audio language', () => {
|
|
849
|
+
// This test is flaky in some Tizen devices, due to codec restrictions.
|
|
850
|
+
if (shaka.util.Platform.isTizen()) {
|
|
851
|
+
pending('Skip flaky test in Tizen');
|
|
852
|
+
}
|
|
950
853
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
951
854
|
manifest.addVariant(0, (variant) => {
|
|
952
855
|
variant.bandwidth = 4058558;
|
|
953
856
|
variant.addAudio(1, (stream) => {
|
|
954
857
|
stream.bandwidth = 100000;
|
|
955
858
|
stream.language = 'en';
|
|
859
|
+
stream.mime('audio/mp4', 'mp4a.40.2');
|
|
956
860
|
});
|
|
957
861
|
});
|
|
958
862
|
manifest.addVariant(2, (variant) => {
|
|
@@ -960,18 +864,21 @@ describe('StreamUtils', () => {
|
|
|
960
864
|
variant.addAudio(3, (stream) => {
|
|
961
865
|
stream.bandwidth = 200000;
|
|
962
866
|
stream.language = 'en';
|
|
867
|
+
stream.mime('audio/mp4', 'flac');
|
|
963
868
|
});
|
|
964
869
|
});
|
|
965
870
|
manifest.addVariant(4, (variant) => {
|
|
966
871
|
variant.addAudio(5, (stream) => {
|
|
967
872
|
stream.bandwidth = 100000;
|
|
968
873
|
stream.language = 'es';
|
|
874
|
+
stream.mime('audio/mp4', 'mp4a.40.2');
|
|
969
875
|
});
|
|
970
876
|
});
|
|
971
877
|
manifest.addVariant(6, (variant) => {
|
|
972
878
|
variant.addAudio(7, (stream) => {
|
|
973
879
|
stream.bandwidth = 500000;
|
|
974
880
|
stream.language = 'es';
|
|
881
|
+
stream.mime('audio/mp4', 'flac');
|
|
975
882
|
});
|
|
976
883
|
});
|
|
977
884
|
});
|
|
@@ -979,7 +886,6 @@ describe('StreamUtils', () => {
|
|
|
979
886
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
|
|
980
887
|
/* preferredVideoCodecs= */[],
|
|
981
888
|
/* preferredAudioCodecs= */[],
|
|
982
|
-
/* preferredAudioChannelCount= */2,
|
|
983
889
|
/* preferredDecodingAttributes= */[]);
|
|
984
890
|
|
|
985
891
|
expect(manifest.variants.length).toBe(2);
|
|
@@ -1009,7 +915,6 @@ describe('StreamUtils', () => {
|
|
|
1009
915
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
|
|
1010
916
|
/* preferredVideoCodecs= */[],
|
|
1011
917
|
/* preferredAudioCodecs= */[],
|
|
1012
|
-
/* preferredAudioChannelCount= */2,
|
|
1013
918
|
/* preferredDecodingAttributes= */[]);
|
|
1014
919
|
|
|
1015
920
|
expect(manifest.variants.length).toBe(2);
|
|
@@ -1128,7 +1033,6 @@ describe('StreamUtils', () => {
|
|
|
1128
1033
|
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
|
|
1129
1034
|
/* preferredVideoCodecs= */[],
|
|
1130
1035
|
/* preferredAudioCodecs= */[],
|
|
1131
|
-
/* preferredAudioChannelCount= */2,
|
|
1132
1036
|
/* preferredDecodingAttributes= */
|
|
1133
1037
|
[shaka.util.StreamUtils.DecodingAttributes.SMOOTH]);
|
|
1134
1038
|
// 2 video codecs are smooth. Choose the one with the lowest bandwidth.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
describe('TsParser', () => {
|
|
8
8
|
const Util = shaka.test.Util;
|
|
9
9
|
const BufferUtils = shaka.util.BufferUtils;
|
|
10
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
10
11
|
|
|
11
12
|
it('probes a TS segment', async () => {
|
|
12
13
|
const responses = await Promise.all([
|
|
@@ -59,9 +60,8 @@ describe('TsParser', () => {
|
|
|
59
60
|
]);
|
|
60
61
|
const tsSegment = BufferUtils.toUint8(responses[0]);
|
|
61
62
|
const starttime = new shaka.util.TsParser().parse(tsSegment)
|
|
62
|
-
.getStartTime();
|
|
63
|
-
expect(starttime
|
|
64
|
-
expect(starttime.video).toBe(null);
|
|
63
|
+
.getStartTime(ContentType.AUDIO);
|
|
64
|
+
expect(starttime).toBeCloseTo(90019.586, 3);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
it('get the codecs from a TS segment', async () => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Use new goog.Uri(string) to parse a URI string.
|
|
10
10
|
*
|
|
11
|
-
* e.g
|
|
11
|
+
* e.g.: <code>var myUri = new goog.Uri(window.location);</code>
|
|
12
12
|
*
|
|
13
13
|
* Implements RFC 3986 for parsing/formatting URIs.
|
|
14
14
|
* http://www.ietf.org/rfc/rfc3986.txt
|
|
@@ -830,6 +830,18 @@ goog.Uri.QueryData.prototype.add = function(key, value) {
|
|
|
830
830
|
};
|
|
831
831
|
|
|
832
832
|
|
|
833
|
+
/**
|
|
834
|
+
* Get the values from a key.
|
|
835
|
+
*
|
|
836
|
+
* @param {string} key Name.
|
|
837
|
+
* @return {Array.<string>}
|
|
838
|
+
*/
|
|
839
|
+
goog.Uri.QueryData.prototype.get = function(key) {
|
|
840
|
+
this.ensureKeyMapInitialized_();
|
|
841
|
+
return this.keyMap_[key] || [];
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
|
|
833
845
|
/**
|
|
834
846
|
* @return {string} Encoded query string.
|
|
835
847
|
* @override
|
|
@@ -68,7 +68,8 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
|
|
|
68
68
|
shaka.ui.LanguageUtils.updateTracks(tracks, this.menu,
|
|
69
69
|
(track) => this.onAudioTrackSelected_(track),
|
|
70
70
|
/* updateChosen= */ true, this.currentSelection, this.localization,
|
|
71
|
-
this.controls.getConfig().trackLabelFormat
|
|
71
|
+
this.controls.getConfig().trackLabelFormat,
|
|
72
|
+
this.controls.getConfig().showAudioChannelCountVariants);
|
|
72
73
|
shaka.ui.Utils.focusOnTheChosenItem(this.menu);
|
|
73
74
|
|
|
74
75
|
this.controls.dispatchEvent(
|
|
@@ -89,7 +90,13 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
|
|
|
89
90
|
* @private
|
|
90
91
|
*/
|
|
91
92
|
onAudioTrackSelected_(track) {
|
|
92
|
-
|
|
93
|
+
if (track.channelsCount &&
|
|
94
|
+
this.controls.getConfig().showAudioChannelCountVariants) {
|
|
95
|
+
this.player.selectAudioLanguage(
|
|
96
|
+
track.language, track.roles[0], track.channelsCount);
|
|
97
|
+
} else {
|
|
98
|
+
this.player.selectAudioLanguage(track.language, track.roles[0]);
|
|
99
|
+
}
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
|
package/ui/externs/ui.js
CHANGED
|
@@ -21,7 +21,9 @@ shaka.extern = {};
|
|
|
21
21
|
* base: string,
|
|
22
22
|
* buffered: string,
|
|
23
23
|
* played: string,
|
|
24
|
-
* adBreaks: string
|
|
24
|
+
* adBreaks: string,
|
|
25
|
+
* chapterMarks: string,
|
|
26
|
+
* chapterLabels: string
|
|
25
27
|
* }}
|
|
26
28
|
*
|
|
27
29
|
* @property {string} base
|
|
@@ -36,6 +38,13 @@ shaka.extern = {};
|
|
|
36
38
|
* @property {string} adBreaks
|
|
37
39
|
* The CSS background color applied to the portion of the seek bar showing
|
|
38
40
|
* when the ad breaks are scheduled to occur on the timeline.
|
|
41
|
+
* @property {string} chapterMarks
|
|
42
|
+
* The CSS border color applied to sections of the seek bar showing
|
|
43
|
+
* when the chapters start and end on the timeline.
|
|
44
|
+
* Defaults to dark grey rgb(27, 27, 27).
|
|
45
|
+
* @property {string} chapterLabels
|
|
46
|
+
* The CSS text color applied to the chapter labels that appear above the
|
|
47
|
+
* seek bar on hover. Defaults to white rgb(255, 255, 255).
|
|
39
48
|
* @exportDoc
|
|
40
49
|
*/
|
|
41
50
|
shaka.extern.UISeekBarColors;
|
|
@@ -88,7 +97,8 @@ shaka.extern.UIVolumeBarColors;
|
|
|
88
97
|
* keyboardSeekDistance: number,
|
|
89
98
|
* keyboardLargeSeekDistance: number,
|
|
90
99
|
* fullScreenElement: HTMLElement,
|
|
91
|
-
* preferDocumentPictureInPicture: boolean
|
|
100
|
+
* preferDocumentPictureInPicture: boolean,
|
|
101
|
+
* showAudioChannelCountVariants: boolean
|
|
92
102
|
* }}
|
|
93
103
|
*
|
|
94
104
|
* @property {!Array.<string>} controlPanelElements
|
|
@@ -200,6 +210,11 @@ shaka.extern.UIVolumeBarColors;
|
|
|
200
210
|
* Changing this property in mid-playback may produce undesired behavior if
|
|
201
211
|
* you are already in PiP.
|
|
202
212
|
* Defaults to true.
|
|
213
|
+
* @property {boolean} showAudioChannelCountVariants
|
|
214
|
+
* Indicates whether the combination of language and channel count should be
|
|
215
|
+
* displayed or if, on the contrary, only the language should be displayed
|
|
216
|
+
* regardless of the channel count.
|
|
217
|
+
* Defaults to true.
|
|
203
218
|
* @exportDoc
|
|
204
219
|
*/
|
|
205
220
|
shaka.extern.UIConfiguration;
|
package/ui/language_utils.js
CHANGED
|
@@ -26,9 +26,13 @@ shaka.ui.LanguageUtils = class {
|
|
|
26
26
|
* @param {!HTMLElement} currentSelectionElement
|
|
27
27
|
* @param {shaka.ui.Localization} localization
|
|
28
28
|
* @param {shaka.ui.Overlay.TrackLabelFormat} trackLabelFormat
|
|
29
|
+
* @param {boolean} showAudioChannelCountVariants
|
|
29
30
|
*/
|
|
30
31
|
static updateTracks(tracks, langMenu, onTrackSelected, updateChosen,
|
|
31
|
-
currentSelectionElement, localization, trackLabelFormat
|
|
32
|
+
currentSelectionElement, localization, trackLabelFormat,
|
|
33
|
+
showAudioChannelCountVariants) {
|
|
34
|
+
const LocIds = shaka.ui.Locales.Ids;
|
|
35
|
+
|
|
32
36
|
// TODO: Do the benefits of having this common code in a method still
|
|
33
37
|
// outweigh the complexity of the parameter list?
|
|
34
38
|
const selectedTrack = tracks.find((track) => {
|
|
@@ -55,8 +59,27 @@ shaka.ui.LanguageUtils = class {
|
|
|
55
59
|
}
|
|
56
60
|
};
|
|
57
61
|
|
|
58
|
-
const getCombination = (language, rolesString) => {
|
|
59
|
-
|
|
62
|
+
const getCombination = (language, rolesString, label, channelsCount) => {
|
|
63
|
+
const keys = [
|
|
64
|
+
language,
|
|
65
|
+
rolesString,
|
|
66
|
+
];
|
|
67
|
+
if (showAudioChannelCountVariants && channelsCount != null) {
|
|
68
|
+
keys.push(channelsCount);
|
|
69
|
+
}
|
|
70
|
+
if (label &&
|
|
71
|
+
trackLabelFormat == shaka.ui.Overlay.TrackLabelFormat.LABEL) {
|
|
72
|
+
keys.push(label);
|
|
73
|
+
}
|
|
74
|
+
return keys.join(': ');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getChannelsCountName = (channelsCount) => {
|
|
78
|
+
let name = '';
|
|
79
|
+
if (channelsCount >= 5) {
|
|
80
|
+
name = ' ' + localization.resolve(LocIds.SURROUND);
|
|
81
|
+
}
|
|
82
|
+
return name;
|
|
60
83
|
};
|
|
61
84
|
|
|
62
85
|
/** @type {!Map.<string, !Set.<string>>} */
|
|
@@ -72,15 +95,18 @@ shaka.ui.LanguageUtils = class {
|
|
|
72
95
|
/** @type {!Set.<string>} */
|
|
73
96
|
const combinationsMade = new Set();
|
|
74
97
|
const selectedCombination = selectedTrack ? getCombination(
|
|
75
|
-
selectedTrack.language, getRolesString(selectedTrack)
|
|
98
|
+
selectedTrack.language, getRolesString(selectedTrack),
|
|
99
|
+
selectedTrack.label, selectedTrack.channelsCount) : '';
|
|
76
100
|
|
|
77
101
|
for (const track of tracks) {
|
|
78
102
|
const language = track.language;
|
|
79
103
|
const forced = track.forced;
|
|
80
|
-
const LocIds = shaka.ui.Locales.Ids;
|
|
81
104
|
const forcedString = localization.resolve(LocIds.SUBTITLE_FORCED);
|
|
82
105
|
const rolesString = getRolesString(track);
|
|
83
|
-
const
|
|
106
|
+
const label = track.label;
|
|
107
|
+
const channelsCount = track.channelsCount;
|
|
108
|
+
const combinationName =
|
|
109
|
+
getCombination(language, rolesString, label, channelsCount);
|
|
84
110
|
if (combinationsMade.has(combinationName)) {
|
|
85
111
|
continue;
|
|
86
112
|
}
|
|
@@ -98,11 +124,17 @@ shaka.ui.LanguageUtils = class {
|
|
|
98
124
|
shaka.ui.LanguageUtils.getLanguageName(language, localization);
|
|
99
125
|
switch (trackLabelFormat) {
|
|
100
126
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE:
|
|
127
|
+
if (showAudioChannelCountVariants) {
|
|
128
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
129
|
+
}
|
|
101
130
|
if (forced) {
|
|
102
131
|
span.textContent += ' (' + forcedString + ')';
|
|
103
132
|
}
|
|
104
133
|
break;
|
|
105
134
|
case shaka.ui.Overlay.TrackLabelFormat.ROLE:
|
|
135
|
+
if (showAudioChannelCountVariants) {
|
|
136
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
137
|
+
}
|
|
106
138
|
if (!rolesString) {
|
|
107
139
|
// Fallback behavior. This probably shouldn't happen.
|
|
108
140
|
shaka.log.alwaysWarn('Track #' + track.id + ' does not have a ' +
|
|
@@ -116,6 +148,9 @@ shaka.ui.LanguageUtils = class {
|
|
|
116
148
|
}
|
|
117
149
|
break;
|
|
118
150
|
case shaka.ui.Overlay.TrackLabelFormat.LANGUAGE_ROLE:
|
|
151
|
+
if (showAudioChannelCountVariants) {
|
|
152
|
+
span.textContent += getChannelsCountName(channelsCount);
|
|
153
|
+
}
|
|
119
154
|
if (rolesString) {
|
|
120
155
|
span.textContent += ': ' + rolesString;
|
|
121
156
|
}
|
|
@@ -124,8 +159,8 @@ shaka.ui.LanguageUtils = class {
|
|
|
124
159
|
}
|
|
125
160
|
break;
|
|
126
161
|
case shaka.ui.Overlay.TrackLabelFormat.LABEL:
|
|
127
|
-
if (
|
|
128
|
-
span.textContent =
|
|
162
|
+
if (label) {
|
|
163
|
+
span.textContent = label;
|
|
129
164
|
} else {
|
|
130
165
|
// Fallback behavior. This probably shouldn't happen.
|
|
131
166
|
shaka.log.alwaysWarn('Track #' + track.id + ' does not have a ' +
|
|
@@ -154,3 +154,36 @@
|
|
|
154
154
|
.shaka-ad-markers {
|
|
155
155
|
.overlay-child();
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
#shaka-player-ui-chapters-container {
|
|
159
|
+
width: 100%;
|
|
160
|
+
height: 100%;
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: row;
|
|
163
|
+
z-index: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.shaka-chapter {
|
|
167
|
+
height: 100%;
|
|
168
|
+
position: relative;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.shaka-chapter-label {
|
|
172
|
+
position: relative;
|
|
173
|
+
top: -2.5em;
|
|
174
|
+
width: 100%;
|
|
175
|
+
text-align: center;
|
|
176
|
+
text-shadow: 1px 1px gray;
|
|
177
|
+
line-height: normal;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.shaka-chapter > div:first-child {
|
|
181
|
+
width: 100%;
|
|
182
|
+
height: 100%;
|
|
183
|
+
border-right: 1px solid;
|
|
184
|
+
position: absolute;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.shaka-chapter:last-child > div:first-child {
|
|
188
|
+
border-right: none;
|
|
189
|
+
}
|
package/ui/locales/en.json
CHANGED
package/ui/locales/es-419.json
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"SKIP_AD": "Omitir anuncio",
|
|
33
33
|
"SKIP_TO_LIVE": "Adelantar hasta la transmisión en vivo",
|
|
34
34
|
"SUBTITLE_FORCED": "Forzado",
|
|
35
|
+
"SURROUND": "Envolvente",
|
|
35
36
|
"UNDETERMINED_LANGUAGE": "Sin especificar",
|
|
36
37
|
"UNMUTE": "Dejar de silenciar",
|
|
37
38
|
"UNRECOGNIZED_LANGUAGE": "No reconocida",
|
package/ui/locales/es.json
CHANGED
package/ui/locales/source.json
CHANGED
|
@@ -151,6 +151,10 @@
|
|
|
151
151
|
"description": "Label used to identify a subtitle track that is forced to be shown.",
|
|
152
152
|
"message": "Forced"
|
|
153
153
|
},
|
|
154
|
+
"SURROUND": {
|
|
155
|
+
"description": "Label used to identify a audio track that has surround audio.",
|
|
156
|
+
"message": "Surround"
|
|
157
|
+
},
|
|
154
158
|
"UNDETERMINED_LANGUAGE": {
|
|
155
159
|
"description": "Label for a button used to select an audio track whose language is undetermined or unknown.",
|
|
156
160
|
"message": "Undetermined"
|
package/ui/localization.js
CHANGED
|
@@ -230,6 +230,16 @@ shaka.ui.Localization = class extends shaka.util.FakeEventTarget {
|
|
|
230
230
|
return '';
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* The locales currently used. An empty set means "no preference".
|
|
235
|
+
*
|
|
236
|
+
* @return {!Set.<string>}
|
|
237
|
+
* @export
|
|
238
|
+
*/
|
|
239
|
+
getCurrentLocales() {
|
|
240
|
+
return this.currentLocales_;
|
|
241
|
+
}
|
|
242
|
+
|
|
233
243
|
/**
|
|
234
244
|
* @private
|
|
235
245
|
*/
|
package/ui/remote_button.js
CHANGED
|
@@ -116,7 +116,9 @@ shaka.ui.RemoteButton = class extends shaka.ui.Element {
|
|
|
116
116
|
/** @override */
|
|
117
117
|
release() {
|
|
118
118
|
if (this.video.remote && this.callbackId_ != -1) {
|
|
119
|
-
this.video.remote.cancelWatchAvailability(this.callbackId_)
|
|
119
|
+
this.video.remote.cancelWatchAvailability(this.callbackId_).catch(() => {
|
|
120
|
+
// Ignore this error.
|
|
121
|
+
});
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
super.release();
|
|
@@ -89,10 +89,18 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
89
89
|
// Remove duplicate entries with the same resolution or quality depending
|
|
90
90
|
// on content type. Pick an arbitrary one.
|
|
91
91
|
tracks = tracks.filter((track, idx) => {
|
|
92
|
-
// Keep the first one with the same height or bandwidth.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
// Keep the first one with the same height and framrate or bandwidth.
|
|
93
|
+
let otherIdx = -1;
|
|
94
|
+
if (this.player.isAudioOnly()) {
|
|
95
|
+
otherIdx = tracks.findIndex((t) => t.bandwidth == track.bandwidth);
|
|
96
|
+
} else {
|
|
97
|
+
otherIdx = tracks.findIndex((t) => {
|
|
98
|
+
return t.height == track.height &&
|
|
99
|
+
t.frameRate == track.frameRate &&
|
|
100
|
+
t.hdr == track.hdr &&
|
|
101
|
+
t.videoLayout == track.videoLayout;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
96
104
|
return otherIdx == idx;
|
|
97
105
|
});
|
|
98
106
|
|
|
@@ -132,14 +140,12 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
132
140
|
() => this.onTrackSelected_(track));
|
|
133
141
|
|
|
134
142
|
const span = shaka.util.Dom.createHTMLElement('span');
|
|
135
|
-
if (this.player.isAudioOnly()) {
|
|
143
|
+
if (this.player.isAudioOnly() && track.bandwidth) {
|
|
136
144
|
span.textContent = Math.round(track.bandwidth / 1000) + ' kbits/s';
|
|
145
|
+
} else if (track.height && track.width) {
|
|
146
|
+
span.textContent = this.getResolutionLabel_(track);
|
|
137
147
|
} else {
|
|
138
|
-
|
|
139
|
-
span.textContent = track.height + 'p (HDR)';
|
|
140
|
-
} else {
|
|
141
|
-
span.textContent = track.height + 'p';
|
|
142
|
-
}
|
|
148
|
+
span.textContent = 'Unknown';
|
|
143
149
|
}
|
|
144
150
|
button.appendChild(span);
|
|
145
151
|
|
|
@@ -191,6 +197,37 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
191
197
|
}
|
|
192
198
|
|
|
193
199
|
|
|
200
|
+
/**
|
|
201
|
+
* @param {!shaka.extern.Track} track
|
|
202
|
+
* @return {string}
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
getResolutionLabel_(track) {
|
|
206
|
+
const trackHeight = track.height || 0;
|
|
207
|
+
const trackWidth = track.width || 0;
|
|
208
|
+
let height = trackHeight;
|
|
209
|
+
const aspectRatio = trackWidth / trackHeight;
|
|
210
|
+
if (aspectRatio > (16 / 9)) {
|
|
211
|
+
height = Math.round(trackWidth * 9 / 16);
|
|
212
|
+
}
|
|
213
|
+
let text = height + 'p';
|
|
214
|
+
if (height == 2160) {
|
|
215
|
+
text = '4K';
|
|
216
|
+
}
|
|
217
|
+
const frameRate = track.frameRate;
|
|
218
|
+
if (frameRate && (frameRate >= 50 || frameRate <= 20)) {
|
|
219
|
+
text += Math.round(track.frameRate);
|
|
220
|
+
}
|
|
221
|
+
if (track.hdr == 'PQ' || track.hdr == 'HLG') {
|
|
222
|
+
text += ' (HDR)';
|
|
223
|
+
}
|
|
224
|
+
if (track.videoLayout == 'CH-STEREO') {
|
|
225
|
+
text += ' (3D)';
|
|
226
|
+
}
|
|
227
|
+
return text;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
194
231
|
/**
|
|
195
232
|
* @param {!shaka.extern.Track} track
|
|
196
233
|
* @private
|