shaka-player 3.3.4 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/config.yml +1 -0
- package/.github/workflows/build-and-test.yaml +0 -1
- package/.github/workflows/demo-version-index.yaml +8 -0
- package/.github/workflows/release-please.yaml +19 -3
- package/.github/workflows/selenium-lab-tests.yaml +0 -1
- package/.github/workflows/sync-labels.yaml +33 -0
- package/.github/workflows/update-issues.yaml +29 -0
- package/.github/workflows/validate-pr-title.yaml +35 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +209 -28
- package/CONTRIBUTORS +1 -0
- package/README.md +10 -7
- package/app-engine/demo-version-index/README.md +3 -3
- package/app-engine/demo-version-index/app.yaml +27 -1
- package/app-engine/demo-version-index/generate.py +164 -0
- package/app-engine/demo-version-index/main.py +4 -155
- package/app-engine/demo-version-index/requirements.txt +0 -1
- package/build/README.md +2 -2
- package/build/compiler.py +1 -1
- package/build/generateTsDefs.py +0 -2
- package/build/misspellings.txt +1 -0
- package/build/shaka-lab.yaml +0 -2
- package/build/test.py +7 -1
- package/build/types/core +0 -1
- package/build/types/polyfill +0 -3
- package/demo/common/asset.js +17 -1
- package/demo/common/assets.js +29 -0
- package/demo/common/message_ids.js +6 -3
- package/demo/config.js +10 -11
- package/demo/custom.js +39 -0
- package/demo/demo_utils.js +0 -1
- package/demo/locales/en.json +6 -3
- package/demo/locales/source.json +22 -10
- package/demo/main.js +9 -6
- package/demo/search.js +2 -1
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +71 -64
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +71 -64
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +16 -20
- package/dist/locales.js +33 -31
- package/dist/receiver.compiled.debug.js +32 -28
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +32 -28
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +78 -82
- package/dist/shaka-player.compiled.debug.d.ts +78 -82
- package/dist/shaka-player.compiled.debug.externs.js +127 -126
- package/dist/shaka-player.compiled.debug.js +471 -523
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +127 -126
- package/dist/shaka-player.compiled.js +844 -858
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +80 -82
- package/dist/shaka-player.ui.debug.d.ts +80 -82
- package/dist/shaka-player.ui.debug.externs.js +135 -126
- package/dist/shaka-player.ui.debug.js +531 -581
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +135 -126
- package/dist/shaka-player.ui.js +991 -1001
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/config.md +0 -2
- package/docs/tutorials/drm-config.md +5 -0
- package/docs/tutorials/fairplay.md +7 -22
- package/docs/tutorials/faq.md +0 -11
- package/docs/tutorials/index.json +2 -8
- package/docs/tutorials/plugins.md +1 -3
- package/docs/tutorials/upgrade.md +85 -11
- package/externs/polyfill.js +15 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/net.js +12 -0
- package/externs/shaka/offline.js +5 -1
- package/externs/shaka/player.js +39 -21
- package/externs/shaka/text.js +12 -12
- package/externs/sourcebuffer.js +15 -0
- package/karma.conf.js +4 -0
- package/lib/ads/client_side_ad.js +13 -2
- package/lib/ads/client_side_ad_manager.js +22 -4
- package/lib/cast/cast_utils.js +0 -1
- package/lib/dash/content_protection.js +85 -5
- package/lib/dash/dash_parser.js +3 -3
- package/lib/hls/hls_parser.js +391 -747
- package/lib/hls/manifest_text_parser.js +2 -3
- package/lib/media/drm_engine.js +102 -37
- package/lib/media/gap_jumping_controller.js +10 -45
- package/lib/media/media_source_engine.js +157 -31
- package/lib/media/playhead.js +2 -5
- package/lib/media/presentation_timeline.js +1 -2
- package/lib/media/segment_index.js +13 -46
- package/lib/media/segment_reference.js +47 -1
- package/lib/media/streaming_engine.js +28 -11
- package/lib/media/time_ranges_utils.js +4 -9
- package/lib/net/networking_engine.js +3 -0
- package/lib/offline/indexeddb/storage_mechanism.js +4 -2
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +100 -132
- package/lib/player.js +181 -307
- package/lib/polyfill/media_capabilities.js +12 -6
- package/lib/polyfill/mediasource.js +0 -28
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
- package/lib/text/cue.js +0 -6
- package/lib/text/lrc_text_parser.js +8 -0
- package/lib/text/mp4_ttml_parser.js +8 -0
- package/lib/text/mp4_vtt_parser.js +8 -0
- package/lib/text/sbv_text_parser.js +8 -0
- package/lib/text/simple_text_displayer.js +1 -7
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +19 -3
- package/lib/text/ttml_text_parser.js +8 -0
- package/lib/text/ui_text_displayer.js +1 -7
- package/lib/text/vtt_text_parser.js +27 -5
- package/lib/text/web_vtt_generator.js +1 -7
- package/lib/util/config_utils.js +25 -0
- package/lib/util/error.js +16 -13
- package/lib/util/fairplay_utils.js +109 -0
- package/lib/util/functional.js +0 -42
- package/lib/util/manifest_parser_utils.js +1 -1
- package/lib/util/mime_utils.js +50 -1
- package/lib/util/periods.js +5 -4
- package/lib/util/platform.js +45 -0
- package/lib/util/player_configuration.js +26 -20
- package/lib/util/pssh.js +23 -4
- package/lib/util/stream_utils.js +96 -24
- package/lib/util/uint8array_utils.js +0 -16
- package/lib/util/xml_utils.js +1 -1
- package/package.json +4 -1
- package/roadmap.md +19 -19
- package/shaka-player.uncompiled.js +0 -3
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/dash/dash_parser_content_protection_unit.js +44 -0
- package/test/dash/dash_parser_manifest_unit.js +0 -24
- package/test/dash/dash_parser_segment_template_unit.js +3 -4
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +121 -220
- package/test/hls/hls_parser_unit.js +515 -432
- package/test/hls/manifest_text_parser_unit.js +19 -0
- package/test/media/drm_engine_unit.js +86 -120
- package/test/media/media_source_engine_integration.js +26 -3
- package/test/media/media_source_engine_unit.js +7 -6
- package/test/media/playhead_unit.js +27 -191
- package/test/media/segment_index_unit.js +15 -25
- package/test/media/streaming_engine_integration.js +4 -39
- package/test/media/streaming_engine_unit.js +3 -2
- package/test/media/time_ranges_utils_unit.js +0 -5
- package/test/offline/indexeddb_storage_unit.js +1 -1
- package/test/offline/manifest_convert_unit.js +34 -4
- package/test/offline/offline_manifest_parser_unit.js +1 -0
- package/test/offline/storage_compatibility_unit.js +1 -1
- package/test/offline/storage_integration.js +5 -4
- package/test/player_external.js +7 -7
- package/test/player_integration.js +22 -10
- package/test/player_src_equals_integration.js +81 -83
- package/test/player_unit.js +124 -1
- package/test/test/boot.js +9 -0
- package/test/test/externs/filters.js +4 -0
- package/test/test/util/fake_media_source_engine.js +11 -4
- package/test/test/util/manifest_generator.js +3 -1
- package/test/test/util/manifest_parser_util.js +4 -1
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +31 -2
- package/test/test/util/streaming_engine_util.js +1 -0
- package/test/test/util/test_scheme.js +24 -1
- package/test/test/util/util.js +4 -4
- package/test/text/cue_integration.js +2 -2
- package/test/text/lrc_text_parser_unit.js +6 -7
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/mp4_vtt_parser_unit.js +6 -5
- package/test/text/sbv_text_parser_unit.js +5 -6
- package/test/text/srt_text_parser_unit.js +5 -6
- package/test/text/ssa_text_parser_unit.js +17 -29
- package/test/text/text_engine_unit.js +45 -5
- package/test/text/ttml_text_parser_unit.js +77 -77
- package/test/text/vtt_text_parser_unit.js +116 -59
- package/test/ui/ui_integration.js +0 -16
- package/test/ui/ui_unit.js +27 -0
- package/test/util/cmcd_manager_unit.js +3 -0
- package/test/util/mime_utils_unit.js +54 -0
- package/test/util/periods_unit.js +79 -0
- package/test/util/stream_utils_unit.js +23 -7
- package/ui/controls.js +65 -40
- package/ui/fullscreen_button.js +26 -6
- package/ui/less/containers.less +3 -3
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +5 -0
- package/ui/resolution_selection.js +31 -33
- package/ui/ui.js +0 -17
- package/docs/tutorials/gsoc-ideas-list.md +0 -3
- package/docs/tutorials/upgrade-v2-5.md +0 -441
- package/docs/tutorials/upgrade-v3.md +0 -38
- package/lib/polyfill/mathround.js +0 -49
- package/lib/polyfill/patchedmediakeys_apple.js +0 -744
- package/lib/polyfill/patchedmediakeys_ms.js +0 -698
- package/lib/util/mutex.js +0 -52
- package/test/util/functional_unit.js +0 -82
|
@@ -24,8 +24,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
24
24
|
* @export
|
|
25
25
|
*/
|
|
26
26
|
static install() {
|
|
27
|
-
// Since MediaCapabilities is not fully supported on Chromecast yet,
|
|
28
|
-
// should always install polyfill for Chromecast.
|
|
27
|
+
// Since MediaCapabilities is not fully supported on some Chromecast yet,
|
|
28
|
+
// we should always install polyfill for all Chromecast not Android-based.
|
|
29
29
|
// TODO: re-evaluate MediaCapabilities in the future versions of Chromecast.
|
|
30
30
|
// Since MediaCapabilities implementation is buggy in Apple browsers, we
|
|
31
31
|
// should always install polyfill for Apple browsers.
|
|
@@ -37,10 +37,16 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
37
37
|
// See: https://github.com/shaka-project/shaka-player/issues/3582
|
|
38
38
|
// TODO: re-evaluate MediaCapabilities in the future versions of PS5
|
|
39
39
|
// Browsers.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
let canUseNativeMCap = true;
|
|
41
|
+
if (shaka.util.Platform.isApple() ||
|
|
42
|
+
shaka.util.Platform.isPS5() ||
|
|
43
|
+
shaka.util.Platform.isChromecast()) {
|
|
44
|
+
canUseNativeMCap = false;
|
|
45
|
+
}
|
|
46
|
+
if (shaka.util.Platform.isAndroidCastDevice()) {
|
|
47
|
+
canUseNativeMCap = true;
|
|
48
|
+
}
|
|
49
|
+
if (canUseNativeMCap && navigator.mediaCapabilities) {
|
|
44
50
|
shaka.log.info(
|
|
45
51
|
'MediaCapabilities: Native mediaCapabilities support found.');
|
|
46
52
|
return;
|
|
@@ -38,11 +38,6 @@ shaka.polyfill.MediaSource = class {
|
|
|
38
38
|
// Chromecast cannot make accurate determinations via isTypeSupported.
|
|
39
39
|
shaka.polyfill.MediaSource.patchCastIsTypeSupported_();
|
|
40
40
|
} else if (safariVersion) {
|
|
41
|
-
// TS content is broken on Safari in general.
|
|
42
|
-
// See https://github.com/shaka-project/shaka-player/issues/743
|
|
43
|
-
// and https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
44
|
-
shaka.polyfill.MediaSource.rejectTsContent_();
|
|
45
|
-
|
|
46
41
|
// NOTE: shaka.Player.isBrowserSupported() has its own restrictions on
|
|
47
42
|
// Safari version.
|
|
48
43
|
if (safariVersion <= 12) {
|
|
@@ -127,29 +122,6 @@ shaka.polyfill.MediaSource = class {
|
|
|
127
122
|
};
|
|
128
123
|
}
|
|
129
124
|
|
|
130
|
-
/**
|
|
131
|
-
* Patch isTypeSupported() to reject TS content. Used to avoid TS-related MSE
|
|
132
|
-
* bugs on Safari.
|
|
133
|
-
*
|
|
134
|
-
* @private
|
|
135
|
-
*/
|
|
136
|
-
static rejectTsContent_() {
|
|
137
|
-
const originalIsTypeSupported = MediaSource.isTypeSupported;
|
|
138
|
-
|
|
139
|
-
MediaSource.isTypeSupported = (mimeType) => {
|
|
140
|
-
// Parse the basic MIME type from its parameters.
|
|
141
|
-
const pieces = mimeType.split(/ *; */);
|
|
142
|
-
const basicMimeType = pieces[0];
|
|
143
|
-
const container = basicMimeType.split('/')[1];
|
|
144
|
-
|
|
145
|
-
if (container.toLowerCase() == 'mp2t') {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return originalIsTypeSupported(mimeType);
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
125
|
/**
|
|
154
126
|
* Patch |MediaSource.isTypeSupported| to always reject |codec|. This is used
|
|
155
127
|
* when we know that we are on a platform that does not work well with a given
|
|
@@ -49,6 +49,8 @@ shaka.polyfill.PatchedMediaKeysNop = class {
|
|
|
49
49
|
// These are not usable, but allow Player.isBrowserSupported to pass.
|
|
50
50
|
window.MediaKeys = PatchedMediaKeysNop.MediaKeys;
|
|
51
51
|
window.MediaKeySystemAccess = PatchedMediaKeysNop.MediaKeySystemAccess;
|
|
52
|
+
|
|
53
|
+
window.shakaMediaKeysPolyfill = true;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -72,6 +72,8 @@ shaka.polyfill.PatchedMediaKeysWebkit = class {
|
|
|
72
72
|
PatchedMediaKeysWebkit.setMediaKeys;
|
|
73
73
|
window.MediaKeys = PatchedMediaKeysWebkit.MediaKeys;
|
|
74
74
|
window.MediaKeySystemAccess = PatchedMediaKeysWebkit.MediaKeySystemAccess;
|
|
75
|
+
|
|
76
|
+
window.shakaMediaKeysPolyfill = true;
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
/**
|
package/lib/text/cue.js
CHANGED
|
@@ -27,6 +27,14 @@ shaka.text.SbvTextParser = class {
|
|
|
27
27
|
goog.asserts.assert(false, 'SubViewer does not have init segments');
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @override
|
|
32
|
+
* @export
|
|
33
|
+
*/
|
|
34
|
+
setSequenceMode(sequenceMode) {
|
|
35
|
+
// Unused.
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
39
|
* @override
|
|
32
40
|
* @export
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
goog.provide('shaka.text.SimpleTextDisplayer');
|
|
13
13
|
|
|
14
14
|
goog.require('goog.asserts');
|
|
15
|
-
goog.require('shaka.Deprecate');
|
|
16
15
|
goog.require('shaka.log');
|
|
17
16
|
goog.require('shaka.text.Cue');
|
|
18
17
|
|
|
@@ -108,12 +107,7 @@ shaka.text.SimpleTextDisplayer = class {
|
|
|
108
107
|
return `${acc}</${tag}>`;
|
|
109
108
|
}, '');
|
|
110
109
|
|
|
111
|
-
if (cue.lineBreak
|
|
112
|
-
if (cue.spacer) {
|
|
113
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
114
|
-
'shaka.extern.Cue',
|
|
115
|
-
'Please use lineBreak instead of spacer.');
|
|
116
|
-
}
|
|
110
|
+
if (cue.lineBreak) {
|
|
117
111
|
// This is a vertical lineBreak, so insert a newline.
|
|
118
112
|
return '\n';
|
|
119
113
|
} else if (cue.nestedCues.length) {
|
package/lib/text/text_engine.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
goog.provide('shaka.text.TextEngine');
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
|
+
goog.require('shaka.log');
|
|
10
11
|
goog.require('shaka.text.Cue');
|
|
11
12
|
goog.require('shaka.util.BufferUtils');
|
|
12
|
-
goog.require('shaka.util.Functional');
|
|
13
13
|
goog.require('shaka.util.IDestroyable');
|
|
14
14
|
goog.require('shaka.util.MimeUtils');
|
|
15
15
|
goog.requireType('shaka.cea.ICaptionDecoder');
|
|
@@ -30,6 +30,9 @@ shaka.text.TextEngine = class {
|
|
|
30
30
|
/** @private {shaka.extern.TextDisplayer} */
|
|
31
31
|
this.displayer_ = displayer;
|
|
32
32
|
|
|
33
|
+
/** @private {boolean} */
|
|
34
|
+
this.segmentRelativeVttTiming_ = false;
|
|
35
|
+
|
|
33
36
|
/** @private {number} */
|
|
34
37
|
this.timestampOffset_ = 0;
|
|
35
38
|
|
|
@@ -128,8 +131,10 @@ shaka.text.TextEngine = class {
|
|
|
128
131
|
* called at least once before appendBuffer.
|
|
129
132
|
*
|
|
130
133
|
* @param {string} mimeType
|
|
134
|
+
* @param {boolean} sequenceMode
|
|
135
|
+
* @param {boolean} segmentRelativeVttTiming
|
|
131
136
|
*/
|
|
132
|
-
initParser(mimeType) {
|
|
137
|
+
initParser(mimeType, sequenceMode, segmentRelativeVttTiming) {
|
|
133
138
|
// No parser for CEA, which is extracted from video and side-loaded
|
|
134
139
|
// into TextEngine and TextDisplayer.
|
|
135
140
|
if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
|
|
@@ -140,7 +145,14 @@ shaka.text.TextEngine = class {
|
|
|
140
145
|
const factory = shaka.text.TextEngine.parserMap_[mimeType];
|
|
141
146
|
goog.asserts.assert(
|
|
142
147
|
factory, 'Text type negotiation should have happened already');
|
|
143
|
-
this.parser_ =
|
|
148
|
+
this.parser_ = factory();
|
|
149
|
+
if (this.parser_.setSequenceMode) {
|
|
150
|
+
this.parser_.setSequenceMode(sequenceMode);
|
|
151
|
+
} else {
|
|
152
|
+
shaka.log.alwaysWarn(
|
|
153
|
+
'Text parsers should have a "setSequenceMode" method!');
|
|
154
|
+
}
|
|
155
|
+
this.segmentRelativeVttTiming_ = segmentRelativeVttTiming;
|
|
144
156
|
}
|
|
145
157
|
|
|
146
158
|
/**
|
|
@@ -166,11 +178,15 @@ shaka.text.TextEngine = class {
|
|
|
166
178
|
return;
|
|
167
179
|
}
|
|
168
180
|
|
|
181
|
+
const vttOffset = this.segmentRelativeVttTiming_ ?
|
|
182
|
+
startTime : this.timestampOffset_;
|
|
183
|
+
|
|
169
184
|
/** @type {shaka.extern.TextParser.TimeContext} **/
|
|
170
185
|
const time = {
|
|
171
186
|
periodStart: this.timestampOffset_,
|
|
172
187
|
segmentStart: startTime,
|
|
173
188
|
segmentEnd: endTime,
|
|
189
|
+
vttOffset: vttOffset,
|
|
174
190
|
};
|
|
175
191
|
|
|
176
192
|
// Parse the buffer and add the new cues.
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
goog.provide('shaka.text.UITextDisplayer');
|
|
9
9
|
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
-
goog.require('shaka.Deprecate');
|
|
12
11
|
goog.require('shaka.text.Cue');
|
|
13
12
|
goog.require('shaka.text.CueRegion');
|
|
14
13
|
goog.require('shaka.util.Dom');
|
|
@@ -343,12 +342,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
343
342
|
createCue_(cue, parents) {
|
|
344
343
|
const isNested = parents.length > 1;
|
|
345
344
|
let type = isNested ? 'span' : 'div';
|
|
346
|
-
if (cue.lineBreak
|
|
347
|
-
if (cue.spacer) {
|
|
348
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
349
|
-
'shaka.extern.Cue',
|
|
350
|
-
'Please use lineBreak instead of spacer.');
|
|
351
|
-
}
|
|
345
|
+
if (cue.lineBreak) {
|
|
352
346
|
type = 'br';
|
|
353
347
|
}
|
|
354
348
|
|
|
@@ -22,6 +22,12 @@ goog.require('shaka.util.XmlUtils');
|
|
|
22
22
|
* @export
|
|
23
23
|
*/
|
|
24
24
|
shaka.text.VttTextParser = class {
|
|
25
|
+
/** Constructs a VTT parser. */
|
|
26
|
+
constructor() {
|
|
27
|
+
/** @private {boolean} */
|
|
28
|
+
this.sequenceMode_ = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
/**
|
|
26
32
|
* @override
|
|
27
33
|
* @export
|
|
@@ -30,6 +36,14 @@ shaka.text.VttTextParser = class {
|
|
|
30
36
|
goog.asserts.assert(false, 'VTT does not have init segments');
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @override
|
|
41
|
+
* @export
|
|
42
|
+
*/
|
|
43
|
+
setSequenceMode(sequenceMode) {
|
|
44
|
+
this.sequenceMode_ = sequenceMode;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
/**
|
|
34
48
|
* @override
|
|
35
49
|
* @export
|
|
@@ -48,11 +62,21 @@ shaka.text.VttTextParser = class {
|
|
|
48
62
|
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
49
63
|
}
|
|
50
64
|
|
|
65
|
+
// Depending on "segmentRelativeVttTiming" configuration,
|
|
66
|
+
// "vttOffset" will correspond to either "periodStart" (default)
|
|
67
|
+
// or "segmentStart", for segmented VTT where timings are relative
|
|
68
|
+
// to the beginning of each segment.
|
|
51
69
|
// NOTE: "periodStart" is the timestamp offset applied via TextEngine.
|
|
52
70
|
// It is no longer closely tied to periods, but the name stuck around.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
// NOTE: This offset and the flag choosing its meaning have no effect on
|
|
72
|
+
// HLS content, which should use X-TIMESTAMP-MAP and periodStart instead.
|
|
73
|
+
let offset = time.vttOffset;
|
|
74
|
+
|
|
75
|
+
// Only use 'X-TIMESTAMP-MAP' in sequence mode, as that is currently
|
|
76
|
+
// shorthand for HLS. Note that an offset based on the first video
|
|
77
|
+
// timestamp has already been extracted, and appears in periodStart.
|
|
78
|
+
// The relative offset from X-TIMESTAMP-MAP will be added to that for HLS.
|
|
79
|
+
if (blocks[0].includes('X-TIMESTAMP-MAP') && this.sequenceMode_) {
|
|
56
80
|
// https://bit.ly/2K92l7y
|
|
57
81
|
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
|
|
58
82
|
// the rest of the media.
|
|
@@ -87,8 +111,6 @@ shaka.text.VttTextParser = class {
|
|
|
87
111
|
mpegTime += shaka.text.VttTextParser.TS_ROLLOVER_;
|
|
88
112
|
}
|
|
89
113
|
|
|
90
|
-
// Apple-encoded HLS content uses absolute timestamps, so assume the
|
|
91
|
-
// presence of the map tag means the content uses absolute timestamps.
|
|
92
114
|
offset = time.periodStart + mpegTime / mpegTimescale - cueTime;
|
|
93
115
|
}
|
|
94
116
|
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.text.WebVttGenerator');
|
|
8
8
|
|
|
9
|
-
goog.require('shaka.Deprecate');
|
|
10
9
|
goog.require('shaka.text.Cue');
|
|
11
10
|
|
|
12
11
|
|
|
@@ -49,12 +48,7 @@ shaka.text.WebVttGenerator = class {
|
|
|
49
48
|
return `${acc}</${tag}>`;
|
|
50
49
|
}, '');
|
|
51
50
|
|
|
52
|
-
if (cue.lineBreak
|
|
53
|
-
if (cue.spacer) {
|
|
54
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
55
|
-
'shaka.text.Cue',
|
|
56
|
-
'Please use lineBreak instead of spacer.');
|
|
57
|
-
}
|
|
51
|
+
if (cue.lineBreak) {
|
|
58
52
|
// This is a vertical lineBreak, so insert a newline.
|
|
59
53
|
return '\n';
|
|
60
54
|
} else if (cue.nestedCues.length) {
|
package/lib/util/config_utils.js
CHANGED
|
@@ -127,4 +127,29 @@ shaka.util.ConfigUtils = class {
|
|
|
127
127
|
last[fieldName.substring(nameStart).replace(/\\\./g, '.')] = value;
|
|
128
128
|
return configObject;
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Reference the input parameters so the compiler doesn't remove them from
|
|
133
|
+
* the calling function. Return whatever value is specified.
|
|
134
|
+
*
|
|
135
|
+
* This allows an empty or default implementation of a config callback that
|
|
136
|
+
* still bears the complete function signature even in compiled mode.
|
|
137
|
+
*
|
|
138
|
+
* The caller should look something like this:
|
|
139
|
+
*
|
|
140
|
+
* const callback = (a, b, c, d) => {
|
|
141
|
+
* return referenceParametersAndReturn(
|
|
142
|
+
[a, b, c, d],
|
|
143
|
+
a); // Can be anything, doesn't need to be one of the parameters
|
|
144
|
+
* };
|
|
145
|
+
*
|
|
146
|
+
* @param {!Array.<?>} parameters
|
|
147
|
+
* @param {T} returnValue
|
|
148
|
+
* @return {T}
|
|
149
|
+
* @template T
|
|
150
|
+
* @noinline
|
|
151
|
+
*/
|
|
152
|
+
static referenceParametersAndReturn(parameters, returnValue) {
|
|
153
|
+
return parameters && returnValue;
|
|
154
|
+
}
|
|
130
155
|
};
|
package/lib/util/error.js
CHANGED
|
@@ -345,6 +345,13 @@ shaka.util.Error.Code = {
|
|
|
345
345
|
*/
|
|
346
346
|
'MISSING_TEXT_PLUGIN': 2014,
|
|
347
347
|
|
|
348
|
+
/**
|
|
349
|
+
* The chapters track failed to load. The browser does not provide any
|
|
350
|
+
* information in this case to identify why it failed, but there may be
|
|
351
|
+
* details in the JavaScript console.
|
|
352
|
+
*/
|
|
353
|
+
'CHAPTERS_TRACK_FAILED': 2015,
|
|
354
|
+
|
|
348
355
|
/**
|
|
349
356
|
* Some component tried to read past the end of a buffer. The segment index,
|
|
350
357
|
* init segment, or PSSH may be malformed.
|
|
@@ -581,13 +588,7 @@ shaka.util.Error.Code = {
|
|
|
581
588
|
|
|
582
589
|
// RETIRED: 'HLS_COULD_NOT_GUESS_MIME_TYPE': 4021,
|
|
583
590
|
|
|
584
|
-
|
|
585
|
-
* No Master Playlist has been provided. Master playlist provides
|
|
586
|
-
* vital information about the streams (like codecs) that is
|
|
587
|
-
* required for MediaSource. We don't support directly providing
|
|
588
|
-
* a Media Playlist.
|
|
589
|
-
*/
|
|
590
|
-
'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
|
|
591
|
+
// RETIRED: 'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
|
|
591
592
|
|
|
592
593
|
/**
|
|
593
594
|
* One of the required attributes was not provided, so the
|
|
@@ -627,12 +628,7 @@ shaka.util.Error.Code = {
|
|
|
627
628
|
|
|
628
629
|
// RETIRED: 'HLS_LIVE_CONTENT_NOT_SUPPORTED': 4029,
|
|
629
630
|
|
|
630
|
-
|
|
631
|
-
* The HLS parser was unable to parse segment start time from the media.
|
|
632
|
-
* <br> error.data[0] is the failed media playlist URI.
|
|
633
|
-
* <br> error.data[1] is the failed media segment URI (if any).
|
|
634
|
-
*/
|
|
635
|
-
'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
|
|
631
|
+
// RETIRED: 'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
|
|
636
632
|
|
|
637
633
|
// RETIRED: 'HLS_MEDIA_SEQUENCE_REQUIRED_IN_LIVE_STREAMS': 4031,
|
|
638
634
|
|
|
@@ -686,6 +682,13 @@ shaka.util.Error.Code = {
|
|
|
686
682
|
*/
|
|
687
683
|
'HLS_VARIABLE_NOT_FOUND': 4039,
|
|
688
684
|
|
|
685
|
+
/**
|
|
686
|
+
* We do not support playing encrypted mp2t with MSE
|
|
687
|
+
*/
|
|
688
|
+
'HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED': 4040,
|
|
689
|
+
|
|
690
|
+
// RETIRED: 'HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED': 4041,
|
|
691
|
+
|
|
689
692
|
|
|
690
693
|
// RETIRED: 'INCONSISTENT_BUFFER_STATE': 5000,
|
|
691
694
|
// RETIRED: 'INVALID_SEGMENT_INDEX': 5001,
|
|
@@ -8,9 +8,11 @@ goog.provide('shaka.util.FairPlayUtils');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.Uri');
|
|
10
10
|
goog.require('goog.asserts');
|
|
11
|
+
goog.require('shaka.net.NetworkingEngine');
|
|
11
12
|
goog.require('shaka.util.BufferUtils');
|
|
12
13
|
goog.require('shaka.util.Error');
|
|
13
14
|
goog.require('shaka.util.StringUtils');
|
|
15
|
+
goog.require('shaka.util.Uint8ArrayUtils');
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -18,6 +20,29 @@ goog.require('shaka.util.StringUtils');
|
|
|
18
20
|
* @export
|
|
19
21
|
*/
|
|
20
22
|
shaka.util.FairPlayUtils = class {
|
|
23
|
+
/**
|
|
24
|
+
* Check if FairPlay is supported.
|
|
25
|
+
*
|
|
26
|
+
* @return {!Promise.<boolean>}
|
|
27
|
+
* @export
|
|
28
|
+
*/
|
|
29
|
+
static async isFairPlaySupported() {
|
|
30
|
+
const config = {
|
|
31
|
+
initDataTypes: ['cenc', 'sinf', 'skd'],
|
|
32
|
+
videoCapabilities: [
|
|
33
|
+
{
|
|
34
|
+
contentType: 'video/mp4; codecs="avc1.42E01E"',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
await navigator.requestMediaKeySystemAccess('com.apple.fps', [config]);
|
|
40
|
+
return true;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
21
46
|
/**
|
|
22
47
|
* Using the default method, extract a content ID from the init data. This is
|
|
23
48
|
* based on the FairPlay example documentation.
|
|
@@ -106,4 +131,88 @@ shaka.util.FairPlayUtils = class {
|
|
|
106
131
|
offset == rebuiltInitData.length, 'Inconsistent init data length');
|
|
107
132
|
return rebuiltInitData;
|
|
108
133
|
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* SPC FairPlay request.
|
|
137
|
+
*
|
|
138
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
139
|
+
* @param {shaka.extern.Request} request
|
|
140
|
+
* @export
|
|
141
|
+
*/
|
|
142
|
+
static spcFairPlayRequest(type, request) {
|
|
143
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const body = /** @type {!(ArrayBuffer|ArrayBufferView)} */(request.body);
|
|
147
|
+
const originalPayload = shaka.util.BufferUtils.toUint8(body);
|
|
148
|
+
const base64Payload = shaka.util.Uint8ArrayUtils.toBase64(originalPayload);
|
|
149
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
150
|
+
request.body = shaka.util.StringUtils.toUTF8('spc=' + base64Payload);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Common FairPlay response transform for some DRMs providers.
|
|
155
|
+
*
|
|
156
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
157
|
+
* @param {shaka.extern.Response} response
|
|
158
|
+
* @export
|
|
159
|
+
*/
|
|
160
|
+
static commonFairPlayResponse(type, response) {
|
|
161
|
+
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// In Apple's docs, responses can be of the form:
|
|
166
|
+
// '\n<ckc>base64encoded</ckc>\n' or 'base64encoded'
|
|
167
|
+
// We have also seen responses in JSON format from some of our partners.
|
|
168
|
+
// In all of these text-based formats, the CKC data is base64-encoded.
|
|
169
|
+
|
|
170
|
+
let responseText;
|
|
171
|
+
try {
|
|
172
|
+
// Convert it to text for further processing.
|
|
173
|
+
responseText = shaka.util.StringUtils.fromUTF8(response.data);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Assume it's not a text format of any kind and leave it alone.
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let licenseProcessing = false;
|
|
180
|
+
|
|
181
|
+
// Trim whitespace.
|
|
182
|
+
responseText = responseText.trim();
|
|
183
|
+
|
|
184
|
+
// Look for <ckc> wrapper and remove it.
|
|
185
|
+
if (responseText.substr(0, 5) === '<ckc>' &&
|
|
186
|
+
responseText.substr(-6) === '</ckc>') {
|
|
187
|
+
responseText = responseText.slice(5, -6);
|
|
188
|
+
licenseProcessing = true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Look for a JSON wrapper and remove it.
|
|
192
|
+
try {
|
|
193
|
+
const responseObject = /** @type {!Object} */(JSON.parse(responseText));
|
|
194
|
+
if (responseObject['ckc']) {
|
|
195
|
+
responseText = responseObject['ckc'];
|
|
196
|
+
licenseProcessing = true;
|
|
197
|
+
}
|
|
198
|
+
if (responseObject['CkcMessage']) {
|
|
199
|
+
responseText = responseObject['CkcMessage'];
|
|
200
|
+
licenseProcessing = true;
|
|
201
|
+
}
|
|
202
|
+
if (responseObject['License']) {
|
|
203
|
+
responseText = responseObject['License'];
|
|
204
|
+
licenseProcessing = true;
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// It wasn't JSON. Fall through with other transformations.
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (licenseProcessing) {
|
|
211
|
+
// Decode the base64-encoded data into the format the browser expects.
|
|
212
|
+
// It's not clear why FairPlay license servers don't just serve this
|
|
213
|
+
// directly.
|
|
214
|
+
response.data = shaka.util.BufferUtils.toArrayBuffer(
|
|
215
|
+
shaka.util.Uint8ArrayUtils.fromBase64(responseText));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
109
218
|
};
|
package/lib/util/functional.js
CHANGED
|
@@ -6,9 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.Functional');
|
|
8
8
|
|
|
9
|
-
goog.require('shaka.Deprecate');
|
|
10
|
-
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* @summary A set of functional utility functions.
|
|
14
11
|
*/
|
|
@@ -70,43 +67,4 @@ shaka.util.Functional = class {
|
|
|
70
67
|
static isNotNull(value) {
|
|
71
68
|
return value != null;
|
|
72
69
|
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Calls a factory function while allowing it to be a constructor for
|
|
76
|
-
* reverse-compatibility.
|
|
77
|
-
*
|
|
78
|
-
* @param {function():!T} factory
|
|
79
|
-
* @return {!T}
|
|
80
|
-
* @template T
|
|
81
|
-
*/
|
|
82
|
-
static callFactory(factory) {
|
|
83
|
-
// See https://stackoverflow.com/q/10428603/1208502
|
|
84
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
85
|
-
const obj = Object.create(factory.prototype || Object.prototype);
|
|
86
|
-
// If this is a constructor, call it with our newly created object to
|
|
87
|
-
// initialize it; if this isn't a constructor, the "this" shouldn't be used
|
|
88
|
-
// since it should be "undefined".
|
|
89
|
-
let ret;
|
|
90
|
-
try {
|
|
91
|
-
ret = factory.call(obj); // eslint-disable-line no-restricted-syntax
|
|
92
|
-
|
|
93
|
-
// If it didn't return anything, assume it is a constructor and return our
|
|
94
|
-
// "this" value instead.
|
|
95
|
-
if (!ret) {
|
|
96
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
97
|
-
'Factories requiring new',
|
|
98
|
-
'Factories should be plain functions');
|
|
99
|
-
ret = obj;
|
|
100
|
-
}
|
|
101
|
-
} catch (e) {
|
|
102
|
-
// This was an ES6 class, so it threw a TypeError because we didn't use
|
|
103
|
-
// "new". Fall back to actually using "new".
|
|
104
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
105
|
-
'Factories requiring new',
|
|
106
|
-
'Factories should be plain functions');
|
|
107
|
-
const FactoryAsClass = /** @type {function(new: T)} */(factory);
|
|
108
|
-
ret = new FactoryAsClass();
|
|
109
|
-
}
|
|
110
|
-
return ret;
|
|
111
|
-
}
|
|
112
70
|
};
|