shaka-player 4.1.1 → 4.2.0
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/build-and-test.yaml +67 -15
- package/.github/workflows/compute-incremental-coverage.py +251 -0
- package/.github/workflows/report-incremental-coverage.yaml +39 -0
- package/.github/workflows/selenium-lab-tests.yaml +44 -1
- package/AUTHORS +1 -0
- package/CHANGELOG.md +36 -8
- package/CONTRIBUTORS +3 -0
- package/README.md +20 -6
- package/demo/common/assets.js +25 -0
- package/demo/common/message_ids.js +2 -0
- package/demo/config.js +5 -1
- package/demo/index.html +1 -3
- package/demo/locales/en.json +2 -0
- package/demo/locales/source.json +8 -0
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +25 -23
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +25 -23
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +6 -5
- package/dist/locales.js +30 -30
- package/dist/receiver.compiled.debug.js +24 -22
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +24 -22
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +69 -5
- package/dist/shaka-player.compiled.debug.d.ts +69 -5
- package/dist/shaka-player.compiled.debug.externs.js +111 -42
- package/dist/shaka-player.compiled.debug.js +352 -301
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +111 -42
- package/dist/shaka-player.compiled.js +823 -802
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +69 -5
- package/dist/shaka-player.ui.debug.d.ts +69 -5
- package/dist/shaka-player.ui.debug.externs.js +111 -42
- package/dist/shaka-player.ui.debug.js +360 -310
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +111 -42
- package/dist/shaka-player.ui.js +980 -957
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +149 -0
- package/docs/tutorials/ui.md +6 -6
- package/docs/tutorials/upgrade.md +1 -0
- package/docs/tutorials/welcome.md +6 -3
- package/externs/shaka/abr_manager.js +8 -0
- package/externs/shaka/manifest.js +43 -0
- package/externs/shaka/player.js +13 -2
- package/karma.conf.js +3 -11
- package/lib/abr/simple_abr_manager.js +72 -4
- package/lib/ads/client_side_ad_manager.js +1 -1
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +123 -27
- package/lib/media/drm_engine.js +1 -3
- package/lib/media/media_source_engine.js +57 -24
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/segment_index.js +8 -0
- package/lib/media/segment_reference.js +7 -1
- package/lib/media/streaming_engine.js +42 -6
- package/lib/media/time_ranges_utils.js +46 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/player.js +8 -6
- package/lib/polyfill/media_capabilities.js +9 -0
- package/lib/polyfill/patchedmediakeys_apple.js +729 -0
- package/lib/polyfill/videoplaybackquality.js +3 -1
- package/lib/text/cue.js +0 -5
- package/lib/text/simple_text_displayer.js +21 -9
- package/lib/text/ui_text_displayer.js +83 -19
- package/lib/text/vtt_text_parser.js +61 -4
- package/lib/util/buffer_utils.js +3 -0
- package/lib/util/error.js +21 -1
- package/lib/util/fairplay_utils.js +100 -2
- package/lib/util/object_utils.js +1 -0
- package/lib/util/platform.js +30 -1
- package/lib/util/player_configuration.js +3 -10
- package/lib/util/stream_utils.js +23 -3
- package/lib/util/string_utils.js +102 -13
- package/maintained-branches.md +15 -0
- package/package.json +3 -5
- package/shaka-player.uncompiled.js +1 -0
- package/test/hls/hls_parser_unit.js +49 -33
- package/test/media/drm_engine_integration.js +24 -8
- package/test/media/media_source_engine_integration.js +24 -10
- package/test/media/media_source_engine_unit.js +53 -38
- package/test/media/streaming_engine_unit.js +107 -32
- package/test/test/util/fake_media_source_engine.js +10 -9
- package/test/test/util/simple_fakes.js +4 -0
- package/test/test/util/streaming_engine_util.js +10 -2
- package/test/text/simple_text_displayer_unit.js +27 -0
- package/test/text/ui_text_displayer_unit.js +65 -0
- package/test/text/vtt_text_parser_unit.js +26 -0
- package/test/util/string_utils_unit.js +46 -8
- package/ui/text_selection.js +2 -2
- package/app-engine/README.md +0 -9
- package/app-engine/demo-version-index/README.md +0 -14
- package/app-engine/demo-version-index/app.yaml +0 -28
- package/app-engine/demo-version-index/generate.py +0 -164
- package/app-engine/demo-version-index/main.py +0 -11
- package/app-engine/demo-version-index/requirements.txt +0 -5
- package/app-engine/demo-version-index/templates/index.html +0 -114
- package/app-engine/shaka-player-demo/README.md +0 -18
- package/app-engine/shaka-player-demo/app.yaml +0 -61
- package/app-engine/shaka-player-demo/main.py +0 -95
- package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
- package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
- package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
- package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
- package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
- package/app-engine/shaka-player-demo/posters/standard.png +0 -0
- package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
- package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
- package/app-engine/shaka-player-demo/posters.py +0 -110
- package/app-engine/shaka-player-demo/requirements.txt +0 -5
- package/app-engine/shaka-player-demo/time.txt +0 -1
- package/build/README.md +0 -127
- package/build/__init__.py +0 -0
- package/build/all.py +0 -150
- package/build/apps.py +0 -186
- package/build/build.py +0 -392
- package/build/check.py +0 -354
- package/build/checkversion.py +0 -84
- package/build/compiler.py +0 -513
- package/build/conformance.textproto +0 -335
- package/build/docker/Dockerfile +0 -20
- package/build/docker/docker-compose.yml +0 -10
- package/build/docs.py +0 -54
- package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
- package/build/eslint-plugin-shaka-rules/index.js +0 -24
- package/build/eslint-plugin-shaka-rules/package.json +0 -7
- package/build/eslint-plugin-shaka-rules/private.js +0 -109
- package/build/gendeps.py +0 -71
- package/build/generateExterns.js +0 -867
- package/build/generateLocalizations.py +0 -262
- package/build/generateTsDefs.py +0 -137
- package/build/install-linux-prereqs.sh +0 -136
- package/build/license-header +0 -5
- package/build/misspellings.txt +0 -39
- package/build/pixelsChanged.js +0 -35
- package/build/shaka-lab.yaml +0 -161
- package/build/shakaBuildHelpers.py +0 -356
- package/build/stats.py +0 -816
- package/build/subprocessWindowsPatch.py +0 -103
- package/build/test.py +0 -541
- package/build/types/ads +0 -8
- package/build/types/cast +0 -6
- package/build/types/cea +0 -13
- package/build/types/complete +0 -9
- package/build/types/core +0 -108
- package/build/types/dash +0 -8
- package/build/types/hls +0 -9
- package/build/types/manifests +0 -5
- package/build/types/networking +0 -6
- package/build/types/offline +0 -22
- package/build/types/polyfill +0 -18
- package/build/types/text +0 -11
- package/build/types/ui +0 -39
- package/build/updateScreenshots.py +0 -85
- package/build/wrapper.template.js +0 -52
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.polyfill.VideoPlaybackQuality');
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.polyfill');
|
|
10
|
+
goog.require('shaka.util.Platform');
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -33,7 +34,8 @@ shaka.polyfill.VideoPlaybackQuality = class {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
if ('webkitDroppedFrameCount' in proto
|
|
37
|
+
if ('webkitDroppedFrameCount' in proto ||
|
|
38
|
+
shaka.util.Platform.isWebOS3()) {
|
|
37
39
|
proto.getVideoPlaybackQuality =
|
|
38
40
|
shaka.polyfill.VideoPlaybackQuality.webkit_;
|
|
39
41
|
}
|
package/lib/text/cue.js
CHANGED
|
@@ -41,14 +41,9 @@ shaka.text.Cue = class {
|
|
|
41
41
|
*/
|
|
42
42
|
this.endTime = endTime;
|
|
43
43
|
|
|
44
|
-
// The explicit type here is to work around an apparent compiler bug where
|
|
45
|
-
// the compiler seems to get confused about the type. Since we are
|
|
46
|
-
// overriding the interface type, it shouldn't be necessary to do this.
|
|
47
|
-
// Compiler version 20200517.
|
|
48
44
|
/**
|
|
49
45
|
* @override
|
|
50
46
|
* @exportInterface
|
|
51
|
-
* @type {string}
|
|
52
47
|
*/
|
|
53
48
|
this.payload = payload;
|
|
54
49
|
|
|
@@ -121,16 +121,28 @@ shaka.text.SimpleTextDisplayer = class {
|
|
|
121
121
|
// We don't want to modify the array or objects passed in, since we don't
|
|
122
122
|
// technically own them. So we build a new array and replace certain items
|
|
123
123
|
// in it if they need to be flattened.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
// We also don't want to flatten the text payloads starting at a container
|
|
125
|
+
// element; otherwise, for containers encapsulating multiple caption lines,
|
|
126
|
+
// the lines would merge into a single cue. This is undesirable when a
|
|
127
|
+
// subset of the captions are outside of the append time window. To fix
|
|
128
|
+
// this, we only call flattenPayload() starting at elements marked as
|
|
129
|
+
// isContainer = false.
|
|
130
|
+
const getCuesToFlatten = (cues, result) => {
|
|
131
|
+
for (const cue of cues) {
|
|
132
|
+
if (cue.isContainer) {
|
|
133
|
+
// Recurse to find the actual text payload cues.
|
|
134
|
+
getCuesToFlatten(cue.nestedCues, result);
|
|
135
|
+
} else {
|
|
136
|
+
// Flatten the payload.
|
|
137
|
+
const flatCue = cue.clone();
|
|
138
|
+
flatCue.nestedCues = [];
|
|
139
|
+
flatCue.payload = flattenPayload(cue);
|
|
140
|
+
result.push(flatCue);
|
|
141
|
+
}
|
|
132
142
|
}
|
|
133
|
-
|
|
143
|
+
return result;
|
|
144
|
+
};
|
|
145
|
+
const flattenedCues = getCuesToFlatten(cues, []);
|
|
134
146
|
|
|
135
147
|
// Convert cues.
|
|
136
148
|
const textTrackCues = [];
|
|
@@ -77,6 +77,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
77
77
|
* the cue (e.g. the HTML element to put nested cues inside).
|
|
78
78
|
* @private {Map.<!shaka.extern.Cue, !{
|
|
79
79
|
* cueElement: !HTMLElement,
|
|
80
|
+
* regionElement: HTMLElement,
|
|
80
81
|
* wrapper: !HTMLElement
|
|
81
82
|
* }>}
|
|
82
83
|
*/
|
|
@@ -97,6 +98,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
97
98
|
});
|
|
98
99
|
this.resizeObserver_.observe(this.textContainer_);
|
|
99
100
|
}
|
|
101
|
+
|
|
102
|
+
/** @private {Map.<string, !HTMLElement>} */
|
|
103
|
+
this.regionElements_ = new Map();
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
|
|
@@ -234,6 +238,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
234
238
|
// even ones which are going to be planted again.
|
|
235
239
|
toUproot.push(cueRegistry.cueElement);
|
|
236
240
|
|
|
241
|
+
// Also uproot all displayed region elements.
|
|
242
|
+
if (cueRegistry.regionElement) {
|
|
243
|
+
toUproot.push(cueRegistry.regionElement);
|
|
244
|
+
}
|
|
245
|
+
|
|
237
246
|
// If the cue should not be displayed, remove it entirely.
|
|
238
247
|
if (!shouldBeDisplayed) {
|
|
239
248
|
// Since something has to be removed, we will need to update the DOM.
|
|
@@ -268,8 +277,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
268
277
|
goog.asserts.assert(topCue == cue, 'Parent cues should be kept in order');
|
|
269
278
|
}
|
|
270
279
|
if (updateDOM) {
|
|
271
|
-
for (const
|
|
272
|
-
|
|
280
|
+
for (const element of toUproot) {
|
|
281
|
+
// NOTE: Because we uproot shared region elements, too, we might hit an
|
|
282
|
+
// element here that has no parent because we've already processed it.
|
|
283
|
+
if (element.parentElement) {
|
|
284
|
+
element.parentElement.removeChild(element);
|
|
285
|
+
}
|
|
273
286
|
}
|
|
274
287
|
toPlant.sort((a, b) => {
|
|
275
288
|
if (a.startTime != b.startTime) {
|
|
@@ -281,7 +294,12 @@ shaka.text.UITextDisplayer = class {
|
|
|
281
294
|
for (const cue of toPlant) {
|
|
282
295
|
const cueRegistry = this.currentCuesMap_.get(cue);
|
|
283
296
|
goog.asserts.assert(cueRegistry, 'cueRegistry should exist.');
|
|
284
|
-
|
|
297
|
+
if (cueRegistry.regionElement) {
|
|
298
|
+
container.appendChild(cueRegistry.regionElement);
|
|
299
|
+
cueRegistry.regionElement.appendChild(cueRegistry.cueElement);
|
|
300
|
+
} else {
|
|
301
|
+
container.appendChild(cueRegistry.cueElement);
|
|
302
|
+
}
|
|
285
303
|
}
|
|
286
304
|
}
|
|
287
305
|
}
|
|
@@ -298,11 +316,15 @@ shaka.text.UITextDisplayer = class {
|
|
|
298
316
|
|
|
299
317
|
const currentTime = this.video_.currentTime;
|
|
300
318
|
if (!this.isTextVisible_ || forceUpdate) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
shaka.util.Dom.removeAllChildren(
|
|
304
|
-
this.currentCuesMap_.clear();
|
|
319
|
+
// Remove child elements from all regions.
|
|
320
|
+
for (const regionElement of this.regionElements_.values()) {
|
|
321
|
+
shaka.util.Dom.removeAllChildren(regionElement);
|
|
305
322
|
}
|
|
323
|
+
// Remove all top-level elements in the text container.
|
|
324
|
+
shaka.util.Dom.removeAllChildren(this.textContainer_);
|
|
325
|
+
// Clear the element maps.
|
|
326
|
+
this.currentCuesMap_.clear();
|
|
327
|
+
this.regionElements_.clear();
|
|
306
328
|
}
|
|
307
329
|
if (this.isTextVisible_) {
|
|
308
330
|
// Log currently attached cue elements for verification, later.
|
|
@@ -332,6 +354,54 @@ shaka.text.UITextDisplayer = class {
|
|
|
332
354
|
}
|
|
333
355
|
}
|
|
334
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Get or create a region element corresponding to the cue region. These are
|
|
359
|
+
* cached by ID.
|
|
360
|
+
*
|
|
361
|
+
* @param {!shaka.extern.Cue} cue
|
|
362
|
+
* @return {!HTMLElement}
|
|
363
|
+
* @private
|
|
364
|
+
*/
|
|
365
|
+
getRegionElement_(cue) {
|
|
366
|
+
const region = cue.region;
|
|
367
|
+
|
|
368
|
+
if (this.regionElements_.has(region.id)) {
|
|
369
|
+
return this.regionElements_.get(region.id);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const regionElement = shaka.util.Dom.createHTMLElement('span');
|
|
373
|
+
|
|
374
|
+
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
375
|
+
const heightUnit = region.heightUnits == percentageUnit ? '%' : 'px';
|
|
376
|
+
const widthUnit = region.widthUnits == percentageUnit ? '%' : 'px';
|
|
377
|
+
const viewportAnchorUnit =
|
|
378
|
+
region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
379
|
+
|
|
380
|
+
regionElement.id = 'shaka-text-region---' + region.id;
|
|
381
|
+
regionElement.classList.add('shaka-text-region');
|
|
382
|
+
|
|
383
|
+
regionElement.style.height = region.height + heightUnit;
|
|
384
|
+
regionElement.style.width = region.width + widthUnit;
|
|
385
|
+
regionElement.style.position = 'absolute';
|
|
386
|
+
regionElement.style.top = region.viewportAnchorY + viewportAnchorUnit;
|
|
387
|
+
regionElement.style.left = region.viewportAnchorX + viewportAnchorUnit;
|
|
388
|
+
|
|
389
|
+
regionElement.style.display = 'flex';
|
|
390
|
+
regionElement.style.flexDirection = 'column';
|
|
391
|
+
regionElement.style.alignItems = 'center';
|
|
392
|
+
|
|
393
|
+
if (cue.displayAlign == shaka.text.Cue.displayAlign.BEFORE) {
|
|
394
|
+
regionElement.style.justifyContent = 'flex-start';
|
|
395
|
+
} else if (cue.displayAlign == shaka.text.Cue.displayAlign.CENTER) {
|
|
396
|
+
regionElement.style.justifyContent = 'center';
|
|
397
|
+
} else {
|
|
398
|
+
regionElement.style.justifyContent = 'flex-end';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
this.regionElements_.set(region.id, regionElement);
|
|
402
|
+
return regionElement;
|
|
403
|
+
}
|
|
404
|
+
|
|
335
405
|
/**
|
|
336
406
|
* Creates the object for a cue.
|
|
337
407
|
*
|
|
@@ -354,6 +424,11 @@ shaka.text.UITextDisplayer = class {
|
|
|
354
424
|
this.setCaptionStyles_(cueElement, cue, parents, needWrapper);
|
|
355
425
|
}
|
|
356
426
|
|
|
427
|
+
let regionElement = null;
|
|
428
|
+
if (cue.region && cue.region.id) {
|
|
429
|
+
regionElement = this.getRegionElement_(cue);
|
|
430
|
+
}
|
|
431
|
+
|
|
357
432
|
let wrapper = cueElement;
|
|
358
433
|
if (needWrapper) {
|
|
359
434
|
// Create a wrapper element which will serve to contain all children into
|
|
@@ -365,7 +440,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
365
440
|
cueElement.appendChild(wrapper);
|
|
366
441
|
}
|
|
367
442
|
|
|
368
|
-
this.currentCuesMap_.set(cue, {cueElement, wrapper});
|
|
443
|
+
this.currentCuesMap_.set(cue, {cueElement, wrapper, regionElement});
|
|
369
444
|
}
|
|
370
445
|
|
|
371
446
|
/**
|
|
@@ -526,17 +601,6 @@ shaka.text.UITextDisplayer = class {
|
|
|
526
601
|
}
|
|
527
602
|
}
|
|
528
603
|
}
|
|
529
|
-
} else if (cue.region && cue.region.id) {
|
|
530
|
-
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
531
|
-
const heightUnit = cue.region.heightUnits == percentageUnit ? '%' : 'px';
|
|
532
|
-
const widthUnit = cue.region.widthUnits == percentageUnit ? '%' : 'px';
|
|
533
|
-
const viewportAnchorUnit =
|
|
534
|
-
cue.region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
535
|
-
style.height = cue.region.height + heightUnit;
|
|
536
|
-
style.width = cue.region.width + widthUnit;
|
|
537
|
-
style.position = 'absolute';
|
|
538
|
-
style.top = cue.region.viewportAnchorY + viewportAnchorUnit;
|
|
539
|
-
style.left = cue.region.viewportAnchorX + viewportAnchorUnit;
|
|
540
604
|
}
|
|
541
605
|
|
|
542
606
|
style.lineHeight = cue.lineHeight;
|
|
@@ -412,6 +412,7 @@ shaka.text.VttTextParser = class {
|
|
|
412
412
|
VttTextParser.addDefaultTextColor_(styles);
|
|
413
413
|
}
|
|
414
414
|
payload = VttTextParser.replaceColorPayload_(payload);
|
|
415
|
+
payload = VttTextParser.replaceKaraokeStylePayload_(payload);
|
|
415
416
|
const xmlPayload = '<span>' + payload + '</span>';
|
|
416
417
|
const element = shaka.util.XmlUtils.parseXmlString(xmlPayload, 'span');
|
|
417
418
|
if (element) {
|
|
@@ -437,6 +438,44 @@ shaka.text.VttTextParser = class {
|
|
|
437
438
|
}
|
|
438
439
|
}
|
|
439
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Converts karaoke style tag to be valid for xml parsing
|
|
443
|
+
* For example,
|
|
444
|
+
* input: Text <00:00:00.450> time <00:00:01.450> 1
|
|
445
|
+
* output: Text <div time="00:00:00.450"> time
|
|
446
|
+
* <div time="00:00:01.450"> 1</div></div>
|
|
447
|
+
*
|
|
448
|
+
* @param {string} payload
|
|
449
|
+
* @return {string} processed payload
|
|
450
|
+
* @private
|
|
451
|
+
*/
|
|
452
|
+
static replaceKaraokeStylePayload_(payload) {
|
|
453
|
+
const names = [];
|
|
454
|
+
let nameStart = -1;
|
|
455
|
+
for (let i = 0; i < payload.length; i++) {
|
|
456
|
+
if (payload[i] === '<') {
|
|
457
|
+
nameStart = i + 1;
|
|
458
|
+
} else if (payload[i] === '>') {
|
|
459
|
+
if (nameStart > 0) {
|
|
460
|
+
const name = payload.substr(nameStart, i - nameStart);
|
|
461
|
+
if (name.match(shaka.text.VttTextParser.timeFormat_)) {
|
|
462
|
+
names.push(name);
|
|
463
|
+
}
|
|
464
|
+
nameStart = -1;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
let newPayload = payload;
|
|
469
|
+
for (const name of names) {
|
|
470
|
+
const replaceTag = '<' + name + '>';
|
|
471
|
+
const startTag = '<div time="' + name + '">';
|
|
472
|
+
const endTag = '</div>';
|
|
473
|
+
newPayload = newPayload.replace(replaceTag, startTag);
|
|
474
|
+
newPayload += endTag;
|
|
475
|
+
}
|
|
476
|
+
return newPayload;
|
|
477
|
+
}
|
|
478
|
+
|
|
440
479
|
/**
|
|
441
480
|
* Converts color end tag to be valid for xml parsing
|
|
442
481
|
* For example,
|
|
@@ -560,6 +599,18 @@ shaka.text.VttTextParser = class {
|
|
|
560
599
|
case 'u':
|
|
561
600
|
nestedCue.textDecoration.push(underline);
|
|
562
601
|
break;
|
|
602
|
+
case 'div': {
|
|
603
|
+
const time = /** @type {!Element} */(element).getAttribute('time');
|
|
604
|
+
if (!time) {
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
const parser = new shaka.util.TextParser(time);
|
|
608
|
+
const cueTime = shaka.text.VttTextParser.parseTime_(parser);
|
|
609
|
+
if (cueTime) {
|
|
610
|
+
nestedCue.startTime = cueTime;
|
|
611
|
+
}
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
563
614
|
default:
|
|
564
615
|
break;
|
|
565
616
|
}
|
|
@@ -776,10 +827,7 @@ shaka.text.VttTextParser = class {
|
|
|
776
827
|
* @private
|
|
777
828
|
*/
|
|
778
829
|
static parseTime_(parser) {
|
|
779
|
-
|
|
780
|
-
// 00:00.00 or 00:00:00.00 or 0:00:00.00
|
|
781
|
-
const regexExpresion = /(?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{2,3})/g;
|
|
782
|
-
const results = parser.readRegex(regexExpresion);
|
|
830
|
+
const results = parser.readRegex(shaka.text.VttTextParser.timeFormat_);
|
|
783
831
|
if (results == null) {
|
|
784
832
|
return null;
|
|
785
833
|
}
|
|
@@ -810,6 +858,15 @@ shaka.text.VttTextParser.MPEG_TIMESCALE_ = 90000;
|
|
|
810
858
|
*/
|
|
811
859
|
shaka.text.VttTextParser.TS_ROLLOVER_ = 0x200000000;
|
|
812
860
|
|
|
861
|
+
/**
|
|
862
|
+
* @const
|
|
863
|
+
* @private {!RegExp}
|
|
864
|
+
* @example 00:00.000 or 00:00:00.000 or 0:00:00.000 or
|
|
865
|
+
* 00:00.00 or 00:00:00.00 or 0:00:00.00
|
|
866
|
+
*/
|
|
867
|
+
shaka.text.VttTextParser.timeFormat_ =
|
|
868
|
+
/(?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{2,3})/g;
|
|
869
|
+
|
|
813
870
|
shaka.text.TextEngine.registerParser(
|
|
814
871
|
'text/vtt', () => new shaka.text.VttTextParser());
|
|
815
872
|
|
package/lib/util/buffer_utils.js
CHANGED
|
@@ -20,6 +20,7 @@ shaka.util.BufferUtils = class {
|
|
|
20
20
|
* @param {?BufferSource} arr2
|
|
21
21
|
* @return {boolean}
|
|
22
22
|
* @export
|
|
23
|
+
* @suppress {strictMissingProperties}
|
|
23
24
|
*/
|
|
24
25
|
static equal(arr1, arr2) {
|
|
25
26
|
const BufferUtils = shaka.util.BufferUtils;
|
|
@@ -135,8 +136,10 @@ shaka.util.BufferUtils = class {
|
|
|
135
136
|
static view_(data, offset, length, Type) {
|
|
136
137
|
const buffer = shaka.util.BufferUtils.unsafeGetArrayBuffer_(data);
|
|
137
138
|
// Absolute end of the |data| view within |buffer|.
|
|
139
|
+
/** @suppress {strictMissingProperties} */
|
|
138
140
|
const dataEnd = (data.byteOffset || 0) + data.byteLength;
|
|
139
141
|
// Absolute start of the result within |buffer|.
|
|
142
|
+
/** @suppress {strictMissingProperties} */
|
|
140
143
|
const rawStart = (data.byteOffset || 0) + offset;
|
|
141
144
|
const start = Math.max(0, Math.min(rawStart, dataEnd));
|
|
142
145
|
// Absolute end of the result within |buffer|.
|
package/lib/util/error.js
CHANGED
|
@@ -693,7 +693,27 @@ shaka.util.Error.Code = {
|
|
|
693
693
|
*/
|
|
694
694
|
'HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED': 4040,
|
|
695
695
|
|
|
696
|
-
|
|
696
|
+
/**
|
|
697
|
+
* We do not support playing encrypted content (different than mp2t) with MSE
|
|
698
|
+
* and legacy Apple MediaKeys API.
|
|
699
|
+
*/
|
|
700
|
+
'HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED': 4041,
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Web Crypto API is not available (to decrypt AES-128 streams). Web Crypto
|
|
704
|
+
* only exists in secure origins like https.
|
|
705
|
+
*/
|
|
706
|
+
'NO_WEB_CRYPTO_API': 4042,
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* AES-128 iv length should be 16 bytes.
|
|
710
|
+
*/
|
|
711
|
+
'HLS_AES_128_INVALID_IV_LENGTH': 4043,
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* AES-128 encryption key length should be 16 bytes.
|
|
715
|
+
*/
|
|
716
|
+
'HLS_AES_128_INVALID_KEY_LENGTH': 4044,
|
|
697
717
|
|
|
698
718
|
|
|
699
719
|
// RETIRED: 'INCONSISTENT_BUFFER_STATE': 5000,
|
|
@@ -133,13 +133,83 @@ shaka.util.FairPlayUtils = class {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
*
|
|
136
|
+
* Verimatrix initDataTransform configuration.
|
|
137
|
+
*
|
|
138
|
+
* @param {!Uint8Array} initData
|
|
139
|
+
* @param {string} initDataType
|
|
140
|
+
* @param {?shaka.extern.DrmInfo} drmInfo
|
|
141
|
+
* @export
|
|
142
|
+
*/
|
|
143
|
+
static verimatrixInitDataTransform(initData, initDataType, drmInfo) {
|
|
144
|
+
if (initDataType !== 'skd') {
|
|
145
|
+
return initData;
|
|
146
|
+
}
|
|
147
|
+
const StringUtils = shaka.util.StringUtils;
|
|
148
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
149
|
+
const cert = drmInfo.serverCertificate;
|
|
150
|
+
const initDataAsString = StringUtils.fromBytesAutoDetect(initData);
|
|
151
|
+
const contentId = initDataAsString.split('skd://').pop();
|
|
152
|
+
return FairPlayUtils.initDataTransform(initData, contentId, cert);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* EZDRM initDataTransform configuration.
|
|
157
|
+
*
|
|
158
|
+
* @param {!Uint8Array} initData
|
|
159
|
+
* @param {string} initDataType
|
|
160
|
+
* @param {?shaka.extern.DrmInfo} drmInfo
|
|
161
|
+
* @export
|
|
162
|
+
*/
|
|
163
|
+
static ezdrmInitDataTransform(initData, initDataType, drmInfo) {
|
|
164
|
+
if (initDataType !== 'skd') {
|
|
165
|
+
return initData;
|
|
166
|
+
}
|
|
167
|
+
const StringUtils = shaka.util.StringUtils;
|
|
168
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
169
|
+
const cert = drmInfo.serverCertificate;
|
|
170
|
+
const initDataAsString = StringUtils.fromBytesAutoDetect(initData);
|
|
171
|
+
const contentId = initDataAsString.split(';').pop();
|
|
172
|
+
return FairPlayUtils.initDataTransform(initData, contentId, cert);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Conax initDataTransform configuration.
|
|
177
|
+
*
|
|
178
|
+
* @param {!Uint8Array} initData
|
|
179
|
+
* @param {string} initDataType
|
|
180
|
+
* @param {?shaka.extern.DrmInfo} drmInfo
|
|
181
|
+
* @export
|
|
182
|
+
*/
|
|
183
|
+
static conaxInitDataTransform(initData, initDataType, drmInfo) {
|
|
184
|
+
if (initDataType !== 'skd') {
|
|
185
|
+
return initData;
|
|
186
|
+
}
|
|
187
|
+
const StringUtils = shaka.util.StringUtils;
|
|
188
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
189
|
+
const cert = drmInfo.serverCertificate;
|
|
190
|
+
const initDataAsString = StringUtils.fromBytesAutoDetect(initData);
|
|
191
|
+
const skdValue = initDataAsString.split('skd://').pop().split('?').shift();
|
|
192
|
+
const stringToArray = (string) => {
|
|
193
|
+
// 2 bytes for each char
|
|
194
|
+
const buffer = new ArrayBuffer(string.length * 2);
|
|
195
|
+
const array = new Uint16Array(buffer);
|
|
196
|
+
for (let i = 0, strLen = string.length; i < strLen; i++) {
|
|
197
|
+
array[i] = string.charCodeAt(i);
|
|
198
|
+
}
|
|
199
|
+
return array;
|
|
200
|
+
};
|
|
201
|
+
const contentId = stringToArray(window.atob(skdValue));
|
|
202
|
+
return FairPlayUtils.initDataTransform(initData, contentId, cert);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Verimatrix FairPlay request.
|
|
137
207
|
*
|
|
138
208
|
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
139
209
|
* @param {shaka.extern.Request} request
|
|
140
210
|
* @export
|
|
141
211
|
*/
|
|
142
|
-
static
|
|
212
|
+
static verimatrixFairPlayRequest(type, request) {
|
|
143
213
|
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
144
214
|
return;
|
|
145
215
|
}
|
|
@@ -150,6 +220,34 @@ shaka.util.FairPlayUtils = class {
|
|
|
150
220
|
request.body = shaka.util.StringUtils.toUTF8('spc=' + base64Payload);
|
|
151
221
|
}
|
|
152
222
|
|
|
223
|
+
/**
|
|
224
|
+
* EZDRM FairPlay request.
|
|
225
|
+
*
|
|
226
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
227
|
+
* @param {shaka.extern.Request} request
|
|
228
|
+
* @export
|
|
229
|
+
*/
|
|
230
|
+
static ezdrmFairPlayRequest(type, request) {
|
|
231
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
request.headers['Content-Type'] = 'application/octet-stream';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Conax FairPlay request.
|
|
239
|
+
*
|
|
240
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
241
|
+
* @param {shaka.extern.Request} request
|
|
242
|
+
* @export
|
|
243
|
+
*/
|
|
244
|
+
static conaxFairPlayRequest(type, request) {
|
|
245
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
request.headers['Content-Type'] = 'application/octet-stream';
|
|
249
|
+
}
|
|
250
|
+
|
|
153
251
|
/**
|
|
154
252
|
* Common FairPlay response transform for some DRMs providers.
|
|
155
253
|
*
|
package/lib/util/object_utils.js
CHANGED
|
@@ -22,6 +22,7 @@ shaka.util.ObjectUtils = class {
|
|
|
22
22
|
const seenObjects = new Set();
|
|
23
23
|
// This recursively clones the value |val|, using the captured variable
|
|
24
24
|
// |seenObjects| to track the objects we have already cloned.
|
|
25
|
+
/** @suppress {strictMissingProperties} */
|
|
25
26
|
const clone = (val) => {
|
|
26
27
|
switch (typeof val) {
|
|
27
28
|
case 'undefined':
|
package/lib/util/platform.js
CHANGED
|
@@ -197,7 +197,10 @@ shaka.util.Platform = class {
|
|
|
197
197
|
*/
|
|
198
198
|
static isApple() {
|
|
199
199
|
return !!navigator.vendor && navigator.vendor.includes('Apple') &&
|
|
200
|
-
!shaka.util.Platform.isTizen()
|
|
200
|
+
!shaka.util.Platform.isTizen() &&
|
|
201
|
+
!shaka.util.Platform.isEOS() &&
|
|
202
|
+
!shaka.util.Platform.isPS4() &&
|
|
203
|
+
!shaka.util.Platform.isAmazonFireTV();
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
/**
|
|
@@ -213,6 +216,23 @@ shaka.util.Platform = class {
|
|
|
213
216
|
return shaka.util.Platform.userAgentContains_('PlayStation 5');
|
|
214
217
|
}
|
|
215
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Check if the current platform is Playstation 4.
|
|
221
|
+
*/
|
|
222
|
+
static isPS4() {
|
|
223
|
+
return shaka.util.Platform.userAgentContains_('PlayStation 4');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Check if the current platform is Amazon Fire TV.
|
|
228
|
+
* https://developer.amazon.com/docs/fire-tv/identify-amazon-fire-tv-devices.html
|
|
229
|
+
*
|
|
230
|
+
* @return {boolean}
|
|
231
|
+
*/
|
|
232
|
+
static isAmazonFireTV() {
|
|
233
|
+
return shaka.util.Platform.userAgentContains_('AFT');
|
|
234
|
+
}
|
|
235
|
+
|
|
216
236
|
/**
|
|
217
237
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
218
238
|
*
|
|
@@ -260,6 +280,15 @@ shaka.util.Platform = class {
|
|
|
260
280
|
return !!shaka.util.Platform.safariVersion();
|
|
261
281
|
}
|
|
262
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Check if the current platform is an EOS set-top box.
|
|
285
|
+
*
|
|
286
|
+
* @return {boolean}
|
|
287
|
+
*/
|
|
288
|
+
static isEOS() {
|
|
289
|
+
return shaka.util.Platform.userAgentContains_('PC=EOS');
|
|
290
|
+
}
|
|
291
|
+
|
|
263
292
|
/**
|
|
264
293
|
* Guesses if the platform is a mobile one (iOS or Android).
|
|
265
294
|
*
|
|
@@ -147,7 +147,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
147
147
|
ignoreTextStreamFailures: false,
|
|
148
148
|
alwaysStreamText: false,
|
|
149
149
|
startAtSegmentBoundary: false,
|
|
150
|
-
gapDetectionThreshold: 0.
|
|
150
|
+
gapDetectionThreshold: 0.5,
|
|
151
151
|
durationBackoff: 1,
|
|
152
152
|
forceTransmuxTS: false,
|
|
153
153
|
// Offset by 5 seconds since Chromecast takes a few seconds to start
|
|
@@ -173,15 +173,6 @@ shaka.util.PlayerConfiguration = class {
|
|
|
173
173
|
maxDisabledTime: 30,
|
|
174
174
|
};
|
|
175
175
|
|
|
176
|
-
// Some browsers will stop earlier than others before a gap (e.g., Edge
|
|
177
|
-
// stops 0.5 seconds before a gap). So for some browsers we need to use a
|
|
178
|
-
// larger threshold. See: https://bit.ly/2K5xmJO
|
|
179
|
-
if (shaka.util.Platform.isLegacyEdge() ||
|
|
180
|
-
shaka.util.Platform.isTizen() ||
|
|
181
|
-
shaka.util.Platform.isChromecast()) {
|
|
182
|
-
streaming.gapDetectionThreshold = 0.5;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
176
|
// WebOS, Tizen, and Chromecast have long hardware pipelines that respond
|
|
186
177
|
// slowly to seeking. Therefore we should not seek when we detect a stall
|
|
187
178
|
// on one of these platforms. Instead, default stallSkip to 0 to force the
|
|
@@ -253,6 +244,8 @@ shaka.util.PlayerConfiguration = class {
|
|
|
253
244
|
fastHalfLife: 2,
|
|
254
245
|
slowHalfLife: 5,
|
|
255
246
|
},
|
|
247
|
+
restrictToElementSize: false,
|
|
248
|
+
ignoreDevicePixelRatio: false,
|
|
256
249
|
};
|
|
257
250
|
|
|
258
251
|
const cmcd = {
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -585,8 +585,16 @@ shaka.util.StreamUtils = class {
|
|
|
585
585
|
// VideoConfiguration
|
|
586
586
|
mediaDecodingConfig.video = {
|
|
587
587
|
contentType: fullType,
|
|
588
|
-
|
|
589
|
-
|
|
588
|
+
|
|
589
|
+
// NOTE: Some decoders strictly check the width and height fields and
|
|
590
|
+
// won't decode smaller than 64x64. So if we don't have this info (as
|
|
591
|
+
// is the case in some of our simpler tests), assume a 64x64 resolution
|
|
592
|
+
// to fill in this required field for MediaCapabilities.
|
|
593
|
+
//
|
|
594
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
595
|
+
width: video.width || 64,
|
|
596
|
+
height: video.height || 64,
|
|
597
|
+
|
|
590
598
|
bitrate: video.bandwidth || variant.bandwidth || 1,
|
|
591
599
|
// framerate must be greater than 0, otherwise the config is invalid.
|
|
592
600
|
framerate: video.frameRate || 1,
|
|
@@ -749,7 +757,19 @@ shaka.util.StreamUtils = class {
|
|
|
749
757
|
*/
|
|
750
758
|
static patchVp9(codec) {
|
|
751
759
|
if (codec == 'vp9') {
|
|
752
|
-
|
|
760
|
+
// This means profile 0, level 4.1, 8-bit color. This supports 1080p @
|
|
761
|
+
// 60Hz. See https://en.wikipedia.org/wiki/VP9#Levels
|
|
762
|
+
//
|
|
763
|
+
// If we don't have more detailed codec info, assume this profile and
|
|
764
|
+
// level because it's high enough to likely accommodate the parameters we
|
|
765
|
+
// do have, such as width and height. If an implementation is checking
|
|
766
|
+
// the profile and level very strictly, we want older VP9 content to
|
|
767
|
+
// still work to some degree. But we don't want to set a level so high
|
|
768
|
+
// that it is rejected by a hardware decoder that can't handle the
|
|
769
|
+
// maximum requirements of the level.
|
|
770
|
+
//
|
|
771
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
772
|
+
return 'vp09.00.41.08';
|
|
753
773
|
}
|
|
754
774
|
return codec;
|
|
755
775
|
}
|