shaka-player 4.3.5 → 4.3.7
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/demo-version-index.yaml +3 -3
- package/.github/workflows/selenium-lab-tests.yaml +23 -1
- package/AUTHORS +2 -1
- package/CHANGELOG.md +53 -0
- package/CONTRIBUTORS +4 -1
- package/README.md +3 -0
- package/demo/demo.less +1 -0
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +167 -296
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +167 -296
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +1 -1
- package/dist/locales.js +32 -32
- package/dist/receiver.compiled.debug.js +34 -63
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +34 -63
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +20 -3
- package/dist/shaka-player.compiled.debug.d.ts +20 -3
- package/dist/shaka-player.compiled.debug.externs.js +29 -14
- package/dist/shaka-player.compiled.debug.js +303 -292
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +29 -14
- package/dist/shaka-player.compiled.js +886 -879
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +20 -3
- package/dist/shaka-player.ui.debug.d.ts +20 -3
- package/dist/shaka-player.ui.debug.externs.js +17 -2
- package/dist/shaka-player.ui.debug.js +321 -309
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +17 -2
- package/dist/shaka-player.ui.js +1027 -1021
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/a11y.md +0 -4
- package/docs/tutorials/ad_monetization.md +0 -4
- package/docs/tutorials/basic-usage.md +0 -5
- package/docs/tutorials/config.md +0 -5
- package/docs/tutorials/debugging.md +0 -5
- package/docs/tutorials/drm-config.md +0 -5
- package/docs/tutorials/fairplay.md +2 -2
- package/docs/tutorials/license-server-auth.md +0 -5
- package/docs/tutorials/license-wrapping.md +0 -5
- package/docs/tutorials/network-and-buffering-config.md +0 -5
- package/docs/tutorials/ui-customization.md +0 -5
- package/docs/tutorials/ui.md +0 -7
- package/docs/tutorials/welcome.md +1 -6
- package/externs/network_information.js +7 -2
- package/externs/shaka/abr_manager.js +6 -0
- package/externs/shaka/net.js +1 -0
- package/externs/shaka/player.js +13 -7
- package/lib/abr/simple_abr_manager.js +27 -3
- package/lib/ads/client_side_ad_manager.js +6 -3
- package/lib/cea/mp4_cea_parser.js +5 -2
- package/lib/dash/dash_parser.js +49 -48
- package/lib/debug/log.js +9 -13
- package/lib/hls/hls_parser.js +60 -7
- package/lib/hls/manifest_text_parser.js +10 -1
- package/lib/media/drm_engine.js +9 -6
- package/lib/media/media_source_engine.js +33 -13
- package/lib/media/presentation_timeline.js +9 -2
- package/lib/media/segment_index.js +2 -0
- package/lib/media/segment_reference.js +25 -2
- package/lib/media/streaming_engine.js +40 -11
- package/lib/net/http_fetch_plugin.js +79 -57
- package/lib/net/networking_engine.js +1 -0
- package/lib/player.js +26 -3
- package/lib/polyfill/media_capabilities.js +13 -0
- package/lib/text/mp4_vtt_parser.js +4 -0
- package/lib/text/text_engine.js +1 -0
- package/lib/util/manifest_parser_utils.js +1 -2
- package/lib/util/mime_utils.js +11 -0
- package/lib/util/periods.js +5 -5
- package/lib/util/stream_utils.js +2 -2
- package/maintained-branches.md +2 -3
- package/package.json +8 -3
- package/test/cea/mp4_cea_parser_unit.js +19 -0
- package/test/dash/dash_parser_live_unit.js +3 -2
- package/test/hls/hls_live_unit.js +3 -1
- package/test/hls/hls_parser_unit.js +156 -0
- package/test/media/content_workarounds_unit.js +43 -0
- package/test/media/drm_engine_integration.js +4 -17
- package/test/media/media_source_engine_unit.js +30 -0
- package/test/media/streaming_engine_unit.js +6 -1
- package/test/net/networking_engine_unit.js +6 -1
- package/test/player_integration.js +39 -0
- package/test/player_unit.js +57 -0
- package/test/polyfill/media_capabilities_unit.js +1 -0
- package/test/test/assets/h265-cea-init.mp4 +0 -0
- package/test/test/assets/h265-cea-segment.mp4 +0 -0
- package/test/test/assets/text-clip-alt.vtt +63 -0
- package/test/test/util/fake_drm_engine.js +3 -0
- package/test/test/util/fake_media_source_engine.js +4 -0
- package/test/test/util/layout_tests.js +4 -3
- package/test/test/util/simple_fakes.js +6 -0
- package/test/test/util/test_scheme.js +9 -14
- package/test/text/mp4_vtt_parser_unit.js +8 -0
- package/test/util/mime_utils_unit.js +10 -0
- package/ui/less/containers.less +4 -0
|
@@ -120,65 +120,77 @@ shaka.net.HttpFetchPlugin = class {
|
|
|
120
120
|
// not the body yet.
|
|
121
121
|
headersReceived(shaka.net.HttpFetchPlugin.headersToGenericObject_(
|
|
122
122
|
response.headers));
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
123
|
+
|
|
124
|
+
// In new versions of Chromium, HEAD requests now have a response body
|
|
125
|
+
// that is null.
|
|
126
|
+
// So just don't try to download the body at all, if it's a HEAD request,
|
|
127
|
+
// to avoid null reference errors.
|
|
128
|
+
// See: https://crbug.com/1297060
|
|
129
|
+
if (init.method != 'HEAD') {
|
|
130
|
+
goog.asserts.assert(response.body,
|
|
131
|
+
'non-HEAD responses should have a body');
|
|
132
|
+
|
|
133
|
+
// Getting the reader in this way allows us to observe the process of
|
|
134
|
+
// downloading the body, instead of just waiting for an opaque promise
|
|
135
|
+
// to resolve.
|
|
136
|
+
// We first clone the response because calling getReader locks the body
|
|
137
|
+
// stream; if we didn't clone it here, we would be unable to get the
|
|
138
|
+
// response's arrayBuffer later.
|
|
139
|
+
const reader = response.clone().body.getReader();
|
|
140
|
+
|
|
141
|
+
const contentLengthRaw = response.headers.get('Content-Length');
|
|
142
|
+
const contentLength =
|
|
143
|
+
contentLengthRaw ? parseInt(contentLengthRaw, 10) : 0;
|
|
144
|
+
|
|
145
|
+
const start = (controller) => {
|
|
146
|
+
const push = async () => {
|
|
147
|
+
let readObj;
|
|
148
|
+
try {
|
|
149
|
+
readObj = await reader.read();
|
|
150
|
+
} catch (e) {
|
|
151
|
+
// If we abort the request, we'll get an error here. Just ignore
|
|
152
|
+
// it since real errors will be reported when we read the buffer
|
|
153
|
+
// below.
|
|
154
|
+
shaka.log.v1('error reading from stream', e.message);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!readObj.done) {
|
|
159
|
+
loaded += readObj.value.byteLength;
|
|
160
|
+
if (streamDataCallback) {
|
|
161
|
+
await streamDataCallback(readObj.value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const currentTime = Date.now();
|
|
166
|
+
// If the time between last time and this time we got progress event
|
|
167
|
+
// is long enough, or if a whole segment is downloaded, call
|
|
168
|
+
// progressUpdated().
|
|
169
|
+
if (currentTime - lastTime > 100 || readObj.done) {
|
|
170
|
+
progressUpdated(currentTime - lastTime, loaded - lastLoaded,
|
|
171
|
+
contentLength - loaded);
|
|
172
|
+
lastLoaded = loaded;
|
|
173
|
+
lastTime = currentTime;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (readObj.done) {
|
|
177
|
+
goog.asserts.assert(!readObj.value,
|
|
178
|
+
'readObj should be unset when "done" is true.');
|
|
179
|
+
controller.close();
|
|
180
|
+
} else {
|
|
181
|
+
controller.enqueue(readObj.value);
|
|
182
|
+
push();
|
|
151
183
|
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const currentTime = Date.now();
|
|
155
|
-
// If the time between last time and this time we got progress event
|
|
156
|
-
// is long enough, or if a whole segment is downloaded, call
|
|
157
|
-
// progressUpdated().
|
|
158
|
-
if (currentTime - lastTime > 100 || readObj.done) {
|
|
159
|
-
progressUpdated(currentTime - lastTime, loaded - lastLoaded,
|
|
160
|
-
contentLength - loaded);
|
|
161
|
-
lastLoaded = loaded;
|
|
162
|
-
lastTime = currentTime;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (readObj.done) {
|
|
166
|
-
goog.asserts.assert(!readObj.value,
|
|
167
|
-
'readObj should be unset when "done" is true.');
|
|
168
|
-
controller.close();
|
|
169
|
-
} else {
|
|
170
|
-
controller.enqueue(readObj.value);
|
|
171
|
-
push();
|
|
172
|
-
}
|
|
184
|
+
};
|
|
185
|
+
push();
|
|
173
186
|
};
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
arrayBuffer = await response.arrayBuffer();
|
|
187
|
+
// Create a ReadableStream to use the reader. We don't need to use the
|
|
188
|
+
// actual stream for anything, though, as we are using the response's
|
|
189
|
+
// arrayBuffer method to get the body, so we don't store the
|
|
190
|
+
// ReadableStream.
|
|
191
|
+
new ReadableStream({start}); // eslint-disable-line no-new
|
|
192
|
+
arrayBuffer = await response.arrayBuffer();
|
|
193
|
+
}
|
|
182
194
|
} catch (error) {
|
|
183
195
|
if (abortStatus.canceled) {
|
|
184
196
|
throw new shaka.util.Error(
|
|
@@ -243,6 +255,16 @@ shaka.net.HttpFetchPlugin = class {
|
|
|
243
255
|
} else {
|
|
244
256
|
return false;
|
|
245
257
|
}
|
|
258
|
+
// Old fetch implementations hasn't body and ReadableStream implementation
|
|
259
|
+
// See: https://github.com/shaka-project/shaka-player/issues/5088
|
|
260
|
+
if (window.Response) {
|
|
261
|
+
const response = new Response('');
|
|
262
|
+
if (!response.body) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
246
268
|
return !!(window.fetch && window.AbortController);
|
|
247
269
|
}
|
|
248
270
|
};
|
|
@@ -312,6 +312,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
312
312
|
if (!responseAndGotProgress.gotProgress &&
|
|
313
313
|
this.onProgressUpdated_ &&
|
|
314
314
|
!response.fromCache &&
|
|
315
|
+
request.method != 'HEAD' &&
|
|
315
316
|
type == shaka.net.NetworkingEngine.RequestType.SEGMENT) {
|
|
316
317
|
this.onProgressUpdated_(response.timeMs, response.data.byteLength);
|
|
317
318
|
}
|
package/lib/player.js
CHANGED
|
@@ -897,7 +897,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
897
897
|
}
|
|
898
898
|
|
|
899
899
|
this.abrManagerFactory_ = null;
|
|
900
|
-
this.abrManager_ = null;
|
|
901
900
|
this.config_ = null;
|
|
902
901
|
this.stats_ = null;
|
|
903
902
|
this.videoContainer_ = null;
|
|
@@ -908,6 +907,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
908
907
|
this.networkingEngine_ = null;
|
|
909
908
|
}
|
|
910
909
|
|
|
910
|
+
if (this.abrManager_) {
|
|
911
|
+
this.abrManager_.release();
|
|
912
|
+
this.abrManager_ = null;
|
|
913
|
+
}
|
|
914
|
+
|
|
911
915
|
// FakeEventTarget implements IReleasable
|
|
912
916
|
super.release();
|
|
913
917
|
}
|
|
@@ -1342,6 +1346,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1342
1346
|
*/
|
|
1343
1347
|
shouldUseSrcEquals_(payload) {
|
|
1344
1348
|
const Platform = shaka.util.Platform;
|
|
1349
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
1345
1350
|
|
|
1346
1351
|
// If we are using a platform that does not support media source, we will
|
|
1347
1352
|
// fall back to src= to handle all playback.
|
|
@@ -1396,7 +1401,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1396
1401
|
// version there.
|
|
1397
1402
|
|
|
1398
1403
|
// Native HLS can be preferred on any platform via this flag:
|
|
1399
|
-
if (
|
|
1404
|
+
if (MimeUtils.isHlsType(mimeType) &&
|
|
1405
|
+
this.config_.streaming.preferNativeHls) {
|
|
1400
1406
|
return true;
|
|
1401
1407
|
}
|
|
1402
1408
|
|
|
@@ -4276,6 +4282,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4276
4282
|
firstVariantWithLabel.language, '', 0, label);
|
|
4277
4283
|
|
|
4278
4284
|
this.chooseVariantAndSwitch_();
|
|
4285
|
+
} else if (this.video_ && this.video_.audioTracks) {
|
|
4286
|
+
const audioTracks = Array.from(this.video_.audioTracks);
|
|
4287
|
+
|
|
4288
|
+
let trackMatch = null;
|
|
4289
|
+
|
|
4290
|
+
for (const audioTrack of audioTracks) {
|
|
4291
|
+
if (audioTrack.label == label) {
|
|
4292
|
+
trackMatch = audioTrack;
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
if (trackMatch) {
|
|
4296
|
+
this.switchHtml5Track_(trackMatch);
|
|
4297
|
+
}
|
|
4279
4298
|
}
|
|
4280
4299
|
}
|
|
4281
4300
|
|
|
@@ -6047,6 +6066,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6047
6066
|
error.category != shaka.util.Error.Category.NETWORK) {
|
|
6048
6067
|
return false;
|
|
6049
6068
|
}
|
|
6069
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE) {
|
|
6070
|
+
return false;
|
|
6071
|
+
}
|
|
6072
|
+
goog.asserts.assert(this.manifest_, 'Should have manifest!');
|
|
6050
6073
|
|
|
6051
6074
|
if (!navigator.onLine) {
|
|
6052
6075
|
// Don't restrict variants if we're completely offline, or else we end up
|
|
@@ -6986,7 +7009,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6986
7009
|
* @define {string} A version number taken from git at compile time.
|
|
6987
7010
|
* @export
|
|
6988
7011
|
*/
|
|
6989
|
-
shaka.Player.version = 'v4.3.
|
|
7012
|
+
shaka.Player.version = 'v4.3.7-uncompiled';
|
|
6990
7013
|
|
|
6991
7014
|
// Initialize the deprecation system using the version string we just set
|
|
6992
7015
|
// on the player.
|
|
@@ -119,6 +119,19 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
119
119
|
if (shaka.util.Platform.isChromecast()) {
|
|
120
120
|
isSupported =
|
|
121
121
|
shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
|
|
122
|
+
} else if (shaka.util.Platform.isTizen()) {
|
|
123
|
+
let extendedType = videoConfig.contentType;
|
|
124
|
+
if (videoConfig.width && videoConfig.height) {
|
|
125
|
+
extendedType += `; width=${videoConfig.width}`;
|
|
126
|
+
extendedType += `; height=${videoConfig.height}`;
|
|
127
|
+
}
|
|
128
|
+
if (videoConfig.framerate) {
|
|
129
|
+
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
130
|
+
}
|
|
131
|
+
if (videoConfig.bitrate) {
|
|
132
|
+
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
133
|
+
}
|
|
134
|
+
isSupported = Capabilities.isTypeSupported(extendedType);
|
|
122
135
|
} else {
|
|
123
136
|
isSupported = Capabilities.isTypeSupported(videoConfig.contentType);
|
|
124
137
|
}
|
package/lib/text/text_engine.js
CHANGED
|
@@ -139,6 +139,7 @@ shaka.text.TextEngine = class {
|
|
|
139
139
|
// into TextEngine and TextDisplayer.
|
|
140
140
|
if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
|
|
141
141
|
mimeType == shaka.util.MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE) {
|
|
142
|
+
this.parser_ = null;
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -185,8 +185,7 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
|
|
|
185
185
|
/^mp4a/,
|
|
186
186
|
/^[ae]c-3$/,
|
|
187
187
|
/^ac-4$/,
|
|
188
|
-
/^dts[
|
|
189
|
-
/^[du]dts$/, // DTS Surround Sound
|
|
188
|
+
/^dts[cex]$/, // DTS Digital Surround (dtsc), DTS Express (dtse), DTS:X (dtsx)
|
|
190
189
|
];
|
|
191
190
|
|
|
192
191
|
|
package/lib/util/mime_utils.js
CHANGED
|
@@ -193,6 +193,17 @@ shaka.util.MimeUtils = class {
|
|
|
193
193
|
return value;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Checks if the given MIME type is HLS MIME type.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} mimeType
|
|
200
|
+
* @return {boolean}
|
|
201
|
+
*/
|
|
202
|
+
static isHlsType(mimeType) {
|
|
203
|
+
return mimeType === 'application/x-mpegurl' ||
|
|
204
|
+
mimeType === 'application/vnd.apple.mpegurl';
|
|
205
|
+
}
|
|
206
|
+
|
|
196
207
|
/**
|
|
197
208
|
* Get the base and profile of a codec string. Where [0] will be the codec
|
|
198
209
|
* base and [1] will be the profile.
|
package/lib/util/periods.js
CHANGED
|
@@ -671,11 +671,11 @@ shaka.util.PeriodCombiner = class {
|
|
|
671
671
|
// Also checks if the segmentIndex is still valid after the async
|
|
672
672
|
// operations, to make sure we stop if the active stream has changed.
|
|
673
673
|
if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
|
|
674
|
-
for (let i =
|
|
674
|
+
for (let i = firstNewPeriodIndex; i < streams.length; i++) {
|
|
675
675
|
const match = streams[i];
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
676
|
+
goog.asserts.assert(match.segmentIndex,
|
|
677
|
+
'stream should have a segmentIndex.');
|
|
678
|
+
if (match.segmentIndex) {
|
|
679
679
|
outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
|
|
680
680
|
}
|
|
681
681
|
}
|
|
@@ -728,7 +728,7 @@ shaka.util.PeriodCombiner = class {
|
|
|
728
728
|
// in advance. concat() will add them to the output's MetaSegmentIndex.
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
-
if (!outputStream.matchedStreams) {
|
|
731
|
+
if (!outputStream.matchedStreams || !outputStream.matchedStreams.length) {
|
|
732
732
|
// This is not a stream we can build output from, but it may become part
|
|
733
733
|
// of another output based on another period's stream.
|
|
734
734
|
return null;
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -830,7 +830,7 @@ shaka.util.StreamUtils = class {
|
|
|
830
830
|
const video = variant.video;
|
|
831
831
|
if (audio && currentVariant && currentVariant.audio) {
|
|
832
832
|
if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
|
|
833
|
-
shaka.log.debug('
|
|
833
|
+
shaka.log.debug('Dropping variant - not compatible with active audio',
|
|
834
834
|
'active audio',
|
|
835
835
|
StreamUtils.getStreamSummaryString_(currentVariant.audio),
|
|
836
836
|
'variant.audio',
|
|
@@ -841,7 +841,7 @@ shaka.util.StreamUtils = class {
|
|
|
841
841
|
|
|
842
842
|
if (video && currentVariant && currentVariant.video) {
|
|
843
843
|
if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
|
|
844
|
-
shaka.log.debug('
|
|
844
|
+
shaka.log.debug('Dropping variant - not compatible with active video',
|
|
845
845
|
'active video',
|
|
846
846
|
StreamUtils.getStreamSummaryString_(currentVariant.video),
|
|
847
847
|
'variant.video',
|
package/maintained-branches.md
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
We are currently maintaining the following branches of Shaka Player:
|
|
4
4
|
|
|
5
|
-
- v4.3 (latest)
|
|
5
|
+
- v4.3 (latest, also in use by the Cast Application Framework)
|
|
6
6
|
- v4.2 (previous)
|
|
7
|
-
-
|
|
8
|
-
- v3.2 (in use by the Cast Application Framework)
|
|
7
|
+
- No active LTS branches at this time
|
|
9
8
|
|
|
10
9
|
Other branches are no longer receiving bug fixes, and we recommend you upgrade
|
|
11
10
|
to a maintained branch. For details on upgrading, please see our
|
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.7",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"awesomplete": "^1.1.5",
|
|
19
19
|
"babel-plugin-istanbul": "^6.1.1",
|
|
20
20
|
"cajon": "^0.4.4",
|
|
21
|
+
"clean-package": "^2.2.0",
|
|
21
22
|
"code-prettify": "^0.1.0",
|
|
22
23
|
"color-themes-for-google-code-prettify": "^2.0.4",
|
|
23
24
|
"core-js": "^3.21.1",
|
|
@@ -94,12 +95,16 @@
|
|
|
94
95
|
},
|
|
95
96
|
"license": "Apache-2.0",
|
|
96
97
|
"scripts": {
|
|
98
|
+
"prepack": "clean-package",
|
|
99
|
+
"postpack": "clean-package restore",
|
|
97
100
|
"prepublishOnly": "python build/checkversion.py && python build/all.py --force"
|
|
98
101
|
},
|
|
99
102
|
"dependencies": {
|
|
100
103
|
"eme-encryption-scheme-polyfill": "^2.1.1"
|
|
101
104
|
},
|
|
102
|
-
"
|
|
103
|
-
"
|
|
105
|
+
"clean-package": {
|
|
106
|
+
"remove": [
|
|
107
|
+
"engines"
|
|
108
|
+
]
|
|
104
109
|
}
|
|
105
110
|
}
|
|
@@ -7,20 +7,30 @@
|
|
|
7
7
|
describe('Mp4CeaParser', () => {
|
|
8
8
|
const ceaInitSegmentUri = '/base/test/test/assets/cea-init.mp4';
|
|
9
9
|
const ceaSegmentUri = '/base/test/test/assets/cea-segment.mp4';
|
|
10
|
+
const h265ceaInitSegmentUri = '/base/test/test/assets/h265-cea-init.mp4';
|
|
11
|
+
const h265ceaSegmentUri = '/base/test/test/assets/h265-cea-segment.mp4';
|
|
10
12
|
const Util = shaka.test.Util;
|
|
11
13
|
|
|
12
14
|
/** @type {!ArrayBuffer} */
|
|
13
15
|
let ceaInitSegment;
|
|
14
16
|
/** @type {!ArrayBuffer} */
|
|
15
17
|
let ceaSegment;
|
|
18
|
+
/** @type {!ArrayBuffer} */
|
|
19
|
+
let h265ceaInitSegment;
|
|
20
|
+
/** @type {!ArrayBuffer} */
|
|
21
|
+
let h265ceaSegment;
|
|
16
22
|
|
|
17
23
|
beforeAll(async () => {
|
|
18
24
|
const responses = await Promise.all([
|
|
19
25
|
shaka.test.Util.fetch(ceaInitSegmentUri),
|
|
20
26
|
shaka.test.Util.fetch(ceaSegmentUri),
|
|
27
|
+
shaka.test.Util.fetch(h265ceaInitSegmentUri),
|
|
28
|
+
shaka.test.Util.fetch(h265ceaSegmentUri),
|
|
21
29
|
]);
|
|
22
30
|
ceaInitSegment = responses[0];
|
|
23
31
|
ceaSegment = responses[1];
|
|
32
|
+
h265ceaInitSegment = responses[2];
|
|
33
|
+
h265ceaSegment = responses[3];
|
|
24
34
|
});
|
|
25
35
|
|
|
26
36
|
/**
|
|
@@ -70,6 +80,15 @@ describe('Mp4CeaParser', () => {
|
|
|
70
80
|
.toEqual(expectedCea708Packet);
|
|
71
81
|
});
|
|
72
82
|
|
|
83
|
+
it('parses cea data from an h265 mp4 stream', () => {
|
|
84
|
+
const ceaParser = new shaka.cea.Mp4CeaParser();
|
|
85
|
+
|
|
86
|
+
ceaParser.init(h265ceaInitSegment);
|
|
87
|
+
const ceaPackets = ceaParser.parse(h265ceaSegment);
|
|
88
|
+
expect(ceaPackets).toBeDefined();
|
|
89
|
+
expect(ceaPackets.length).toBe(60);
|
|
90
|
+
});
|
|
91
|
+
|
|
73
92
|
it('parses an invalid init segment', () => {
|
|
74
93
|
const cea708Parser = new shaka.cea.Mp4CeaParser();
|
|
75
94
|
|
|
@@ -194,7 +194,8 @@ describe('DashParser Live', () => {
|
|
|
194
194
|
template, {updateTime: updateTime, contents: basicLines.join('\n')});
|
|
195
195
|
|
|
196
196
|
fakeNetEngine.setResponseText('dummy://foo', text);
|
|
197
|
-
|
|
197
|
+
const baseTime = new Date(2015, 11, 30);
|
|
198
|
+
Date.now = () => baseTime.getTime();
|
|
198
199
|
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
199
200
|
|
|
200
201
|
expect(manifest).toBeTruthy();
|
|
@@ -211,7 +212,7 @@ describe('DashParser Live', () => {
|
|
|
211
212
|
// seconds long in all of these cases. So 11 seconds after the
|
|
212
213
|
// manifest was parsed, the first segment should have fallen out of
|
|
213
214
|
// the availability window.
|
|
214
|
-
Date.now = () => 11 * 1000;
|
|
215
|
+
Date.now = () => baseTime.getTime() + (11 * 1000);
|
|
215
216
|
await updateManifest();
|
|
216
217
|
// The first reference should have been evicted.
|
|
217
218
|
expect(stream.segmentIndex.find(0)).toBe(firstPosition + 1);
|
|
@@ -590,7 +590,8 @@ describe('HlsParser live', () => {
|
|
|
590
590
|
// partialRef3
|
|
591
591
|
'#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
|
|
592
592
|
// preloadRef
|
|
593
|
-
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210
|
|
593
|
+
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210,',
|
|
594
|
+
'BYTERANGE-LENGTH=210\n',
|
|
594
595
|
].join('');
|
|
595
596
|
|
|
596
597
|
const partialRef = makeReference(
|
|
@@ -613,6 +614,7 @@ describe('HlsParser live', () => {
|
|
|
613
614
|
const preloadRef = makeReference(
|
|
614
615
|
'test:/partial.mp4', 6, 7.5, /* syncTime= */ null,
|
|
615
616
|
/* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
|
|
617
|
+
preloadRef.markAsPreload();
|
|
616
618
|
|
|
617
619
|
// ref2 is not fully published yet, so it doesn't have a segment uri.
|
|
618
620
|
const ref2 = makeReference(
|
|
@@ -987,6 +987,118 @@ describe('HlsParser', () => {
|
|
|
987
987
|
await testHlsParser(master, media, manifest);
|
|
988
988
|
});
|
|
989
989
|
|
|
990
|
+
it('parses discontinuity tags', async () => {
|
|
991
|
+
const master = [
|
|
992
|
+
'#EXTM3U\n',
|
|
993
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
|
|
994
|
+
'video\n',
|
|
995
|
+
].join('');
|
|
996
|
+
|
|
997
|
+
const media = [
|
|
998
|
+
'#EXTM3U\n',
|
|
999
|
+
'#EXT-X-VERSION:3\n',
|
|
1000
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
1001
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
1002
|
+
'#EXTINF:3,\n',
|
|
1003
|
+
'clip0-video-0.ts\n',
|
|
1004
|
+
'#EXTINF:1,\n',
|
|
1005
|
+
'clip0-video-1.ts\n',
|
|
1006
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1007
|
+
'#EXTINF:2,\n',
|
|
1008
|
+
'clip1-video-1.ts\n',
|
|
1009
|
+
'#EXTINF:3,\n',
|
|
1010
|
+
'clip1-video-2.ts\n',
|
|
1011
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1012
|
+
'#EXTINF:1,\n',
|
|
1013
|
+
'media-clip2-video-0.ts\n',
|
|
1014
|
+
'#EXTINF:1,\n',
|
|
1015
|
+
'media-clip2-video-1.ts\n',
|
|
1016
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1017
|
+
'#EXTINF:4,\n',
|
|
1018
|
+
'media-clip3-video-1.ts\n',
|
|
1019
|
+
'#EXT-X-ENDLIST\n',
|
|
1020
|
+
].join('');
|
|
1021
|
+
|
|
1022
|
+
fakeNetEngine
|
|
1023
|
+
.setResponseText('test:/master', master)
|
|
1024
|
+
.setResponseText('test:/video', media);
|
|
1025
|
+
|
|
1026
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
1027
|
+
await manifest.variants[0].video.createSegmentIndex();
|
|
1028
|
+
|
|
1029
|
+
const segmentIndex = manifest.variants[0].video.segmentIndex;
|
|
1030
|
+
const references = [];
|
|
1031
|
+
|
|
1032
|
+
for (let i = 0; i < 7; i++) {
|
|
1033
|
+
references.push(segmentIndex.get(i));
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
expect(references[0].discontinuitySequence).toBe(0);
|
|
1037
|
+
expect(references[1].discontinuitySequence).toBe(0);
|
|
1038
|
+
expect(references[2].discontinuitySequence).toBe(1);
|
|
1039
|
+
expect(references[3].discontinuitySequence).toBe(1);
|
|
1040
|
+
expect(references[4].discontinuitySequence).toBe(2);
|
|
1041
|
+
expect(references[5].discontinuitySequence).toBe(2);
|
|
1042
|
+
expect(references[6].discontinuitySequence).toBe(3);
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
it('sets reference timetampOffset based on discontinuity start time',
|
|
1046
|
+
async () => {
|
|
1047
|
+
const master = [
|
|
1048
|
+
'#EXTM3U\n',
|
|
1049
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
|
|
1050
|
+
'video\n',
|
|
1051
|
+
].join('');
|
|
1052
|
+
|
|
1053
|
+
const media = [
|
|
1054
|
+
'#EXTM3U\n',
|
|
1055
|
+
'#EXT-X-VERSION:3\n',
|
|
1056
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
1057
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
1058
|
+
'#EXTINF:3,\n',
|
|
1059
|
+
'clip0-video-0.ts\n',
|
|
1060
|
+
'#EXTINF:1,\n',
|
|
1061
|
+
'clip0-video-1.ts\n',
|
|
1062
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1063
|
+
'#EXTINF:2,\n',
|
|
1064
|
+
'clip1-video-1.ts\n',
|
|
1065
|
+
'#EXTINF:3,\n',
|
|
1066
|
+
'clip1-video-2.ts\n',
|
|
1067
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1068
|
+
'#EXTINF:1,\n',
|
|
1069
|
+
'media-clip2-video-0.ts\n',
|
|
1070
|
+
'#EXTINF:1,\n',
|
|
1071
|
+
'media-clip2-video-1.ts\n',
|
|
1072
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1073
|
+
'#EXTINF:4,\n',
|
|
1074
|
+
'media-clip3-video-1.ts\n',
|
|
1075
|
+
'#EXT-X-ENDLIST\n',
|
|
1076
|
+
].join('');
|
|
1077
|
+
|
|
1078
|
+
fakeNetEngine
|
|
1079
|
+
.setResponseText('test:/master', master)
|
|
1080
|
+
.setResponseText('test:/video', media);
|
|
1081
|
+
|
|
1082
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
1083
|
+
await manifest.variants[0].video.createSegmentIndex();
|
|
1084
|
+
|
|
1085
|
+
const segmentIndex = manifest.variants[0].video.segmentIndex;
|
|
1086
|
+
const references = [];
|
|
1087
|
+
|
|
1088
|
+
for (let i = 0; i < 7; i++) {
|
|
1089
|
+
references.push(segmentIndex.get(i));
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
expect(references[0].timestampOffset).toBe(0);
|
|
1093
|
+
expect(references[1].timestampOffset).toBe(0);
|
|
1094
|
+
expect(references[2].timestampOffset).toBe(4);
|
|
1095
|
+
expect(references[3].timestampOffset).toBe(4);
|
|
1096
|
+
expect(references[4].timestampOffset).toBe(9);
|
|
1097
|
+
expect(references[5].timestampOffset).toBe(9);
|
|
1098
|
+
expect(references[6].timestampOffset).toBe(11);
|
|
1099
|
+
},
|
|
1100
|
+
);
|
|
1101
|
+
|
|
990
1102
|
it('parses characteristics from audio tags', async () => {
|
|
991
1103
|
const master = [
|
|
992
1104
|
'#EXTM3U\n',
|
|
@@ -2132,6 +2244,50 @@ describe('HlsParser', () => {
|
|
|
2132
2244
|
expect(actual).toEqual(manifest);
|
|
2133
2245
|
});
|
|
2134
2246
|
|
|
2247
|
+
it('parses manifest with MP4+WEBVTT streams', async () => {
|
|
2248
|
+
const master = [
|
|
2249
|
+
'#EXTM3U\n',
|
|
2250
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
2251
|
+
'CODECS="wvtt",URI="text"\n',
|
|
2252
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2253
|
+
'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
|
|
2254
|
+
'video\n',
|
|
2255
|
+
].join('');
|
|
2256
|
+
|
|
2257
|
+
const media = [
|
|
2258
|
+
'#EXTM3U\n',
|
|
2259
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2260
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2261
|
+
'#EXTINF:5,\n',
|
|
2262
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2263
|
+
'main.mp4',
|
|
2264
|
+
].join('');
|
|
2265
|
+
|
|
2266
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
2267
|
+
manifest.anyTimeline();
|
|
2268
|
+
manifest.addPartialVariant((variant) => {
|
|
2269
|
+
variant.addPartialStream(ContentType.VIDEO);
|
|
2270
|
+
});
|
|
2271
|
+
manifest.addPartialTextStream((stream) => {
|
|
2272
|
+
stream.language = 'en';
|
|
2273
|
+
stream.mime('application/mp4', 'wvtt');
|
|
2274
|
+
});
|
|
2275
|
+
manifest.sequenceMode = true;
|
|
2276
|
+
});
|
|
2277
|
+
|
|
2278
|
+
fakeNetEngine
|
|
2279
|
+
.setResponseText('test:/master', master)
|
|
2280
|
+
.setResponseText('test:/audio', media)
|
|
2281
|
+
.setResponseText('test:/video', media)
|
|
2282
|
+
.setResponseText('test:/text', media)
|
|
2283
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2284
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
2285
|
+
|
|
2286
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
2287
|
+
await loadAllStreamsFor(actual);
|
|
2288
|
+
expect(actual).toEqual(manifest);
|
|
2289
|
+
});
|
|
2290
|
+
|
|
2135
2291
|
it('detects VTT streams by codec', async () => {
|
|
2136
2292
|
const master = [
|
|
2137
2293
|
'#EXTM3U\n',
|