shaka-player 3.3.5 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/config.yml +1 -0
- package/.github/workflows/demo-version-index.yaml +8 -0
- package/.github/workflows/release-please.yaml +18 -2
- package/.github/workflows/sync-labels.yaml +33 -0
- package/.github/workflows/update-issues.yaml +29 -0
- package/.github/workflows/validate-pr-title.yaml +35 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +215 -41
- package/CONTRIBUTORS +1 -0
- package/README.md +14 -11
- package/app-engine/demo-version-index/README.md +3 -3
- package/app-engine/demo-version-index/app.yaml +27 -1
- package/app-engine/demo-version-index/generate.py +164 -0
- package/app-engine/demo-version-index/main.py +4 -155
- package/app-engine/demo-version-index/requirements.txt +0 -1
- package/build/checkversion.py +1 -1
- package/build/compiler.py +1 -1
- package/build/misspellings.txt +1 -0
- package/build/shaka-lab.yaml +0 -2
- package/build/types/polyfill +0 -3
- package/demo/common/asset.js +17 -1
- package/demo/common/assets.js +29 -0
- package/demo/common/message_ids.js +6 -3
- package/demo/config.js +10 -11
- package/demo/custom.js +39 -0
- package/demo/demo.less +0 -1
- package/demo/demo_utils.js +0 -1
- package/demo/locales/en.json +6 -3
- package/demo/locales/source.json +22 -10
- package/demo/main.js +9 -6
- package/demo/search.js +2 -1
- package/dist/controls.css +3 -3
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +71 -64
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +71 -64
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +17 -20
- package/dist/locales.js +33 -31
- package/dist/receiver.compiled.debug.js +32 -28
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +32 -28
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +311 -314
- package/dist/shaka-player.compiled.debug.d.ts +311 -314
- package/dist/shaka-player.compiled.debug.externs.js +126 -126
- package/dist/shaka-player.compiled.debug.js +430 -484
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +126 -126
- package/dist/shaka-player.compiled.js +829 -845
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +357 -358
- package/dist/shaka-player.ui.debug.d.ts +357 -358
- package/dist/shaka-player.ui.debug.externs.js +134 -126
- package/dist/shaka-player.ui.debug.js +489 -541
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +134 -126
- package/dist/shaka-player.ui.js +988 -1000
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/config.md +0 -2
- package/docs/tutorials/drm-config.md +5 -0
- package/docs/tutorials/fairplay.md +7 -22
- package/docs/tutorials/faq.md +0 -11
- package/docs/tutorials/index.json +2 -8
- package/docs/tutorials/plugins.md +1 -3
- package/docs/tutorials/upgrade.md +85 -11
- package/externs/polyfill.js +15 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/net.js +12 -0
- package/externs/shaka/offline.js +5 -1
- package/externs/shaka/player.js +39 -21
- package/externs/shaka/text.js +12 -12
- package/externs/sourcebuffer.js +15 -0
- package/lib/abr/simple_abr_manager.js +2 -1
- package/lib/ads/client_side_ad.js +13 -2
- package/lib/ads/client_side_ad_manager.js +22 -4
- package/lib/cast/cast_utils.js +0 -1
- package/lib/dash/content_protection.js +85 -5
- package/lib/dash/dash_parser.js +1 -0
- package/lib/hls/hls_parser.js +390 -747
- package/lib/hls/manifest_text_parser.js +2 -3
- package/lib/media/drm_engine.js +105 -37
- package/lib/media/gap_jumping_controller.js +10 -45
- package/lib/media/media_source_engine.js +150 -30
- package/lib/media/playhead.js +2 -5
- package/lib/media/presentation_timeline.js +1 -2
- package/lib/media/segment_index.js +13 -46
- package/lib/media/segment_reference.js +47 -1
- package/lib/media/streaming_engine.js +28 -11
- package/lib/media/time_ranges_utils.js +4 -9
- package/lib/net/networking_engine.js +3 -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 +8 -41
- package/lib/player.js +17 -201
- package/lib/polyfill/media_capabilities.js +12 -6
- package/lib/polyfill/mediasource.js +0 -28
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
- package/lib/text/cue.js +0 -6
- package/lib/text/lrc_text_parser.js +8 -0
- package/lib/text/mp4_ttml_parser.js +8 -0
- package/lib/text/mp4_vtt_parser.js +8 -0
- package/lib/text/sbv_text_parser.js +8 -0
- package/lib/text/simple_text_displayer.js +1 -7
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +19 -3
- package/lib/text/ttml_text_parser.js +8 -0
- package/lib/text/ui_text_displayer.js +1 -7
- package/lib/text/vtt_text_parser.js +27 -5
- package/lib/text/web_vtt_generator.js +1 -7
- package/lib/util/error.js +9 -13
- package/lib/util/fairplay_utils.js +109 -0
- package/lib/util/functional.js +0 -42
- package/lib/util/mime_utils.js +16 -5
- package/lib/util/platform.js +45 -0
- package/lib/util/player_configuration.js +17 -6
- package/lib/util/pssh.js +23 -4
- package/lib/util/stream_utils.js +92 -22
- package/lib/util/uint8array_utils.js +0 -16
- package/lib/util/xml_utils.js +1 -1
- package/package.json +5 -2
- package/roadmap.md +19 -19
- package/shaka-player.uncompiled.js +0 -3
- package/test/dash/dash_parser_content_protection_unit.js +44 -0
- package/test/dash/dash_parser_segment_template_unit.js +3 -4
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +155 -230
- package/test/hls/hls_parser_unit.js +515 -432
- package/test/media/drm_engine_unit.js +86 -120
- package/test/media/media_source_engine_integration.js +25 -3
- package/test/media/media_source_engine_unit.js +3 -2
- package/test/media/playhead_unit.js +27 -191
- package/test/media/segment_index_unit.js +15 -25
- package/test/media/streaming_engine_integration.js +2 -39
- package/test/media/streaming_engine_unit.js +3 -2
- package/test/media/time_ranges_utils_unit.js +0 -5
- package/test/offline/manifest_convert_unit.js +34 -4
- package/test/offline/offline_manifest_parser_unit.js +1 -0
- package/test/offline/storage_integration.js +5 -4
- package/test/player_external.js +0 -6
- package/test/player_integration.js +16 -0
- package/test/player_unit.js +26 -0
- package/test/test/util/fake_media_source_engine.js +11 -4
- package/test/test/util/manifest_generator.js +3 -1
- package/test/test/util/manifest_parser_util.js +4 -1
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +1 -0
- package/test/test/util/test_scheme.js +24 -1
- package/test/test/util/util.js +4 -4
- package/test/text/cue_integration.js +2 -2
- package/test/text/lrc_text_parser_unit.js +6 -7
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/mp4_vtt_parser_unit.js +6 -5
- package/test/text/sbv_text_parser_unit.js +5 -6
- package/test/text/srt_text_parser_unit.js +5 -6
- package/test/text/ssa_text_parser_unit.js +17 -29
- package/test/text/text_engine_unit.js +45 -5
- package/test/text/ttml_text_parser_unit.js +77 -77
- package/test/text/vtt_text_parser_unit.js +116 -59
- package/test/ui/ui_integration.js +0 -16
- package/test/ui/ui_unit.js +27 -0
- package/test/util/cmcd_manager_unit.js +3 -0
- package/test/util/stream_utils_unit.js +23 -7
- package/ui/controls.js +65 -40
- package/ui/fullscreen_button.js +26 -6
- package/ui/less/containers.less +4 -4
- package/ui/less/general.less +1 -1
- package/ui/less/range_elements.less +1 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +5 -0
- package/ui/resolution_selection.js +31 -33
- package/ui/ui.js +0 -17
- package/.github/pull_request_template.md +0 -10
- package/docs/tutorials/upgrade-v2-5.md +0 -441
- package/docs/tutorials/upgrade-v3.md +0 -38
- package/lib/polyfill/mathround.js +0 -49
- package/lib/polyfill/patchedmediakeys_apple.js +0 -744
- package/lib/polyfill/patchedmediakeys_ms.js +0 -698
- package/test/util/functional_unit.js +0 -82
|
@@ -28,14 +28,6 @@ describe('HlsParser live', () => {
|
|
|
28
28
|
let segmentData;
|
|
29
29
|
/** @type {!Uint8Array} */
|
|
30
30
|
let selfInitializingSegmentData;
|
|
31
|
-
/** @type {!Uint8Array} */
|
|
32
|
-
let tsSegmentData;
|
|
33
|
-
/** @type {!Uint8Array} */
|
|
34
|
-
let pastRolloverSegmentData;
|
|
35
|
-
/** @type {number} */
|
|
36
|
-
let rolloverOffset;
|
|
37
|
-
/** @type {number} */
|
|
38
|
-
let segmentDataStartTime;
|
|
39
31
|
|
|
40
32
|
beforeEach(() => {
|
|
41
33
|
// TODO: use StreamGenerator?
|
|
@@ -66,36 +58,6 @@ describe('HlsParser live', () => {
|
|
|
66
58
|
0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
|
|
67
59
|
0x00, 0x00, 0x07, 0xd0, // baseMediaDecodeTime last 4 bytes (2000)
|
|
68
60
|
]);
|
|
69
|
-
tsSegmentData = new Uint8Array([
|
|
70
|
-
0x47, // TS sync byte (fixed value)
|
|
71
|
-
0x41, 0x01, // not corrupt, payload follows, packet ID 257
|
|
72
|
-
0x10, // not scrambled, no adaptation field, payload only, seq #0
|
|
73
|
-
0x00, 0x00, 0x01, // PES start code (fixed value)
|
|
74
|
-
0xe0, // stream ID (video stream 0)
|
|
75
|
-
0x00, 0x00, // PES packet length (doesn't matter)
|
|
76
|
-
0x80, // marker bits (fixed value), not scrambled, not priority
|
|
77
|
-
0x80, // PTS only, no DTS, other flags 0 (don't matter)
|
|
78
|
-
0x05, // remaining PES header length == 5 (one timestamp)
|
|
79
|
-
0x21, 0x00, 0x0b, 0x7e, 0x41, // PTS = 180000, encoded into 5 bytes
|
|
80
|
-
]);
|
|
81
|
-
// 180000 divided by TS timescale (90000) = segment starts at 2s.
|
|
82
|
-
segmentDataStartTime = 2;
|
|
83
|
-
|
|
84
|
-
pastRolloverSegmentData = new Uint8Array([
|
|
85
|
-
0x00, 0x00, 0x00, 0x24, // size (36)
|
|
86
|
-
0x6D, 0x6F, 0x6F, 0x66, // type (moof)
|
|
87
|
-
0x00, 0x00, 0x00, 0x1C, // traf size (28)
|
|
88
|
-
0x74, 0x72, 0x61, 0x66, // type (traf)
|
|
89
|
-
0x00, 0x00, 0x00, 0x14, // tfdt size (20)
|
|
90
|
-
0x74, 0x66, 0x64, 0x74, // type (tfdt)
|
|
91
|
-
0x01, 0x00, 0x00, 0x00, // version and flags
|
|
92
|
-
0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
|
|
93
|
-
0x0b, 0x60, 0xbc, 0x28, // baseMediaDecodeTime last 4 bytes (190889000)
|
|
94
|
-
]);
|
|
95
|
-
|
|
96
|
-
// The timestamp above would roll over twice, so this rollover offset should
|
|
97
|
-
// be applied.
|
|
98
|
-
rolloverOffset = (0x200000000 * 2) / 90000;
|
|
99
61
|
|
|
100
62
|
selfInitializingSegmentData =
|
|
101
63
|
shaka.util.Uint8ArrayUtils.concat(initSegmentData, segmentData);
|
|
@@ -221,8 +183,10 @@ describe('HlsParser live', () => {
|
|
|
221
183
|
|
|
222
184
|
describe('update', () => {
|
|
223
185
|
it('adds new segments when they appear', async () => {
|
|
224
|
-
const ref1 =
|
|
225
|
-
|
|
186
|
+
const ref1 = makeReference(
|
|
187
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
188
|
+
const ref2 = makeReference(
|
|
189
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
226
190
|
|
|
227
191
|
await testUpdate(
|
|
228
192
|
master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
|
|
@@ -236,8 +200,10 @@ describe('HlsParser live', () => {
|
|
|
236
200
|
].join('');
|
|
237
201
|
|
|
238
202
|
const masterWithTwoVariants = master + secondVariant;
|
|
239
|
-
const ref1 =
|
|
240
|
-
|
|
203
|
+
const ref1 = makeReference(
|
|
204
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
205
|
+
const ref2 = makeReference(
|
|
206
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
241
207
|
|
|
242
208
|
await testUpdate(
|
|
243
209
|
masterWithTwoVariants, media, [ref1], mediaWithAdditionalSegment,
|
|
@@ -257,8 +223,10 @@ describe('HlsParser live', () => {
|
|
|
257
223
|
].join('');
|
|
258
224
|
|
|
259
225
|
const masterWithAudio = masterlist + audio;
|
|
260
|
-
const ref1 =
|
|
261
|
-
|
|
226
|
+
const ref1 = makeReference(
|
|
227
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
228
|
+
const ref2 = makeReference(
|
|
229
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
262
230
|
|
|
263
231
|
await testUpdate(
|
|
264
232
|
masterWithAudio, media, [ref1], mediaWithAdditionalSegment,
|
|
@@ -278,9 +246,12 @@ describe('HlsParser live', () => {
|
|
|
278
246
|
|
|
279
247
|
const updatedMedia1 = media + newSegment1;
|
|
280
248
|
const updatedMedia2 = updatedMedia1 + newSegment2;
|
|
281
|
-
const ref1 =
|
|
282
|
-
|
|
283
|
-
const
|
|
249
|
+
const ref1 = makeReference(
|
|
250
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
251
|
+
const ref2 = makeReference(
|
|
252
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
253
|
+
const ref3 = makeReference(
|
|
254
|
+
'test:/main3.mp4', 4, 6, /* syncTime= */ null);
|
|
284
255
|
|
|
285
256
|
fakeNetEngine
|
|
286
257
|
.setResponseText('test:/master', master)
|
|
@@ -386,19 +357,6 @@ describe('HlsParser live', () => {
|
|
|
386
357
|
'main.mp4\n',
|
|
387
358
|
].join('');
|
|
388
359
|
|
|
389
|
-
const mediaWithByteRange = [
|
|
390
|
-
'#EXTM3U\n',
|
|
391
|
-
'#EXT-X-TARGETDURATION:5\n',
|
|
392
|
-
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
393
|
-
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
394
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
395
|
-
'#EXTINF:2,\n',
|
|
396
|
-
'main.mp4\n',
|
|
397
|
-
].join('');
|
|
398
|
-
|
|
399
|
-
const expectedStartByte = 616;
|
|
400
|
-
const expectedEndByte = 121705;
|
|
401
|
-
|
|
402
360
|
const mediaWithAdditionalSegment = [
|
|
403
361
|
'#EXTM3U\n',
|
|
404
362
|
'#EXT-X-TARGETDURATION:5\n',
|
|
@@ -563,17 +521,17 @@ describe('HlsParser live', () => {
|
|
|
563
521
|
.setResponseValue('test:/main.mp4', segmentData)
|
|
564
522
|
.setResponseValue('test:/main2.mp4', segmentData);
|
|
565
523
|
|
|
566
|
-
const ref1 =
|
|
567
|
-
'test:/main.mp4',
|
|
524
|
+
const ref1 = makeReference(
|
|
525
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null,
|
|
568
526
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
569
527
|
/* timestampOffset= */ 0);
|
|
570
528
|
|
|
571
529
|
// Expect the timestamp offset to be set for the segment after the
|
|
572
530
|
// EXT-X-DISCONTINUITY tag.
|
|
573
|
-
const ref2 =
|
|
574
|
-
'test:/main2.mp4',
|
|
531
|
+
const ref2 = makeReference(
|
|
532
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null,
|
|
575
533
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
576
|
-
/* timestampOffset= */
|
|
534
|
+
/* timestampOffset= */ 0);
|
|
577
535
|
|
|
578
536
|
const manifest = await parser.start('test:/master', playerInterface);
|
|
579
537
|
const video = manifest.variants[0].video;
|
|
@@ -581,62 +539,13 @@ describe('HlsParser live', () => {
|
|
|
581
539
|
ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
|
|
582
540
|
});
|
|
583
541
|
|
|
584
|
-
|
|
585
|
-
const masterWithVtt = [
|
|
586
|
-
'#EXTM3U\n',
|
|
587
|
-
'#EXT-X-MEDIA:TYPE=SUBTITLES,LANGUAGE="fra",URI="text",',
|
|
588
|
-
'GROUP-ID="sub1"\n',
|
|
589
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
590
|
-
'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
|
|
591
|
-
'video\n',
|
|
592
|
-
].join('');
|
|
593
|
-
|
|
594
|
-
const textPlaylist = [
|
|
595
|
-
'#EXTM3U\n',
|
|
596
|
-
'#EXT-X-TARGETDURATION:5\n',
|
|
597
|
-
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
598
|
-
'#EXTINF:2,\n',
|
|
599
|
-
'main.vtt\n',
|
|
600
|
-
].join('');
|
|
601
|
-
|
|
602
|
-
const vtt = [
|
|
603
|
-
'WEBVTT\n',
|
|
604
|
-
'\n',
|
|
605
|
-
'00:00.000 --> 00:01.000\n',
|
|
606
|
-
'Hello, world!\n',
|
|
607
|
-
].join('');
|
|
608
|
-
|
|
609
|
-
fakeNetEngine
|
|
610
|
-
.setResponseText('test:/master', masterWithVtt)
|
|
611
|
-
.setResponseText('test:/video', media)
|
|
612
|
-
.setResponseText('test:/text', textPlaylist)
|
|
613
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
614
|
-
.setResponseValue('test:/main.mp4', pastRolloverSegmentData)
|
|
615
|
-
.setResponseText('test:/main.vtt', vtt);
|
|
616
|
-
|
|
617
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
618
|
-
const textStream = manifest.textStreams[0];
|
|
619
|
-
await textStream.createSegmentIndex();
|
|
620
|
-
goog.asserts.assert(textStream.segmentIndex, 'Null segmentIndex!');
|
|
621
|
-
|
|
622
|
-
let ref = Array.from(textStream.segmentIndex)[0];
|
|
623
|
-
expect(ref).not.toBe(null);
|
|
624
|
-
expect(ref.startTime).not.toBeLessThan(rolloverOffset);
|
|
625
|
-
|
|
626
|
-
const videoStream = manifest.variants[0].video;
|
|
627
|
-
await videoStream.createSegmentIndex();
|
|
628
|
-
goog.asserts.assert(videoStream.segmentIndex, 'Null segmentIndex!');
|
|
629
|
-
|
|
630
|
-
ref = Array.from(videoStream.segmentIndex)[0];
|
|
631
|
-
expect(ref).not.toBe(null);
|
|
632
|
-
expect(ref.startTime).not.toBeLessThan(rolloverOffset);
|
|
633
|
-
});
|
|
634
|
-
|
|
542
|
+
// Test for https://github.com/shaka-project/shaka-player/issues/4223
|
|
635
543
|
it('parses streams with partial and preload hinted segments', async () => {
|
|
636
544
|
playerInterface.isLowLatencyMode = () => true;
|
|
637
545
|
const mediaWithPartialSegments = [
|
|
638
546
|
'#EXTM3U\n',
|
|
639
547
|
'#EXT-X-TARGETDURATION:5\n',
|
|
548
|
+
'#EXT-X-PART-INF:PART-TARGET=1.5\n',
|
|
640
549
|
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
641
550
|
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
642
551
|
// ref includes partialRef, partialRef2
|
|
@@ -661,35 +570,30 @@ describe('HlsParser live', () => {
|
|
|
661
570
|
.setResponseValue('test:/partial.mp4', segmentData)
|
|
662
571
|
.setResponseValue('test:/partial2.mp4', segmentData);
|
|
663
572
|
|
|
664
|
-
const partialRef =
|
|
665
|
-
'test:/partial.mp4',
|
|
573
|
+
const partialRef = makeReference(
|
|
574
|
+
'test:/partial.mp4', 0, 2, /* syncTime= */ null,
|
|
666
575
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 199);
|
|
667
576
|
|
|
668
|
-
const partialRef2 =
|
|
669
|
-
'test:/partial2.mp4',
|
|
670
|
-
|
|
671
|
-
|
|
577
|
+
const partialRef2 = makeReference(
|
|
578
|
+
'test:/partial2.mp4', 2, 4, /* syncTime= */ null,
|
|
579
|
+
/* baseUri= */ '', /* startByte= */ 200, /* endByte= */ 429);
|
|
580
|
+
|
|
581
|
+
const ref = makeReference(
|
|
582
|
+
'test:/main.mp4', 0, 4, /* syncTime= */ null,
|
|
583
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
|
|
584
|
+
/* timestampOffset= */ 0, [partialRef, partialRef2]);
|
|
672
585
|
|
|
673
|
-
const partialRef3 =
|
|
674
|
-
'test:/partial.mp4',
|
|
675
|
-
segmentDataStartTime + 6,
|
|
586
|
+
const partialRef3 = makeReference(
|
|
587
|
+
'test:/partial.mp4', 4, 6, /* syncTime= */ null,
|
|
676
588
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
|
|
677
589
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
const preloadRef = ManifestParser.makeReference(
|
|
681
|
-
'test:/partial.mp4', segmentDataStartTime + 6,
|
|
682
|
-
segmentDataStartTime + 6,
|
|
590
|
+
const preloadRef = makeReference(
|
|
591
|
+
'test:/partial.mp4', 6, 7.5, /* syncTime= */ null,
|
|
683
592
|
/* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
|
|
684
593
|
|
|
685
|
-
const ref = ManifestParser.makeReference(
|
|
686
|
-
'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
|
|
687
|
-
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
|
|
688
|
-
/* timestampOffset= */ 0, [partialRef, partialRef2]);
|
|
689
|
-
|
|
690
594
|
// ref2 is not fully published yet, so it doesn't have a segment uri.
|
|
691
|
-
const ref2 =
|
|
692
|
-
'',
|
|
595
|
+
const ref2 = makeReference(
|
|
596
|
+
'', 4, 7.5, /* syncTime= */ null,
|
|
693
597
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
694
598
|
/* timestampOffset= */ 0, [partialRef3, preloadRef]);
|
|
695
599
|
|
|
@@ -699,18 +603,23 @@ describe('HlsParser live', () => {
|
|
|
699
603
|
ManifestParser.verifySegmentIndex(video, [ref, ref2]);
|
|
700
604
|
});
|
|
701
605
|
|
|
702
|
-
// Test for https://github.com/shaka-project/shaka-player/issues/
|
|
703
|
-
it('
|
|
704
|
-
|
|
705
|
-
playerInterface.isLowLatencyMode = () => false;
|
|
606
|
+
// Test for https://github.com/shaka-project/shaka-player/issues/4223
|
|
607
|
+
it('ignores preload hinted segments without target duration', async () => {
|
|
608
|
+
playerInterface.isLowLatencyMode = () => true;
|
|
706
609
|
|
|
610
|
+
// Missing PART-TARGET, so preload hints are skipped.
|
|
707
611
|
const mediaWithPartialSegments = [
|
|
708
612
|
'#EXTM3U\n',
|
|
709
613
|
'#EXT-X-TARGETDURATION:5\n',
|
|
710
614
|
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
615
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
711
616
|
'#EXTINF:4,\n',
|
|
617
|
+
// ref1
|
|
712
618
|
'main.mp4\n',
|
|
619
|
+
// ref2 includes partialRef, but not preloadRef
|
|
620
|
+
// partialRef
|
|
713
621
|
'#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
|
|
622
|
+
// preloadRef
|
|
714
623
|
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
|
|
715
624
|
].join('');
|
|
716
625
|
|
|
@@ -719,7 +628,48 @@ describe('HlsParser live', () => {
|
|
|
719
628
|
.setResponseText('test:/video', mediaWithPartialSegments)
|
|
720
629
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
721
630
|
.setResponseValue('test:/main.mp4', segmentData)
|
|
722
|
-
.setResponseValue('test:/partial.mp4', segmentData)
|
|
631
|
+
.setResponseValue('test:/partial.mp4', segmentData)
|
|
632
|
+
.setResponseValue('test:/partial2.mp4', segmentData);
|
|
633
|
+
|
|
634
|
+
const ref = makeReference(
|
|
635
|
+
'test:/main.mp4', 0, 4, /* syncTime= */ null,
|
|
636
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
637
|
+
/* timestampOffset= */ 0, []);
|
|
638
|
+
|
|
639
|
+
const partialRef = makeReference(
|
|
640
|
+
'test:/partial.mp4', 4, 6, /* syncTime= */ null,
|
|
641
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
|
|
642
|
+
|
|
643
|
+
// ref2 is not fully published yet, so it doesn't have a segment uri.
|
|
644
|
+
const ref2 = makeReference(
|
|
645
|
+
'', 4, 6, /* syncTime= */ null,
|
|
646
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209,
|
|
647
|
+
/* timestampOffset= */ 0, [partialRef]);
|
|
648
|
+
|
|
649
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
650
|
+
const video = manifest.variants[0].video;
|
|
651
|
+
await video.createSegmentIndex();
|
|
652
|
+
ManifestParser.verifySegmentIndex(video, [ref, ref2]);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// Test for https://github.com/shaka-project/shaka-player/issues/4185
|
|
656
|
+
it('does not fail on preload hints with LL mode off', async () => {
|
|
657
|
+
// LL mode must be off for this test!
|
|
658
|
+
playerInterface.isLowLatencyMode = () => false;
|
|
659
|
+
|
|
660
|
+
const mediaWithPartialSegments = [
|
|
661
|
+
'#EXTM3U\n',
|
|
662
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
663
|
+
'#EXT-X-PART-INF:PART-TARGET=1.5\n',
|
|
664
|
+
'#EXTINF:4,\n',
|
|
665
|
+
'main.mp4\n',
|
|
666
|
+
'#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
|
|
667
|
+
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
|
|
668
|
+
].join('');
|
|
669
|
+
|
|
670
|
+
fakeNetEngine
|
|
671
|
+
.setResponseText('test:/master', master)
|
|
672
|
+
.setResponseText('test:/video', mediaWithPartialSegments);
|
|
723
673
|
|
|
724
674
|
// If this throws, the test fails. Otherwise, it passes.
|
|
725
675
|
await parser.start('test:/master', playerInterface);
|
|
@@ -727,16 +677,20 @@ describe('HlsParser live', () => {
|
|
|
727
677
|
|
|
728
678
|
describe('update', () => {
|
|
729
679
|
it('adds new segments when they appear', async () => {
|
|
730
|
-
const ref1 =
|
|
731
|
-
|
|
680
|
+
const ref1 = makeReference(
|
|
681
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
682
|
+
const ref2 = makeReference(
|
|
683
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
732
684
|
|
|
733
685
|
await testUpdate(
|
|
734
686
|
master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
|
|
735
687
|
});
|
|
736
688
|
|
|
737
689
|
it('evicts removed segments', async () => {
|
|
738
|
-
const ref1 =
|
|
739
|
-
|
|
690
|
+
const ref1 = makeReference(
|
|
691
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
692
|
+
const ref2 = makeReference(
|
|
693
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
740
694
|
|
|
741
695
|
await testUpdate(
|
|
742
696
|
master, mediaWithAdditionalSegment, [ref1, ref2],
|
|
@@ -744,12 +698,13 @@ describe('HlsParser live', () => {
|
|
|
744
698
|
});
|
|
745
699
|
|
|
746
700
|
it('handles updates with redirects', async () => {
|
|
747
|
-
const oldRef1 =
|
|
701
|
+
const oldRef1 = makeReference(
|
|
702
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
748
703
|
|
|
749
|
-
const newRef1 =
|
|
750
|
-
|
|
751
|
-
const newRef2 =
|
|
752
|
-
|
|
704
|
+
const newRef1 = makeReference(
|
|
705
|
+
'test:/redirected/main.mp4', 0, 2, /* syncTime= */ null);
|
|
706
|
+
const newRef2 = makeReference(
|
|
707
|
+
'test:/redirected/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
753
708
|
|
|
754
709
|
let playlistFetchCount = 0;
|
|
755
710
|
|
|
@@ -776,8 +731,8 @@ describe('HlsParser live', () => {
|
|
|
776
731
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
777
732
|
.setResponseValue('test:/main.mp4', segmentData);
|
|
778
733
|
|
|
779
|
-
const expectedRef =
|
|
780
|
-
'test:/main.mp4',
|
|
734
|
+
const expectedRef = makeReference(
|
|
735
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
781
736
|
// In live content, we do not set timestampOffset.
|
|
782
737
|
expectedRef.timestampOffset = 0;
|
|
783
738
|
|
|
@@ -794,12 +749,11 @@ describe('HlsParser live', () => {
|
|
|
794
749
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
795
750
|
.setResponseValue('test:/main.mp4', segmentData);
|
|
796
751
|
|
|
797
|
-
const ref1 =
|
|
798
|
-
'test:/main.mp4',
|
|
752
|
+
const ref1 = makeReference(
|
|
753
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
799
754
|
|
|
800
|
-
const ref2 =
|
|
801
|
-
'test:/main2.mp4',
|
|
802
|
-
segmentDataStartTime + 4);
|
|
755
|
+
const ref2 = makeReference(
|
|
756
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
803
757
|
|
|
804
758
|
const manifest = await parser.start('test:/master', playerInterface);
|
|
805
759
|
const video = manifest.variants[0].video;
|
|
@@ -835,11 +789,11 @@ describe('HlsParser live', () => {
|
|
|
835
789
|
.setResponseValue('test:/main.mp4', segmentData)
|
|
836
790
|
.setResponseValue('test:/main2.mp4', segmentData);
|
|
837
791
|
|
|
838
|
-
const ref1 =
|
|
839
|
-
|
|
792
|
+
const ref1 = makeReference(
|
|
793
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
840
794
|
|
|
841
|
-
const ref2 =
|
|
842
|
-
|
|
795
|
+
const ref2 = makeReference(
|
|
796
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
843
797
|
|
|
844
798
|
const manifest =
|
|
845
799
|
await parser.start('test:/master', playerInterface);
|
|
@@ -872,57 +826,6 @@ describe('HlsParser live', () => {
|
|
|
872
826
|
shaka.net.NetworkingEngine.RequestType.SEGMENT);
|
|
873
827
|
});
|
|
874
828
|
|
|
875
|
-
it('parses start time from ts segments', async () => {
|
|
876
|
-
const tsMediaPlaylist =
|
|
877
|
-
mediaWithRemovedSegment.replace(/\.mp4/g, '.ts');
|
|
878
|
-
|
|
879
|
-
fakeNetEngine
|
|
880
|
-
.setResponseText('test:/master', master)
|
|
881
|
-
.setResponseText('test:/video', tsMediaPlaylist)
|
|
882
|
-
.setResponseValue('test:/main2.ts', tsSegmentData);
|
|
883
|
-
|
|
884
|
-
const expectedRef = ManifestParser.makeReference(
|
|
885
|
-
'test:/main2.ts', segmentDataStartTime, segmentDataStartTime + 2);
|
|
886
|
-
// In live content, we do not set timestampOffset.
|
|
887
|
-
expectedRef.timestampOffset = 0;
|
|
888
|
-
|
|
889
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
890
|
-
const video = manifest.variants[0].video;
|
|
891
|
-
await video.createSegmentIndex();
|
|
892
|
-
ManifestParser.verifySegmentIndex(video, [expectedRef]);
|
|
893
|
-
});
|
|
894
|
-
|
|
895
|
-
it('gets start time of segments with byte range', async () => {
|
|
896
|
-
// Nit: this value is an implementation detail of the fix for #1106
|
|
897
|
-
const partialEndByte = expectedStartByte + 2048 - 1;
|
|
898
|
-
|
|
899
|
-
fakeNetEngine
|
|
900
|
-
.setResponseText('test:/master', master)
|
|
901
|
-
.setResponseText('test:/video', mediaWithByteRange)
|
|
902
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
903
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
904
|
-
|
|
905
|
-
const expectedRef = ManifestParser.makeReference(
|
|
906
|
-
/* uri= */ 'test:/main.mp4',
|
|
907
|
-
/* start= */ segmentDataStartTime,
|
|
908
|
-
/* end= */ segmentDataStartTime + 2,
|
|
909
|
-
/* baseUri= */ '',
|
|
910
|
-
expectedStartByte,
|
|
911
|
-
expectedEndByte); // Complete segment reference
|
|
912
|
-
|
|
913
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
914
|
-
const video = manifest.variants[0].video;
|
|
915
|
-
await video.createSegmentIndex();
|
|
916
|
-
ManifestParser.verifySegmentIndex(video, [expectedRef]);
|
|
917
|
-
|
|
918
|
-
// There should have been a range request for this segment to get the
|
|
919
|
-
// start time.
|
|
920
|
-
fakeNetEngine.expectRangeRequest(
|
|
921
|
-
'test:/main.mp4',
|
|
922
|
-
expectedStartByte,
|
|
923
|
-
partialEndByte); // partial segment request
|
|
924
|
-
});
|
|
925
|
-
|
|
926
829
|
it('request playlist delta updates to skip segments', async () => {
|
|
927
830
|
const mediaWithDeltaUpdates = [
|
|
928
831
|
'#EXTM3U\n',
|
|
@@ -987,9 +890,12 @@ describe('HlsParser live', () => {
|
|
|
987
890
|
].join('');
|
|
988
891
|
|
|
989
892
|
playerInterface.isLowLatencyMode = () => true;
|
|
990
|
-
const ref1 =
|
|
991
|
-
|
|
992
|
-
const
|
|
893
|
+
const ref1 = makeReference(
|
|
894
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null);
|
|
895
|
+
const ref2 = makeReference(
|
|
896
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null);
|
|
897
|
+
const ref3 = makeReference(
|
|
898
|
+
'test:/main3.mp4', 4, 6, /* syncTime= */ null);
|
|
993
899
|
// With 'SKIPPED-SEGMENTS', ref1 is skipped from the playlist,
|
|
994
900
|
// and ref1 should be in the SegmentReferences list.
|
|
995
901
|
// ref3 should be appended to the SegmentReferences list.
|
|
@@ -1029,29 +935,29 @@ describe('HlsParser live', () => {
|
|
|
1029
935
|
|
|
1030
936
|
playerInterface.isLowLatencyMode = () => true;
|
|
1031
937
|
|
|
1032
|
-
const ref1 =
|
|
1033
|
-
'test:/main.mp4',
|
|
938
|
+
const ref1 = makeReference(
|
|
939
|
+
'test:/main.mp4', 0, 2, /* syncTime= */ null,
|
|
1034
940
|
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
1035
941
|
/* timestampOffset= */ 0);
|
|
1036
942
|
|
|
1037
943
|
// Expect the timestamp offset to be set for the segment after the
|
|
1038
944
|
// EXT-X-DISCONTINUITY tag.
|
|
1039
|
-
const ref2 =
|
|
1040
|
-
'test:/main2.mp4',
|
|
1041
|
-
|
|
1042
|
-
/*
|
|
945
|
+
const ref2 = makeReference(
|
|
946
|
+
'test:/main2.mp4', 2, 4, /* syncTime= */ null,
|
|
947
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
948
|
+
/* timestampOffset= */ 0);
|
|
1043
949
|
|
|
1044
950
|
// Expect the timestamp offset to be set for the segment, with the
|
|
1045
951
|
// EXT-X-DISCONTINUITY tag skipped in the playlist.
|
|
1046
|
-
const ref3 =
|
|
1047
|
-
'test:/main3.mp4',
|
|
1048
|
-
|
|
1049
|
-
/*
|
|
952
|
+
const ref3 = makeReference(
|
|
953
|
+
'test:/main3.mp4', 4, 6, /* syncTime= */ null,
|
|
954
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
955
|
+
/* timestampOffset= */ 0);
|
|
1050
956
|
|
|
1051
|
-
const ref4 =
|
|
1052
|
-
'test:/main4.mp4',
|
|
1053
|
-
|
|
1054
|
-
/*
|
|
957
|
+
const ref4 = makeReference(
|
|
958
|
+
'test:/main4.mp4', 6, 8, /* syncTime= */ null,
|
|
959
|
+
/* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
|
|
960
|
+
/* timestampOffset= */ 0);
|
|
1055
961
|
|
|
1056
962
|
// With 'SKIPPED-SEGMENTS', ref1, ref2 are skipped from the playlist,
|
|
1057
963
|
// and ref1,ref2 should be in the SegmentReferences list.
|
|
@@ -1062,4 +968,23 @@ describe('HlsParser live', () => {
|
|
|
1062
968
|
});
|
|
1063
969
|
}); // describe('update')
|
|
1064
970
|
}); // describe('playlist type LIVE')
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* @param {string} uri A relative URI to http://example.com
|
|
974
|
+
* @param {number} start
|
|
975
|
+
* @param {number} end
|
|
976
|
+
* @param {?number} syncTime
|
|
977
|
+
* @param {string=} baseUri
|
|
978
|
+
* @param {number=} startByte
|
|
979
|
+
* @param {?number=} endByte
|
|
980
|
+
* @param {number=} timestampOffset
|
|
981
|
+
* @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
|
|
982
|
+
* @param {?string=} tilesLayout
|
|
983
|
+
* @return {!shaka.media.SegmentReference}
|
|
984
|
+
*/
|
|
985
|
+
function makeReference(uri, start, end, syncTime, baseUri, startByte, endByte,
|
|
986
|
+
timestampOffset, partialReferences, tilesLayout) {
|
|
987
|
+
return ManifestParser.makeReference(uri, start, end, baseUri, startByte,
|
|
988
|
+
endByte, timestampOffset, partialReferences, tilesLayout, syncTime);
|
|
989
|
+
}
|
|
1065
990
|
}); // describe('HlsParser live')
|