shaka-player 3.1.3 → 3.2.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/AUTHORS +3 -0
- package/CHANGELOG.md +175 -3
- package/CONTRIBUTORS +3 -0
- package/README.md +4 -4
- package/build/generateExterns.js +1 -1
- package/build/types/polyfill +1 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +11 -2
- package/demo/common/message_ids.js +2 -1
- package/demo/config.js +5 -2
- package/demo/index.html +1 -1
- package/demo/locales/en.json +2 -1
- package/demo/locales/source.json +8 -4
- package/demo/main.js +2 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +15 -15
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +15 -15
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +22 -21
- package/dist/locales.js +36 -36
- package/dist/receiver.compiled.debug.js +9 -9
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +9 -9
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.externs.js +777 -717
- package/dist/shaka-player.compiled.debug.js +639 -607
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +777 -717
- package/dist/shaka-player.compiled.js +826 -819
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +58 -10
- package/dist/shaka-player.ui.debug.d.ts +58 -10
- package/dist/shaka-player.ui.debug.externs.js +529 -469
- package/dist/shaka-player.ui.debug.js +676 -645
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +529 -469
- package/dist/shaka-player.ui.js +963 -955
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/ui.md +5 -5
- package/externs/aria.js +6 -0
- package/externs/shaka/ads.js +24 -1
- package/externs/shaka/manifest.js +6 -1
- package/externs/shaka/offline.js +5 -0
- package/externs/shaka/player.js +53 -9
- package/externs/shaka/text.js +10 -10
- package/externs/texttrack.js +3 -0
- package/karma.conf.js +1 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad_manager.js +52 -88
- package/lib/ads/server_side_ad_manager.js +26 -12
- package/lib/cast/cast_proxy.js +11 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +6 -1
- package/lib/cea/cea608_data_channel.js +56 -56
- package/lib/cea/cea608_memory.js +33 -33
- package/lib/cea/cea708_service.js +43 -43
- package/lib/cea/cea708_window.js +38 -38
- package/lib/cea/cea_decoder.js +13 -14
- package/lib/cea/cea_utils.js +23 -23
- package/lib/cea/dtvcc_packet_builder.js +7 -7
- package/lib/cea/i_caption_decoder.js +2 -3
- package/lib/cea/i_cea_parser.js +2 -2
- package/lib/cea/mp4_cea_parser.js +6 -6
- package/lib/dash/dash_parser.js +98 -2
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +159 -29
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +169 -192
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/segment_index.js +3 -1
- package/lib/media/segment_reference.js +19 -2
- package/lib/media/streaming_engine.js +8 -7
- package/lib/net/networking_engine.js +3 -1
- package/lib/offline/download_manager.js +1 -2
- 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 +3 -1
- package/lib/offline/storage.js +12 -14
- package/lib/player.js +437 -167
- package/lib/polyfill/aria.js +82 -0
- package/lib/polyfill/media_capabilities.js +7 -1
- package/lib/polyfill/mediasource.js +6 -0
- package/lib/polyfill/orientation.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +4 -4
- package/lib/polyfill/patchedmediakeys_ms.js +4 -4
- package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
- package/lib/routing/walker.js +2 -3
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +16 -4
- package/lib/text/ttml_text_parser.js +5 -0
- package/lib/text/ui_text_displayer.js +85 -37
- package/lib/text/vtt_text_parser.js +2 -2
- package/lib/text/web_vtt_generator.js +55 -12
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event.js +53 -7
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_box_parsers.js +20 -20
- package/lib/util/multi_map.js +8 -0
- package/lib/util/periods.js +4 -1
- package/lib/util/platform.js +13 -1
- package/lib/util/player_configuration.js +13 -1
- package/lib/util/stream_utils.js +153 -85
- package/lib/util/xml_utils.js +31 -12
- package/package.json +1 -1
- package/roadmap.md +24 -22
- package/shaka-player.uncompiled.js +1 -0
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +2 -1
- package/test/cea/cea608_memory_unit.js +1 -1
- package/test/cea/cea708_service_unit.js +8 -8
- package/test/cea/cea708_window_unit.js +6 -6
- package/test/cea/cea_decoder_unit.js +1 -1
- package/test/cea/dtvcc_packet_builder_unit.js +2 -2
- package/test/dash/dash_parser_manifest_unit.js +230 -2
- package/test/hls/hls_parser_unit.js +255 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +353 -450
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +9 -19
- package/test/player_integration.js +90 -0
- package/test/player_src_equals_integration.js +52 -0
- package/test/player_unit.js +11 -33
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/assets/chapters.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/fake_ad_manager.js +8 -1
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/text/ttml_text_parser_unit.js +9 -0
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/util/stream_utils_unit.js +153 -10
- package/ui/airplay_button.js +1 -1
- package/ui/audio_language_selection.js +2 -5
- package/ui/cast_button.js +6 -9
- package/ui/constants.js +0 -3
- package/ui/controls.js +4 -6
- package/ui/fast_forward_button.js +2 -3
- package/ui/fullscreen_button.js +1 -3
- package/ui/language_utils.js +1 -1
- package/ui/less/containers.less +3 -7
- package/ui/locales/ru.json +6 -6
- package/ui/localization.js +28 -51
- package/ui/loop_button.js +1 -3
- package/ui/mute_button.js +1 -3
- package/ui/overflow_menu.js +2 -3
- package/ui/pip_button.js +7 -10
- package/ui/playback_rate_selection.js +3 -6
- package/ui/presentation_time.js +1 -3
- package/ui/resolution_selection.js +4 -7
- package/ui/rewind_button.js +2 -3
- package/ui/seek_bar.js +2 -4
- package/ui/spacer.js +1 -1
- package/ui/text_selection.js +8 -11
- package/ui/ui_utils.js +1 -1
- package/ui/volume_bar.js +1 -3
|
@@ -783,7 +783,7 @@ describe('HlsParser', () => {
|
|
|
783
783
|
'RESOLUTION=960x540,FRAME-RATE=120,AUDIO="aud2"\n',
|
|
784
784
|
'video2\n',
|
|
785
785
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
786
|
-
'URI="audio"\n',
|
|
786
|
+
'DEFAULT=YES,URI="audio"\n',
|
|
787
787
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud2",LANGUAGE="fr",',
|
|
788
788
|
'URI="audio2"\n',
|
|
789
789
|
].join('');
|
|
@@ -801,6 +801,7 @@ describe('HlsParser', () => {
|
|
|
801
801
|
manifest.anyTimeline();
|
|
802
802
|
manifest.addPartialVariant((variant) => {
|
|
803
803
|
variant.bandwidth = 200;
|
|
804
|
+
variant.primary = true;
|
|
804
805
|
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
805
806
|
stream.size(960, 540);
|
|
806
807
|
});
|
|
@@ -810,6 +811,7 @@ describe('HlsParser', () => {
|
|
|
810
811
|
});
|
|
811
812
|
manifest.addPartialVariant((variant) => {
|
|
812
813
|
variant.bandwidth = 300;
|
|
814
|
+
variant.primary = false;
|
|
813
815
|
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
814
816
|
stream.size(960, 540);
|
|
815
817
|
});
|
|
@@ -1307,6 +1309,8 @@ describe('HlsParser', () => {
|
|
|
1307
1309
|
// stream.
|
|
1308
1310
|
const timeline = actual.presentationTimeline;
|
|
1309
1311
|
expect(timeline.getDuration()).toBe(10);
|
|
1312
|
+
expect(timeline.getSeekRangeStart()).toBe(0);
|
|
1313
|
+
expect(timeline.getSeekRangeEnd()).toBe(10);
|
|
1310
1314
|
|
|
1311
1315
|
expect(actual.textStreams.length).toBe(1);
|
|
1312
1316
|
expect(actual.variants.length).toBe(1);
|
|
@@ -1314,6 +1318,103 @@ describe('HlsParser', () => {
|
|
|
1314
1318
|
expect(actual.variants[0].video).toBeTruthy();
|
|
1315
1319
|
});
|
|
1316
1320
|
|
|
1321
|
+
it('parse image streams', async () => {
|
|
1322
|
+
const master = [
|
|
1323
|
+
'#EXTM3U\n',
|
|
1324
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
1325
|
+
'URI="text"\n',
|
|
1326
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
1327
|
+
'CHANNELS="2",URI="audio"\n',
|
|
1328
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1329
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1330
|
+
'video\n',
|
|
1331
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg",',
|
|
1332
|
+
'URI="image"\n',
|
|
1333
|
+
].join('');
|
|
1334
|
+
|
|
1335
|
+
const video = [
|
|
1336
|
+
'#EXTM3U\n',
|
|
1337
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1338
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1339
|
+
'#EXTINF:5,\n',
|
|
1340
|
+
'main.mp4\n',
|
|
1341
|
+
'#EXTINF:5,\n',
|
|
1342
|
+
'main.mp4\n',
|
|
1343
|
+
'#EXTINF:5,\n',
|
|
1344
|
+
'main.mp4\n',
|
|
1345
|
+
].join('');
|
|
1346
|
+
|
|
1347
|
+
const audio = [
|
|
1348
|
+
'#EXTM3U\n',
|
|
1349
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1350
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1351
|
+
'#EXTINF:5,\n',
|
|
1352
|
+
'main.mp4\n',
|
|
1353
|
+
'#EXTINF:5,\n',
|
|
1354
|
+
'main.mp4\n',
|
|
1355
|
+
'#EXTINF:5,\n',
|
|
1356
|
+
'main.mp4\n',
|
|
1357
|
+
].join('');
|
|
1358
|
+
|
|
1359
|
+
const text = [
|
|
1360
|
+
'#EXTM3U\n',
|
|
1361
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1362
|
+
'#EXTINF:5,\n',
|
|
1363
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1364
|
+
'main.vtt',
|
|
1365
|
+
].join('');
|
|
1366
|
+
|
|
1367
|
+
const image = [
|
|
1368
|
+
'#EXTM3U\n',
|
|
1369
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1370
|
+
'#EXTINF:5,\n',
|
|
1371
|
+
'image.jpg\n',
|
|
1372
|
+
'#EXTINF:5,\n',
|
|
1373
|
+
'#EXT-X-TILES:RESOLUTION=640x360,LAYOUT=5x2,DURATION=6.006\n',
|
|
1374
|
+
'image.jpg\n',
|
|
1375
|
+
'#EXTINF:5,\n',
|
|
1376
|
+
'image.jpg\n',
|
|
1377
|
+
].join('');
|
|
1378
|
+
|
|
1379
|
+
fakeNetEngine
|
|
1380
|
+
.setResponseText('test:/master', master)
|
|
1381
|
+
.setResponseText('test:/audio', audio)
|
|
1382
|
+
.setResponseText('test:/video', video)
|
|
1383
|
+
.setResponseText('test:/text', text)
|
|
1384
|
+
.setResponseText('test:/image', image)
|
|
1385
|
+
.setResponseText('test:/main.vtt', vttText)
|
|
1386
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1387
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
1388
|
+
|
|
1389
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1390
|
+
|
|
1391
|
+
expect(actual.imageStreams.length).toBe(1);
|
|
1392
|
+
expect(actual.textStreams.length).toBe(1);
|
|
1393
|
+
expect(actual.variants.length).toBe(1);
|
|
1394
|
+
|
|
1395
|
+
const thumbnails = actual.imageStreams[0];
|
|
1396
|
+
|
|
1397
|
+
await thumbnails.createSegmentIndex();
|
|
1398
|
+
goog.asserts.assert(thumbnails.segmentIndex != null, 'Null segmentIndex!');
|
|
1399
|
+
|
|
1400
|
+
const firstThumbnailReference = thumbnails.segmentIndex.get(0);
|
|
1401
|
+
const secondThumbnailReference = thumbnails.segmentIndex.get(1);
|
|
1402
|
+
const thirdThumbnailReference = thumbnails.segmentIndex.get(2);
|
|
1403
|
+
|
|
1404
|
+
expect(firstThumbnailReference).not.toBe(null);
|
|
1405
|
+
expect(secondThumbnailReference).not.toBe(null);
|
|
1406
|
+
expect(thirdThumbnailReference).not.toBe(null);
|
|
1407
|
+
if (firstThumbnailReference) {
|
|
1408
|
+
expect(firstThumbnailReference.getTilesLayout()).toBe('1x1');
|
|
1409
|
+
}
|
|
1410
|
+
if (secondThumbnailReference) {
|
|
1411
|
+
expect(secondThumbnailReference.getTilesLayout()).toBe('5x2');
|
|
1412
|
+
}
|
|
1413
|
+
if (thirdThumbnailReference) {
|
|
1414
|
+
expect(thirdThumbnailReference.getTilesLayout()).toBe('1x1');
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
|
|
1317
1418
|
it('Disable audio does not create audio streams', async () => {
|
|
1318
1419
|
const master = [
|
|
1319
1420
|
'#EXTM3U\n',
|
|
@@ -1324,6 +1425,8 @@ describe('HlsParser', () => {
|
|
|
1324
1425
|
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1325
1426
|
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1326
1427
|
'video\n',
|
|
1428
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg",',
|
|
1429
|
+
'URI="image"\n',
|
|
1327
1430
|
].join('');
|
|
1328
1431
|
|
|
1329
1432
|
const video = [
|
|
@@ -1356,11 +1459,23 @@ describe('HlsParser', () => {
|
|
|
1356
1459
|
'main.vtt',
|
|
1357
1460
|
].join('');
|
|
1358
1461
|
|
|
1462
|
+
const image = [
|
|
1463
|
+
'#EXTM3U\n',
|
|
1464
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1465
|
+
'#EXTINF:5,\n',
|
|
1466
|
+
'image.jpg\n',
|
|
1467
|
+
'#EXTINF:5,\n',
|
|
1468
|
+
'image.jpg\n',
|
|
1469
|
+
'#EXTINF:5,\n',
|
|
1470
|
+
'image.jpg\n',
|
|
1471
|
+
].join('');
|
|
1472
|
+
|
|
1359
1473
|
fakeNetEngine
|
|
1360
1474
|
.setResponseText('test:/master', master)
|
|
1361
1475
|
.setResponseText('test:/audio', audio)
|
|
1362
1476
|
.setResponseText('test:/video', video)
|
|
1363
1477
|
.setResponseText('test:/text', text)
|
|
1478
|
+
.setResponseText('test:/image', image)
|
|
1364
1479
|
.setResponseText('test:/main.vtt', vttText)
|
|
1365
1480
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1366
1481
|
.setResponseValue('test:/main.mp4', segmentData);
|
|
@@ -1385,6 +1500,8 @@ describe('HlsParser', () => {
|
|
|
1385
1500
|
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1386
1501
|
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1387
1502
|
'video\n',
|
|
1503
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg",',
|
|
1504
|
+
'URI="image"\n',
|
|
1388
1505
|
].join('');
|
|
1389
1506
|
|
|
1390
1507
|
const video = [
|
|
@@ -1417,11 +1534,23 @@ describe('HlsParser', () => {
|
|
|
1417
1534
|
'main.vtt',
|
|
1418
1535
|
].join('');
|
|
1419
1536
|
|
|
1537
|
+
const image = [
|
|
1538
|
+
'#EXTM3U\n',
|
|
1539
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1540
|
+
'#EXTINF:5,\n',
|
|
1541
|
+
'image.jpg\n',
|
|
1542
|
+
'#EXTINF:5,\n',
|
|
1543
|
+
'image.jpg\n',
|
|
1544
|
+
'#EXTINF:5,\n',
|
|
1545
|
+
'image.jpg\n',
|
|
1546
|
+
].join('');
|
|
1547
|
+
|
|
1420
1548
|
fakeNetEngine
|
|
1421
1549
|
.setResponseText('test:/master', master)
|
|
1422
1550
|
.setResponseText('test:/audio', audio)
|
|
1423
1551
|
.setResponseText('test:/video', video)
|
|
1424
1552
|
.setResponseText('test:/text', text)
|
|
1553
|
+
.setResponseText('test:/image', image)
|
|
1425
1554
|
.setResponseText('test:/main.vtt', vttText)
|
|
1426
1555
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1427
1556
|
.setResponseValue('test:/main.mp4', segmentData);
|
|
@@ -1446,6 +1575,8 @@ describe('HlsParser', () => {
|
|
|
1446
1575
|
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1447
1576
|
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1448
1577
|
'video\n',
|
|
1578
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg",',
|
|
1579
|
+
'URI="image"\n',
|
|
1449
1580
|
].join('');
|
|
1450
1581
|
|
|
1451
1582
|
const video = [
|
|
@@ -1478,11 +1609,23 @@ describe('HlsParser', () => {
|
|
|
1478
1609
|
'main.vtt',
|
|
1479
1610
|
].join('');
|
|
1480
1611
|
|
|
1612
|
+
const image = [
|
|
1613
|
+
'#EXTM3U\n',
|
|
1614
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1615
|
+
'#EXTINF:5,\n',
|
|
1616
|
+
'image.jpg\n',
|
|
1617
|
+
'#EXTINF:5,\n',
|
|
1618
|
+
'image.jpg\n',
|
|
1619
|
+
'#EXTINF:5,\n',
|
|
1620
|
+
'image.jpg\n',
|
|
1621
|
+
].join('');
|
|
1622
|
+
|
|
1481
1623
|
fakeNetEngine
|
|
1482
1624
|
.setResponseText('test:/master', master)
|
|
1483
1625
|
.setResponseText('test:/audio', audio)
|
|
1484
1626
|
.setResponseText('test:/video', video)
|
|
1485
1627
|
.setResponseText('test:/text', text)
|
|
1628
|
+
.setResponseText('test:/image', image)
|
|
1486
1629
|
.setResponseText('test:/main.vtt', vttText)
|
|
1487
1630
|
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1488
1631
|
.setResponseValue('test:/main.mp4', segmentData);
|
|
@@ -1496,6 +1639,80 @@ describe('HlsParser', () => {
|
|
|
1496
1639
|
expect(stream).toBeUndefined();
|
|
1497
1640
|
});
|
|
1498
1641
|
|
|
1642
|
+
it('Disable thumbnails does not create image streams', async () => {
|
|
1643
|
+
const master = [
|
|
1644
|
+
'#EXTM3U\n',
|
|
1645
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
1646
|
+
'URI="text"\n',
|
|
1647
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
1648
|
+
'CHANNELS="2",URI="audio"\n',
|
|
1649
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1650
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1651
|
+
'video\n',
|
|
1652
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg",',
|
|
1653
|
+
'URI="image"\n',
|
|
1654
|
+
].join('');
|
|
1655
|
+
|
|
1656
|
+
const video = [
|
|
1657
|
+
'#EXTM3U\n',
|
|
1658
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1659
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1660
|
+
'#EXTINF:5,\n',
|
|
1661
|
+
'main.mp4\n',
|
|
1662
|
+
'#EXTINF:5,\n',
|
|
1663
|
+
'main.mp4\n',
|
|
1664
|
+
'#EXTINF:5,\n',
|
|
1665
|
+
'main.mp4\n',
|
|
1666
|
+
].join('');
|
|
1667
|
+
|
|
1668
|
+
const audio = [
|
|
1669
|
+
'#EXTM3U\n',
|
|
1670
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1671
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1672
|
+
'#EXTINF:5,\n',
|
|
1673
|
+
'main.mp4\n',
|
|
1674
|
+
'#EXTINF:5,\n',
|
|
1675
|
+
'main.mp4\n',
|
|
1676
|
+
].join('');
|
|
1677
|
+
|
|
1678
|
+
const text = [
|
|
1679
|
+
'#EXTM3U\n',
|
|
1680
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1681
|
+
'#EXTINF:5,\n',
|
|
1682
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1683
|
+
'main.vtt',
|
|
1684
|
+
].join('');
|
|
1685
|
+
|
|
1686
|
+
const image = [
|
|
1687
|
+
'#EXTM3U\n',
|
|
1688
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1689
|
+
'#EXTINF:5,\n',
|
|
1690
|
+
'image.jpg\n',
|
|
1691
|
+
'#EXTINF:5,\n',
|
|
1692
|
+
'image.jpg\n',
|
|
1693
|
+
'#EXTINF:5,\n',
|
|
1694
|
+
'image.jpg\n',
|
|
1695
|
+
].join('');
|
|
1696
|
+
|
|
1697
|
+
fakeNetEngine
|
|
1698
|
+
.setResponseText('test:/master', master)
|
|
1699
|
+
.setResponseText('test:/audio', audio)
|
|
1700
|
+
.setResponseText('test:/video', video)
|
|
1701
|
+
.setResponseText('test:/text', text)
|
|
1702
|
+
.setResponseText('test:/image', image)
|
|
1703
|
+
.setResponseText('test:/main.vtt', vttText)
|
|
1704
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1705
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
1706
|
+
|
|
1707
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
1708
|
+
config.disableThumbnails = true;
|
|
1709
|
+
parser.configure(config);
|
|
1710
|
+
|
|
1711
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1712
|
+
const stream = actual.imageStreams[0];
|
|
1713
|
+
expect(stream).toBeUndefined();
|
|
1714
|
+
});
|
|
1715
|
+
|
|
1499
1716
|
it('parses manifest with MP4+TTML streams', async () => {
|
|
1500
1717
|
const master = [
|
|
1501
1718
|
'#EXTM3U\n',
|
|
@@ -1666,6 +1883,43 @@ describe('HlsParser', () => {
|
|
|
1666
1883
|
expect(actual).toEqual(manifest);
|
|
1667
1884
|
});
|
|
1668
1885
|
|
|
1886
|
+
it('drops failed image streams when configured to', async () => {
|
|
1887
|
+
const master = [
|
|
1888
|
+
'#EXTM3U\n',
|
|
1889
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
1890
|
+
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
1891
|
+
'video\n',
|
|
1892
|
+
'#EXT-X-IMAGE-STREAM-INF:RESOLUTION=240×135,CODECS="jpeg"\n',
|
|
1893
|
+
].join('');
|
|
1894
|
+
|
|
1895
|
+
const media = [
|
|
1896
|
+
'#EXTM3U\n',
|
|
1897
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1898
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1899
|
+
'#EXTINF:5,\n',
|
|
1900
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1901
|
+
'main.mp4',
|
|
1902
|
+
].join('');
|
|
1903
|
+
|
|
1904
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
1905
|
+
manifest.anyTimeline();
|
|
1906
|
+
manifest.addPartialVariant((variant) => {
|
|
1907
|
+
variant.addPartialStream(ContentType.VIDEO);
|
|
1908
|
+
});
|
|
1909
|
+
});
|
|
1910
|
+
|
|
1911
|
+
fakeNetEngine
|
|
1912
|
+
.setResponseText('test:/master', master)
|
|
1913
|
+
.setResponseText('test:/audio', media)
|
|
1914
|
+
.setResponseText('test:/video', media)
|
|
1915
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1916
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
1917
|
+
|
|
1918
|
+
config.hls.ignoreImageStreamFailures = true;
|
|
1919
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1920
|
+
expect(actual).toEqual(manifest);
|
|
1921
|
+
});
|
|
1922
|
+
|
|
1669
1923
|
it('parses video described by a media tag', async () => {
|
|
1670
1924
|
const master = [
|
|
1671
1925
|
'#EXTM3U\n',
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
goog.require('shaka.media.ClosedCaptionParser');
|
|
2
8
|
goog.require('shaka.test.Util');
|
|
3
9
|
|
|
@@ -12,4 +18,3 @@ describe('ClosedCaptionParser', () => {
|
|
|
12
18
|
parser.parseFrom(videoSegment);
|
|
13
19
|
});
|
|
14
20
|
});
|
|
15
|
-
|
|
@@ -162,7 +162,7 @@ describe('DrmEngine', () => {
|
|
|
162
162
|
document.body.removeChild(video);
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
-
function
|
|
165
|
+
function checkTrueDrmSupport() {
|
|
166
166
|
if (shaka.util.Platform.isXboxOne()) {
|
|
167
167
|
// Axinom won't issue a license for an Xbox One. The error message from
|
|
168
168
|
// the license server says "Your DRM client's security level is 150, but
|
|
@@ -174,16 +174,11 @@ describe('DrmEngine', () => {
|
|
|
174
174
|
return support['com.widevine.alpha'] || support['com.microsoft.playready'];
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
filterDescribe('basic flow with MediaCapabilities ' + isEnabled,
|
|
180
|
-
checkSupport, () => {
|
|
181
|
-
testBasicFlow(useMediaCapabilities);
|
|
182
|
-
});
|
|
177
|
+
function checkClearKeySupport() {
|
|
178
|
+
return support['org.w3.clearkey'];
|
|
183
179
|
}
|
|
184
180
|
|
|
185
|
-
|
|
186
|
-
function testBasicFlow(useMediaCapabilities) {
|
|
181
|
+
filterDescribe('basic flow', checkTrueDrmSupport, () => {
|
|
187
182
|
drmIt('gets a license and can play encrypted segments', async () => {
|
|
188
183
|
// The error callback should not be invoked.
|
|
189
184
|
onErrorSpy.and.callFake(fail);
|
|
@@ -226,8 +221,7 @@ describe('DrmEngine', () => {
|
|
|
226
221
|
|
|
227
222
|
const variants = manifest.variants;
|
|
228
223
|
|
|
229
|
-
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds
|
|
230
|
-
useMediaCapabilities);
|
|
224
|
+
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
|
|
231
225
|
await drmEngine.attach(video);
|
|
232
226
|
await mediaSourceEngine.appendBuffer(
|
|
233
227
|
ContentType.VIDEO, videoInitSegment, null, null,
|
|
@@ -283,5 +277,85 @@ describe('DrmEngine', () => {
|
|
|
283
277
|
expect(video.readyState).toBeGreaterThan(1);
|
|
284
278
|
expect(video.currentTime).toBeGreaterThan(0);
|
|
285
279
|
});
|
|
286
|
-
} // describe('basic flow')
|
|
280
|
+
}); // describe('basic flow')
|
|
281
|
+
|
|
282
|
+
filterDescribe('ClearKey', checkClearKeySupport, () => {
|
|
283
|
+
drmIt('plays encrypted content with the ClearKey CDM', async () => {
|
|
284
|
+
// Configure DrmEngine for ClearKey playback.
|
|
285
|
+
const config = shaka.util.PlayerConfiguration.createDefault().drm;
|
|
286
|
+
config.clearKeys = {
|
|
287
|
+
// From https://github.com/Axinom/public-test-vectors/tree/conservative#v61-multidrm
|
|
288
|
+
'6e5a1d26275747d78046eaa5d1d34b5a': '197f26f572c864d2338b3ae5d114ea9c',
|
|
289
|
+
};
|
|
290
|
+
drmEngine.configure(config);
|
|
291
|
+
|
|
292
|
+
// The error callback should not be invoked.
|
|
293
|
+
onErrorSpy.and.callFake(fail);
|
|
294
|
+
|
|
295
|
+
/** @type {!shaka.util.PublicPromise} */
|
|
296
|
+
const encryptedEventSeen = new shaka.util.PublicPromise();
|
|
297
|
+
eventManager.listen(video, 'encrypted', () => {
|
|
298
|
+
encryptedEventSeen.resolve();
|
|
299
|
+
});
|
|
300
|
+
eventManager.listen(video, 'error', () => {
|
|
301
|
+
fail('MediaError code ' + video.error.code);
|
|
302
|
+
let extended = video.error.msExtendedCode;
|
|
303
|
+
if (extended) {
|
|
304
|
+
if (extended < 0) {
|
|
305
|
+
extended += Math.pow(2, 32);
|
|
306
|
+
}
|
|
307
|
+
fail('MediaError msExtendedCode ' + extended.toString(16));
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
/** @type {!shaka.util.PublicPromise} */
|
|
312
|
+
const keyStatusEventSeen = new shaka.util.PublicPromise();
|
|
313
|
+
onKeyStatusSpy.and.callFake(() => {
|
|
314
|
+
keyStatusEventSeen.resolve();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const variants = manifest.variants;
|
|
318
|
+
|
|
319
|
+
await drmEngine.initForPlayback(variants, manifest.offlineSessionIds);
|
|
320
|
+
await drmEngine.attach(video);
|
|
321
|
+
await mediaSourceEngine.appendBuffer(
|
|
322
|
+
ContentType.VIDEO, videoInitSegment, null, null,
|
|
323
|
+
/* hasClosedCaptions= */ false);
|
|
324
|
+
await mediaSourceEngine.appendBuffer(
|
|
325
|
+
ContentType.AUDIO, audioInitSegment, null, null,
|
|
326
|
+
/* hasClosedCaptions= */ false);
|
|
327
|
+
await encryptedEventSeen;
|
|
328
|
+
|
|
329
|
+
// Some platforms (notably 2017 Tizen TVs) do not fire key status
|
|
330
|
+
// events.
|
|
331
|
+
const keyStatusTimeout = shaka.test.Util.delay(5);
|
|
332
|
+
await Promise.race([keyStatusTimeout, keyStatusEventSeen]);
|
|
333
|
+
|
|
334
|
+
const call = onKeyStatusSpy.calls.mostRecent();
|
|
335
|
+
if (call) {
|
|
336
|
+
const map = /** @type {!Object} */ (call.args[0]);
|
|
337
|
+
expect(Object.keys(map).length).not.toBe(0);
|
|
338
|
+
for (const k in map) {
|
|
339
|
+
expect(map[k]).toBe('usable');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
await mediaSourceEngine.appendBuffer(
|
|
344
|
+
ContentType.VIDEO, videoSegment, 0, 10,
|
|
345
|
+
/* hasClosedCaptions= */ false);
|
|
346
|
+
await mediaSourceEngine.appendBuffer(
|
|
347
|
+
ContentType.AUDIO, audioSegment, 0, 10,
|
|
348
|
+
/* hasClosedCaptions= */ false);
|
|
349
|
+
|
|
350
|
+
expect(video.buffered.end(0)).toBeGreaterThan(0);
|
|
351
|
+
video.play();
|
|
352
|
+
|
|
353
|
+
const waiter = new shaka.test.Waiter(eventManager).timeoutAfter(15);
|
|
354
|
+
await waiter.waitForMovement(video);
|
|
355
|
+
|
|
356
|
+
// Something should have played by now.
|
|
357
|
+
expect(video.readyState).toBeGreaterThan(1);
|
|
358
|
+
expect(video.currentTime).toBeGreaterThan(0);
|
|
359
|
+
});
|
|
360
|
+
}); // describe('ClearKey')
|
|
287
361
|
});
|