shaka-player 3.1.3 → 3.2.2
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/AUTHORS +3 -0
- package/CHANGELOG.md +175 -3
- package/CONTRIBUTORS +3 -0
- package/README.md +4 -4
- package/build/generateExterns.js +1 -1
- package/build/types/polyfill +1 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +11 -2
- package/demo/common/message_ids.js +2 -1
- package/demo/config.js +5 -2
- package/demo/index.html +1 -1
- package/demo/locales/en.json +2 -1
- package/demo/locales/source.json +8 -4
- package/demo/main.js +2 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +15 -15
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +15 -15
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +22 -21
- package/dist/locales.js +36 -36
- package/dist/receiver.compiled.debug.js +9 -9
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +9 -9
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.d.ts +58 -10
- package/dist/shaka-player.compiled.debug.externs.js +777 -717
- package/dist/shaka-player.compiled.debug.js +639 -607
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +777 -717
- package/dist/shaka-player.compiled.js +826 -819
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +58 -10
- package/dist/shaka-player.ui.debug.d.ts +58 -10
- package/dist/shaka-player.ui.debug.externs.js +529 -469
- package/dist/shaka-player.ui.debug.js +676 -645
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +529 -469
- package/dist/shaka-player.ui.js +963 -955
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/ui.md +5 -5
- package/externs/aria.js +6 -0
- package/externs/shaka/ads.js +24 -1
- package/externs/shaka/manifest.js +6 -1
- package/externs/shaka/offline.js +5 -0
- package/externs/shaka/player.js +53 -9
- package/externs/shaka/text.js +10 -10
- package/externs/texttrack.js +3 -0
- package/karma.conf.js +1 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad_manager.js +52 -88
- package/lib/ads/server_side_ad_manager.js +26 -12
- package/lib/cast/cast_proxy.js +11 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +6 -1
- package/lib/cea/cea608_data_channel.js +56 -56
- package/lib/cea/cea608_memory.js +33 -33
- package/lib/cea/cea708_service.js +43 -43
- package/lib/cea/cea708_window.js +38 -38
- package/lib/cea/cea_decoder.js +13 -14
- package/lib/cea/cea_utils.js +23 -23
- package/lib/cea/dtvcc_packet_builder.js +7 -7
- package/lib/cea/i_caption_decoder.js +2 -3
- package/lib/cea/i_cea_parser.js +2 -2
- package/lib/cea/mp4_cea_parser.js +6 -6
- package/lib/dash/dash_parser.js +98 -2
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +159 -29
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +169 -192
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/segment_index.js +3 -1
- package/lib/media/segment_reference.js +19 -2
- package/lib/media/streaming_engine.js +8 -7
- package/lib/net/networking_engine.js +3 -1
- package/lib/offline/download_manager.js +1 -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 +3 -1
- package/lib/offline/storage.js +12 -14
- package/lib/player.js +437 -167
- package/lib/polyfill/aria.js +82 -0
- package/lib/polyfill/media_capabilities.js +7 -1
- package/lib/polyfill/mediasource.js +6 -0
- package/lib/polyfill/orientation.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +4 -4
- package/lib/polyfill/patchedmediakeys_ms.js +4 -4
- package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
- package/lib/routing/walker.js +2 -3
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +16 -4
- package/lib/text/ttml_text_parser.js +5 -0
- package/lib/text/ui_text_displayer.js +85 -37
- package/lib/text/vtt_text_parser.js +2 -2
- package/lib/text/web_vtt_generator.js +55 -12
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event.js +53 -7
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_box_parsers.js +20 -20
- package/lib/util/multi_map.js +8 -0
- package/lib/util/periods.js +4 -1
- package/lib/util/platform.js +13 -1
- package/lib/util/player_configuration.js +13 -1
- package/lib/util/stream_utils.js +153 -85
- package/lib/util/xml_utils.js +31 -12
- package/package.json +1 -1
- package/roadmap.md +24 -22
- package/shaka-player.uncompiled.js +1 -0
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +2 -1
- package/test/cea/cea608_memory_unit.js +1 -1
- package/test/cea/cea708_service_unit.js +8 -8
- package/test/cea/cea708_window_unit.js +6 -6
- package/test/cea/cea_decoder_unit.js +1 -1
- package/test/cea/dtvcc_packet_builder_unit.js +2 -2
- package/test/dash/dash_parser_manifest_unit.js +230 -2
- package/test/hls/hls_parser_unit.js +255 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +353 -450
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +9 -19
- package/test/player_integration.js +90 -0
- package/test/player_src_equals_integration.js +52 -0
- package/test/player_unit.js +11 -33
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/assets/chapters.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/fake_ad_manager.js +8 -1
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/text/ttml_text_parser_unit.js +9 -0
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/util/stream_utils_unit.js +153 -10
- package/ui/airplay_button.js +1 -1
- package/ui/audio_language_selection.js +2 -5
- package/ui/cast_button.js +6 -9
- package/ui/constants.js +0 -3
- package/ui/controls.js +4 -6
- package/ui/fast_forward_button.js +2 -3
- package/ui/fullscreen_button.js +1 -3
- package/ui/language_utils.js +1 -1
- package/ui/less/containers.less +3 -7
- package/ui/locales/ru.json +6 -6
- package/ui/localization.js +28 -51
- package/ui/loop_button.js +1 -3
- package/ui/mute_button.js +1 -3
- package/ui/overflow_menu.js +2 -3
- package/ui/pip_button.js +7 -10
- package/ui/playback_rate_selection.js +3 -6
- package/ui/presentation_time.js +1 -3
- package/ui/resolution_selection.js +4 -7
- package/ui/rewind_button.js +2 -3
- package/ui/seek_bar.js +2 -4
- package/ui/spacer.js +1 -1
- package/ui/text_selection.js +8 -11
- package/ui/ui_utils.js +1 -1
- package/ui/volume_bar.js +1 -3
package/lib/util/fake_event.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.FakeEvent');
|
|
8
8
|
|
|
9
|
+
goog.require('goog.asserts');
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @summary Create an Event work-alike object based on the provided dictionary.
|
|
@@ -16,18 +18,62 @@ goog.provide('shaka.util.FakeEvent');
|
|
|
16
18
|
*/
|
|
17
19
|
shaka.util.FakeEvent = class {
|
|
18
20
|
/**
|
|
19
|
-
* @param {
|
|
20
|
-
* @
|
|
21
|
+
* @param {!Event} event
|
|
22
|
+
* @return {!shaka.util.FakeEvent}
|
|
21
23
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
for (const key in
|
|
25
|
-
Object.defineProperty(
|
|
26
|
-
value:
|
|
24
|
+
static fromRealEvent(event) {
|
|
25
|
+
const fakeEvent = new shaka.util.FakeEvent(event.type);
|
|
26
|
+
for (const key in event) {
|
|
27
|
+
Object.defineProperty(fakeEvent, key, {
|
|
28
|
+
value: event[key],
|
|
27
29
|
writable: true,
|
|
28
30
|
enumerable: true,
|
|
29
31
|
});
|
|
30
32
|
}
|
|
33
|
+
return fakeEvent;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Allows us to tell the compiler that the dictionary "map" is actually a
|
|
38
|
+
* generic object, for backwards compatibility.
|
|
39
|
+
* @param {!Map.<string, Object>} dict
|
|
40
|
+
* @return {!Object}
|
|
41
|
+
* @suppress {invalidCasts}
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
static recastDictAsObject_(dict) {
|
|
45
|
+
goog.asserts.assert(!(dict instanceof Map), 'dict should not be a map');
|
|
46
|
+
return /** @type {!Object} */ (dict);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} type
|
|
51
|
+
* @param {Map.<string, Object>=} dict
|
|
52
|
+
*/
|
|
53
|
+
constructor(type, dict) {
|
|
54
|
+
if (dict) {
|
|
55
|
+
if (dict instanceof Map) {
|
|
56
|
+
// Take properties from dict if present.
|
|
57
|
+
for (const key of dict.keys()) {
|
|
58
|
+
Object.defineProperty(this, key, {
|
|
59
|
+
value: dict.get(key),
|
|
60
|
+
writable: true,
|
|
61
|
+
enumerable: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// For backwards compatibility with external apps that may make use of
|
|
66
|
+
// this public constructor, this should still accept generic objects.
|
|
67
|
+
const obj = shaka.util.FakeEvent.recastDictAsObject_(dict);
|
|
68
|
+
for (const key in obj) {
|
|
69
|
+
Object.defineProperty(this, key, {
|
|
70
|
+
value: obj[key],
|
|
71
|
+
writable: true,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
31
77
|
|
|
32
78
|
// The properties below cannot be set by the dict. They are all provided
|
|
33
79
|
// for compatibility with native events.
|
|
@@ -14,7 +14,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
14
14
|
/**
|
|
15
15
|
* Parses a TFHD Box.
|
|
16
16
|
* @param {!shaka.util.DataViewReader} reader
|
|
17
|
-
* @param {
|
|
17
|
+
* @param {number} flags
|
|
18
18
|
* @return {!shaka.util.ParsedTFHDBox}
|
|
19
19
|
*/
|
|
20
20
|
static parseTFHD(reader, flags) {
|
|
@@ -53,7 +53,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
53
53
|
/**
|
|
54
54
|
* Parses a TFDT Box.
|
|
55
55
|
* @param {!shaka.util.DataViewReader} reader
|
|
56
|
-
* @param {
|
|
56
|
+
* @param {number} version
|
|
57
57
|
* @return {!shaka.util.ParsedTFDTBox}
|
|
58
58
|
*/
|
|
59
59
|
static parseTFDT(reader, version) {
|
|
@@ -68,7 +68,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
68
68
|
/**
|
|
69
69
|
* Parses a MDHD Box.
|
|
70
70
|
* @param {!shaka.util.DataViewReader} reader
|
|
71
|
-
* @param {
|
|
71
|
+
* @param {number} version
|
|
72
72
|
* @return {!shaka.util.ParsedMDHDBox}
|
|
73
73
|
*/
|
|
74
74
|
static parseMDHD(reader, version) {
|
|
@@ -107,8 +107,8 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
107
107
|
/**
|
|
108
108
|
* Parses a TRUN Box.
|
|
109
109
|
* @param {!shaka.util.DataViewReader} reader
|
|
110
|
-
* @param {
|
|
111
|
-
* @param {
|
|
110
|
+
* @param {number} version
|
|
111
|
+
* @param {number} flags
|
|
112
112
|
* @return {!shaka.util.ParsedTRUNBox}
|
|
113
113
|
*/
|
|
114
114
|
static parseTRUN(reader, version, flags) {
|
|
@@ -168,7 +168,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
168
168
|
/**
|
|
169
169
|
* Parses a TKHD Box.
|
|
170
170
|
* @param {!shaka.util.DataViewReader} reader
|
|
171
|
-
* @param {
|
|
171
|
+
* @param {number} version
|
|
172
172
|
* @return {!shaka.util.ParsedTKHDBox}
|
|
173
173
|
*/
|
|
174
174
|
static parseTKHD(reader, version) {
|
|
@@ -192,12 +192,12 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
192
192
|
|
|
193
193
|
/**
|
|
194
194
|
* @typedef {{
|
|
195
|
-
* trackId:
|
|
195
|
+
* trackId: number,
|
|
196
196
|
* defaultSampleDuration: ?number,
|
|
197
197
|
* defaultSampleSize: ?number
|
|
198
198
|
* }}
|
|
199
199
|
*
|
|
200
|
-
* @property {
|
|
200
|
+
* @property {number} trackId
|
|
201
201
|
* As per the spec: an integer that uniquely identifies this
|
|
202
202
|
* track over the entire life‐time of this presentation
|
|
203
203
|
* @property {?number} defaultSampleDuration
|
|
@@ -213,10 +213,10 @@ shaka.util.ParsedTFHDBox;
|
|
|
213
213
|
|
|
214
214
|
/**
|
|
215
215
|
* @typedef {{
|
|
216
|
-
* baseMediaDecodeTime:
|
|
216
|
+
* baseMediaDecodeTime: number
|
|
217
217
|
* }}
|
|
218
218
|
*
|
|
219
|
-
* @property {
|
|
219
|
+
* @property {number} baseMediaDecodeTime
|
|
220
220
|
* As per the spec: the absolute decode time, measured on the media
|
|
221
221
|
* timeline, of the first sample in decode order in the track fragment
|
|
222
222
|
*
|
|
@@ -226,10 +226,10 @@ shaka.util.ParsedTFDTBox;
|
|
|
226
226
|
|
|
227
227
|
/**
|
|
228
228
|
* @typedef {{
|
|
229
|
-
* timescale:
|
|
229
|
+
* timescale: number
|
|
230
230
|
* }}
|
|
231
231
|
*
|
|
232
|
-
* @property {
|
|
232
|
+
* @property {number} timescale
|
|
233
233
|
* As per the spec: an integer that specifies the time‐scale for this media;
|
|
234
234
|
* this is the number of time units that pass in one second
|
|
235
235
|
*
|
|
@@ -239,13 +239,13 @@ shaka.util.ParsedMDHDBox;
|
|
|
239
239
|
|
|
240
240
|
/**
|
|
241
241
|
* @typedef {{
|
|
242
|
-
* defaultSampleDuration:
|
|
243
|
-
* defaultSampleSize:
|
|
242
|
+
* defaultSampleDuration: number,
|
|
243
|
+
* defaultSampleSize: number
|
|
244
244
|
* }}
|
|
245
245
|
*
|
|
246
|
-
* @property {
|
|
246
|
+
* @property {number} defaultSampleDuration
|
|
247
247
|
* The default sample duration to be used in track fragments
|
|
248
|
-
* @property {
|
|
248
|
+
* @property {number} defaultSampleSize
|
|
249
249
|
* The default sample size to be used in track fragments
|
|
250
250
|
*
|
|
251
251
|
* @exportDoc
|
|
@@ -254,11 +254,11 @@ shaka.util.ParsedTREXBox;
|
|
|
254
254
|
|
|
255
255
|
/**
|
|
256
256
|
* @typedef {{
|
|
257
|
-
* sampleCount:
|
|
257
|
+
* sampleCount: number,
|
|
258
258
|
* sampleData: !Array.<shaka.util.ParsedTRUNSample>
|
|
259
259
|
* }}
|
|
260
260
|
*
|
|
261
|
-
* @property {
|
|
261
|
+
* @property {number} sampleCount
|
|
262
262
|
* As per the spec: the number of samples being added in this run;
|
|
263
263
|
* @property {!Array.<shaka.util.ParsedTRUNSample>} sampleData
|
|
264
264
|
* An array of size <sampleCount> containing data for each sample
|
|
@@ -290,10 +290,10 @@ shaka.util.ParsedTRUNSample;
|
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
292
|
* @typedef {{
|
|
293
|
-
* trackId:
|
|
293
|
+
* trackId: number
|
|
294
294
|
* }}
|
|
295
295
|
*
|
|
296
|
-
* @property {
|
|
296
|
+
* @property {number} trackId
|
|
297
297
|
* Unique ID indicative of this track
|
|
298
298
|
*
|
|
299
299
|
* @exportDoc
|
package/lib/util/multi_map.js
CHANGED
package/lib/util/periods.js
CHANGED
|
@@ -80,7 +80,10 @@ shaka.util.PeriodCombiner = class {
|
|
|
80
80
|
|
|
81
81
|
/** @return {!Array.<shaka.extern.Stream>} */
|
|
82
82
|
getTextStreams() {
|
|
83
|
-
|
|
83
|
+
// Return a copy of the array because makeTextStreamsForClosedCaptions
|
|
84
|
+
// may make changes to the contents of the array. Those changes should not
|
|
85
|
+
// propagate back to the PeriodCombiner.
|
|
86
|
+
return this.textStreams_.slice();
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
/** @return {!Array.<shaka.extern.Stream>} */
|
package/lib/util/platform.js
CHANGED
|
@@ -163,7 +163,6 @@ shaka.util.Platform = class {
|
|
|
163
163
|
!shaka.util.Platform.isEdge();
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
167
166
|
/**
|
|
168
167
|
* Check if the current platform is from Apple.
|
|
169
168
|
*
|
|
@@ -179,6 +178,19 @@ shaka.util.Platform = class {
|
|
|
179
178
|
&& !shaka.util.Platform.isTizen();
|
|
180
179
|
}
|
|
181
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Check if the current platform is Playstation 5.
|
|
183
|
+
*
|
|
184
|
+
* Returns true on Playstation 5 browsers.
|
|
185
|
+
*
|
|
186
|
+
* Returns false for Playstation 5 browsers
|
|
187
|
+
*
|
|
188
|
+
* @return {boolean}
|
|
189
|
+
*/
|
|
190
|
+
static isPS5() {
|
|
191
|
+
return shaka.util.Platform.userAgentContains_('PlayStation 5');
|
|
192
|
+
}
|
|
193
|
+
|
|
182
194
|
/**
|
|
183
195
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
184
196
|
*
|
|
@@ -75,6 +75,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
75
75
|
initDataTransform: shaka.media.DrmEngine.defaultInitDataTransform,
|
|
76
76
|
logLicenseExchange: false,
|
|
77
77
|
updateExpirationTime: 1,
|
|
78
|
+
preferredKeySystems: [],
|
|
78
79
|
};
|
|
79
80
|
|
|
80
81
|
const manifest = {
|
|
@@ -108,9 +109,16 @@ shaka.util.PlayerConfiguration = class {
|
|
|
108
109
|
'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb':
|
|
109
110
|
'com.adobe.primetime',
|
|
110
111
|
},
|
|
112
|
+
// Need some operation in the callback or else closure may remove calls
|
|
113
|
+
// to the function as it would be a no-op. The operation can't just be
|
|
114
|
+
// a log message, because those are stripped in the compiled build.
|
|
115
|
+
manifestPreprocessor: (element) => {
|
|
116
|
+
return element;
|
|
117
|
+
},
|
|
111
118
|
},
|
|
112
119
|
hls: {
|
|
113
120
|
ignoreTextStreamFailures: false,
|
|
121
|
+
ignoreImageStreamFailures: false,
|
|
114
122
|
useFullSegmentsForStartTime: false,
|
|
115
123
|
},
|
|
116
124
|
};
|
|
@@ -154,6 +162,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
154
162
|
autoLowLatencyMode: false,
|
|
155
163
|
forceHTTPS: false,
|
|
156
164
|
preferNativeHls: false,
|
|
165
|
+
updateIntervalSeconds: 1,
|
|
157
166
|
};
|
|
158
167
|
|
|
159
168
|
// Some browsers will stop earlier than others before a gap (e.g., Edge
|
|
@@ -241,7 +250,10 @@ shaka.util.PlayerConfiguration = class {
|
|
|
241
250
|
preferredVariantRole: '',
|
|
242
251
|
preferredTextRole: '',
|
|
243
252
|
preferredAudioChannelCount: 2,
|
|
253
|
+
preferredVideoCodecs: [],
|
|
254
|
+
preferredAudioCodecs: [],
|
|
244
255
|
preferForcedSubs: false,
|
|
256
|
+
preferredDecodingAttributes: [],
|
|
245
257
|
restrictions: {
|
|
246
258
|
minWidth: 0,
|
|
247
259
|
maxWidth: Infinity,
|
|
@@ -256,7 +268,6 @@ shaka.util.PlayerConfiguration = class {
|
|
|
256
268
|
},
|
|
257
269
|
playRangeStart: 0,
|
|
258
270
|
playRangeEnd: Infinity,
|
|
259
|
-
useMediaCapabilities: false,
|
|
260
271
|
textDisplayFactory: () => null,
|
|
261
272
|
};
|
|
262
273
|
|
|
@@ -293,6 +304,7 @@ shaka.util.PlayerConfiguration = class {
|
|
|
293
304
|
audioRobustness: '',
|
|
294
305
|
sessionType: '',
|
|
295
306
|
serverCertificate: new Uint8Array(0),
|
|
307
|
+
serverCertificateUri: '',
|
|
296
308
|
individualizationServer: '',
|
|
297
309
|
},
|
|
298
310
|
};
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -8,7 +8,6 @@ goog.provide('shaka.util.StreamUtils');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
-
goog.require('shaka.media.MediaSourceEngine');
|
|
12
11
|
goog.require('shaka.text.TextEngine');
|
|
13
12
|
goog.require('shaka.util.Functional');
|
|
14
13
|
goog.require('shaka.util.LanguageUtils');
|
|
@@ -28,30 +27,43 @@ shaka.util.StreamUtils = class {
|
|
|
28
27
|
* bandwidth and filter out the rest.
|
|
29
28
|
* Also filters out variants that have too many audio channels.
|
|
30
29
|
* @param {!shaka.extern.Manifest} manifest
|
|
30
|
+
* @param {!Array.<string>} preferredVideoCodecs
|
|
31
|
+
* @param {!Array.<string>} preferredAudioCodecs
|
|
31
32
|
* @param {number} preferredAudioChannelCount
|
|
33
|
+
* @param {!Array.<string>} preferredDecodingAttributes
|
|
32
34
|
*/
|
|
33
|
-
static chooseCodecsAndFilterManifest(manifest,
|
|
35
|
+
static chooseCodecsAndFilterManifest(manifest, preferredVideoCodecs,
|
|
36
|
+
preferredAudioCodecs, preferredAudioChannelCount,
|
|
37
|
+
preferredDecodingAttributes) {
|
|
34
38
|
const StreamUtils = shaka.util.StreamUtils;
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
let variants = manifest.variants;
|
|
41
|
+
// To start, choose the codecs based on configured preferences if available.
|
|
42
|
+
if (preferredVideoCodecs.length || preferredAudioCodecs.length) {
|
|
43
|
+
variants = StreamUtils.choosePreferredCodecs(variants,
|
|
44
|
+
preferredVideoCodecs, preferredAudioCodecs);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Consider a subset of variants based on audio channel
|
|
37
48
|
// preferences.
|
|
38
49
|
// For some content (#1013), surround-sound variants will use a different
|
|
39
50
|
// codec than stereo variants, so it is important to choose codecs **after**
|
|
40
51
|
// considering the audio channel config.
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
variants = StreamUtils.filterVariantsByAudioChannelCount(
|
|
53
|
+
variants, preferredAudioChannelCount);
|
|
43
54
|
|
|
44
55
|
// Now organize variants into buckets by codecs.
|
|
45
56
|
/** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
|
|
46
57
|
let variantsByCodecs = StreamUtils.getVariantsByCodecs_(variants);
|
|
47
58
|
variantsByCodecs = StreamUtils.filterVariantsByDensity_(variantsByCodecs);
|
|
48
59
|
|
|
49
|
-
const bestCodecs = StreamUtils.
|
|
60
|
+
const bestCodecs = StreamUtils.chooseCodecsByDecodingAttributes_(
|
|
61
|
+
variantsByCodecs, preferredDecodingAttributes);
|
|
50
62
|
|
|
51
63
|
// Filter out any variants that don't match, forcing AbrManager to choose
|
|
52
|
-
// from
|
|
64
|
+
// from a single video codec and a single audio codec possible.
|
|
53
65
|
manifest.variants = manifest.variants.filter((variant) => {
|
|
54
|
-
const codecs = StreamUtils.
|
|
66
|
+
const codecs = StreamUtils.getVariantCodecs_(variant);
|
|
55
67
|
if (codecs == bestCodecs) {
|
|
56
68
|
return true;
|
|
57
69
|
}
|
|
@@ -71,8 +83,8 @@ shaka.util.StreamUtils = class {
|
|
|
71
83
|
static getVariantsByCodecs_(variants) {
|
|
72
84
|
const variantsByCodecs = new shaka.util.MultiMap();
|
|
73
85
|
for (const variant of variants) {
|
|
74
|
-
const
|
|
75
|
-
variantsByCodecs.push(
|
|
86
|
+
const variantCodecs = shaka.util.StreamUtils.getVariantCodecs_(variant);
|
|
87
|
+
variantsByCodecs.push(variantCodecs, variant);
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
return variantsByCodecs;
|
|
@@ -80,6 +92,8 @@ shaka.util.StreamUtils = class {
|
|
|
80
92
|
|
|
81
93
|
/**
|
|
82
94
|
* Filters variants by density.
|
|
95
|
+
* Get variants by codecs map with the max density where all codecs are
|
|
96
|
+
* present.
|
|
83
97
|
*
|
|
84
98
|
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
85
99
|
* @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
|
|
@@ -120,6 +134,107 @@ shaka.util.StreamUtils = class {
|
|
|
120
134
|
return maxDensity ? codecGroupsByDensity.get(maxDensity) : variantsByCodecs;
|
|
121
135
|
}
|
|
122
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Choose the codecs by configured preferred audio and video codecs.
|
|
139
|
+
*
|
|
140
|
+
* @param {!Array<shaka.extern.Variant>} variants
|
|
141
|
+
* @param {!Array.<string>} preferredVideoCodecs
|
|
142
|
+
* @param {!Array.<string>} preferredAudioCodecs
|
|
143
|
+
* @return {!Array<shaka.extern.Variant>}
|
|
144
|
+
*/
|
|
145
|
+
static choosePreferredCodecs(variants, preferredVideoCodecs,
|
|
146
|
+
preferredAudioCodecs) {
|
|
147
|
+
let subset = variants;
|
|
148
|
+
for (const videoCodec of preferredVideoCodecs) {
|
|
149
|
+
const filtered = subset.filter((variant) => {
|
|
150
|
+
return variant.video && variant.video.codecs.startsWith(videoCodec);
|
|
151
|
+
});
|
|
152
|
+
if (filtered.length) {
|
|
153
|
+
subset = filtered;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (const audioCodec of preferredAudioCodecs) {
|
|
159
|
+
const filtered = subset.filter((variant) => {
|
|
160
|
+
return variant.audio && variant.audio.codecs.startsWith(audioCodec);
|
|
161
|
+
});
|
|
162
|
+
if (filtered.length) {
|
|
163
|
+
subset = filtered;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return subset;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Choose the codecs by configured preferred decoding attributes.
|
|
172
|
+
*
|
|
173
|
+
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
174
|
+
* @param {!Array.<string>} attributes
|
|
175
|
+
* @return {string}
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
static chooseCodecsByDecodingAttributes_(variantsByCodecs, attributes) {
|
|
179
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
180
|
+
|
|
181
|
+
for (const attribute of attributes) {
|
|
182
|
+
if (attribute == StreamUtils.DecodingAttributes.SMOOTH ||
|
|
183
|
+
attribute == StreamUtils.DecodingAttributes.POWER) {
|
|
184
|
+
variantsByCodecs = StreamUtils.chooseCodecsByMediaCapabilitiesInfo_(
|
|
185
|
+
variantsByCodecs, attribute);
|
|
186
|
+
// If we only have one smooth or powerEfficient codecs, choose it as the
|
|
187
|
+
// best codecs.
|
|
188
|
+
if (variantsByCodecs.size() == 1) {
|
|
189
|
+
return variantsByCodecs.keys()[0];
|
|
190
|
+
}
|
|
191
|
+
} else if (attribute == StreamUtils.DecodingAttributes.BANDWIDTH) {
|
|
192
|
+
return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// If there's no configured decoding preferences, or we have multiple codecs
|
|
196
|
+
// that meets the configured decoding preferences, choose the one with
|
|
197
|
+
// the lowest bandwidth.
|
|
198
|
+
return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Choose the best codecs by configured preferred MediaCapabilitiesInfo
|
|
203
|
+
* attributes.
|
|
204
|
+
*
|
|
205
|
+
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
206
|
+
* @param {string} attribute
|
|
207
|
+
* @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
|
|
208
|
+
* @private
|
|
209
|
+
*/
|
|
210
|
+
static chooseCodecsByMediaCapabilitiesInfo_(variantsByCodecs, attribute) {
|
|
211
|
+
let highestScore = 0;
|
|
212
|
+
const bestVariantsByCodecs = new shaka.util.MultiMap();
|
|
213
|
+
variantsByCodecs.forEach((codecs, variants) => {
|
|
214
|
+
let sum = 0;
|
|
215
|
+
let num = 0;
|
|
216
|
+
|
|
217
|
+
for (const variant of variants) {
|
|
218
|
+
if (variant.decodingInfos.length) {
|
|
219
|
+
sum += variant.decodingInfos[0][attribute] ? 1 : 0;
|
|
220
|
+
num++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const averageScore = sum / num;
|
|
225
|
+
shaka.log.debug('codecs', codecs, 'avg', attribute, averageScore);
|
|
226
|
+
|
|
227
|
+
if (averageScore > highestScore) {
|
|
228
|
+
bestVariantsByCodecs.clear();
|
|
229
|
+
bestVariantsByCodecs.push(codecs, variants);
|
|
230
|
+
highestScore = averageScore;
|
|
231
|
+
} else if (averageScore == highestScore) {
|
|
232
|
+
bestVariantsByCodecs.push(codecs, variants);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
return bestVariantsByCodecs;
|
|
236
|
+
}
|
|
237
|
+
|
|
123
238
|
/**
|
|
124
239
|
* Find the lowest-bandwidth (best) codecs.
|
|
125
240
|
* Compute the average bandwidth for each group of variants.
|
|
@@ -128,7 +243,7 @@ shaka.util.StreamUtils = class {
|
|
|
128
243
|
* @return {string}
|
|
129
244
|
* @private
|
|
130
245
|
*/
|
|
131
|
-
static
|
|
246
|
+
static findCodecsByLowestBandwidth_(variantsByCodecs) {
|
|
132
247
|
let bestCodecs = '';
|
|
133
248
|
let lowestAverageBandwidth = Infinity;
|
|
134
249
|
|
|
@@ -163,7 +278,7 @@ shaka.util.StreamUtils = class {
|
|
|
163
278
|
* @return {string}
|
|
164
279
|
* @private
|
|
165
280
|
*/
|
|
166
|
-
static
|
|
281
|
+
static getVariantCodecs_(variant) {
|
|
167
282
|
// Only consider the base of the codec string. For example, these should
|
|
168
283
|
// both be considered the same codec: avc1.42c01e, avc1.4d401f
|
|
169
284
|
let baseVideoCodec = '';
|
|
@@ -183,7 +298,7 @@ shaka.util.StreamUtils = class {
|
|
|
183
298
|
* Filter the variants in |manifest| to only include the variants that meet
|
|
184
299
|
* the given restrictions.
|
|
185
300
|
*
|
|
186
|
-
* @param {shaka.extern.Manifest} manifest
|
|
301
|
+
* @param {!shaka.extern.Manifest} manifest
|
|
187
302
|
* @param {shaka.extern.Restrictions} restrictions
|
|
188
303
|
* @param {{width: number, height:number}} maxHwResolution
|
|
189
304
|
*/
|
|
@@ -283,17 +398,11 @@ shaka.util.StreamUtils = class {
|
|
|
283
398
|
* @param {shaka.media.DrmEngine} drmEngine
|
|
284
399
|
* @param {?shaka.extern.Variant} currentVariant
|
|
285
400
|
* @param {shaka.extern.Manifest} manifest
|
|
286
|
-
* @param {boolean=} useMediaCapabilities
|
|
287
401
|
*/
|
|
288
402
|
static async filterManifest(
|
|
289
|
-
drmEngine, currentVariant, manifest
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
manifest.offlineSessionIds.length > 0);
|
|
293
|
-
} else {
|
|
294
|
-
shaka.util.StreamUtils.filterManifestByDrm(manifest, drmEngine);
|
|
295
|
-
shaka.util.StreamUtils.filterManifestByMediaSource(manifest);
|
|
296
|
-
}
|
|
403
|
+
drmEngine, currentVariant, manifest) {
|
|
404
|
+
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest,
|
|
405
|
+
manifest.offlineSessionIds.length > 0);
|
|
297
406
|
shaka.util.StreamUtils.filterManifestByCurrentVariant(
|
|
298
407
|
currentVariant, manifest);
|
|
299
408
|
shaka.util.StreamUtils.filterTextStreams_(manifest);
|
|
@@ -301,29 +410,6 @@ shaka.util.StreamUtils = class {
|
|
|
301
410
|
}
|
|
302
411
|
|
|
303
412
|
|
|
304
|
-
/**
|
|
305
|
-
* Filter the variants in |manifest| to only include those that are supported
|
|
306
|
-
* by |drm|.
|
|
307
|
-
* @param {shaka.extern.Manifest} manifest
|
|
308
|
-
* @param {shaka.media.DrmEngine} drmEngine
|
|
309
|
-
*/
|
|
310
|
-
static filterManifestByDrm(manifest, drmEngine) {
|
|
311
|
-
manifest.variants = manifest.variants.filter((variant) => {
|
|
312
|
-
if (drmEngine && drmEngine.initialized()) {
|
|
313
|
-
if (!drmEngine.supportsVariant(variant)) {
|
|
314
|
-
shaka.log.debug('Dropping variant - not compatible with key system',
|
|
315
|
-
variant);
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
shaka.log.debug('DrmEngine is not initialized yet.');
|
|
322
|
-
return true;
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
|
|
327
413
|
/**
|
|
328
414
|
* Alters the given Manifest to filter out any streams unsupported by the
|
|
329
415
|
* platform via MediaCapabilities.decodingInfo() API.
|
|
@@ -363,46 +449,6 @@ shaka.util.StreamUtils = class {
|
|
|
363
449
|
}
|
|
364
450
|
|
|
365
451
|
|
|
366
|
-
/**
|
|
367
|
-
* Filter the variants in the |manifest| to only include those that are
|
|
368
|
-
* supported by media source.
|
|
369
|
-
* TODO: remove once MediaCap implementations are done.
|
|
370
|
-
* @param {shaka.extern.Manifest} manifest
|
|
371
|
-
*/
|
|
372
|
-
static filterManifestByMediaSource(manifest) {
|
|
373
|
-
const StreamUtils = shaka.util.StreamUtils;
|
|
374
|
-
|
|
375
|
-
manifest.variants = manifest.variants.filter((variant) => {
|
|
376
|
-
const audio = variant.audio;
|
|
377
|
-
const video = variant.video;
|
|
378
|
-
|
|
379
|
-
if (audio && !shaka.media.MediaSourceEngine.isStreamSupported(audio)) {
|
|
380
|
-
shaka.log.debug('Dropping variant - audio not compatible with platform',
|
|
381
|
-
StreamUtils.getStreamSummaryString_(audio));
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (video && !shaka.media.MediaSourceEngine.isStreamSupported(video)) {
|
|
386
|
-
shaka.log.debug('Dropping variant - video not compatible with platform',
|
|
387
|
-
StreamUtils.getStreamSummaryString_(video));
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// See: https://github.com/google/shaka-player/issues/3380
|
|
392
|
-
if (shaka.util.Platform.isXboxOne() && video &&
|
|
393
|
-
((video.width && video.width > 1920) ||
|
|
394
|
-
(video.height && video.height > 1080)) &&
|
|
395
|
-
video.codecs.includes('avc1.')) {
|
|
396
|
-
shaka.log.debug('Dropping variant - video not compatible with platform',
|
|
397
|
-
StreamUtils.getStreamSummaryString_(video));
|
|
398
|
-
return false;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return true;
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
452
|
/**
|
|
407
453
|
* Get the decodingInfo results of the variants via MediaCapabilities.
|
|
408
454
|
* This should be called after the DrmEngine is created and configured, and
|
|
@@ -501,6 +547,19 @@ shaka.util.StreamUtils = class {
|
|
|
501
547
|
// framerate must be greater than 0, otherwise the config is invalid.
|
|
502
548
|
framerate: video.frameRate || 1,
|
|
503
549
|
};
|
|
550
|
+
if (video.hdr) {
|
|
551
|
+
switch (video.hdr) {
|
|
552
|
+
case 'SDR':
|
|
553
|
+
mediaDecodingConfig.video.transferFunction = 'srgb';
|
|
554
|
+
break;
|
|
555
|
+
case 'PQ':
|
|
556
|
+
mediaDecodingConfig.video.transferFunction = 'pq';
|
|
557
|
+
break;
|
|
558
|
+
case 'HLG':
|
|
559
|
+
mediaDecodingConfig.video.transferFunction = 'hlg';
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
504
563
|
}
|
|
505
564
|
if (audio) {
|
|
506
565
|
// Some Tizen devices seem to misreport AC-3 support, but correctly
|
|
@@ -1358,3 +1417,12 @@ shaka.util.StreamUtils = class {
|
|
|
1358
1417
|
|
|
1359
1418
|
/** @private {number} */
|
|
1360
1419
|
shaka.util.StreamUtils.nextTrackId_ = 0;
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* @enum {string}
|
|
1423
|
+
*/
|
|
1424
|
+
shaka.util.StreamUtils.DecodingAttributes = {
|
|
1425
|
+
SMOOTH: 'smooth',
|
|
1426
|
+
POWER: 'powerEfficient',
|
|
1427
|
+
BANDWIDTH: 'bandwidth',
|
|
1428
|
+
};
|