shaka-player 4.4.2 → 4.5.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/workflows/release-please.yaml +2 -27
- package/CHANGELOG.md +67 -25
- package/README.md +16 -10
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +27 -5
- package/demo/common/assets.js +150 -52
- package/demo/config.js +192 -253
- package/demo/custom.js +39 -98
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +52 -124
- package/demo/search.js +23 -35
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/demo.compiled.debug.js +187 -211
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +187 -211
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +27 -24
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +42 -61
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +42 -61
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.externs.js +475 -51
- package/dist/shaka-player.compiled.debug.js +576 -480
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +475 -51
- package/dist/shaka-player.compiled.js +1117 -1056
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +783 -410
- package/dist/shaka-player.ui.debug.d.ts +783 -410
- package/dist/shaka-player.ui.debug.externs.js +496 -51
- package/dist/shaka-player.ui.debug.js +647 -542
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +496 -51
- package/dist/shaka-player.ui.js +1260 -1194
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +1 -1
- package/docs/tutorials/ui-customization.md +4 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/manifest.js +10 -5
- package/externs/shaka/manifest_parser.js +7 -1
- package/externs/shaka/offline.js +4 -0
- package/externs/shaka/player.js +12 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +43 -3
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +828 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +79 -13
- package/lib/dash/mpd_utils.js +10 -6
- package/lib/dash/segment_base.js +13 -5
- package/lib/dash/segment_list.js +13 -5
- package/lib/dash/segment_template.js +43 -85
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_parser.js +101 -37
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +22 -11
- package/lib/media/adaptation_set_criteria.js +25 -7
- package/lib/media/media_source_engine.js +215 -27
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_reference.js +10 -5
- package/lib/media/streaming_engine.js +44 -39
- package/lib/mss/mss_parser.js +1 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +3 -0
- package/lib/player.js +142 -72
- package/lib/routing/payload.js +5 -1
- package/lib/text/cue.js +62 -47
- package/lib/text/ttml_text_parser.js +17 -0
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +35 -22
- package/lib/transmuxer/h265.js +862 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
- package/lib/transmuxer/ts_transmuxer.js +160 -15
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/error.js +28 -9
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fake_event.js +3 -0
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/mp4_generator.js +4 -4
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +54 -0
- package/lib/util/player_configuration.js +8 -0
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +133 -217
- package/lib/util/ts_parser.js +229 -43
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +2 -1
- package/support.html +0 -1
- package/test/cast/cast_receiver_integration.js +47 -0
- package/test/codec_switching/codec_switching_integration.js +181 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +73 -0
- package/test/dash/dash_parser_live_unit.js +2 -0
- package/test/dash/dash_parser_manifest_unit.js +47 -0
- package/test/dash/dash_parser_segment_base_unit.js +7 -0
- package/test/dash/dash_parser_segment_list_unit.js +23 -17
- package/test/dash/dash_parser_segment_template_unit.js +49 -0
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +35 -0
- package/test/hls/hls_parser_unit.js +8 -61
- package/test/media/adaptation_set_criteria_unit.js +118 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/media_source_engine_unit.js +165 -1
- package/test/media/segment_index_unit.js +4 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/storage_integration.js +1 -4
- package/test/player_unit.js +102 -131
- package/test/routing/walker_unit.js +1 -0
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +20 -7
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +8 -2
- package/test/test/util/manifest_generator.js +7 -3
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +7 -4
- package/test/text/ttml_text_parser_unit.js +52 -0
- package/test/text/vtt_text_parser_unit.js +105 -48
- package/test/transmuxer/transmuxer_integration.js +121 -4
- package/test/ui/ui_unit.js +3 -10
- package/test/util/stream_utils_unit.js +208 -74
- package/test/util/ts_parser_unit.js +1 -1
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +8 -1
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +201 -0
- package/ui/ui.js +5 -2
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -287
- package/demo/locales/source.json +0 -1142
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('Codec Switching', () => {
|
|
8
|
+
/** @type {!HTMLVideoElement} */
|
|
9
|
+
let video;
|
|
10
|
+
/** @type {shaka.Player} */
|
|
11
|
+
let player;
|
|
12
|
+
/** @type {!shaka.util.EventManager} */
|
|
13
|
+
let eventManager;
|
|
14
|
+
|
|
15
|
+
let compiledShaka;
|
|
16
|
+
|
|
17
|
+
/** @type {!shaka.test.Waiter} */
|
|
18
|
+
let waiter;
|
|
19
|
+
|
|
20
|
+
beforeAll(async () => {
|
|
21
|
+
video = shaka.test.UiUtils.createVideoElement();
|
|
22
|
+
document.body.appendChild(video);
|
|
23
|
+
compiledShaka =
|
|
24
|
+
await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
|
|
29
|
+
player = new compiledShaka.Player(video);
|
|
30
|
+
|
|
31
|
+
// Disable stall detection, which can interfere with playback tests.
|
|
32
|
+
player.configure('streaming.stallEnabled', false);
|
|
33
|
+
|
|
34
|
+
eventManager = new shaka.util.EventManager();
|
|
35
|
+
waiter = new shaka.test.Waiter(eventManager);
|
|
36
|
+
waiter.setPlayer(player);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(async () => {
|
|
40
|
+
eventManager.release();
|
|
41
|
+
await player.destroy();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
document.body.removeChild(video);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('for audio and only-audio content', () => {
|
|
49
|
+
it('can switch codecs RELOAD', async () => {
|
|
50
|
+
if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
|
|
51
|
+
pending('Codec OPUS in WEBM is not supported by the platform.');
|
|
52
|
+
}
|
|
53
|
+
const preferredAudioLanguage = 'en';
|
|
54
|
+
player.configure({preferredAudioLanguage: preferredAudioLanguage});
|
|
55
|
+
player.configure('manifest.disableVideo', true);
|
|
56
|
+
player.configure('streaming.mediaSource.codecSwitchingStrategy',
|
|
57
|
+
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
58
|
+
|
|
59
|
+
await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
|
|
60
|
+
await video.play();
|
|
61
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
62
|
+
|
|
63
|
+
expect(player.isLive()).toBe(false);
|
|
64
|
+
|
|
65
|
+
let variants = player.getVariantTracks();
|
|
66
|
+
|
|
67
|
+
expect(variants.length).toBe(2);
|
|
68
|
+
expect(variants.find((v) => !!v.active).language).toBe('en');
|
|
69
|
+
|
|
70
|
+
player.selectAudioLanguage('es');
|
|
71
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
|
|
72
|
+
|
|
73
|
+
variants = player.getVariantTracks();
|
|
74
|
+
|
|
75
|
+
expect(variants.find((v) => !!v.active).language).toBe('es');
|
|
76
|
+
|
|
77
|
+
await player.unload();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('can switch codecs SMOOTH', async () => {
|
|
81
|
+
if (!shaka.util.Platform.supportsSmoothCodecSwitching()) {
|
|
82
|
+
pending('Mediasource.ChangeType is not considered ' +
|
|
83
|
+
'reliable on this device');
|
|
84
|
+
}
|
|
85
|
+
if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
|
|
86
|
+
pending('Codec OPUS in WEBM is not supported by the platform.');
|
|
87
|
+
}
|
|
88
|
+
const preferredAudioLanguage = 'en';
|
|
89
|
+
player.configure({preferredAudioLanguage: preferredAudioLanguage});
|
|
90
|
+
player.configure('manifest.disableVideo', true);
|
|
91
|
+
player.configure('streaming.mediaSource.codecSwitchingStrategy',
|
|
92
|
+
shaka.config.CodecSwitchingStrategy.SMOOTH);
|
|
93
|
+
|
|
94
|
+
await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
|
|
95
|
+
await video.play();
|
|
96
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
97
|
+
|
|
98
|
+
expect(player.isLive()).toBe(false);
|
|
99
|
+
|
|
100
|
+
let variants = player.getVariantTracks();
|
|
101
|
+
|
|
102
|
+
expect(variants.length).toBe(2);
|
|
103
|
+
expect(variants.find((v) => !!v.active).language).toBe('en');
|
|
104
|
+
|
|
105
|
+
player.selectAudioLanguage('es');
|
|
106
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
|
|
107
|
+
|
|
108
|
+
variants = player.getVariantTracks();
|
|
109
|
+
|
|
110
|
+
expect(variants.find((v) => !!v.active).language).toBe('es');
|
|
111
|
+
|
|
112
|
+
await player.unload();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('for audio', () => {
|
|
117
|
+
it('can switch codecs RELOAD', async () => {
|
|
118
|
+
if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
|
|
119
|
+
pending('Codec OPUS in WEBM is not supported by the platform.');
|
|
120
|
+
}
|
|
121
|
+
const preferredAudioLanguage = 'en';
|
|
122
|
+
player.configure({preferredAudioLanguage: preferredAudioLanguage});
|
|
123
|
+
player.configure('streaming.mediaSource.codecSwitchingStrategy',
|
|
124
|
+
shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
125
|
+
|
|
126
|
+
await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
|
|
127
|
+
await video.play();
|
|
128
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
129
|
+
|
|
130
|
+
expect(player.isLive()).toBe(false);
|
|
131
|
+
|
|
132
|
+
let variants = player.getVariantTracks();
|
|
133
|
+
|
|
134
|
+
expect(variants.length).toBe(2);
|
|
135
|
+
expect(variants.find((v) => !!v.active).language).toBe('en');
|
|
136
|
+
|
|
137
|
+
player.selectAudioLanguage('es');
|
|
138
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
|
|
139
|
+
|
|
140
|
+
variants = player.getVariantTracks();
|
|
141
|
+
|
|
142
|
+
expect(variants.find((v) => !!v.active).language).toBe('es');
|
|
143
|
+
|
|
144
|
+
await player.unload();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('can switch codecs SMOOTH', async () => {
|
|
148
|
+
if (!shaka.util.Platform.supportsSmoothCodecSwitching()) {
|
|
149
|
+
pending('Mediasource.ChangeType is not considered ' +
|
|
150
|
+
'reliable on this device');
|
|
151
|
+
}
|
|
152
|
+
if (!MediaSource.isTypeSupported('audio/webm; codecs="opus"')) {
|
|
153
|
+
pending('Codec OPUS in WEBM is not supported by the platform.');
|
|
154
|
+
}
|
|
155
|
+
const preferredAudioLanguage = 'en';
|
|
156
|
+
player.configure({preferredAudioLanguage: preferredAudioLanguage});
|
|
157
|
+
player.configure('streaming.mediaSource.codecSwitchingStrategy',
|
|
158
|
+
shaka.config.CodecSwitchingStrategy.SMOOTH);
|
|
159
|
+
|
|
160
|
+
await player.load('/base/test/test/assets/dash-multi-codec/dash.mpd', 9);
|
|
161
|
+
await video.play();
|
|
162
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
163
|
+
|
|
164
|
+
expect(player.isLive()).toBe(false);
|
|
165
|
+
|
|
166
|
+
let variants = player.getVariantTracks();
|
|
167
|
+
|
|
168
|
+
expect(variants.length).toBe(2);
|
|
169
|
+
expect(variants.find((v) => !!v.active).language).toBe('en');
|
|
170
|
+
|
|
171
|
+
player.selectAudioLanguage('es');
|
|
172
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 45);
|
|
173
|
+
|
|
174
|
+
variants = player.getVariantTracks();
|
|
175
|
+
|
|
176
|
+
expect(variants.find((v) => !!v.active).language).toBe('es');
|
|
177
|
+
|
|
178
|
+
await player.unload();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -45,6 +45,8 @@ describe('DashParser ContentProtection', () => {
|
|
|
45
45
|
enableLowLatencyMode: () => {},
|
|
46
46
|
updateDuration: () => {},
|
|
47
47
|
newDrmInfo: (stream) => {},
|
|
48
|
+
onManifestUpdated: () => {},
|
|
49
|
+
getBandwidthEstimate: () => 1e6,
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
const actual = await dashParser.start(
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('DashParser', () => {
|
|
8
|
+
const Util = shaka.test.Util;
|
|
9
|
+
|
|
10
|
+
/** @type {!jasmine.Spy} */
|
|
11
|
+
let onErrorSpy;
|
|
12
|
+
|
|
13
|
+
/** @type {!HTMLVideoElement} */
|
|
14
|
+
let video;
|
|
15
|
+
/** @type {shaka.Player} */
|
|
16
|
+
let player;
|
|
17
|
+
/** @type {!shaka.util.EventManager} */
|
|
18
|
+
let eventManager;
|
|
19
|
+
|
|
20
|
+
let compiledShaka;
|
|
21
|
+
|
|
22
|
+
/** @type {!shaka.test.Waiter} */
|
|
23
|
+
let waiter;
|
|
24
|
+
|
|
25
|
+
beforeAll(async () => {
|
|
26
|
+
video = shaka.test.UiUtils.createVideoElement();
|
|
27
|
+
document.body.appendChild(video);
|
|
28
|
+
compiledShaka =
|
|
29
|
+
await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
beforeEach(async () => {
|
|
33
|
+
await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
|
|
34
|
+
player = new compiledShaka.Player(video);
|
|
35
|
+
|
|
36
|
+
// Disable stall detection, which can interfere with playback tests.
|
|
37
|
+
player.configure('streaming.stallEnabled', false);
|
|
38
|
+
|
|
39
|
+
// Grab event manager from the uncompiled library:
|
|
40
|
+
eventManager = new shaka.util.EventManager();
|
|
41
|
+
waiter = new shaka.test.Waiter(eventManager);
|
|
42
|
+
waiter.setPlayer(player);
|
|
43
|
+
|
|
44
|
+
onErrorSpy = jasmine.createSpy('onError');
|
|
45
|
+
onErrorSpy.and.callFake((event) => fail(event.detail));
|
|
46
|
+
eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
eventManager.release();
|
|
51
|
+
await player.destroy();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterAll(() => {
|
|
55
|
+
document.body.removeChild(video);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('supports AES-128 streaming', async () => {
|
|
59
|
+
await player.load('/base/test/test/assets/dash-aes-128/dash.mpd');
|
|
60
|
+
await video.play();
|
|
61
|
+
expect(player.isLive()).toBe(false);
|
|
62
|
+
|
|
63
|
+
// Wait for the video to start playback. If it takes longer than 10
|
|
64
|
+
// seconds, fail the test.
|
|
65
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
66
|
+
|
|
67
|
+
// Play for 10 seconds, but stop early if the video ends. If it takes
|
|
68
|
+
// longer than 30 seconds, fail the test.
|
|
69
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 10, 30);
|
|
70
|
+
|
|
71
|
+
await player.unload();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -54,9 +54,16 @@ describe('DashParser Manifest', () => {
|
|
|
54
54
|
enableLowLatencyMode: () => {},
|
|
55
55
|
updateDuration: () => {},
|
|
56
56
|
newDrmInfo: (stream) => {},
|
|
57
|
+
onManifestUpdated: () => {},
|
|
58
|
+
getBandwidthEstimate: () => 1e6,
|
|
57
59
|
};
|
|
58
60
|
});
|
|
59
61
|
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
// Dash parser stop is synchronous.
|
|
64
|
+
parser.stop();
|
|
65
|
+
});
|
|
66
|
+
|
|
60
67
|
/**
|
|
61
68
|
* Makes a series of tests for the given manifest type.
|
|
62
69
|
*
|
|
@@ -1175,6 +1182,46 @@ describe('DashParser Manifest', () => {
|
|
|
1175
1182
|
expect(trickModeVideo).toBe(null);
|
|
1176
1183
|
});
|
|
1177
1184
|
|
|
1185
|
+
it('populates groupId if configuration enabled', async () => {
|
|
1186
|
+
const manifestText = [
|
|
1187
|
+
'<MPD minBufferTime="PT75S">',
|
|
1188
|
+
' <Period id="1" duration="PT30S">',
|
|
1189
|
+
' <AdaptationSet id="1" contentType="text">',
|
|
1190
|
+
' <Representation id="text-en" mimeType="text/webvtt">',
|
|
1191
|
+
' <BaseURL>t-en.vtt</BaseURL>',
|
|
1192
|
+
' </Representation>',
|
|
1193
|
+
' </AdaptationSet>',
|
|
1194
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
1195
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
1196
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
1197
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1198
|
+
' </Representation>',
|
|
1199
|
+
' </AdaptationSet>',
|
|
1200
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
1201
|
+
' <Representation id="audio-en">',
|
|
1202
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
1203
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1204
|
+
' </Representation>',
|
|
1205
|
+
' </AdaptationSet>',
|
|
1206
|
+
' </Period>',
|
|
1207
|
+
'</MPD>',
|
|
1208
|
+
].join('\n');
|
|
1209
|
+
|
|
1210
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
1211
|
+
|
|
1212
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
1213
|
+
config.dash.enableAudioGroups = true;
|
|
1214
|
+
parser.configure(config);
|
|
1215
|
+
|
|
1216
|
+
/** @type {shaka.extern.Manifest} */
|
|
1217
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
expect(manifest.variants.length).toBe(1);
|
|
1221
|
+
const variant = manifest.variants[0];
|
|
1222
|
+
expect(variant.audio.groupId).toBe('3');
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1178
1225
|
it('sets contentType to text for embedded text mime types', async () => {
|
|
1179
1226
|
// One MIME type for embedded TTML, one for embedded WebVTT.
|
|
1180
1227
|
// One MIME type specified on AdaptationSet, on one Representation.
|
|
@@ -40,9 +40,16 @@ describe('DashParser SegmentBase', () => {
|
|
|
40
40
|
enableLowLatencyMode: () => {},
|
|
41
41
|
updateDuration: () => {},
|
|
42
42
|
newDrmInfo: (stream) => {},
|
|
43
|
+
onManifestUpdated: () => {},
|
|
44
|
+
getBandwidthEstimate: () => 1e6,
|
|
43
45
|
};
|
|
44
46
|
});
|
|
45
47
|
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
// Dash parser stop is synchronous.
|
|
50
|
+
parser.stop();
|
|
51
|
+
});
|
|
52
|
+
|
|
46
53
|
it('requests init data for WebM', async () => {
|
|
47
54
|
const source = [
|
|
48
55
|
'<MPD mediaPresentationDuration="PT75S">',
|
|
@@ -350,25 +350,31 @@ describe('DashParser SegmentList', () => {
|
|
|
350
350
|
enableLowLatencyMode: () => {},
|
|
351
351
|
updateDuration: () => {},
|
|
352
352
|
newDrmInfo: (stream) => {},
|
|
353
|
+
onManifestUpdated: () => {},
|
|
354
|
+
getBandwidthEstimate: () => 1e6,
|
|
353
355
|
};
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
356
|
+
try {
|
|
357
|
+
const manifest = await dashParser.start('dummy://foo', playerInterface);
|
|
358
|
+
const stream = manifest.variants[0].video;
|
|
359
|
+
await stream.createSegmentIndex();
|
|
360
|
+
goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
|
|
358
361
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
362
|
+
// Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
|
|
363
|
+
// doesn't reproduce this issue. We want to use Array.from which uses
|
|
364
|
+
// the iterator.
|
|
365
|
+
const expected = [
|
|
366
|
+
ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
|
|
367
|
+
ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
|
|
368
|
+
ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
|
|
366
369
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
370
|
+
ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
|
|
371
|
+
ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
|
|
372
|
+
ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
|
|
373
|
+
];
|
|
374
|
+
const actual = Array.from(stream.segmentIndex);
|
|
375
|
+
expect(actual).toEqual(expected);
|
|
376
|
+
} finally {
|
|
377
|
+
dashParser.stop();
|
|
378
|
+
}
|
|
373
379
|
});
|
|
374
380
|
});
|
|
@@ -49,9 +49,16 @@ describe('DashParser SegmentTemplate', () => {
|
|
|
49
49
|
enableLowLatencyMode: () => {},
|
|
50
50
|
updateDuration: () => {},
|
|
51
51
|
newDrmInfo: (stream) => {},
|
|
52
|
+
onManifestUpdated: () => {},
|
|
53
|
+
getBandwidthEstimate: () => 1e6,
|
|
52
54
|
};
|
|
53
55
|
});
|
|
54
56
|
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
// Dash parser stop is synchronous.
|
|
59
|
+
parser.stop();
|
|
60
|
+
});
|
|
61
|
+
|
|
55
62
|
shaka.test.Dash.makeTimelineTests(
|
|
56
63
|
'SegmentTemplate', 'media="s$Number$.mp4"', []);
|
|
57
64
|
|
|
@@ -670,6 +677,48 @@ describe('DashParser SegmentTemplate', () => {
|
|
|
670
677
|
expect(pos).toBe(1);
|
|
671
678
|
});
|
|
672
679
|
|
|
680
|
+
it('finds correct position in multiperiod content', async () => {
|
|
681
|
+
const source = [
|
|
682
|
+
'<MPD type="static" availabilityStartTime="1970-01-01T00:00:00Z">',
|
|
683
|
+
' <Period duration="PT30S">',
|
|
684
|
+
' <AdaptationSet mimeType="video/mp4">',
|
|
685
|
+
' <Representation bandwidth="500">',
|
|
686
|
+
' <BaseURL>http://example.com</BaseURL>',
|
|
687
|
+
' <SegmentTemplate startNumber="0"',
|
|
688
|
+
' media="$Number$-$Time$-$Bandwidth$.mp4">',
|
|
689
|
+
' <SegmentTimeline>',
|
|
690
|
+
' <S t="0" d="5" r="6" />',
|
|
691
|
+
' </SegmentTimeline>',
|
|
692
|
+
' </SegmentTemplate>',
|
|
693
|
+
' </Representation>',
|
|
694
|
+
' </AdaptationSet>',
|
|
695
|
+
' </Period>',
|
|
696
|
+
' <Period duration="PT30S">',
|
|
697
|
+
' <AdaptationSet mimeType="video/mp4">',
|
|
698
|
+
' <Representation bandwidth="500">',
|
|
699
|
+
' <BaseURL>http://example.com</BaseURL>',
|
|
700
|
+
' <SegmentTemplate startNumber="6"',
|
|
701
|
+
' media="$Number$-$Time$-$Bandwidth$.mp4">',
|
|
702
|
+
' <SegmentTimeline>',
|
|
703
|
+
' <S t="0" d="5" r="6" />',
|
|
704
|
+
' </SegmentTimeline>',
|
|
705
|
+
' </SegmentTemplate>',
|
|
706
|
+
' </Representation>',
|
|
707
|
+
' </AdaptationSet>',
|
|
708
|
+
' </Period>',
|
|
709
|
+
'</MPD>',
|
|
710
|
+
].join('\n');
|
|
711
|
+
|
|
712
|
+
fakeNetEngine.setResponseText('dummy://foo', source);
|
|
713
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
714
|
+
const stream = manifest.variants[0].video;
|
|
715
|
+
await stream.createSegmentIndex();
|
|
716
|
+
|
|
717
|
+
// simulate a seek into the second period
|
|
718
|
+
const segmentIterator = stream.segmentIndex.getIteratorForTime(42);
|
|
719
|
+
const ref = segmentIterator.next().value;
|
|
720
|
+
expect(ref.startTime).toBe(40);
|
|
721
|
+
});
|
|
673
722
|
|
|
674
723
|
it('returns null if time === last end time', async () => {
|
|
675
724
|
const info = makeTemplateInfo(makeRanges(0, 2.0, 2));
|
package/test/demo/demo_unit.js
CHANGED
|
@@ -33,22 +33,6 @@ describe('Demo', () => {
|
|
|
33
33
|
await shakaDemoMain.cleanup();
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it('has all messages defined', async () => {
|
|
37
|
-
const englishBuffer =
|
|
38
|
-
await shaka.test.Util.fetch('/base/demo/locales/en.json');
|
|
39
|
-
const englishMessages = JSON.parse(shaka.util.StringUtils.fromUTF8(
|
|
40
|
-
englishBuffer));
|
|
41
|
-
const sourceBuffer =
|
|
42
|
-
await shaka.test.Util.fetch('/base/demo/locales/source.json');
|
|
43
|
-
const sourceMessages = JSON.parse(shaka.util.StringUtils.fromUTF8(
|
|
44
|
-
sourceBuffer));
|
|
45
|
-
|
|
46
|
-
for (const id of Object.values(shakaDemo.MessageIds)) {
|
|
47
|
-
expect(englishMessages[id]).withContext(`id=${id}, English`).toBeTruthy();
|
|
48
|
-
expect(sourceMessages[id]).withContext(`id=${id}, source`).toBeTruthy();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
36
|
describe('config', () => {
|
|
53
37
|
it('does not have entries for invalid config options', () => {
|
|
54
38
|
// We determine whether a config option has been made or not by looking at
|
|
@@ -77,6 +77,8 @@ describe('HlsParser live', () => {
|
|
|
77
77
|
enableLowLatencyMode: () => {},
|
|
78
78
|
updateDuration: () => {},
|
|
79
79
|
newDrmInfo: (stream) => {},
|
|
80
|
+
onManifestUpdated: () => {},
|
|
81
|
+
getBandwidthEstimate: () => 1e6,
|
|
80
82
|
};
|
|
81
83
|
|
|
82
84
|
parser = new shaka.hls.HlsParser();
|
|
@@ -540,10 +542,43 @@ describe('HlsParser live', () => {
|
|
|
540
542
|
|
|
541
543
|
it('sets 3 times target duration as presentation delay if not configured',
|
|
542
544
|
async () => {
|
|
545
|
+
const media = [
|
|
546
|
+
'#EXTM3U\n',
|
|
547
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
548
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
549
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
550
|
+
'#EXTINF:2,\n',
|
|
551
|
+
'main.mp4\n',
|
|
552
|
+
'#EXTINF:2,\n',
|
|
553
|
+
'main.mp4\n',
|
|
554
|
+
'#EXTINF:2,\n',
|
|
555
|
+
'main.mp4\n',
|
|
556
|
+
'#EXTINF:2,\n',
|
|
557
|
+
'main.mp4\n',
|
|
558
|
+
'#EXTINF:2,\n',
|
|
559
|
+
'main.mp4\n',
|
|
560
|
+
'#EXTINF:2,\n',
|
|
561
|
+
'main.mp4\n',
|
|
562
|
+
].join('');
|
|
543
563
|
const manifest = await testInitialManifest(master, media);
|
|
544
564
|
expect(manifest.presentationTimeline.getDelay()).toBe(15);
|
|
545
565
|
});
|
|
546
566
|
|
|
567
|
+
it('sets 1 times target duration as presentation delay if there are not enough segments', async () => { // eslint-disable-line max-len
|
|
568
|
+
const media = [
|
|
569
|
+
'#EXTM3U\n',
|
|
570
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
571
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
572
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
573
|
+
'#EXTINF:2,\n',
|
|
574
|
+
'main.mp4\n',
|
|
575
|
+
'#EXTINF:2,\n',
|
|
576
|
+
'main.mp4\n',
|
|
577
|
+
].join('');
|
|
578
|
+
const manifest = await testInitialManifest(master, media);
|
|
579
|
+
expect(manifest.presentationTimeline.getDelay()).toBe(5);
|
|
580
|
+
});
|
|
581
|
+
|
|
547
582
|
it('sets presentation delay if defined', async () => {
|
|
548
583
|
const media = [
|
|
549
584
|
'#EXTM3U\n',
|
|
@@ -90,6 +90,8 @@ describe('HlsParser', () => {
|
|
|
90
90
|
enableLowLatencyMode: () => {},
|
|
91
91
|
updateDuration: () => {},
|
|
92
92
|
newDrmInfo: shaka.test.Util.spyFunc(newDrmInfoSpy),
|
|
93
|
+
onManifestUpdated: () => {},
|
|
94
|
+
getBandwidthEstimate: () => 1e6,
|
|
93
95
|
};
|
|
94
96
|
|
|
95
97
|
parser = new shaka.hls.HlsParser();
|
|
@@ -1136,63 +1138,6 @@ describe('HlsParser', () => {
|
|
|
1136
1138
|
expect(references[6].discontinuitySequence).toBe(3);
|
|
1137
1139
|
});
|
|
1138
1140
|
|
|
1139
|
-
it('sets reference timetampOffset based on discontinuity start time',
|
|
1140
|
-
async () => {
|
|
1141
|
-
const master = [
|
|
1142
|
-
'#EXTM3U\n',
|
|
1143
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
|
|
1144
|
-
'video\n',
|
|
1145
|
-
].join('');
|
|
1146
|
-
|
|
1147
|
-
const media = [
|
|
1148
|
-
'#EXTM3U\n',
|
|
1149
|
-
'#EXT-X-VERSION:3\n',
|
|
1150
|
-
'#EXT-X-TARGETDURATION:5\n',
|
|
1151
|
-
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
1152
|
-
'#EXTINF:3,\n',
|
|
1153
|
-
'clip0-video-0.ts\n',
|
|
1154
|
-
'#EXTINF:1,\n',
|
|
1155
|
-
'clip0-video-1.ts\n',
|
|
1156
|
-
'#EXT-X-DISCONTINUITY\n',
|
|
1157
|
-
'#EXTINF:2,\n',
|
|
1158
|
-
'clip1-video-1.ts\n',
|
|
1159
|
-
'#EXTINF:3,\n',
|
|
1160
|
-
'clip1-video-2.ts\n',
|
|
1161
|
-
'#EXT-X-DISCONTINUITY\n',
|
|
1162
|
-
'#EXTINF:1,\n',
|
|
1163
|
-
'media-clip2-video-0.ts\n',
|
|
1164
|
-
'#EXTINF:1,\n',
|
|
1165
|
-
'media-clip2-video-1.ts\n',
|
|
1166
|
-
'#EXT-X-DISCONTINUITY\n',
|
|
1167
|
-
'#EXTINF:4,\n',
|
|
1168
|
-
'media-clip3-video-1.ts\n',
|
|
1169
|
-
'#EXT-X-ENDLIST\n',
|
|
1170
|
-
].join('');
|
|
1171
|
-
|
|
1172
|
-
fakeNetEngine
|
|
1173
|
-
.setResponseText('test:/master', master)
|
|
1174
|
-
.setResponseText('test:/video', media);
|
|
1175
|
-
|
|
1176
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
1177
|
-
await manifest.variants[0].video.createSegmentIndex();
|
|
1178
|
-
|
|
1179
|
-
const segmentIndex = manifest.variants[0].video.segmentIndex;
|
|
1180
|
-
const references = [];
|
|
1181
|
-
|
|
1182
|
-
for (let i = 0; i < 7; i++) {
|
|
1183
|
-
references.push(segmentIndex.get(i));
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
expect(references[0].timestampOffset).toBe(0);
|
|
1187
|
-
expect(references[1].timestampOffset).toBe(0);
|
|
1188
|
-
expect(references[2].timestampOffset).toBe(4);
|
|
1189
|
-
expect(references[3].timestampOffset).toBe(4);
|
|
1190
|
-
expect(references[4].timestampOffset).toBe(9);
|
|
1191
|
-
expect(references[5].timestampOffset).toBe(9);
|
|
1192
|
-
expect(references[6].timestampOffset).toBe(11);
|
|
1193
|
-
},
|
|
1194
|
-
);
|
|
1195
|
-
|
|
1196
1141
|
it('parses characteristics from audio tags', async () => {
|
|
1197
1142
|
const master = [
|
|
1198
1143
|
'#EXTM3U\n',
|
|
@@ -3181,9 +3126,11 @@ describe('HlsParser', () => {
|
|
|
3181
3126
|
'Null segmentIndex!');
|
|
3182
3127
|
|
|
3183
3128
|
const firstMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(0);
|
|
3184
|
-
expect(firstMp4Segment.
|
|
3129
|
+
expect(firstMp4Segment.aes128Key).toBeDefined();
|
|
3130
|
+
expect(firstMp4Segment.initSegmentReference.aes128Key).toBeDefined();
|
|
3185
3131
|
const secondMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(1);
|
|
3186
|
-
expect(secondMp4Segment.
|
|
3132
|
+
expect(secondMp4Segment.aes128Key).toBeNull();
|
|
3133
|
+
expect(secondMp4Segment.initSegmentReference.aes128Key).toBeDefined();
|
|
3187
3134
|
|
|
3188
3135
|
const tsAesEncryptionVideo = actual.variants[2].video;
|
|
3189
3136
|
await tsAesEncryptionVideo.createSegmentIndex();
|
|
@@ -3191,9 +3138,9 @@ describe('HlsParser', () => {
|
|
|
3191
3138
|
'Null segmentIndex!');
|
|
3192
3139
|
|
|
3193
3140
|
const firstTsSegment = tsAesEncryptionVideo.segmentIndex.get(0);
|
|
3194
|
-
expect(firstTsSegment.
|
|
3141
|
+
expect(firstTsSegment.aes128Key).toBeDefined();
|
|
3195
3142
|
const secondTsSegment = tsAesEncryptionVideo.segmentIndex.get(1);
|
|
3196
|
-
expect(secondTsSegment.
|
|
3143
|
+
expect(secondTsSegment.aes128Key).toBeNull();
|
|
3197
3144
|
});
|
|
3198
3145
|
|
|
3199
3146
|
it('fails on AES-128 if WebCrypto APIs are not available', async () => {
|