shaka-player 4.5.0 → 4.6.1
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 +109 -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 +34 -30
- 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 +789 -738
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +162 -77
- package/dist/shaka-player.compiled.js +1147 -1113
- 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 +857 -791
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +167 -77
- package/dist/shaka-player.ui.js +1359 -1314
- 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 +251 -84
- 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 +92 -29
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +770 -652
- 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 +72 -44
- 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 +998 -1503
- 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 +417 -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
|
@@ -2611,8 +2611,8 @@ describe('DashParser Manifest', () => {
|
|
|
2611
2611
|
'<MPD minBufferTime="PT75S" type="dynamic"',
|
|
2612
2612
|
' availabilityStartTime="1970-01-01T00:00:00Z">',
|
|
2613
2613
|
' <ServiceDescription id="0">',
|
|
2614
|
-
' <Latency max="2000" min="
|
|
2615
|
-
' <PlaybackRate max="1.10" min="0.
|
|
2614
|
+
' <Latency max="2000" min="1000" referenceId="0" target="4000" />',
|
|
2615
|
+
' <PlaybackRate max="1.10" min="0.95" />',
|
|
2616
2616
|
' </ServiceDescription>',
|
|
2617
2617
|
'</MPD>',
|
|
2618
2618
|
].join('\n');
|
|
@@ -2624,6 +2624,498 @@ describe('DashParser Manifest', () => {
|
|
|
2624
2624
|
|
|
2625
2625
|
expect(manifest.serviceDescription.maxLatency).toBe(2);
|
|
2626
2626
|
expect(manifest.serviceDescription.maxPlaybackRate).toBe(1.1);
|
|
2627
|
+
expect(manifest.serviceDescription.minLatency).toBe(1);
|
|
2628
|
+
expect(manifest.serviceDescription.minPlaybackRate).toBe(0.95);
|
|
2629
|
+
});
|
|
2630
|
+
});
|
|
2631
|
+
|
|
2632
|
+
it('parses urn:mpeg:dash:ssr:2023', async () => { // eslint-disable-line max-len
|
|
2633
|
+
const manifestText = [
|
|
2634
|
+
'<MPD minBufferTime="PT75S">',
|
|
2635
|
+
' <Period id="1" duration="PT30S">',
|
|
2636
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
2637
|
+
' <Representation bandwidth="2" codecs="avc1.4d401f"',
|
|
2638
|
+
' height="1080" width="1920">',
|
|
2639
|
+
' <SegmentTemplate startNumber="1" media="l2-$Number$.mp4"',
|
|
2640
|
+
' initialization="init.mp4" timescale="50" duration="100">',
|
|
2641
|
+
' <SegmentTimeline>',
|
|
2642
|
+
' <S t="0" d="100"/>',
|
|
2643
|
+
' <S d="100"/>',
|
|
2644
|
+
' </SegmentTimeline>',
|
|
2645
|
+
' </SegmentTemplate>',
|
|
2646
|
+
' </Representation>',
|
|
2647
|
+
' </AdaptationSet>',
|
|
2648
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2649
|
+
' <EssentialProperty value="video_primary" ',
|
|
2650
|
+
' schemeIdUri="urn:mpeg:dash:ssr:2023" />',
|
|
2651
|
+
' <Representation bandwidth="1" codecs="avc1.4d401f"',
|
|
2652
|
+
' height="720" width="1280">',
|
|
2653
|
+
' <SegmentTemplate startNumber="1"',
|
|
2654
|
+
' media="l-$Number$-p$SubNumber$.mp4"',
|
|
2655
|
+
' initialization="init.mp4" timescale="50" duration="100">',
|
|
2656
|
+
' <SegmentTimeline>',
|
|
2657
|
+
' <S t="0" d="100" k="4"/>',
|
|
2658
|
+
' <S d="100" k="4"/>',
|
|
2659
|
+
' </SegmentTimeline>',
|
|
2660
|
+
' </SegmentTemplate>',
|
|
2661
|
+
' </Representation>',
|
|
2662
|
+
' </AdaptationSet>',
|
|
2663
|
+
' </Period>',
|
|
2664
|
+
'</MPD>',
|
|
2665
|
+
].join('\n');
|
|
2666
|
+
|
|
2667
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2668
|
+
/** @type {shaka.extern.Manifest} */
|
|
2669
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2670
|
+
expect(manifest.variants.length).toBe(2);
|
|
2671
|
+
|
|
2672
|
+
const normalStream = manifest.variants[0].video;
|
|
2673
|
+
expect(normalStream.width).toBe(1920);
|
|
2674
|
+
expect(normalStream.height).toBe(1080);
|
|
2675
|
+
expect(normalStream.fastSwitching).toBe(false);
|
|
2676
|
+
await normalStream.createSegmentIndex();
|
|
2677
|
+
goog.asserts.assert(normalStream.segmentIndex != null,
|
|
2678
|
+
'Null segmentIndex!');
|
|
2679
|
+
|
|
2680
|
+
const firstNormalReference = normalStream.segmentIndex.get(0);
|
|
2681
|
+
expect(firstNormalReference.partialReferences.length).toBe(0);
|
|
2682
|
+
|
|
2683
|
+
const stream = manifest.variants[1].video;
|
|
2684
|
+
expect(stream.width).toBe(1280);
|
|
2685
|
+
expect(stream.height).toBe(720);
|
|
2686
|
+
expect(stream.fastSwitching).toBe(true);
|
|
2687
|
+
await stream.createSegmentIndex();
|
|
2688
|
+
goog.asserts.assert(stream.segmentIndex != null,
|
|
2689
|
+
'Null segmentIndex!');
|
|
2690
|
+
|
|
2691
|
+
const firstReference = stream.segmentIndex.get(0);
|
|
2692
|
+
expect(firstReference.partialReferences.length).toBe(4);
|
|
2693
|
+
});
|
|
2694
|
+
|
|
2695
|
+
describe('parses partial segments correctly', () => {
|
|
2696
|
+
it('whitout cadence', async () => {
|
|
2697
|
+
const manifestText = [
|
|
2698
|
+
'<MPD minBufferTime="PT75S">',
|
|
2699
|
+
' <Period id="1" duration="PT30S">',
|
|
2700
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
2701
|
+
' <Representation bandwidth="1" codecs="avc1.4d401f">',
|
|
2702
|
+
' <SegmentTemplate startNumber="1"',
|
|
2703
|
+
' media="l-$Number$-p$SubNumber$.mp4"',
|
|
2704
|
+
' initialization="init.mp4" timescale="50" duration="100">',
|
|
2705
|
+
' <SegmentTimeline>',
|
|
2706
|
+
' <S t="0" d="100" k="4"/>',
|
|
2707
|
+
' <S d="100" k="4"/>',
|
|
2708
|
+
' </SegmentTimeline>',
|
|
2709
|
+
' </SegmentTemplate>',
|
|
2710
|
+
' </Representation>',
|
|
2711
|
+
' </AdaptationSet>',
|
|
2712
|
+
' </Period>',
|
|
2713
|
+
'</MPD>',
|
|
2714
|
+
].join('\n');
|
|
2715
|
+
|
|
2716
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2717
|
+
/** @type {shaka.extern.Manifest} */
|
|
2718
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2719
|
+
const stream = manifest.variants[0].video;
|
|
2720
|
+
await stream.createSegmentIndex();
|
|
2721
|
+
goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
|
|
2722
|
+
|
|
2723
|
+
const firstReference = stream.segmentIndex.get(0);
|
|
2724
|
+
expect(firstReference.startTime).toBe(0);
|
|
2725
|
+
expect(firstReference.endTime).toBe(2);
|
|
2726
|
+
expect(firstReference.getUris()).toEqual([]);
|
|
2727
|
+
expect(firstReference.partialReferences.length).toBe(4);
|
|
2728
|
+
const firstPartialReference = firstReference.partialReferences[0];
|
|
2729
|
+
expect(firstPartialReference.startTime).toBe(0);
|
|
2730
|
+
expect(firstPartialReference.endTime).toBe(0.5);
|
|
2731
|
+
expect(firstPartialReference.getUris())
|
|
2732
|
+
.toEqual(['dummy://foo/l-1-p1.mp4']);
|
|
2733
|
+
const secondPartialReference = firstReference.partialReferences[1];
|
|
2734
|
+
expect(secondPartialReference.startTime).toBe(0.5);
|
|
2735
|
+
expect(secondPartialReference.endTime).toBe(1);
|
|
2736
|
+
expect(secondPartialReference.getUris())
|
|
2737
|
+
.toEqual(['dummy://foo/l-1-p2.mp4']);
|
|
2738
|
+
const thirdPartialReference = firstReference.partialReferences[2];
|
|
2739
|
+
expect(thirdPartialReference.startTime).toBe(1);
|
|
2740
|
+
expect(thirdPartialReference.endTime).toBe(1.5);
|
|
2741
|
+
expect(thirdPartialReference.getUris())
|
|
2742
|
+
.toEqual(['dummy://foo/l-1-p3.mp4']);
|
|
2743
|
+
const fourthPartialReference = firstReference.partialReferences[3];
|
|
2744
|
+
expect(fourthPartialReference.startTime).toBe(1.5);
|
|
2745
|
+
expect(fourthPartialReference.endTime).toBe(2);
|
|
2746
|
+
expect(fourthPartialReference.getUris())
|
|
2747
|
+
.toEqual(['dummy://foo/l-1-p4.mp4']);
|
|
2748
|
+
});
|
|
2749
|
+
|
|
2750
|
+
it('with cadence equal to 1', async () => {
|
|
2751
|
+
const manifestText = [
|
|
2752
|
+
'<MPD minBufferTime="PT75S">',
|
|
2753
|
+
' <Period id="1" duration="PT30S">',
|
|
2754
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
2755
|
+
' <Representation bandwidth="1" codecs="avc1.4d401f">',
|
|
2756
|
+
' <SegmentTemplate startNumber="1"',
|
|
2757
|
+
' media="l-$Number$-p$SubNumber$.mp4"',
|
|
2758
|
+
' initialization="init.mp4" timescale="50" duration="100">',
|
|
2759
|
+
' <SegmentTimeline>',
|
|
2760
|
+
' <S t="0" d="100" k="4"/>',
|
|
2761
|
+
' <S d="100" k="4"/>',
|
|
2762
|
+
' </SegmentTimeline>',
|
|
2763
|
+
' </SegmentTemplate>',
|
|
2764
|
+
' <SegmentSequenceProperties>',
|
|
2765
|
+
' <SAP type="1" cadence="1" />',
|
|
2766
|
+
' </SegmentSequenceProperties>',
|
|
2767
|
+
' </Representation>',
|
|
2768
|
+
' </AdaptationSet>',
|
|
2769
|
+
' </Period>',
|
|
2770
|
+
'</MPD>',
|
|
2771
|
+
].join('\n');
|
|
2772
|
+
|
|
2773
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2774
|
+
/** @type {shaka.extern.Manifest} */
|
|
2775
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2776
|
+
const stream = manifest.variants[0].video;
|
|
2777
|
+
await stream.createSegmentIndex();
|
|
2778
|
+
goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
|
|
2779
|
+
|
|
2780
|
+
const firstReference = stream.segmentIndex.get(0);
|
|
2781
|
+
const firstPartialReference = firstReference.partialReferences[0];
|
|
2782
|
+
expect(firstPartialReference.isIndependent()).toBeTruthy();
|
|
2783
|
+
const secondPartialReference = firstReference.partialReferences[1];
|
|
2784
|
+
expect(secondPartialReference.isIndependent()).toBeTruthy();
|
|
2785
|
+
const thirdPartialReference = firstReference.partialReferences[2];
|
|
2786
|
+
expect(thirdPartialReference.isIndependent()).toBeTruthy();
|
|
2787
|
+
const fourthPartialReference = firstReference.partialReferences[3];
|
|
2788
|
+
expect(fourthPartialReference.isIndependent()).toBeTruthy();
|
|
2789
|
+
});
|
|
2790
|
+
|
|
2791
|
+
it('with cadence equal to 2', async () => {
|
|
2792
|
+
const manifestText = [
|
|
2793
|
+
'<MPD minBufferTime="PT75S">',
|
|
2794
|
+
' <Period id="1" duration="PT30S">',
|
|
2795
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
2796
|
+
' <Representation bandwidth="1" codecs="avc1.4d401f">',
|
|
2797
|
+
' <SegmentTemplate startNumber="1"',
|
|
2798
|
+
' media="l-$Number$-p$SubNumber$.mp4"',
|
|
2799
|
+
' initialization="init.mp4" timescale="50" duration="100">',
|
|
2800
|
+
' <SegmentTimeline>',
|
|
2801
|
+
' <S t="0" d="100" k="4"/>',
|
|
2802
|
+
' <S d="100" k="4"/>',
|
|
2803
|
+
' </SegmentTimeline>',
|
|
2804
|
+
' </SegmentTemplate>',
|
|
2805
|
+
' <SegmentSequenceProperties>',
|
|
2806
|
+
' <SAP type="1" cadence="2" />',
|
|
2807
|
+
' </SegmentSequenceProperties>',
|
|
2808
|
+
' </Representation>',
|
|
2809
|
+
' </AdaptationSet>',
|
|
2810
|
+
' </Period>',
|
|
2811
|
+
'</MPD>',
|
|
2812
|
+
].join('\n');
|
|
2813
|
+
|
|
2814
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2815
|
+
/** @type {shaka.extern.Manifest} */
|
|
2816
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2817
|
+
const stream = manifest.variants[0].video;
|
|
2818
|
+
await stream.createSegmentIndex();
|
|
2819
|
+
goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
|
|
2820
|
+
|
|
2821
|
+
const firstReference = stream.segmentIndex.get(0);
|
|
2822
|
+
const firstPartialReference = firstReference.partialReferences[0];
|
|
2823
|
+
expect(firstPartialReference.isIndependent()).toBeTruthy();
|
|
2824
|
+
const secondPartialReference = firstReference.partialReferences[1];
|
|
2825
|
+
expect(secondPartialReference.isIndependent()).toBeFalsy();
|
|
2826
|
+
const thirdPartialReference = firstReference.partialReferences[2];
|
|
2827
|
+
expect(thirdPartialReference.isIndependent()).toBeTruthy();
|
|
2828
|
+
const fourthPartialReference = firstReference.partialReferences[3];
|
|
2829
|
+
expect(fourthPartialReference.isIndependent()).toBeFalsy();
|
|
2830
|
+
});
|
|
2831
|
+
});
|
|
2832
|
+
|
|
2833
|
+
describe('supports ContentSteering', () => {
|
|
2834
|
+
it('with defaultServiceLocation', async () => {
|
|
2835
|
+
const manifestText = [
|
|
2836
|
+
'<MPD type="static">',
|
|
2837
|
+
' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
|
|
2838
|
+
' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
|
|
2839
|
+
' <ContentSteering defaultServiceLocation="a,b" ',
|
|
2840
|
+
'queryBeforeStart="true">http://contentsteering</ContentSteering>',
|
|
2841
|
+
' <Period id="1" duration="PT30S">',
|
|
2842
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2843
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
2844
|
+
' <SegmentTimeline>',
|
|
2845
|
+
' <S t="0" d="30" />',
|
|
2846
|
+
' </SegmentTimeline>',
|
|
2847
|
+
' </SegmentTemplate>',
|
|
2848
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
2849
|
+
' </Representation>',
|
|
2850
|
+
' </AdaptationSet>',
|
|
2851
|
+
' </Period>',
|
|
2852
|
+
'</MPD>',
|
|
2853
|
+
].join('\n');
|
|
2854
|
+
|
|
2855
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2856
|
+
|
|
2857
|
+
const contentSteering = JSON.stringify({
|
|
2858
|
+
'VERSION': 1,
|
|
2859
|
+
'TTL': 1,
|
|
2860
|
+
'RELOAD-URI': 'http://contentsteering/update',
|
|
2861
|
+
'PATHWAY-PRIORITY': [],
|
|
2862
|
+
});
|
|
2863
|
+
|
|
2864
|
+
fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
|
|
2865
|
+
|
|
2866
|
+
/** @type {shaka.extern.Manifest} */
|
|
2867
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2868
|
+
|
|
2869
|
+
const video0 = manifest.variants[0].video;
|
|
2870
|
+
await video0.createSegmentIndex();
|
|
2871
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
2872
|
+
const segment0 = Array.from(video0.segmentIndex)[0];
|
|
2873
|
+
const uri0 = segment0.getUris()[0];
|
|
2874
|
+
const uri1 = segment0.getUris()[1];
|
|
2875
|
+
|
|
2876
|
+
expect(uri0).toBe('http://example.com/r0/1.mp4');
|
|
2877
|
+
expect(uri1).toBe('http://example.com/r1/1.mp4');
|
|
2878
|
+
});
|
|
2879
|
+
|
|
2880
|
+
it('without defaultServiceLocation', async () => {
|
|
2881
|
+
const manifestText = [
|
|
2882
|
+
'<MPD type="static">',
|
|
2883
|
+
' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
|
|
2884
|
+
' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
|
|
2885
|
+
' <ContentSteering',
|
|
2886
|
+
'queryBeforeStart="true">http://contentsteering</ContentSteering>',
|
|
2887
|
+
' <Period id="1" duration="PT30S">',
|
|
2888
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2889
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
2890
|
+
' <SegmentTimeline>',
|
|
2891
|
+
' <S t="0" d="30" />',
|
|
2892
|
+
' </SegmentTimeline>',
|
|
2893
|
+
' </SegmentTemplate>',
|
|
2894
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
2895
|
+
' </Representation>',
|
|
2896
|
+
' </AdaptationSet>',
|
|
2897
|
+
' </Period>',
|
|
2898
|
+
'</MPD>',
|
|
2899
|
+
].join('\n');
|
|
2900
|
+
|
|
2901
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2902
|
+
|
|
2903
|
+
const contentSteering = JSON.stringify({
|
|
2904
|
+
'VERSION': 1,
|
|
2905
|
+
'TTL': 1,
|
|
2906
|
+
'RELOAD-URI': 'http://contentsteering/update',
|
|
2907
|
+
'PATHWAY-PRIORITY': [
|
|
2908
|
+
'b',
|
|
2909
|
+
'a',
|
|
2910
|
+
],
|
|
2911
|
+
});
|
|
2912
|
+
|
|
2913
|
+
fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
|
|
2914
|
+
|
|
2915
|
+
/** @type {shaka.extern.Manifest} */
|
|
2916
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2917
|
+
|
|
2918
|
+
const video0 = manifest.variants[0].video;
|
|
2919
|
+
await video0.createSegmentIndex();
|
|
2920
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
2921
|
+
const segment0 = Array.from(video0.segmentIndex)[0];
|
|
2922
|
+
const uri0 = segment0.getUris()[0];
|
|
2923
|
+
const uri1 = segment0.getUris()[1];
|
|
2924
|
+
|
|
2925
|
+
expect(uri0).toBe('http://example.com/r1/1.mp4');
|
|
2926
|
+
expect(uri1).toBe('http://example.com/r0/1.mp4');
|
|
2927
|
+
});
|
|
2928
|
+
|
|
2929
|
+
it('with queryBeforeStart', async () => {
|
|
2930
|
+
const manifestText = [
|
|
2931
|
+
'<MPD type="static">',
|
|
2932
|
+
' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
|
|
2933
|
+
' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
|
|
2934
|
+
' <ContentSteering defaultServiceLocation="b" ',
|
|
2935
|
+
'queryBeforeStart="true">http://contentsteering</ContentSteering>',
|
|
2936
|
+
' <Period id="1" duration="PT30S">',
|
|
2937
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2938
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
2939
|
+
' <SegmentTimeline>',
|
|
2940
|
+
' <S t="0" d="30" />',
|
|
2941
|
+
' </SegmentTimeline>',
|
|
2942
|
+
' </SegmentTemplate>',
|
|
2943
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
2944
|
+
' </Representation>',
|
|
2945
|
+
' </AdaptationSet>',
|
|
2946
|
+
' </Period>',
|
|
2947
|
+
'</MPD>',
|
|
2948
|
+
].join('\n');
|
|
2949
|
+
|
|
2950
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2951
|
+
|
|
2952
|
+
const contentSteering = JSON.stringify({
|
|
2953
|
+
'VERSION': 1,
|
|
2954
|
+
'TTL': 1,
|
|
2955
|
+
'RELOAD-URI': 'http://contentsteering/update',
|
|
2956
|
+
'PATHWAY-PRIORITY': [
|
|
2957
|
+
'a',
|
|
2958
|
+
],
|
|
2959
|
+
});
|
|
2960
|
+
|
|
2961
|
+
fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
|
|
2962
|
+
|
|
2963
|
+
/** @type {shaka.extern.Manifest} */
|
|
2964
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2965
|
+
|
|
2966
|
+
const video0 = manifest.variants[0].video;
|
|
2967
|
+
await video0.createSegmentIndex();
|
|
2968
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
2969
|
+
const segment0 = Array.from(video0.segmentIndex)[0];
|
|
2970
|
+
expect(segment0.getUris().length).toBe(1);
|
|
2971
|
+
const uri0 = segment0.getUris()[0];
|
|
2972
|
+
|
|
2973
|
+
expect(uri0).toBe('http://example.com/r0/1.mp4');
|
|
2974
|
+
});
|
|
2975
|
+
|
|
2976
|
+
it('without queryBeforeStart', async () => {
|
|
2977
|
+
const manifestText = [
|
|
2978
|
+
'<MPD type="static">',
|
|
2979
|
+
' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
|
|
2980
|
+
' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
|
|
2981
|
+
' <ContentSteering defaultServiceLocation="b">',
|
|
2982
|
+
'http://contentsteering</ContentSteering>',
|
|
2983
|
+
' <Period id="1" duration="PT30S">',
|
|
2984
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2985
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
2986
|
+
' <SegmentTimeline>',
|
|
2987
|
+
' <S t="0" d="30" />',
|
|
2988
|
+
' </SegmentTimeline>',
|
|
2989
|
+
' </SegmentTemplate>',
|
|
2990
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
2991
|
+
' </Representation>',
|
|
2992
|
+
' </AdaptationSet>',
|
|
2993
|
+
' </Period>',
|
|
2994
|
+
'</MPD>',
|
|
2995
|
+
].join('\n');
|
|
2996
|
+
|
|
2997
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2998
|
+
|
|
2999
|
+
fakeNetEngine.setResponseText('http://contentsteering', 'foo');
|
|
3000
|
+
|
|
3001
|
+
/** @type {shaka.extern.Manifest} */
|
|
3002
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
3003
|
+
|
|
3004
|
+
const video0 = manifest.variants[0].video;
|
|
3005
|
+
await video0.createSegmentIndex();
|
|
3006
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
3007
|
+
const segment0 = Array.from(video0.segmentIndex)[0];
|
|
3008
|
+
expect(segment0.getUris().length).toBe(1);
|
|
3009
|
+
const uri0 = segment0.getUris()[0];
|
|
3010
|
+
|
|
3011
|
+
expect(uri0).toBe('http://example.com/r1/1.mp4');
|
|
3012
|
+
});
|
|
3013
|
+
|
|
3014
|
+
it('without serviceLocation in BaseURL', async () => {
|
|
3015
|
+
const manifestText = [
|
|
3016
|
+
'<MPD type="static">',
|
|
3017
|
+
' <BaseURL>http://example.com/r0/</BaseURL>',
|
|
3018
|
+
' <BaseURL>http://example.com/r1/</BaseURL>',
|
|
3019
|
+
' <ContentSteering',
|
|
3020
|
+
'queryBeforeStart="true">http://contentsteering</ContentSteering>',
|
|
3021
|
+
' <Period id="1" duration="PT30S">',
|
|
3022
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
3023
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
3024
|
+
' <SegmentTimeline>',
|
|
3025
|
+
' <S t="0" d="30" />',
|
|
3026
|
+
' </SegmentTimeline>',
|
|
3027
|
+
' </SegmentTemplate>',
|
|
3028
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
3029
|
+
' </Representation>',
|
|
3030
|
+
' </AdaptationSet>',
|
|
3031
|
+
' </Period>',
|
|
3032
|
+
'</MPD>',
|
|
3033
|
+
].join('\n');
|
|
3034
|
+
|
|
3035
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
3036
|
+
|
|
3037
|
+
fakeNetEngine.setResponseText('http://contentsteering', 'foo');
|
|
3038
|
+
|
|
3039
|
+
/** @type {shaka.extern.Manifest} */
|
|
3040
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
3041
|
+
|
|
3042
|
+
const video0 = manifest.variants[0].video;
|
|
3043
|
+
await video0.createSegmentIndex();
|
|
3044
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
3045
|
+
const segment0 = Array.from(video0.segmentIndex)[0];
|
|
3046
|
+
const uri0 = segment0.getUris()[0];
|
|
3047
|
+
const uri1 = segment0.getUris()[1];
|
|
3048
|
+
|
|
3049
|
+
expect(uri0).toBe('http://example.com/r0/1.mp4');
|
|
3050
|
+
expect(uri1).toBe('http://example.com/r1/1.mp4');
|
|
3051
|
+
});
|
|
3052
|
+
|
|
3053
|
+
it('specify MPD BaseURL and AdaptationSet BaseURL', async () => {
|
|
3054
|
+
const manifestText = [
|
|
3055
|
+
'<MPD type="static">',
|
|
3056
|
+
' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
|
|
3057
|
+
' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
|
|
3058
|
+
' <ContentSteering defaultServiceLocation="a,b" ',
|
|
3059
|
+
'queryBeforeStart="true">http://contentsteering</ContentSteering>',
|
|
3060
|
+
' <Period id="1" duration="PT30S">',
|
|
3061
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
3062
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
3063
|
+
' <SegmentTimeline>',
|
|
3064
|
+
' <S t="0" d="30" />',
|
|
3065
|
+
' </SegmentTimeline>',
|
|
3066
|
+
' </SegmentTemplate>',
|
|
3067
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
3068
|
+
' </Representation>',
|
|
3069
|
+
' </AdaptationSet>',
|
|
3070
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
3071
|
+
' <BaseURL serviceLocation="c">http://example.foo/r0/</BaseURL>',
|
|
3072
|
+
' <BaseURL serviceLocation="d">http://example.foo/r1/</BaseURL>',
|
|
3073
|
+
' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
|
|
3074
|
+
' <SegmentTimeline>',
|
|
3075
|
+
' <S t="0" d="30" />',
|
|
3076
|
+
' </SegmentTimeline>',
|
|
3077
|
+
' </SegmentTemplate>',
|
|
3078
|
+
' <Representation id="audio">',
|
|
3079
|
+
' </Representation>',
|
|
3080
|
+
' </AdaptationSet>',
|
|
3081
|
+
' </Period>',
|
|
3082
|
+
'</MPD>',
|
|
3083
|
+
].join('\n');
|
|
3084
|
+
|
|
3085
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
3086
|
+
|
|
3087
|
+
const contentSteering = JSON.stringify({
|
|
3088
|
+
'VERSION': 1,
|
|
3089
|
+
'TTL': 1,
|
|
3090
|
+
'RELOAD-URI': 'http://contentsteering/update',
|
|
3091
|
+
'PATHWAY-PRIORITY': [
|
|
3092
|
+
'a',
|
|
3093
|
+
'c',
|
|
3094
|
+
],
|
|
3095
|
+
});
|
|
3096
|
+
|
|
3097
|
+
fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
|
|
3098
|
+
|
|
3099
|
+
/** @type {shaka.extern.Manifest} */
|
|
3100
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
3101
|
+
|
|
3102
|
+
const video0 = manifest.variants[0].video;
|
|
3103
|
+
await video0.createSegmentIndex();
|
|
3104
|
+
goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
|
|
3105
|
+
const videoSegment0 = Array.from(video0.segmentIndex)[0];
|
|
3106
|
+
expect(videoSegment0.getUris().length).toBe(1);
|
|
3107
|
+
const videoUri0 = videoSegment0.getUris()[0];
|
|
3108
|
+
|
|
3109
|
+
expect(videoUri0).toBe('http://example.com/r0/1.mp4');
|
|
3110
|
+
|
|
3111
|
+
const audio0 = manifest.variants[0].audio;
|
|
3112
|
+
await audio0.createSegmentIndex();
|
|
3113
|
+
goog.asserts.assert(audio0.segmentIndex, 'Null segmentIndex!');
|
|
3114
|
+
const audioSegment0 = Array.from(audio0.segmentIndex)[0];
|
|
3115
|
+
expect(audioSegment0.getUris().length).toBe(1);
|
|
3116
|
+
const audioUri0 = audioSegment0.getUris()[0];
|
|
3117
|
+
|
|
3118
|
+
expect(audioUri0).toBe('http://example.foo/r0/1.mp4');
|
|
2627
3119
|
});
|
|
2628
3120
|
});
|
|
2629
3121
|
});
|