shaka-player 4.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/config.yml +1 -0
- package/.github/workflows/release-please.yaml +6 -11
- package/CHANGELOG.md +15 -0
- package/build/misspellings.txt +1 -0
- package/dist/controls.css +1 -1
- package/dist/locales.js +32 -32
- package/dist/shaka-player.compiled.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.externs.js +1 -0
- package/dist/shaka-player.compiled.debug.js +170 -165
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +1 -0
- package/dist/shaka-player.compiled.js +783 -779
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +2 -1
- package/dist/shaka-player.ui.debug.d.ts +2 -1
- package/dist/shaka-player.ui.debug.externs.js +1 -0
- package/dist/shaka-player.ui.debug.js +182 -177
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +1 -0
- package/dist/shaka-player.ui.js +924 -920
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/upgrade.md +4 -2
- package/externs/shaka/player.js +11 -0
- package/karma.conf.js +4 -0
- package/lib/dash/dash_parser.js +2 -2
- package/lib/hls/hls_parser.js +20 -11
- package/lib/media/drm_engine.js +16 -0
- package/lib/media/media_source_engine.js +91 -37
- package/lib/media/streaming_engine.js +1 -2
- package/lib/offline/indexeddb/storage_mechanism.js +4 -2
- package/lib/player.js +165 -107
- package/lib/text/vtt_text_parser.js +7 -7
- package/lib/util/config_utils.js +25 -0
- package/lib/util/error.js +7 -0
- package/lib/util/manifest_parser_utils.js +1 -1
- package/lib/util/mime_utils.js +48 -1
- package/lib/util/periods.js +5 -4
- package/lib/util/player_configuration.js +14 -14
- package/lib/util/stream_utils.js +4 -2
- package/package.json +4 -1
- package/test/hls/hls_live_unit.js +22 -0
- package/test/hls/manifest_text_parser_unit.js +19 -0
- package/test/offline/indexeddb_storage_unit.js +1 -1
- package/test/offline/storage_compatibility_unit.js +1 -1
- package/test/player_external.js +7 -1
- package/test/player_integration.js +6 -10
- package/test/player_src_equals_integration.js +81 -83
- package/test/player_unit.js +98 -1
- package/test/test/boot.js +9 -0
- package/test/test/externs/filters.js +4 -0
- package/test/test/util/simple_fakes.js +31 -2
- package/test/text/vtt_text_parser_unit.js +64 -5
- package/test/util/mime_utils_unit.js +54 -0
- package/test/util/periods_unit.js +79 -0
- package/ui/resolution_selection.js +1 -1
- package/docs/tutorials/gsoc-ideas-list.md +0 -3
|
@@ -535,7 +535,61 @@ describe('VttTextParser', () => {
|
|
|
535
535
|
'Test\n\n' +
|
|
536
536
|
'00:00:40.000 --> 00:00:50.000 line:-1\n' +
|
|
537
537
|
'Test2',
|
|
538
|
-
{periodStart: 0, segmentStart: 25, segmentEnd: 65, vttOffset: 0}
|
|
538
|
+
{periodStart: 0, segmentStart: 25, segmentEnd: 65, vttOffset: 0},
|
|
539
|
+
/* sequenceMode= */ true);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it('ignores X-TIMESTAMP-MAP header if not in sequence mode', () => {
|
|
543
|
+
verifyHelper(
|
|
544
|
+
[
|
|
545
|
+
{startTime: 20, endTime: 40, payload: 'Test'},
|
|
546
|
+
{startTime: 40, endTime: 50, payload: 'Test2'},
|
|
547
|
+
],
|
|
548
|
+
'WEBVTT\n' +
|
|
549
|
+
'X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:01:00:00.000\n\n' +
|
|
550
|
+
'00:00:20.000 --> 00:00:40.000 line:0\n' +
|
|
551
|
+
'Test\n\n' +
|
|
552
|
+
'00:00:40.000 --> 00:00:50.000 line:-1\n' +
|
|
553
|
+
'Test2',
|
|
554
|
+
{periodStart: 0, segmentStart: 25, segmentEnd: 65, vttOffset: 0},
|
|
555
|
+
/* sequenceMode= */ false);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('parses X-TIMESTAMP-MAP header with non-zero local base', () => {
|
|
559
|
+
verifyHelper(
|
|
560
|
+
[
|
|
561
|
+
{startTime: 1800, endTime: 1810, payload: 'Test'},
|
|
562
|
+
{startTime: 1820, endTime: 1830, payload: 'Test2'},
|
|
563
|
+
],
|
|
564
|
+
// 162000000 = 30 * 60 * 90k = 30 minutes for the TS part of the map.
|
|
565
|
+
// The local (VTT) part of the map is 1 hour.
|
|
566
|
+
// So text times of 1 hour map to media times of 30 minutes.
|
|
567
|
+
'WEBVTT\n' +
|
|
568
|
+
'X-TIMESTAMP-MAP=MPEGTS:162000000,LOCAL:01:00:00.000\n\n' +
|
|
569
|
+
'01:00:00.000 --> 01:00:10.000 line:0\n' +
|
|
570
|
+
'Test\n\n' +
|
|
571
|
+
'01:00:20.000 --> 01:00:30.000 line:-1\n' +
|
|
572
|
+
'Test2',
|
|
573
|
+
{periodStart: 0, segmentStart: 25, segmentEnd: 65, vttOffset: 0},
|
|
574
|
+
/* sequenceMode= */ true);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
it('combines X-TIMESTAMP-MAP header with periodStart', () => {
|
|
578
|
+
verifyHelper(
|
|
579
|
+
[
|
|
580
|
+
{startTime: 130, endTime: 150, payload: 'Test'},
|
|
581
|
+
{startTime: 150, endTime: 160, payload: 'Test2'},
|
|
582
|
+
],
|
|
583
|
+
// 900000 = 10 sec, so expect every timestamp to be 10
|
|
584
|
+
// seconds ahead of what is specified.
|
|
585
|
+
'WEBVTT\n' +
|
|
586
|
+
'X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000\n\n' +
|
|
587
|
+
'00:00:20.000 --> 00:00:40.000 line:0\n' +
|
|
588
|
+
'Test\n\n' +
|
|
589
|
+
'00:00:40.000 --> 00:00:50.000 line:-1\n' +
|
|
590
|
+
'Test2',
|
|
591
|
+
{periodStart: 100, segmentStart: 25, segmentEnd: 65, vttOffset: 0},
|
|
592
|
+
/* sequenceMode= */ true);
|
|
539
593
|
});
|
|
540
594
|
|
|
541
595
|
it('handles timestamp rollover with X-TIMESTAMP-MAP header', () => {
|
|
@@ -551,7 +605,8 @@ describe('VttTextParser', () => {
|
|
|
551
605
|
'Test',
|
|
552
606
|
// Non-null segmentStart takes precedence over X-TIMESTAMP-MAP.
|
|
553
607
|
// This protects us from rollover in the MPEGTS field.
|
|
554
|
-
{periodStart: 0, segmentStart: 95440, segmentEnd: 95550, vttOffset: 0}
|
|
608
|
+
{periodStart: 0, segmentStart: 95440, segmentEnd: 95550, vttOffset: 0},
|
|
609
|
+
/* sequenceMode= */ true);
|
|
555
610
|
|
|
556
611
|
verifyHelper(
|
|
557
612
|
[
|
|
@@ -564,7 +619,8 @@ describe('VttTextParser', () => {
|
|
|
564
619
|
'X-TIMESTAMP-MAP=MPEGTS:9745408,LOCAL:00:00:00.000\n\n' +
|
|
565
620
|
'00:00:00.000 --> 00:00:02.000 line:0\n' +
|
|
566
621
|
'Test2',
|
|
567
|
-
{periodStart: 0, segmentStart: 95550, segmentEnd: 95560, vttOffset: 0}
|
|
622
|
+
{periodStart: 0, segmentStart: 95550, segmentEnd: 95560, vttOffset: 0},
|
|
623
|
+
/* sequenceMode= */ true);
|
|
568
624
|
});
|
|
569
625
|
|
|
570
626
|
it('supports global style blocks', () => {
|
|
@@ -978,11 +1034,14 @@ describe('VttTextParser', () => {
|
|
|
978
1034
|
* @param {!Array} cues
|
|
979
1035
|
* @param {string} text
|
|
980
1036
|
* @param {shaka.extern.TextParser.TimeContext} time
|
|
1037
|
+
* @param {boolean=} sequenceMode
|
|
981
1038
|
*/
|
|
982
|
-
function verifyHelper(cues, text, time) {
|
|
1039
|
+
function verifyHelper(cues, text, time, sequenceMode = false) {
|
|
983
1040
|
const data =
|
|
984
1041
|
shaka.util.BufferUtils.toUint8(shaka.util.StringUtils.toUTF8(text));
|
|
985
|
-
const
|
|
1042
|
+
const parser = new shaka.text.VttTextParser();
|
|
1043
|
+
parser.setSequenceMode(sequenceMode);
|
|
1044
|
+
const result = parser.parseMedia(data, time);
|
|
986
1045
|
|
|
987
1046
|
const expected = cues.map((cue) => {
|
|
988
1047
|
if (cue.nestedCues) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('MimeUtils', () => {
|
|
8
|
+
const getNormalizedCodec = (codecs) =>
|
|
9
|
+
shaka.util.MimeUtils.getNormalizedCodec(codecs);
|
|
10
|
+
|
|
11
|
+
it('normalizes codecs', () => {
|
|
12
|
+
expect(getNormalizedCodec('mp4a.66')).toBe('aac');
|
|
13
|
+
expect(getNormalizedCodec('mp4a.67')).toBe('aac');
|
|
14
|
+
expect(getNormalizedCodec('mp4a.68')).toBe('aac');
|
|
15
|
+
|
|
16
|
+
expect(getNormalizedCodec('mp3')).toBe('mp3');
|
|
17
|
+
expect(getNormalizedCodec('mp4a.69')).toBe('mp3');
|
|
18
|
+
expect(getNormalizedCodec('mp4a.6B')).toBe('mp3');
|
|
19
|
+
expect(getNormalizedCodec('mp4a.6b')).toBe('mp3');
|
|
20
|
+
|
|
21
|
+
expect(getNormalizedCodec('mp4a.40.2')).toBe('aac');
|
|
22
|
+
expect(getNormalizedCodec('mp4a.40.02')).toBe('aac');
|
|
23
|
+
expect(getNormalizedCodec('mp4a.40.5')).toBe('aac');
|
|
24
|
+
expect(getNormalizedCodec('mp4a.40.05')).toBe('aac');
|
|
25
|
+
expect(getNormalizedCodec('mp4a.40.29')).toBe('aac');
|
|
26
|
+
expect(getNormalizedCodec('mp4a.40.42')).toBe('aac');
|
|
27
|
+
|
|
28
|
+
expect(getNormalizedCodec('ac-3')).toBe('ac-3');
|
|
29
|
+
expect(getNormalizedCodec('mp4a.a5')).toBe('ac-3');
|
|
30
|
+
expect(getNormalizedCodec('mp4a.A5')).toBe('ac-3');
|
|
31
|
+
|
|
32
|
+
expect(getNormalizedCodec('ec-3')).toBe('ec-3');
|
|
33
|
+
expect(getNormalizedCodec('mp4a.a6')).toBe('ec-3');
|
|
34
|
+
expect(getNormalizedCodec('mp4a.A6')).toBe('ec-3');
|
|
35
|
+
|
|
36
|
+
expect(getNormalizedCodec('dtsc')).toBe('dtsc');
|
|
37
|
+
expect(getNormalizedCodec('mp4a.a9')).toBe('dtsc');
|
|
38
|
+
|
|
39
|
+
expect(getNormalizedCodec('dtsx')).toBe('dtsx');
|
|
40
|
+
expect(getNormalizedCodec('mp4a.b2')).toBe('dtsx');
|
|
41
|
+
|
|
42
|
+
expect(getNormalizedCodec('vp8')).toBe('vp8');
|
|
43
|
+
expect(getNormalizedCodec('vp8.0')).toBe('vp8');
|
|
44
|
+
|
|
45
|
+
expect(getNormalizedCodec('avc1')).toBe('avc');
|
|
46
|
+
expect(getNormalizedCodec('avc3')).toBe('avc');
|
|
47
|
+
|
|
48
|
+
expect(getNormalizedCodec('hvc1')).toBe('hevc');
|
|
49
|
+
expect(getNormalizedCodec('hev1')).toBe('hevc');
|
|
50
|
+
|
|
51
|
+
expect(getNormalizedCodec('dvh1.05')).toBe('dovi');
|
|
52
|
+
expect(getNormalizedCodec('dvhe.05')).toBe('dovi');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -996,6 +996,85 @@ describe('PeriodCombiner', () => {
|
|
|
996
996
|
expect(audio2.originalId).toBe('2,4');
|
|
997
997
|
});
|
|
998
998
|
|
|
999
|
+
it('Matches streams with related codecs', async () => {
|
|
1000
|
+
const stream1 = makeVideoStream(1080);
|
|
1001
|
+
stream1.originalId = '1';
|
|
1002
|
+
stream1.bandwidth = 120000;
|
|
1003
|
+
stream1.codecs = 'hvc1.1.4.L126.B0';
|
|
1004
|
+
|
|
1005
|
+
const stream2 = makeVideoStream(1080);
|
|
1006
|
+
stream2.originalId = '2';
|
|
1007
|
+
stream2.bandwidth = 120000;
|
|
1008
|
+
stream2.codecs = 'hev1.2.4.L123.B0';
|
|
1009
|
+
|
|
1010
|
+
const stream3 = makeVideoStream(1080);
|
|
1011
|
+
stream3.originalId = '3';
|
|
1012
|
+
stream3.bandwidth = 120000;
|
|
1013
|
+
stream3.codecs = 'dvhe.05.01';
|
|
1014
|
+
|
|
1015
|
+
const stream4 = makeVideoStream(1080);
|
|
1016
|
+
stream4.originalId = '4';
|
|
1017
|
+
stream4.bandwidth = 120000;
|
|
1018
|
+
stream4.codecs = 'dvh1.05.01';
|
|
1019
|
+
|
|
1020
|
+
const stream5 = makeVideoStream(1080);
|
|
1021
|
+
stream5.originalId = '5';
|
|
1022
|
+
stream5.bandwidth = 120000;
|
|
1023
|
+
stream5.codecs = 'avc1.42001f';
|
|
1024
|
+
|
|
1025
|
+
const stream6 = makeVideoStream(1080);
|
|
1026
|
+
stream6.originalId = '6';
|
|
1027
|
+
stream6.bandwidth = 120000;
|
|
1028
|
+
stream6.codecs = 'avc3.42001f';
|
|
1029
|
+
|
|
1030
|
+
const stream7 = makeVideoStream(1080);
|
|
1031
|
+
stream7.originalId = '7';
|
|
1032
|
+
stream7.bandwidth = 120000;
|
|
1033
|
+
stream7.codecs = 'vp09.00.10.08';
|
|
1034
|
+
|
|
1035
|
+
const stream8 = makeVideoStream(1080);
|
|
1036
|
+
stream8.originalId = '8';
|
|
1037
|
+
stream8.bandwidth = 120000;
|
|
1038
|
+
stream8.codecs = 'vp09.01.20.08.01';
|
|
1039
|
+
|
|
1040
|
+
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
1041
|
+
const periods = [
|
|
1042
|
+
{
|
|
1043
|
+
id: '0',
|
|
1044
|
+
videoStreams: [
|
|
1045
|
+
stream1, stream3, stream5, stream7,
|
|
1046
|
+
],
|
|
1047
|
+
audioStreams: [],
|
|
1048
|
+
textStreams: [],
|
|
1049
|
+
imageStreams: [],
|
|
1050
|
+
},
|
|
1051
|
+
{
|
|
1052
|
+
id: '1',
|
|
1053
|
+
videoStreams: [
|
|
1054
|
+
stream2, stream4, stream6, stream8,
|
|
1055
|
+
],
|
|
1056
|
+
audioStreams: [],
|
|
1057
|
+
textStreams: [],
|
|
1058
|
+
imageStreams: [],
|
|
1059
|
+
},
|
|
1060
|
+
];
|
|
1061
|
+
|
|
1062
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ true);
|
|
1063
|
+
const variants = combiner.getVariants();
|
|
1064
|
+
expect(variants.length).toBe(4);
|
|
1065
|
+
// We can use the originalId field to see what each track is composed of.
|
|
1066
|
+
const video1 = variants[0].video;
|
|
1067
|
+
expect(video1.originalId).toBe('1,2');
|
|
1068
|
+
|
|
1069
|
+
const video2 = variants[1].video;
|
|
1070
|
+
expect(video2.originalId).toBe('3,4');
|
|
1071
|
+
|
|
1072
|
+
const video3 = variants[2].video;
|
|
1073
|
+
expect(video3.originalId).toBe('5,6');
|
|
1074
|
+
|
|
1075
|
+
const video4 = variants[3].video;
|
|
1076
|
+
expect(video4.originalId).toBe('7,8');
|
|
1077
|
+
});
|
|
999
1078
|
|
|
1000
1079
|
it('Matches streams with most roles in common', async () => {
|
|
1001
1080
|
const makeAudioStreamWithRoles = (roles) => {
|
|
@@ -90,7 +90,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
90
90
|
return otherIdx == idx;
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
// Sort the tracks by height or
|
|
93
|
+
// Sort the tracks by height or bandwidth depending on content type.
|
|
94
94
|
if (this.player.isAudioOnly()) {
|
|
95
95
|
tracks.sort((t1, t2) => {
|
|
96
96
|
goog.asserts.assert(t1.bandwidth != null, 'Null bandwidth');
|