shaka-player 4.3.7 → 4.3.8
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/appspot.yaml +39 -0
- package/CHANGELOG.md +25 -0
- package/CONTRIBUTORS +1 -0
- package/demo/custom.js +1 -1
- package/dist/demo.compiled.debug.js +2 -2
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +2 -2
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +1 -1
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +22 -0
- package/dist/shaka-player.compiled.debug.d.ts +22 -0
- package/dist/shaka-player.compiled.debug.js +215 -213
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +789 -786
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +22 -0
- package/dist/shaka-player.ui.debug.d.ts +22 -0
- package/dist/shaka-player.ui.debug.js +253 -252
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +823 -820
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/drm-config.md +9 -6
- package/externs/ima.js +34 -0
- package/lib/abr/simple_abr_manager.js +1 -1
- package/lib/cea/mp4_cea_parser.js +24 -18
- package/lib/dash/dash_parser.js +18 -3
- package/lib/hls/hls_parser.js +23 -4
- package/lib/media/drm_engine.js +14 -8
- package/lib/media/gap_jumping_controller.js +24 -2
- package/lib/media/media_source_engine.js +5 -3
- package/lib/media/playhead.js +11 -0
- package/lib/media/region_observer.js +19 -1
- package/lib/media/streaming_engine.js +39 -19
- package/lib/media/video_wrapper.js +6 -1
- package/lib/player.js +12 -5
- package/lib/polyfill/abort_controller.js +7 -0
- package/lib/text/vtt_text_parser.js +2 -1
- package/lib/util/manifest_parser_utils.js +1 -1
- package/lib/util/stream_utils.js +1 -0
- package/package.json +2 -2
- package/test/cea/mp4_cea_parser_unit.js +28 -5
- package/test/dash/dash_parser_manifest_unit.js +120 -0
- package/test/hls/hls_parser_unit.js +144 -0
- package/test/media/region_observer_unit.js +2 -1
- package/test/media/streaming_engine_unit.js +26 -2
- package/test/test/assets/multiple-trun-init.mp4 +0 -0
- package/test/test/assets/multiple-trun-segment.mp4 +0 -0
- package/ui/resolution_selection.js +7 -1
package/lib/player.js
CHANGED
|
@@ -99,7 +99,9 @@ goog.requireType('shaka.routing.Payload');
|
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* @event shaka.Player.EmsgEvent
|
|
102
|
-
* @description Fired when
|
|
102
|
+
* @description Fired when an emsg box is found in a segment.
|
|
103
|
+
* If the application calls preventDefault() on this event, further parsing
|
|
104
|
+
* will not happen, and no 'metadata' event will be raised for ID3 payloads.
|
|
103
105
|
* @property {string} type
|
|
104
106
|
* 'emsg'
|
|
105
107
|
* @property {shaka.extern.EmsgInfo} detail
|
|
@@ -2191,7 +2193,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2191
2193
|
}
|
|
2192
2194
|
|
|
2193
2195
|
this.playhead_ = this.createPlayhead(has.startTime);
|
|
2194
|
-
this.playheadObservers_ =
|
|
2196
|
+
this.playheadObservers_ =
|
|
2197
|
+
this.createPlayheadObserversForMSE_(has.startTimeOfLoad);
|
|
2195
2198
|
|
|
2196
2199
|
// We need to start the buffer management code near the end because it will
|
|
2197
2200
|
// set the initial buffering state and that depends on other components
|
|
@@ -2918,17 +2921,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2918
2921
|
* Create the observers for MSE playback. These observers are responsible for
|
|
2919
2922
|
* notifying the app and player of specific events during MSE playback.
|
|
2920
2923
|
*
|
|
2924
|
+
* @param {number} startTimeOfLoad
|
|
2921
2925
|
* @return {!shaka.media.PlayheadObserverManager}
|
|
2922
2926
|
* @private
|
|
2923
2927
|
*/
|
|
2924
|
-
createPlayheadObserversForMSE_() {
|
|
2928
|
+
createPlayheadObserversForMSE_(startTimeOfLoad) {
|
|
2925
2929
|
goog.asserts.assert(this.manifest_, 'Must have manifest');
|
|
2926
2930
|
goog.asserts.assert(this.regionTimeline_, 'Must have region timeline');
|
|
2927
2931
|
goog.asserts.assert(this.video_, 'Must have video element');
|
|
2928
2932
|
|
|
2933
|
+
const startsPastZero = this.isLive() || startTimeOfLoad > 0;
|
|
2934
|
+
|
|
2929
2935
|
// Create the region observer. This will allow us to notify the app when we
|
|
2930
2936
|
// move in and out of timeline regions.
|
|
2931
|
-
const regionObserver = new shaka.media.RegionObserver(
|
|
2937
|
+
const regionObserver = new shaka.media.RegionObserver(
|
|
2938
|
+
this.regionTimeline_, startsPastZero);
|
|
2932
2939
|
|
|
2933
2940
|
regionObserver.addEventListener('enter', (event) => {
|
|
2934
2941
|
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
@@ -7009,7 +7016,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7009
7016
|
* @define {string} A version number taken from git at compile time.
|
|
7010
7017
|
* @export
|
|
7011
7018
|
*/
|
|
7012
|
-
shaka.Player.version = 'v4.3.
|
|
7019
|
+
shaka.Player.version = 'v4.3.8-uncompiled';
|
|
7013
7020
|
|
|
7014
7021
|
// Initialize the deprecation system using the version string we just set
|
|
7015
7022
|
// on the player.
|
|
@@ -785,7 +785,8 @@ shaka.text.VttTextParser = class {
|
|
|
785
785
|
} else if ((results = /^size:([\d.]+)%$/.exec(word))) {
|
|
786
786
|
cue.size = Number(results[1]);
|
|
787
787
|
} else if ((results =
|
|
788
|
-
|
|
788
|
+
// eslint-disable-next-line max-len
|
|
789
|
+
/^position:([\d.]+)%(?:,(line-left|line-right|middle|center|start|end))?$/
|
|
789
790
|
.exec(word))) {
|
|
790
791
|
cue.position = Number(results[1]);
|
|
791
792
|
if (results[2]) {
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -1068,6 +1068,7 @@ shaka.util.StreamUtils = class {
|
|
|
1068
1068
|
track.frameRate = video.frameRate || null;
|
|
1069
1069
|
track.pixelAspectRatio = video.pixelAspectRatio || null;
|
|
1070
1070
|
track.videoBandwidth = video.bandwidth || null;
|
|
1071
|
+
track.hdr = video.hdr || null;
|
|
1071
1072
|
}
|
|
1072
1073
|
|
|
1073
1074
|
if (audio) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shaka-player",
|
|
3
3
|
"description": "DASH/EME video player library",
|
|
4
|
-
"version": "4.3.
|
|
4
|
+
"version": "4.3.8",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"karma-coverage": "^2.2.0",
|
|
43
43
|
"karma-jasmine": "^4.0.1",
|
|
44
44
|
"karma-jasmine-ajax": "^0.1.13",
|
|
45
|
-
"karma-local-wd-launcher": "^1.6.
|
|
45
|
+
"karma-local-wd-launcher": "^1.6.2",
|
|
46
46
|
"karma-opera-launcher": "^1.0.0",
|
|
47
47
|
"karma-sourcemap-loader": "^0.3.8",
|
|
48
48
|
"karma-spec-reporter": "^0.0.34",
|
|
@@ -9,6 +9,10 @@ describe('Mp4CeaParser', () => {
|
|
|
9
9
|
const ceaSegmentUri = '/base/test/test/assets/cea-segment.mp4';
|
|
10
10
|
const h265ceaInitSegmentUri = '/base/test/test/assets/h265-cea-init.mp4';
|
|
11
11
|
const h265ceaSegmentUri = '/base/test/test/assets/h265-cea-segment.mp4';
|
|
12
|
+
const multipleTrunInitSegmentUri =
|
|
13
|
+
'/base/test/test/assets/multiple-trun-init.mp4';
|
|
14
|
+
const multipleTrunSegmentUri =
|
|
15
|
+
'/base/test/test/assets/multiple-trun-segment.mp4';
|
|
12
16
|
const Util = shaka.test.Util;
|
|
13
17
|
|
|
14
18
|
/** @type {!ArrayBuffer} */
|
|
@@ -19,18 +23,27 @@ describe('Mp4CeaParser', () => {
|
|
|
19
23
|
let h265ceaInitSegment;
|
|
20
24
|
/** @type {!ArrayBuffer} */
|
|
21
25
|
let h265ceaSegment;
|
|
26
|
+
/** @type {!ArrayBuffer} */
|
|
27
|
+
let multipleTrunInitSegment;
|
|
28
|
+
/** @type {!ArrayBuffer} */
|
|
29
|
+
let multipleTrunSegment;
|
|
22
30
|
|
|
23
31
|
beforeAll(async () => {
|
|
24
|
-
|
|
32
|
+
[
|
|
33
|
+
ceaInitSegment,
|
|
34
|
+
ceaSegment,
|
|
35
|
+
h265ceaInitSegment,
|
|
36
|
+
h265ceaSegment,
|
|
37
|
+
multipleTrunInitSegment,
|
|
38
|
+
multipleTrunSegment,
|
|
39
|
+
] = await Promise.all([
|
|
25
40
|
shaka.test.Util.fetch(ceaInitSegmentUri),
|
|
26
41
|
shaka.test.Util.fetch(ceaSegmentUri),
|
|
27
42
|
shaka.test.Util.fetch(h265ceaInitSegmentUri),
|
|
28
43
|
shaka.test.Util.fetch(h265ceaSegmentUri),
|
|
44
|
+
shaka.test.Util.fetch(multipleTrunInitSegmentUri),
|
|
45
|
+
shaka.test.Util.fetch(multipleTrunSegmentUri),
|
|
29
46
|
]);
|
|
30
|
-
ceaInitSegment = responses[0];
|
|
31
|
-
ceaSegment = responses[1];
|
|
32
|
-
h265ceaInitSegment = responses[2];
|
|
33
|
-
h265ceaSegment = responses[3];
|
|
34
47
|
});
|
|
35
48
|
|
|
36
49
|
/**
|
|
@@ -89,6 +102,16 @@ describe('Mp4CeaParser', () => {
|
|
|
89
102
|
expect(ceaPackets.length).toBe(60);
|
|
90
103
|
});
|
|
91
104
|
|
|
105
|
+
it('parses cea data from a segment with multiple trun boxes', () => {
|
|
106
|
+
const ceaParser = new shaka.cea.Mp4CeaParser();
|
|
107
|
+
|
|
108
|
+
ceaParser.init(multipleTrunInitSegment);
|
|
109
|
+
const ceaPackets = ceaParser.parse(multipleTrunSegment);
|
|
110
|
+
// The first trun box references samples with 48 CEA packets.
|
|
111
|
+
// The second trun box references samples with 132 more, for a total of 180.
|
|
112
|
+
expect(ceaPackets.length).toBe(180);
|
|
113
|
+
});
|
|
114
|
+
|
|
92
115
|
it('parses an invalid init segment', () => {
|
|
93
116
|
const cea708Parser = new shaka.cea.Mp4CeaParser();
|
|
94
117
|
|
|
@@ -2023,6 +2023,66 @@ describe('DashParser Manifest', () => {
|
|
|
2023
2023
|
expect(stream.hdr).toBe('PQ');
|
|
2024
2024
|
});
|
|
2025
2025
|
|
|
2026
|
+
it('supports SupplementalProperty MatrixCoefficients', async () => {
|
|
2027
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2028
|
+
const scheme = cicpScheme('MatrixCoefficients');
|
|
2029
|
+
const manifestText = [
|
|
2030
|
+
'<MPD minBufferTime="PT75S">',
|
|
2031
|
+
' <Period id="1" duration="PT30S">',
|
|
2032
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2033
|
+
` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
|
|
2034
|
+
' <Representation codecs="hvc1.2.4.L153.B0">',
|
|
2035
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2036
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2037
|
+
' </Representation>',
|
|
2038
|
+
' </AdaptationSet>',
|
|
2039
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2040
|
+
' <Representation id="audio-en">',
|
|
2041
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2042
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2043
|
+
' </Representation>',
|
|
2044
|
+
' </AdaptationSet>',
|
|
2045
|
+
' </Period>',
|
|
2046
|
+
'</MPD>',
|
|
2047
|
+
].join('\n');
|
|
2048
|
+
|
|
2049
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2050
|
+
|
|
2051
|
+
/** @type {shaka.extern.Manifest} */
|
|
2052
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2053
|
+
expect(manifest.variants.length).toBe(1);
|
|
2054
|
+
});
|
|
2055
|
+
|
|
2056
|
+
it('supports SupplementalProperty ColourPrimaries', async () => {
|
|
2057
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2058
|
+
const scheme = cicpScheme('ColourPrimaries');
|
|
2059
|
+
const manifestText = [
|
|
2060
|
+
'<MPD minBufferTime="PT75S">',
|
|
2061
|
+
' <Period id="1" duration="PT30S">',
|
|
2062
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2063
|
+
` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
|
|
2064
|
+
' <Representation codecs="hvc1.2.4.L153.B0">',
|
|
2065
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2066
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2067
|
+
' </Representation>',
|
|
2068
|
+
' </AdaptationSet>',
|
|
2069
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2070
|
+
' <Representation id="audio-en">',
|
|
2071
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2072
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2073
|
+
' </Representation>',
|
|
2074
|
+
' </AdaptationSet>',
|
|
2075
|
+
' </Period>',
|
|
2076
|
+
'</MPD>',
|
|
2077
|
+
].join('\n');
|
|
2078
|
+
|
|
2079
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2080
|
+
|
|
2081
|
+
/** @type {shaka.extern.Manifest} */
|
|
2082
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2083
|
+
expect(manifest.variants.length).toBe(1);
|
|
2084
|
+
});
|
|
2085
|
+
|
|
2026
2086
|
it('supports HDR signaling via EssentialProperty', async () => {
|
|
2027
2087
|
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2028
2088
|
const hdrScheme = cicpScheme('TransferCharacteristics');
|
|
@@ -2056,6 +2116,66 @@ describe('DashParser Manifest', () => {
|
|
|
2056
2116
|
expect(stream.hdr).toBe('HLG');
|
|
2057
2117
|
});
|
|
2058
2118
|
|
|
2119
|
+
it('supports EssentialProperty MatrixCoefficients', async () => {
|
|
2120
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2121
|
+
const hdrScheme = cicpScheme('MatrixCoefficients');
|
|
2122
|
+
const manifestText = [
|
|
2123
|
+
'<MPD minBufferTime="PT75S">',
|
|
2124
|
+
' <Period id="1" duration="PT30S">',
|
|
2125
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2126
|
+
` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
|
|
2127
|
+
' <Representation codecs="hvc1.2.4.L153.B0">',
|
|
2128
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2129
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2130
|
+
' </Representation>',
|
|
2131
|
+
' </AdaptationSet>',
|
|
2132
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2133
|
+
' <Representation id="audio-en">',
|
|
2134
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2135
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2136
|
+
' </Representation>',
|
|
2137
|
+
' </AdaptationSet>',
|
|
2138
|
+
' </Period>',
|
|
2139
|
+
'</MPD>',
|
|
2140
|
+
].join('\n');
|
|
2141
|
+
|
|
2142
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2143
|
+
|
|
2144
|
+
/** @type {shaka.extern.Manifest} */
|
|
2145
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2146
|
+
expect(manifest.variants.length).toBe(1);
|
|
2147
|
+
});
|
|
2148
|
+
|
|
2149
|
+
it('supports EssentialProperty ColourPrimaries', async () => {
|
|
2150
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2151
|
+
const hdrScheme = cicpScheme('ColourPrimaries');
|
|
2152
|
+
const manifestText = [
|
|
2153
|
+
'<MPD minBufferTime="PT75S">',
|
|
2154
|
+
' <Period id="1" duration="PT30S">',
|
|
2155
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2156
|
+
` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
|
|
2157
|
+
' <Representation codecs="hvc1.2.4.L153.B0">',
|
|
2158
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2159
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2160
|
+
' </Representation>',
|
|
2161
|
+
' </AdaptationSet>',
|
|
2162
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2163
|
+
' <Representation id="audio-en">',
|
|
2164
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2165
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2166
|
+
' </Representation>',
|
|
2167
|
+
' </AdaptationSet>',
|
|
2168
|
+
' </Period>',
|
|
2169
|
+
'</MPD>',
|
|
2170
|
+
].join('\n');
|
|
2171
|
+
|
|
2172
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2173
|
+
|
|
2174
|
+
/** @type {shaka.extern.Manifest} */
|
|
2175
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2176
|
+
expect(manifest.variants.length).toBe(1);
|
|
2177
|
+
});
|
|
2178
|
+
|
|
2059
2179
|
it('supports SDR signalling via EssentialProperty', async () => {
|
|
2060
2180
|
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2061
2181
|
const scheme = cicpScheme('TransferCharacteristics');
|
|
@@ -1150,6 +1150,74 @@ describe('HlsParser', () => {
|
|
|
1150
1150
|
await testHlsParser(master, media, manifest);
|
|
1151
1151
|
});
|
|
1152
1152
|
|
|
1153
|
+
it('adds subtitle role when characteristics are empty', async () => {
|
|
1154
|
+
const master = [
|
|
1155
|
+
'#EXTM3U\n',
|
|
1156
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
1157
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1158
|
+
'video\n',
|
|
1159
|
+
|
|
1160
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="en",',
|
|
1161
|
+
'NAME="English",URI="audio"\n',
|
|
1162
|
+
|
|
1163
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="en",',
|
|
1164
|
+
'CHARACTERISTICS="public.accessibility.describes-video,',
|
|
1165
|
+
'public.accessibility.describes-music-and-sound",',
|
|
1166
|
+
'NAME="English (describes-video)",URI="audio2"\n',
|
|
1167
|
+
|
|
1168
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="en",',
|
|
1169
|
+
'NAME="English (subtitle)",DEFAULT=YES,AUTOSELECT=YES,',
|
|
1170
|
+
'URI="text"\n',
|
|
1171
|
+
|
|
1172
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="en",',
|
|
1173
|
+
'NAME="English (caption)",DEFAULT=YES,AUTOSELECT=YES,',
|
|
1174
|
+
'CHARACTERISTICS="public.accessibility.describes-music-and-sound",',
|
|
1175
|
+
'URI="text2"\n',
|
|
1176
|
+
].join('');
|
|
1177
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
1178
|
+
manifest.anyTimeline();
|
|
1179
|
+
manifest.addPartialVariant((variant) => {
|
|
1180
|
+
variant.language = 'en';
|
|
1181
|
+
variant.addPartialStream(ContentType.VIDEO);
|
|
1182
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
1183
|
+
stream.language = 'en';
|
|
1184
|
+
stream.roles = [];
|
|
1185
|
+
});
|
|
1186
|
+
});
|
|
1187
|
+
manifest.addPartialVariant((variant) => {
|
|
1188
|
+
variant.language = 'en';
|
|
1189
|
+
variant.addPartialStream(ContentType.VIDEO);
|
|
1190
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
1191
|
+
stream.language = 'en';
|
|
1192
|
+
stream.roles = [
|
|
1193
|
+
'public.accessibility.describes-video',
|
|
1194
|
+
'public.accessibility.describes-music-and-sound',
|
|
1195
|
+
];
|
|
1196
|
+
});
|
|
1197
|
+
});
|
|
1198
|
+
manifest.addPartialTextStream((stream) => {
|
|
1199
|
+
stream.language = 'en';
|
|
1200
|
+
stream.kind = TextStreamKind.SUBTITLE;
|
|
1201
|
+
stream.roles = [
|
|
1202
|
+
'subtitle',
|
|
1203
|
+
];
|
|
1204
|
+
});
|
|
1205
|
+
manifest.addPartialTextStream((stream) => {
|
|
1206
|
+
stream.language = 'en';
|
|
1207
|
+
stream.kind = TextStreamKind.SUBTITLE;
|
|
1208
|
+
stream.roles = [
|
|
1209
|
+
'public.accessibility.describes-music-and-sound',
|
|
1210
|
+
];
|
|
1211
|
+
});
|
|
1212
|
+
manifest.sequenceMode = true;
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
fakeNetEngine.setResponseText('test:/master', master);
|
|
1216
|
+
|
|
1217
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1218
|
+
expect(actual).toEqual(manifest);
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1153
1221
|
it('parses characteristics from text tags', async () => {
|
|
1154
1222
|
const master = [
|
|
1155
1223
|
'#EXTM3U\n',
|
|
@@ -1898,6 +1966,82 @@ describe('HlsParser', () => {
|
|
|
1898
1966
|
}
|
|
1899
1967
|
});
|
|
1900
1968
|
|
|
1969
|
+
it('ignore segments with #EXTINF:0', async () => {
|
|
1970
|
+
const master = [
|
|
1971
|
+
'#EXTM3U\n',
|
|
1972
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
1973
|
+
'CHANNELS="2",URI="audio"\n',
|
|
1974
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1975
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
|
|
1976
|
+
'video\n',
|
|
1977
|
+
].join('');
|
|
1978
|
+
|
|
1979
|
+
const video = [
|
|
1980
|
+
'#EXTM3U\n',
|
|
1981
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1982
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1983
|
+
'#EXTINF:5,\n',
|
|
1984
|
+
'main.mp4\n',
|
|
1985
|
+
'#EXTINF:0,\n',
|
|
1986
|
+
'main.mp4\n',
|
|
1987
|
+
'#EXTINF:5,\n',
|
|
1988
|
+
'main.mp4\n',
|
|
1989
|
+
].join('');
|
|
1990
|
+
|
|
1991
|
+
const audio = [
|
|
1992
|
+
'#EXTM3U\n',
|
|
1993
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1994
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1995
|
+
'#EXTINF:5,\n',
|
|
1996
|
+
'main.mp4\n',
|
|
1997
|
+
'#EXTINF:0,\n',
|
|
1998
|
+
'main.mp4\n',
|
|
1999
|
+
'#EXTINF:5,\n',
|
|
2000
|
+
'main.mp4\n',
|
|
2001
|
+
].join('');
|
|
2002
|
+
|
|
2003
|
+
fakeNetEngine
|
|
2004
|
+
.setResponseText('test:/master', master)
|
|
2005
|
+
.setResponseText('test:/audio', audio)
|
|
2006
|
+
.setResponseText('test:/video', video)
|
|
2007
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2008
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
2009
|
+
|
|
2010
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
2011
|
+
await loadAllStreamsFor(actual);
|
|
2012
|
+
|
|
2013
|
+
expect(actual.variants.length).toBe(1);
|
|
2014
|
+
|
|
2015
|
+
const variant = actual.variants[0];
|
|
2016
|
+
expect(variant.video).toBeTruthy();
|
|
2017
|
+
expect(variant.audio).toBeTruthy();
|
|
2018
|
+
|
|
2019
|
+
await variant.video.createSegmentIndex();
|
|
2020
|
+
goog.asserts.assert(variant.video.segmentIndex != null,
|
|
2021
|
+
'Null segmentIndex!');
|
|
2022
|
+
|
|
2023
|
+
const firstVideoReference = variant.video.segmentIndex.get(0);
|
|
2024
|
+
const secondVideoReference = variant.video.segmentIndex.get(1);
|
|
2025
|
+
const thirdVideoReference = variant.video.segmentIndex.get(2);
|
|
2026
|
+
|
|
2027
|
+
expect(firstVideoReference).not.toBe(null);
|
|
2028
|
+
expect(secondVideoReference).not.toBe(null);
|
|
2029
|
+
expect(thirdVideoReference).toBe(null);
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
await variant.audio.createSegmentIndex();
|
|
2033
|
+
goog.asserts.assert(variant.audio.segmentIndex != null,
|
|
2034
|
+
'Null segmentIndex!');
|
|
2035
|
+
|
|
2036
|
+
const firstAudioReference = variant.audio.segmentIndex.get(0);
|
|
2037
|
+
const secondAudioReference = variant.audio.segmentIndex.get(1);
|
|
2038
|
+
const thirdAudioReference = variant.audio.segmentIndex.get(2);
|
|
2039
|
+
|
|
2040
|
+
expect(firstAudioReference).not.toBe(null);
|
|
2041
|
+
expect(secondAudioReference).not.toBe(null);
|
|
2042
|
+
expect(thirdAudioReference).toBe(null);
|
|
2043
|
+
});
|
|
2044
|
+
|
|
1901
2045
|
it('Disable audio does not create audio streams', async () => {
|
|
1902
2046
|
const master = [
|
|
1903
2047
|
'#EXTM3U\n',
|
|
@@ -31,7 +31,8 @@ describe('RegionObserver', () => {
|
|
|
31
31
|
timeline = new shaka.media.RegionTimeline(
|
|
32
32
|
shaka.test.Util.spyFunc(onSeekRange));
|
|
33
33
|
|
|
34
|
-
observer = new shaka.media.RegionObserver(
|
|
34
|
+
observer = new shaka.media.RegionObserver(
|
|
35
|
+
timeline, /* startsPastZero= */ false);
|
|
35
36
|
observer.addEventListener('enter', (event) => {
|
|
36
37
|
shaka.test.Util.spyFunc(onEnterRegion)(event['region'], event['seeking']);
|
|
37
38
|
});
|
|
@@ -2913,10 +2913,14 @@ describe('StreamingEngine', () => {
|
|
|
2913
2913
|
expect(onManifestUpdate).toHaveBeenCalled();
|
|
2914
2914
|
});
|
|
2915
2915
|
|
|
2916
|
-
it('triggers metadata event', async () => {
|
|
2916
|
+
it('triggers both emsg event and metadata event for ID3', async () => {
|
|
2917
2917
|
setSegment0(emsgSegmentV0ID3);
|
|
2918
2918
|
videoStream.emsgSchemeIdUris = [id3SchemeUri];
|
|
2919
2919
|
|
|
2920
|
+
onEvent.and.callFake((emsgEvent) => {
|
|
2921
|
+
expect(emsgEvent.type).toBe('emsg');
|
|
2922
|
+
});
|
|
2923
|
+
|
|
2920
2924
|
// Here we go!
|
|
2921
2925
|
streamingEngine.switchVariant(variant);
|
|
2922
2926
|
streamingEngine.switchTextStream(textStream);
|
|
@@ -2924,10 +2928,30 @@ describe('StreamingEngine', () => {
|
|
|
2924
2928
|
playing = true;
|
|
2925
2929
|
await runTest();
|
|
2926
2930
|
|
|
2927
|
-
expect(onEvent).
|
|
2931
|
+
expect(onEvent).toHaveBeenCalled();
|
|
2928
2932
|
expect(onMetadata).toHaveBeenCalled();
|
|
2929
2933
|
});
|
|
2930
2934
|
|
|
2935
|
+
it('only triggers emsg event for ID3 if event canceled', async () => {
|
|
2936
|
+
setSegment0(emsgSegmentV0ID3);
|
|
2937
|
+
videoStream.emsgSchemeIdUris = [id3SchemeUri];
|
|
2938
|
+
|
|
2939
|
+
onEvent.and.callFake((emsgEvent) => {
|
|
2940
|
+
expect(emsgEvent.type).toBe('emsg');
|
|
2941
|
+
emsgEvent.preventDefault();
|
|
2942
|
+
});
|
|
2943
|
+
|
|
2944
|
+
// Here we go!
|
|
2945
|
+
streamingEngine.switchVariant(variant);
|
|
2946
|
+
streamingEngine.switchTextStream(textStream);
|
|
2947
|
+
await streamingEngine.start();
|
|
2948
|
+
playing = true;
|
|
2949
|
+
await runTest();
|
|
2950
|
+
|
|
2951
|
+
expect(onEvent).toHaveBeenCalled();
|
|
2952
|
+
expect(onMetadata).not.toHaveBeenCalled();
|
|
2953
|
+
});
|
|
2954
|
+
|
|
2931
2955
|
it('event start matches presentation time', async () => {
|
|
2932
2956
|
// This box has a non-zero event time, which doesn't matter.
|
|
2933
2957
|
setSegment0(emsgSegmentV1NonZeroStart);
|
|
Binary file
|
|
Binary file
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
goog.provide('shaka.ui.ResolutionSelection');
|
|
9
9
|
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
+
goog.require('shaka.Player');
|
|
11
12
|
goog.require('shaka.ui.Controls');
|
|
12
13
|
goog.require('shaka.ui.Enums');
|
|
13
14
|
goog.require('shaka.ui.Locales');
|
|
@@ -67,7 +68,12 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
67
68
|
/** @private */
|
|
68
69
|
updateResolutionSelection_() {
|
|
69
70
|
/** @type {!Array.<shaka.extern.Track>} */
|
|
70
|
-
let tracks =
|
|
71
|
+
let tracks = [];
|
|
72
|
+
// When played with src=, the variant tracks available from
|
|
73
|
+
// player.getVariantTracks() represent languages, not resolutions.
|
|
74
|
+
if (this.player.getLoadMode() != shaka.Player.LoadMode.SRC_EQUALS) {
|
|
75
|
+
tracks = this.player.getVariantTracks();
|
|
76
|
+
}
|
|
71
77
|
|
|
72
78
|
// If there is a selected variant track, then we filter out any tracks in
|
|
73
79
|
// a different language. Then we use those remaining tracks to display the
|