shaka-player 4.2.9 → 4.2.11
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 +44 -0
- package/CONTRIBUTORS +4 -1
- package/README.md +3 -0
- package/demo/demo.less +1 -0
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +154 -276
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +154 -276
- 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 +33 -33
- package/dist/receiver.compiled.debug.js +36 -65
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +36 -65
- 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 +26 -12
- package/dist/shaka-player.compiled.debug.js +185 -180
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +26 -12
- package/dist/shaka-player.compiled.js +821 -818
- 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 +14 -0
- package/dist/shaka-player.ui.debug.js +266 -261
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +14 -0
- package/dist/shaka-player.ui.js +964 -960
- 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/dash/dash_parser.js +49 -48
- package/lib/debug/log.js +9 -13
- package/lib/hls/hls_parser.js +6 -0
- package/lib/hls/manifest_text_parser.js +10 -1
- package/lib/media/drm_engine.js +9 -6
- package/lib/media/media_source_engine.js +17 -8
- package/lib/media/segment_index.js +2 -0
- package/lib/media/segment_reference.js +22 -0
- package/lib/media/streaming_engine.js +17 -7
- 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 +3 -4
- package/package.json +9 -3
- package/test/hls/hls_live_unit.js +3 -1
- 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 +31 -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 +0 -1
- package/test/test/assets/text-clip-alt.vtt +63 -0
- package/test/test/util/fake_drm_engine.js +3 -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
|
@@ -238,6 +238,9 @@ shaka.media.SegmentReference = class {
|
|
|
238
238
|
/** @type {shaka.media.SegmentReference.Status} */
|
|
239
239
|
this.status = status;
|
|
240
240
|
|
|
241
|
+
/** @type {boolean} */
|
|
242
|
+
this.preload = false;
|
|
243
|
+
|
|
241
244
|
/** @type {?shaka.extern.HlsAes128Key} */
|
|
242
245
|
this.hlsAes128Key = hlsAes128Key;
|
|
243
246
|
|
|
@@ -358,6 +361,25 @@ shaka.media.SegmentReference = class {
|
|
|
358
361
|
this.status = shaka.media.SegmentReference.Status.UNAVAILABLE;
|
|
359
362
|
}
|
|
360
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Mark the reference as preload.
|
|
366
|
+
*
|
|
367
|
+
* @export
|
|
368
|
+
*/
|
|
369
|
+
markAsPreload() {
|
|
370
|
+
this.preload = true;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Returns true if the segment is preloaded.
|
|
375
|
+
*
|
|
376
|
+
* @return {boolean}
|
|
377
|
+
* @export
|
|
378
|
+
*/
|
|
379
|
+
isPreload() {
|
|
380
|
+
return this.preload;
|
|
381
|
+
}
|
|
382
|
+
|
|
361
383
|
/**
|
|
362
384
|
* Offset the segment reference by a fixed amount.
|
|
363
385
|
*
|
|
@@ -77,6 +77,9 @@ shaka.media.StreamingEngine = class {
|
|
|
77
77
|
/** @private {?shaka.extern.Stream} */
|
|
78
78
|
this.currentTextStream_ = null;
|
|
79
79
|
|
|
80
|
+
/** @private {number} */
|
|
81
|
+
this.textStreamSequenceId_ = 0;
|
|
82
|
+
|
|
80
83
|
/**
|
|
81
84
|
* Maps a content type, e.g., 'audio', 'video', or 'text', to a MediaState.
|
|
82
85
|
*
|
|
@@ -220,6 +223,8 @@ shaka.media.StreamingEngine = class {
|
|
|
220
223
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
221
224
|
goog.asserts.assert(!this.mediaStates_.has(ContentType.TEXT),
|
|
222
225
|
'Should not call loadNewTextStream_ while streaming text!');
|
|
226
|
+
this.textStreamSequenceId_++;
|
|
227
|
+
const currentSequenceId = this.textStreamSequenceId_;
|
|
223
228
|
|
|
224
229
|
try {
|
|
225
230
|
// Clear MediaSource's buffered text, so that the new text stream will
|
|
@@ -242,7 +247,7 @@ shaka.media.StreamingEngine = class {
|
|
|
242
247
|
const streamText =
|
|
243
248
|
textDisplayer.isTextVisible() || this.config_.alwaysStreamText;
|
|
244
249
|
|
|
245
|
-
if (streamText) {
|
|
250
|
+
if (streamText && (this.textStreamSequenceId_ == currentSequenceId)) {
|
|
246
251
|
const state = this.createMediaState_(stream);
|
|
247
252
|
this.mediaStates_.set(ContentType.TEXT, state);
|
|
248
253
|
this.scheduleUpdate_(state, 0);
|
|
@@ -635,10 +640,15 @@ shaka.media.StreamingEngine = class {
|
|
|
635
640
|
const mediaState = this.mediaStates_.get(type);
|
|
636
641
|
const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
637
642
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
643
|
+
let segment = null;
|
|
644
|
+
if (mediaState.segmentIterator) {
|
|
645
|
+
segment = mediaState.segmentIterator.current();
|
|
646
|
+
}
|
|
647
|
+
// Only reset the iterator if we seek outside the current segment.
|
|
648
|
+
if (!segment || segment.startTime > presentationTime ||
|
|
649
|
+
segment.endTime < presentationTime) {
|
|
650
|
+
mediaState.segmentIterator = null;
|
|
651
|
+
}
|
|
642
652
|
|
|
643
653
|
if (!newTimeIsBuffered(type)) {
|
|
644
654
|
const bufferEnd =
|
|
@@ -1559,10 +1569,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1559
1569
|
'waiting for another stream to recover...');
|
|
1560
1570
|
}
|
|
1561
1571
|
|
|
1562
|
-
// QuotaExceededError gets thrown if
|
|
1572
|
+
// QuotaExceededError gets thrown if eviction didn't help to make room
|
|
1563
1573
|
// for a segment. We want to wait for a while (4 seconds is just an
|
|
1564
1574
|
// arbitrary number) before updating to give the playhead a chance to
|
|
1565
|
-
// advance, so we don't
|
|
1575
|
+
// advance, so we don't immediately throw again.
|
|
1566
1576
|
this.scheduleUpdate_(mediaState, 4);
|
|
1567
1577
|
}
|
|
1568
1578
|
|
|
@@ -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
|
@@ -806,7 +806,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
806
806
|
}
|
|
807
807
|
|
|
808
808
|
this.abrManagerFactory_ = null;
|
|
809
|
-
this.abrManager_ = null;
|
|
810
809
|
this.config_ = null;
|
|
811
810
|
this.stats_ = null;
|
|
812
811
|
this.videoContainer_ = null;
|
|
@@ -817,6 +816,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
817
816
|
this.networkingEngine_ = null;
|
|
818
817
|
}
|
|
819
818
|
|
|
819
|
+
if (this.abrManager_) {
|
|
820
|
+
this.abrManager_.release();
|
|
821
|
+
this.abrManager_ = null;
|
|
822
|
+
}
|
|
823
|
+
|
|
820
824
|
// FakeEventTarget implements IReleasable
|
|
821
825
|
super.release();
|
|
822
826
|
}
|
|
@@ -1232,6 +1236,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1232
1236
|
*/
|
|
1233
1237
|
shouldUseSrcEquals_(payload) {
|
|
1234
1238
|
const Platform = shaka.util.Platform;
|
|
1239
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
1235
1240
|
|
|
1236
1241
|
// If we are using a platform that does not support media source, we will
|
|
1237
1242
|
// fall back to src= to handle all playback.
|
|
@@ -1286,7 +1291,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1286
1291
|
// version there.
|
|
1287
1292
|
|
|
1288
1293
|
// Native HLS can be preferred on any platform via this flag:
|
|
1289
|
-
if (
|
|
1294
|
+
if (MimeUtils.isHlsType(mimeType) &&
|
|
1295
|
+
this.config_.streaming.preferNativeHls) {
|
|
1290
1296
|
return true;
|
|
1291
1297
|
}
|
|
1292
1298
|
|
|
@@ -4086,6 +4092,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4086
4092
|
firstVariantWithLabel.language, '', 0, label);
|
|
4087
4093
|
|
|
4088
4094
|
this.chooseVariantAndSwitch_();
|
|
4095
|
+
} else if (this.video_ && this.video_.audioTracks) {
|
|
4096
|
+
const audioTracks = Array.from(this.video_.audioTracks);
|
|
4097
|
+
|
|
4098
|
+
let trackMatch = null;
|
|
4099
|
+
|
|
4100
|
+
for (const audioTrack of audioTracks) {
|
|
4101
|
+
if (audioTrack.label == label) {
|
|
4102
|
+
trackMatch = audioTrack;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
if (trackMatch) {
|
|
4106
|
+
this.switchHtml5Track_(trackMatch);
|
|
4107
|
+
}
|
|
4089
4108
|
}
|
|
4090
4109
|
}
|
|
4091
4110
|
|
|
@@ -5667,6 +5686,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5667
5686
|
error.category != shaka.util.Error.Category.NETWORK) {
|
|
5668
5687
|
return false;
|
|
5669
5688
|
}
|
|
5689
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE) {
|
|
5690
|
+
return false;
|
|
5691
|
+
}
|
|
5692
|
+
goog.asserts.assert(this.manifest_, 'Should have manifest!');
|
|
5670
5693
|
|
|
5671
5694
|
if (!navigator.onLine) {
|
|
5672
5695
|
// Don't restrict variants if we're completely offline, or else we end up
|
|
@@ -6607,7 +6630,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6607
6630
|
* @define {string} A version number taken from git at compile time.
|
|
6608
6631
|
* @export
|
|
6609
6632
|
*/
|
|
6610
|
-
shaka.Player.version = 'v4.2.
|
|
6633
|
+
shaka.Player.version = 'v4.2.11-uncompiled';
|
|
6611
6634
|
|
|
6612
6635
|
// Initialize the deprecation system using the version string we just set
|
|
6613
6636
|
// on the player.
|
|
@@ -115,6 +115,19 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
115
115
|
if (shaka.util.Platform.isChromecast()) {
|
|
116
116
|
isSupported =
|
|
117
117
|
shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
|
|
118
|
+
} else if (shaka.util.Platform.isTizen()) {
|
|
119
|
+
let extendedType = videoConfig.contentType;
|
|
120
|
+
if (videoConfig.width && videoConfig.height) {
|
|
121
|
+
extendedType += `; width=${videoConfig.width}`;
|
|
122
|
+
extendedType += `; height=${videoConfig.height}`;
|
|
123
|
+
}
|
|
124
|
+
if (videoConfig.framerate) {
|
|
125
|
+
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
126
|
+
}
|
|
127
|
+
if (videoConfig.bitrate) {
|
|
128
|
+
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
129
|
+
}
|
|
130
|
+
isSupported = MediaSource.isTypeSupported(extendedType);
|
|
118
131
|
} else {
|
|
119
132
|
isSupported = MediaSource.isTypeSupported(videoConfig.contentType);
|
|
120
133
|
}
|
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
|
@@ -196,6 +196,17 @@ shaka.util.MimeUtils = class {
|
|
|
196
196
|
return value;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Checks if the given MIME type is HLS MIME type.
|
|
201
|
+
*
|
|
202
|
+
* @param {string} mimeType
|
|
203
|
+
* @return {boolean}
|
|
204
|
+
*/
|
|
205
|
+
static isHlsType(mimeType) {
|
|
206
|
+
return mimeType === 'application/x-mpegurl' ||
|
|
207
|
+
mimeType === 'application/vnd.apple.mpegurl';
|
|
208
|
+
}
|
|
209
|
+
|
|
199
210
|
/**
|
|
200
211
|
* Get the base and profile of a codec string. Where [0] will be the codec
|
|
201
212
|
* 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
|
@@ -828,7 +828,7 @@ shaka.util.StreamUtils = class {
|
|
|
828
828
|
const video = variant.video;
|
|
829
829
|
if (audio && currentVariant && currentVariant.audio) {
|
|
830
830
|
if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
|
|
831
|
-
shaka.log.debug('
|
|
831
|
+
shaka.log.debug('Dropping variant - not compatible with active audio',
|
|
832
832
|
'active audio',
|
|
833
833
|
StreamUtils.getStreamSummaryString_(currentVariant.audio),
|
|
834
834
|
'variant.audio',
|
|
@@ -839,7 +839,7 @@ shaka.util.StreamUtils = class {
|
|
|
839
839
|
|
|
840
840
|
if (video && currentVariant && currentVariant.video) {
|
|
841
841
|
if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
|
|
842
|
-
shaka.log.debug('
|
|
842
|
+
shaka.log.debug('Dropping variant - not compatible with active video',
|
|
843
843
|
'active video',
|
|
844
844
|
StreamUtils.getStreamSummaryString_(currentVariant.video),
|
|
845
845
|
'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.
|
|
6
|
-
- v4.
|
|
7
|
-
-
|
|
8
|
-
- v3.2 (in use by the Cast Application Framework)
|
|
5
|
+
- v4.3 (latest, also in use by the Cast Application Framework)
|
|
6
|
+
- v4.2 (previous)
|
|
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.2.
|
|
4
|
+
"version": "4.2.11",
|
|
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",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"demoDeps": [
|
|
67
68
|
"awesomplete/awesomplete.css",
|
|
68
69
|
"awesomplete/awesomplete.min.js",
|
|
70
|
+
"codem-isoboxer/dist/iso_boxer.min.js",
|
|
69
71
|
"dialog-polyfill/dialog-polyfill.css",
|
|
70
72
|
"dialog-polyfill/dist/dialog-polyfill.js",
|
|
71
73
|
"eme-encryption-scheme-polyfill/index.js",
|
|
@@ -91,12 +93,16 @@
|
|
|
91
93
|
},
|
|
92
94
|
"license": "Apache-2.0",
|
|
93
95
|
"scripts": {
|
|
96
|
+
"prepack": "clean-package",
|
|
97
|
+
"postpack": "clean-package restore",
|
|
94
98
|
"prepublishOnly": "python build/checkversion.py && python build/all.py --force"
|
|
95
99
|
},
|
|
96
100
|
"dependencies": {
|
|
97
101
|
"eme-encryption-scheme-polyfill": "^2.1.1"
|
|
98
102
|
},
|
|
99
|
-
"
|
|
100
|
-
"
|
|
103
|
+
"clean-package": {
|
|
104
|
+
"remove": [
|
|
105
|
+
"engines"
|
|
106
|
+
]
|
|
101
107
|
}
|
|
102
108
|
}
|
|
@@ -560,7 +560,8 @@ describe('HlsParser live', () => {
|
|
|
560
560
|
// partialRef3
|
|
561
561
|
'#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
|
|
562
562
|
// preloadRef
|
|
563
|
-
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210
|
|
563
|
+
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210,',
|
|
564
|
+
'BYTERANGE-LENGTH=210\n',
|
|
564
565
|
].join('');
|
|
565
566
|
|
|
566
567
|
const partialRef = makeReference(
|
|
@@ -583,6 +584,7 @@ describe('HlsParser live', () => {
|
|
|
583
584
|
const preloadRef = makeReference(
|
|
584
585
|
'test:/partial.mp4', 6, 7.5, /* syncTime= */ null,
|
|
585
586
|
/* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
|
|
587
|
+
preloadRef.markAsPreload();
|
|
586
588
|
|
|
587
589
|
// ref2 is not fully published yet, so it doesn't have a segment uri.
|
|
588
590
|
const ref2 = makeReference(
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('ContentWorkarounds', () => {
|
|
8
|
+
const encryptionBoxes = {
|
|
9
|
+
'encv': ['hev1', 'hvc1', 'avc1', 'avc3'],
|
|
10
|
+
'enca': ['ac-3', 'ec-3', 'mp4a'],
|
|
11
|
+
};
|
|
12
|
+
for (const encryptionBox of Object.keys(encryptionBoxes)) {
|
|
13
|
+
for (const box of encryptionBoxes[encryptionBox]) {
|
|
14
|
+
it(`adds ${encryptionBox} box for ${box}`, () => {
|
|
15
|
+
const boxType = [];
|
|
16
|
+
for (const char of box) {
|
|
17
|
+
boxType.push(char.charCodeAt(0));
|
|
18
|
+
}
|
|
19
|
+
const unencrypted = new Uint8Array([
|
|
20
|
+
0x00, 0x00, 0x00, 0x20, // size
|
|
21
|
+
0x73, 0x74, 0x73, 0x64, // stsd
|
|
22
|
+
0x01, // version
|
|
23
|
+
0x12, 0x34, 0x56, // flags
|
|
24
|
+
0x00, 0x00, 0x00, 0x01, // count
|
|
25
|
+
0x00, 0x00, 0x00, 0x10, // size
|
|
26
|
+
...boxType, // box type
|
|
27
|
+
0x01, // version
|
|
28
|
+
0x12, 0x34, 0x56, // flags
|
|
29
|
+
0x00, 0x11, 0x22, 0x33, // payload
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const faked =
|
|
33
|
+
shaka.media.ContentWorkarounds.fakeEncryption(unencrypted);
|
|
34
|
+
const spy = jasmine.createSpy('boxCallback');
|
|
35
|
+
new shaka.util.Mp4Parser()
|
|
36
|
+
.fullBox('stsd', shaka.util.Mp4Parser.sampleDescription)
|
|
37
|
+
.box(encryptionBox, /** @type {!Function} */ (spy))
|
|
38
|
+
.parse(faked);
|
|
39
|
+
expect(spy).toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -74,19 +74,6 @@ describe('DrmEngine', () => {
|
|
|
74
74
|
onEventSpy = jasmine.createSpy('onEvent');
|
|
75
75
|
|
|
76
76
|
networkingEngine = new shaka.net.NetworkingEngine();
|
|
77
|
-
networkingEngine.registerRequestFilter((type, request) => {
|
|
78
|
-
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
request.headers['X-AxDRM-Message'] = [
|
|
83
|
-
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lk',
|
|
84
|
-
'IjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc2FnZSI6e',
|
|
85
|
-
'yJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiNmU1YTFkMj',
|
|
86
|
-
'YtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflOPv9qHnu3ZWJNZ12j',
|
|
87
|
-
'gkqTabmwXbDWk_47tLNE',
|
|
88
|
-
].join('');
|
|
89
|
-
});
|
|
90
77
|
|
|
91
78
|
const playerInterface = {
|
|
92
79
|
netEngine: networkingEngine,
|
|
@@ -99,22 +86,22 @@ describe('DrmEngine', () => {
|
|
|
99
86
|
drmEngine = new shaka.media.DrmEngine(playerInterface);
|
|
100
87
|
const config = shaka.util.PlayerConfiguration.createDefault().drm;
|
|
101
88
|
config.servers['com.widevine.alpha'] =
|
|
102
|
-
'https://
|
|
89
|
+
'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA';
|
|
103
90
|
config.servers['com.microsoft.playready'] =
|
|
104
|
-
'https://
|
|
91
|
+
'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)';
|
|
105
92
|
drmEngine.configure(config);
|
|
106
93
|
|
|
107
94
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
108
95
|
manifest.addVariant(0, (variant) => {
|
|
109
96
|
variant.addVideo(1, (stream) => {
|
|
110
97
|
stream.encrypted = true;
|
|
111
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
112
98
|
stream.addDrmInfo('com.microsoft.playready');
|
|
99
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
113
100
|
});
|
|
114
101
|
variant.addAudio(2, (stream) => {
|
|
115
102
|
stream.encrypted = true;
|
|
116
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
117
103
|
stream.addDrmInfo('com.microsoft.playready');
|
|
104
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
118
105
|
});
|
|
119
106
|
});
|
|
120
107
|
});
|