shaka-player 4.7.13 → 4.8.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/AUTHORS +2 -0
- package/CONTRIBUTORS +2 -0
- package/LICENSE +54 -0
- package/README.md +22 -1
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +34 -23
- package/dist/locales.js +41 -31
- package/dist/shaka-player.compiled.d.ts +196 -45
- package/dist/shaka-player.compiled.debug.d.ts +196 -45
- package/dist/shaka-player.compiled.debug.externs.js +491 -348
- package/dist/shaka-player.compiled.debug.js +969 -847
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +491 -348
- package/dist/shaka-player.compiled.js +1238 -1171
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +259 -48
- package/dist/shaka-player.ui.debug.d.ts +259 -48
- package/dist/shaka-player.ui.debug.externs.js +598 -377
- package/dist/shaka-player.ui.debug.js +1185 -980
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +598 -377
- package/dist/shaka-player.ui.js +1526 -1408
- package/dist/shaka-player.ui.map +4 -4
- package/externs/device_sensor_event.js +18 -0
- package/externs/hisense.js +16 -0
- package/externs/playstation.js +31 -0
- package/externs/shaka/abr_manager.js +3 -1
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/codecs.js +13 -0
- package/externs/shaka/manifest.js +58 -6
- package/externs/shaka/net.js +13 -1
- package/externs/shaka/player.js +184 -13
- package/externs/shaka/text.js +19 -0
- package/externs/tizen.js +41 -0
- package/externs/webos.js +19 -0
- package/externs/xbox.js +43 -0
- package/lib/abr/simple_abr_manager.js +9 -1
- package/lib/ads/ad_manager.js +19 -2
- package/lib/ads/client_side_ad_manager.js +5 -3
- package/lib/ads/media_tailor_ad_manager.js +9 -0
- package/lib/cast/cast_receiver.js +0 -14
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/mp4_cea_parser.js +6 -1
- package/lib/dash/content_protection.js +97 -53
- package/lib/dash/dash_parser.js +237 -177
- package/lib/dash/mpd_utils.js +72 -65
- package/lib/dash/segment_base.js +27 -21
- package/lib/dash/segment_list.js +18 -16
- package/lib/dash/segment_template.js +45 -22
- package/lib/hls/hls_parser.js +358 -164
- package/lib/media/buffering_observer.js +25 -1
- package/lib/media/drm_engine.js +91 -71
- package/lib/media/manifest_filterer.js +220 -0
- package/lib/media/media_source_engine.js +34 -5
- package/lib/media/preload_manager.js +827 -0
- package/lib/media/presentation_timeline.js +11 -0
- package/lib/media/segment_index.js +93 -47
- package/lib/media/segment_prefetch.js +140 -43
- package/lib/media/segment_reference.js +43 -8
- package/lib/media/segment_utils.js +208 -25
- package/lib/media/streaming_engine.js +355 -66
- package/lib/mss/content_protection.js +31 -25
- package/lib/mss/mss_parser.js +79 -55
- package/lib/net/networking_engine.js +49 -4
- package/lib/offline/storage.js +3 -3
- package/lib/player.js +882 -672
- package/lib/polyfill/media_capabilities.js +16 -1
- package/lib/text/simple_text_displayer.js +9 -0
- package/lib/text/stub_text_displayer.js +7 -0
- package/lib/text/text_engine.js +16 -3
- package/lib/text/ttml_text_parser.js +116 -114
- package/lib/text/ui_text_displayer.js +28 -11
- package/lib/text/vtt_text_parser.js +54 -115
- package/lib/transmuxer/opus.js +91 -0
- package/lib/transmuxer/ts_transmuxer.js +115 -0
- package/lib/util/cmcd_manager.js +153 -3
- package/lib/util/dom_utils.js +11 -0
- package/lib/util/error.js +5 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/manifest_parser_utils.js +97 -3
- package/lib/util/mp4_box_parsers.js +346 -17
- package/lib/util/mp4_generator.js +23 -0
- package/lib/util/periods.js +19 -0
- package/lib/util/platform.js +161 -9
- package/lib/util/player_configuration.js +79 -13
- package/lib/util/stats.js +16 -0
- package/lib/util/stream_utils.js +22 -8
- package/lib/util/string_utils.js +36 -0
- package/lib/util/tXml.js +814 -0
- package/lib/util/ts_parser.js +50 -0
- package/lib/util/xml_utils.js +10 -338
- package/package.json +2 -2
- package/shaka-player.uncompiled.js +8 -0
- package/ui/controls.js +187 -5
- package/ui/enums.js +2 -0
- package/ui/externs/ui.js +30 -3
- package/ui/gl_matrix/matrix_4x4.js +568 -0
- package/ui/gl_matrix/matrix_quaternion.js +45 -0
- package/ui/less/containers.less +11 -0
- package/ui/locales/en-GB.json +2 -0
- package/ui/locales/en.json +2 -0
- package/ui/locales/es-419.json +2 -0
- package/ui/locales/es.json +2 -0
- package/ui/locales/source.json +8 -0
- package/ui/recenter_vr.js +126 -0
- package/ui/resolution_selection.js +25 -5
- package/ui/statistics_button.js +12 -0
- package/ui/text_selection.js +1 -1
- package/ui/toggle_stereoscopic.js +127 -0
- package/ui/ui.js +74 -38
- package/ui/vr_manager.js +557 -0
- package/ui/vr_utils.js +232 -0
- package/ui/vr_webgl.js +697 -0
package/lib/util/dom_utils.js
CHANGED
|
@@ -53,6 +53,17 @@ shaka.util.Dom = class {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Cast a Node/Element to an HTMLCanvasElement
|
|
58
|
+
*
|
|
59
|
+
* @param {!Node|!Element} original
|
|
60
|
+
* @return {!HTMLCanvasElement}
|
|
61
|
+
*/
|
|
62
|
+
static asHTMLCanvasElement(original) {
|
|
63
|
+
return /** @type {!HTMLCanvasElement}*/ (original);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
56
67
|
/**
|
|
57
68
|
* Cast a Node/Element to an HTMLMediaElement
|
|
58
69
|
*
|
package/lib/util/error.js
CHANGED
|
@@ -946,6 +946,11 @@ shaka.util.Error.Code = {
|
|
|
946
946
|
*/
|
|
947
947
|
'CONTENT_NOT_LOADED': 7004,
|
|
948
948
|
|
|
949
|
+
/**
|
|
950
|
+
* The call to preload failed, due to being called on src= content.
|
|
951
|
+
*/
|
|
952
|
+
'SRC_EQUALS_PRELOAD_NOT_SUPPORTED': 7005,
|
|
953
|
+
|
|
949
954
|
/**
|
|
950
955
|
* The Cast API is unavailable. This may be because of one of the following:
|
|
951
956
|
* 1. The browser may not have Cast support
|
package/lib/util/fake_event.js
CHANGED
|
@@ -174,10 +174,12 @@ shaka.util.FakeEvent.EventName = {
|
|
|
174
174
|
MediaQualityChanged: 'mediaqualitychanged',
|
|
175
175
|
Metadata: 'metadata',
|
|
176
176
|
Midpoint: 'midpoint',
|
|
177
|
+
NoSpatialVideoInfoEvent: 'nospatialvideoinfo',
|
|
177
178
|
OnStateChange: 'onstatechange',
|
|
178
179
|
RateChange: 'ratechange',
|
|
179
180
|
SegmentAppended: 'segmentappended',
|
|
180
181
|
SessionDataEvent: 'sessiondata',
|
|
182
|
+
SpatialVideoInfoEvent: 'spatialvideoinfo',
|
|
181
183
|
StallDetected: 'stalldetected',
|
|
182
184
|
Started: 'started',
|
|
183
185
|
StateChanged: 'statechanged',
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
goog.provide('shaka.util.ManifestParserUtils');
|
|
8
8
|
|
|
9
9
|
goog.require('goog.Uri');
|
|
10
|
+
goog.require('shaka.util.BufferUtils');
|
|
10
11
|
goog.require('shaka.util.Error');
|
|
12
|
+
goog.require('shaka.util.StringUtils');
|
|
13
|
+
goog.require('shaka.util.Uint8ArrayUtils');
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
/**
|
|
@@ -56,12 +59,14 @@ shaka.util.ManifestParserUtils = class {
|
|
|
56
59
|
* Creates a DrmInfo object from the given info.
|
|
57
60
|
*
|
|
58
61
|
* @param {string} keySystem
|
|
62
|
+
* @param {string} encryptionScheme
|
|
59
63
|
* @param {Array.<shaka.extern.InitDataOverride>} initData
|
|
60
64
|
* @return {shaka.extern.DrmInfo}
|
|
61
65
|
*/
|
|
62
|
-
static createDrmInfo(keySystem, initData) {
|
|
66
|
+
static createDrmInfo(keySystem, encryptionScheme, initData) {
|
|
63
67
|
return {
|
|
64
|
-
keySystem
|
|
68
|
+
keySystem,
|
|
69
|
+
encryptionScheme,
|
|
65
70
|
licenseServerUri: '',
|
|
66
71
|
distinctiveIdentifierRequired: false,
|
|
67
72
|
persistentStateRequired: false,
|
|
@@ -75,6 +80,69 @@ shaka.util.ManifestParserUtils = class {
|
|
|
75
80
|
};
|
|
76
81
|
}
|
|
77
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Creates a DrmInfo object from ClearKeys.
|
|
85
|
+
*
|
|
86
|
+
* @param {!Map.<string, string>} clearKeys
|
|
87
|
+
* @param {string=} encryptionScheme
|
|
88
|
+
* @return {shaka.extern.DrmInfo}
|
|
89
|
+
*/
|
|
90
|
+
static createDrmInfoFromClearKeys(clearKeys, encryptionScheme = 'cenc') {
|
|
91
|
+
const StringUtils = shaka.util.StringUtils;
|
|
92
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
93
|
+
const keys = [];
|
|
94
|
+
const keyIds = [];
|
|
95
|
+
const originalKeyIds = [];
|
|
96
|
+
|
|
97
|
+
clearKeys.forEach((key, keyId) => {
|
|
98
|
+
let kid = keyId;
|
|
99
|
+
if (kid.length != 22) {
|
|
100
|
+
kid = Uint8ArrayUtils.toBase64(
|
|
101
|
+
Uint8ArrayUtils.fromHex(keyId), false);
|
|
102
|
+
}
|
|
103
|
+
let k = key;
|
|
104
|
+
if (k.length != 22) {
|
|
105
|
+
k = Uint8ArrayUtils.toBase64(
|
|
106
|
+
Uint8ArrayUtils.fromHex(key), false);
|
|
107
|
+
}
|
|
108
|
+
const keyObj = {
|
|
109
|
+
kty: 'oct',
|
|
110
|
+
kid: kid,
|
|
111
|
+
k: k,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
keys.push(keyObj);
|
|
115
|
+
keyIds.push(keyObj.kid);
|
|
116
|
+
originalKeyIds.push(keyId);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const jwkSet = {keys: keys};
|
|
120
|
+
const license = JSON.stringify(jwkSet);
|
|
121
|
+
|
|
122
|
+
// Use the keyids init data since is suggested by EME.
|
|
123
|
+
// Suggestion: https://bit.ly/2JYcNTu
|
|
124
|
+
// Format: https://www.w3.org/TR/eme-initdata-keyids/
|
|
125
|
+
const initDataStr = JSON.stringify({'kids': keyIds});
|
|
126
|
+
const initData =
|
|
127
|
+
shaka.util.BufferUtils.toUint8(StringUtils.toUTF8(initDataStr));
|
|
128
|
+
const initDatas = [{initData: initData, initDataType: 'keyids'}];
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
keySystem: 'org.w3.clearkey',
|
|
132
|
+
encryptionScheme,
|
|
133
|
+
licenseServerUri: 'data:application/json;base64,' + window.btoa(license),
|
|
134
|
+
distinctiveIdentifierRequired: false,
|
|
135
|
+
persistentStateRequired: false,
|
|
136
|
+
audioRobustness: '',
|
|
137
|
+
videoRobustness: '',
|
|
138
|
+
serverCertificate: null,
|
|
139
|
+
serverCertificateUri: '',
|
|
140
|
+
sessionType: '',
|
|
141
|
+
initData: initDatas,
|
|
142
|
+
keyIds: new Set(originalKeyIds),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
78
146
|
|
|
79
147
|
/**
|
|
80
148
|
* Attempts to guess which codecs from the codecs list belong to a given
|
|
@@ -134,6 +202,30 @@ shaka.util.ManifestParserUtils = class {
|
|
|
134
202
|
|
|
135
203
|
return null;
|
|
136
204
|
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Attempts to guess which codecs from the codecs list belong to a given
|
|
209
|
+
* content.
|
|
210
|
+
*
|
|
211
|
+
* @param {string} contentType
|
|
212
|
+
* @param {!Array.<string>} codecs
|
|
213
|
+
* @return {!Array.<string>}
|
|
214
|
+
*/
|
|
215
|
+
static guessAllCodecsSafe(contentType, codecs) {
|
|
216
|
+
const allCodecs = [];
|
|
217
|
+
const formats = shaka.util.ManifestParserUtils
|
|
218
|
+
.CODEC_REGEXPS_BY_CONTENT_TYPE_[contentType];
|
|
219
|
+
for (const format of formats) {
|
|
220
|
+
for (const codec of codecs) {
|
|
221
|
+
if (format.test(codec.trim())) {
|
|
222
|
+
allCodecs.push(codec.trim());
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return allCodecs;
|
|
228
|
+
}
|
|
137
229
|
};
|
|
138
230
|
|
|
139
231
|
|
|
@@ -183,7 +275,9 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
|
|
|
183
275
|
/^vvi/,
|
|
184
276
|
/^vp0?[89]/,
|
|
185
277
|
/^av01/,
|
|
186
|
-
/^dvh/,
|
|
278
|
+
/^dvh/, // Dolby Vision based in HEVC
|
|
279
|
+
/^dva/, // Dolby Vision based in AVC
|
|
280
|
+
/^dav/, // Dolby Vision based in AV1
|
|
187
281
|
];
|
|
188
282
|
|
|
189
283
|
|
|
@@ -8,6 +8,7 @@ goog.provide('shaka.util.Mp4BoxParsers');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.util.DataViewReader');
|
|
10
10
|
goog.require('shaka.util.Mp4Parser');
|
|
11
|
+
goog.require('shaka.util.Uint8ArrayUtils');
|
|
11
12
|
|
|
12
13
|
shaka.util.Mp4BoxParsers = class {
|
|
13
14
|
/**
|
|
@@ -329,7 +330,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
329
330
|
}
|
|
330
331
|
}
|
|
331
332
|
if (oti) {
|
|
332
|
-
codec += '.' +
|
|
333
|
+
codec += '.' + shaka.util.Mp4BoxParsers.toHex_(oti);
|
|
333
334
|
if (tag == 0x05 && reader.hasMoreData()) {
|
|
334
335
|
const firstData = reader.readUint8();
|
|
335
336
|
let audioObjectType = (firstData & 0xF8) >> 3;
|
|
@@ -344,15 +345,146 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
344
345
|
}
|
|
345
346
|
|
|
346
347
|
/**
|
|
347
|
-
* Parses a
|
|
348
|
+
* Parses a AVCC box.
|
|
349
|
+
* @param {string} codecBase
|
|
348
350
|
* @param {!shaka.util.DataViewReader} reader
|
|
349
351
|
* @param {string} boxName
|
|
350
|
-
* @return {!shaka.util.
|
|
352
|
+
* @return {!shaka.util.ParsedAVCCBox}
|
|
351
353
|
*/
|
|
352
|
-
static
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
static parseAVCC(codecBase, reader, boxName) {
|
|
355
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
356
|
+
reader.skip(1); // Skip "configurationVersion"
|
|
357
|
+
const codec = codecBase + '.' +
|
|
358
|
+
Mp4BoxParsers.toHex_(reader.readUint8()) +
|
|
359
|
+
Mp4BoxParsers.toHex_(reader.readUint8()) +
|
|
360
|
+
Mp4BoxParsers.toHex_(reader.readUint8());
|
|
361
|
+
return {codec};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Parses a HVCC box.
|
|
366
|
+
* @param {string} codecBase
|
|
367
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
368
|
+
* @param {string} boxName
|
|
369
|
+
* @return {!shaka.util.ParsedHVCCBox}
|
|
370
|
+
*/
|
|
371
|
+
static parseHVCC(codecBase, reader, boxName) {
|
|
372
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
373
|
+
reader.skip(1); // Skip "configurationVersion"
|
|
374
|
+
const profileByte = reader.readUint8();
|
|
375
|
+
const profileSpace = ['', 'A', 'B', 'C'][profileByte >> 6];
|
|
376
|
+
const generalProfileIdc = profileByte & 0x1f;
|
|
377
|
+
const profileCompat = reader.readUint32();
|
|
378
|
+
const tierFlag = (profileByte & 0x20) >> 5 ? 'H' : 'L';
|
|
379
|
+
const constraintIndicator = [
|
|
380
|
+
reader.readUint8(),
|
|
381
|
+
reader.readUint8(),
|
|
382
|
+
reader.readUint8(),
|
|
383
|
+
reader.readUint8(),
|
|
384
|
+
reader.readUint8(),
|
|
385
|
+
reader.readUint8(),
|
|
386
|
+
];
|
|
387
|
+
const levelIDC = reader.readUint8();
|
|
388
|
+
let codec = codecBase;
|
|
389
|
+
codec += '.' + profileSpace + generalProfileIdc;
|
|
390
|
+
codec += '.' + Mp4BoxParsers.toHex_(
|
|
391
|
+
Mp4BoxParsers.reverseBits_(profileCompat),
|
|
392
|
+
/* removeInitialZero= */ true);
|
|
393
|
+
codec += '.' + tierFlag + levelIDC;
|
|
394
|
+
let constraintString = '';
|
|
395
|
+
for (let i = constraintIndicator.length; i--; ) {
|
|
396
|
+
const byte = constraintIndicator[i];
|
|
397
|
+
if (byte || constraintString) {
|
|
398
|
+
const encodedByte = byte.toString(16).toUpperCase();
|
|
399
|
+
constraintString = '.' + encodedByte + constraintString;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
codec += constraintString;
|
|
403
|
+
|
|
404
|
+
return {codec};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Parses a DVCC box.
|
|
409
|
+
* @param {string} codecBase
|
|
410
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
411
|
+
* @param {string} boxName
|
|
412
|
+
* @return {!shaka.util.ParsedDVCCBox}
|
|
413
|
+
*/
|
|
414
|
+
static parseDVCC(codecBase, reader, boxName) {
|
|
415
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
416
|
+
reader.skip(2); // Skip "dv_version_major" and "dv_version_minor"
|
|
417
|
+
const thirdByte = reader.readUint8();
|
|
418
|
+
const fourthByte = reader.readUint8();
|
|
419
|
+
const profile = (thirdByte >> 1) & 0x7f;
|
|
420
|
+
const level = ((thirdByte << 5) & 0x20) | ((fourthByte >> 3) & 0x1f);
|
|
421
|
+
const codec = codecBase + '.' +
|
|
422
|
+
Mp4BoxParsers.addLeadingZero_(profile) + '.' +
|
|
423
|
+
Mp4BoxParsers.addLeadingZero_(level);
|
|
424
|
+
|
|
425
|
+
return {codec};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Parses a VPCC box.
|
|
430
|
+
* @param {string} codecBase
|
|
431
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
432
|
+
* @param {string} boxName
|
|
433
|
+
* @return {!shaka.util.ParsedVPCCBox}
|
|
434
|
+
*/
|
|
435
|
+
static parseVPCC(codecBase, reader, boxName) {
|
|
436
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
437
|
+
const profile = reader.readUint8();
|
|
438
|
+
const level = reader.readUint8();
|
|
439
|
+
const bitDepth = (reader.readUint8() >> 4) & 0x0f;
|
|
440
|
+
const codec = codecBase + '.' +
|
|
441
|
+
Mp4BoxParsers.addLeadingZero_(profile) + '.' +
|
|
442
|
+
Mp4BoxParsers.addLeadingZero_(level) + '.' +
|
|
443
|
+
Mp4BoxParsers.addLeadingZero_(bitDepth);
|
|
444
|
+
|
|
445
|
+
return {codec};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Parses a AV1C box.
|
|
450
|
+
* @param {string} codecBase
|
|
451
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
452
|
+
* @param {string} boxName
|
|
453
|
+
* @return {!shaka.util.ParsedAV1CBox}
|
|
454
|
+
*/
|
|
455
|
+
static parseAV1C(codecBase, reader, boxName) {
|
|
456
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
457
|
+
// More info https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox-syntax
|
|
458
|
+
reader.skip(1); // Skip "marker" and "version"
|
|
459
|
+
const secondByte = reader.readUint8();
|
|
460
|
+
const thirdByte = reader.readUint8();
|
|
461
|
+
const profile = secondByte >>> 5;
|
|
462
|
+
const level = secondByte & 0x1f;
|
|
463
|
+
const tierFlag = thirdByte >>> 7 ? 'H' : 'M';
|
|
464
|
+
const highBitDepth = (thirdByte & 0x40) >> 6;
|
|
465
|
+
const twelveBit = (thirdByte & 0x20) >> 5;
|
|
466
|
+
const bitDepth = profile === 2 && highBitDepth ?
|
|
467
|
+
(twelveBit ? 12 : 10) : (highBitDepth ? 10 : 8);
|
|
468
|
+
const monochrome = (thirdByte & 0x10) >> 4;
|
|
469
|
+
const chromaSubsamplingX = (thirdByte & 0x08) >> 3;
|
|
470
|
+
const chromaSubsamplingY = (thirdByte & 0x04) >> 2;
|
|
471
|
+
const chromaSamplePosition = thirdByte & 0x03;
|
|
472
|
+
// TODO: parse color_description_present_flag
|
|
473
|
+
// default it to BT.709/limited range for now
|
|
474
|
+
const colorPrimaries = 1;
|
|
475
|
+
const transferCharacteristics = 1;
|
|
476
|
+
const matrixCoefficients = 1;
|
|
477
|
+
const videoFullRangeFlag = 0;
|
|
478
|
+
const codec = codecBase + '.' + profile +
|
|
479
|
+
'.' + Mp4BoxParsers.addLeadingZero_(level) + tierFlag +
|
|
480
|
+
'.' + Mp4BoxParsers.addLeadingZero_(bitDepth) +
|
|
481
|
+
'.' + monochrome +
|
|
482
|
+
'.' + chromaSubsamplingX + chromaSubsamplingY + chromaSamplePosition +
|
|
483
|
+
'.' + Mp4BoxParsers.addLeadingZero_(colorPrimaries) +
|
|
484
|
+
'.' + Mp4BoxParsers.addLeadingZero_(transferCharacteristics) +
|
|
485
|
+
'.' + Mp4BoxParsers.addLeadingZero_(matrixCoefficients) +
|
|
486
|
+
'.' + videoFullRangeFlag;
|
|
487
|
+
|
|
356
488
|
return {codec};
|
|
357
489
|
}
|
|
358
490
|
|
|
@@ -367,6 +499,21 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
367
499
|
return {codec};
|
|
368
500
|
}
|
|
369
501
|
|
|
502
|
+
/**
|
|
503
|
+
* Parses a TENC box.
|
|
504
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
505
|
+
* @return {!shaka.util.ParsedTENCBox}
|
|
506
|
+
*/
|
|
507
|
+
static parseTENC(reader) {
|
|
508
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
509
|
+
reader.readUint8(); // reserved
|
|
510
|
+
reader.readUint8();
|
|
511
|
+
reader.readUint8(); // default_isProtected
|
|
512
|
+
reader.readUint8(); // default_Per_Sample_IV_Size
|
|
513
|
+
const defaultKID = Uint8ArrayUtils.toHex(reader.readBytes(16));
|
|
514
|
+
return {defaultKID};
|
|
515
|
+
}
|
|
516
|
+
|
|
370
517
|
/**
|
|
371
518
|
* Parses a HDLR box.
|
|
372
519
|
* @param {!shaka.util.DataViewReader} reader
|
|
@@ -375,24 +522,112 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
375
522
|
static parseHDLR(reader) {
|
|
376
523
|
reader.skip(8); // Skip "pre_defined"
|
|
377
524
|
|
|
378
|
-
const
|
|
379
|
-
let handlerType = '';
|
|
380
|
-
handlerType += String.fromCharCode(data[0]);
|
|
381
|
-
handlerType += String.fromCharCode(data[1]);
|
|
382
|
-
handlerType += String.fromCharCode(data[2]);
|
|
383
|
-
handlerType += String.fromCharCode(data[3]);
|
|
384
|
-
|
|
525
|
+
const handlerType = reader.readTerminatedString();
|
|
385
526
|
return {handlerType};
|
|
386
527
|
}
|
|
387
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Parses a PRJI box.
|
|
531
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
532
|
+
* @return {!shaka.util.ParsedPRJIBox}
|
|
533
|
+
*/
|
|
534
|
+
static parsePRJI(reader) {
|
|
535
|
+
const projection = reader.readTerminatedString();
|
|
536
|
+
return {projection};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Parses a HFOV box.
|
|
541
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
542
|
+
* @return {!shaka.util.ParsedHFOVBox}
|
|
543
|
+
*/
|
|
544
|
+
static parseHFOV(reader) {
|
|
545
|
+
const millidegrees = reader.readUint32();
|
|
546
|
+
|
|
547
|
+
return {
|
|
548
|
+
hfov: millidegrees / 1000,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Parses a COLR box.
|
|
554
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
555
|
+
* @return {!shaka.util.ParsedCOLRBox}
|
|
556
|
+
*/
|
|
557
|
+
static parseCOLR(reader) {
|
|
558
|
+
let videoRange = null;
|
|
559
|
+
const data = reader.readBytes(4);
|
|
560
|
+
let colorType = '';
|
|
561
|
+
colorType += String.fromCharCode(data[0]);
|
|
562
|
+
colorType += String.fromCharCode(data[1]);
|
|
563
|
+
colorType += String.fromCharCode(data[2]);
|
|
564
|
+
colorType += String.fromCharCode(data[3]);
|
|
565
|
+
if (colorType === 'nclx') {
|
|
566
|
+
reader.readUint16(); // colour_primaries
|
|
567
|
+
const transferCharacteristics = reader.readUint16();
|
|
568
|
+
reader.readUint16(); // matrix_coefficients
|
|
569
|
+
switch (transferCharacteristics) {
|
|
570
|
+
case 1:
|
|
571
|
+
case 6:
|
|
572
|
+
case 13:
|
|
573
|
+
case 14:
|
|
574
|
+
case 15:
|
|
575
|
+
videoRange = 'SDR';
|
|
576
|
+
break;
|
|
577
|
+
case 16:
|
|
578
|
+
videoRange = 'PQ';
|
|
579
|
+
break;
|
|
580
|
+
case 18:
|
|
581
|
+
videoRange = 'HLG';
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return {videoRange};
|
|
586
|
+
}
|
|
587
|
+
|
|
388
588
|
/**
|
|
389
589
|
* Convert a number to hex
|
|
390
590
|
* @param {number} x
|
|
591
|
+
* @param {boolean=} removeInitialZero
|
|
592
|
+
* @return {string}
|
|
593
|
+
* @private
|
|
594
|
+
*/
|
|
595
|
+
static toHex_(x, removeInitialZero = false) {
|
|
596
|
+
const value = x.toString(16).toUpperCase();
|
|
597
|
+
if (removeInitialZero) {
|
|
598
|
+
return value;
|
|
599
|
+
}
|
|
600
|
+
return ('0' + value).slice(-2);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Reverse a number bit to bit
|
|
605
|
+
* @param {number} x
|
|
606
|
+
* @return {number}
|
|
607
|
+
* @private
|
|
608
|
+
*/
|
|
609
|
+
static reverseBits_(x) {
|
|
610
|
+
let val = x;
|
|
611
|
+
let reversed = 0;
|
|
612
|
+
for (let i = 0; i < 32; i++) {
|
|
613
|
+
reversed |= val & 1;
|
|
614
|
+
if (i == 31) {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
reversed <<= 1;
|
|
618
|
+
val >>= 1;
|
|
619
|
+
}
|
|
620
|
+
return reversed;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
*
|
|
625
|
+
* @param {number} x
|
|
391
626
|
* @return {string}
|
|
392
627
|
* @private
|
|
393
628
|
*/
|
|
394
|
-
static
|
|
395
|
-
return ('0' + x
|
|
629
|
+
static addLeadingZero_(x) {
|
|
630
|
+
return (x < 10 ? '0' : '') + x;
|
|
396
631
|
}
|
|
397
632
|
};
|
|
398
633
|
|
|
@@ -544,6 +779,17 @@ shaka.util.ParsedTKHDBox;
|
|
|
544
779
|
*/
|
|
545
780
|
shaka.util.ParsedFRMABox;
|
|
546
781
|
|
|
782
|
+
/**
|
|
783
|
+
* @typedef {{
|
|
784
|
+
* defaultKID: string
|
|
785
|
+
* }}
|
|
786
|
+
*
|
|
787
|
+
* @property {string} defaultKID
|
|
788
|
+
*
|
|
789
|
+
* @exportDoc
|
|
790
|
+
*/
|
|
791
|
+
shaka.util.ParsedTENCBox;
|
|
792
|
+
|
|
547
793
|
/**
|
|
548
794
|
* @typedef {{
|
|
549
795
|
* channelCount: number,
|
|
@@ -577,7 +823,51 @@ shaka.util.ParsedESDSBox;
|
|
|
577
823
|
*
|
|
578
824
|
* @exportDoc
|
|
579
825
|
*/
|
|
580
|
-
shaka.util.
|
|
826
|
+
shaka.util.ParsedAVCCBox;
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* @typedef {{
|
|
830
|
+
* codec: string
|
|
831
|
+
* }}
|
|
832
|
+
*
|
|
833
|
+
* @property {string} codec
|
|
834
|
+
*
|
|
835
|
+
* @exportDoc
|
|
836
|
+
*/
|
|
837
|
+
shaka.util.ParsedHVCCBox;
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* @typedef {{
|
|
841
|
+
* codec: string
|
|
842
|
+
* }}
|
|
843
|
+
*
|
|
844
|
+
* @property {string} codec
|
|
845
|
+
*
|
|
846
|
+
* @exportDoc
|
|
847
|
+
*/
|
|
848
|
+
shaka.util.ParsedDVCCBox;
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* @typedef {{
|
|
852
|
+
* codec: string
|
|
853
|
+
* }}
|
|
854
|
+
*
|
|
855
|
+
* @property {string} codec
|
|
856
|
+
*
|
|
857
|
+
* @exportDoc
|
|
858
|
+
*/
|
|
859
|
+
shaka.util.ParsedVPCCBox;
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* @typedef {{
|
|
863
|
+
* codec: string
|
|
864
|
+
* }}
|
|
865
|
+
*
|
|
866
|
+
* @property {string} codec
|
|
867
|
+
*
|
|
868
|
+
* @exportDoc
|
|
869
|
+
*/
|
|
870
|
+
shaka.util.ParsedAV1CBox;
|
|
581
871
|
|
|
582
872
|
/**
|
|
583
873
|
* @typedef {{
|
|
@@ -592,3 +882,42 @@ shaka.util.ParsedAVCBox;
|
|
|
592
882
|
* @exportDoc
|
|
593
883
|
*/
|
|
594
884
|
shaka.util.ParsedHDLRBox;
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* @typedef {{
|
|
888
|
+
* projection: string
|
|
889
|
+
* }}
|
|
890
|
+
*
|
|
891
|
+
* @property {string} projection
|
|
892
|
+
* A four-character code that identifies the type of the projection.
|
|
893
|
+
* Possible values:
|
|
894
|
+
* - Rectangular: ‘rect’
|
|
895
|
+
* - Half equirectangular: ‘hequ’
|
|
896
|
+
* - Equirectanguler: ?
|
|
897
|
+
* - Fisheye: ‘fish’
|
|
898
|
+
*
|
|
899
|
+
* @exportDoc
|
|
900
|
+
*/
|
|
901
|
+
shaka.util.ParsedPRJIBox;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* @typedef {{
|
|
905
|
+
* hfov: number
|
|
906
|
+
* }}
|
|
907
|
+
*
|
|
908
|
+
* @property {number} hfov
|
|
909
|
+
*
|
|
910
|
+
* @exportDoc
|
|
911
|
+
*/
|
|
912
|
+
shaka.util.ParsedHFOVBox;
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* @typedef {{
|
|
916
|
+
* videoRange: ?string
|
|
917
|
+
* }}
|
|
918
|
+
*
|
|
919
|
+
* @property {?string} videoRange
|
|
920
|
+
*
|
|
921
|
+
* @exportDoc
|
|
922
|
+
*/
|
|
923
|
+
shaka.util.ParsedCOLRBox;
|
|
@@ -314,6 +314,8 @@ shaka.util.Mp4Generator = class {
|
|
|
314
314
|
bytes = this.ac3_(streamInfo);
|
|
315
315
|
} else if (streamInfo.codecs.includes('ec-3')) {
|
|
316
316
|
bytes = this.ec3_(streamInfo);
|
|
317
|
+
} else if (streamInfo.codecs.includes('opus')) {
|
|
318
|
+
bytes = this.opus_(streamInfo);
|
|
317
319
|
} else {
|
|
318
320
|
bytes = this.mp4a_(streamInfo);
|
|
319
321
|
}
|
|
@@ -611,6 +613,27 @@ shaka.util.Mp4Generator = class {
|
|
|
611
613
|
this.audioStsd_(streamInfo), dec3Box, sinfBox);
|
|
612
614
|
}
|
|
613
615
|
|
|
616
|
+
/**
|
|
617
|
+
* Generate a Opus box
|
|
618
|
+
*
|
|
619
|
+
* @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
|
|
620
|
+
* @return {!Uint8Array}
|
|
621
|
+
* @private
|
|
622
|
+
*/
|
|
623
|
+
opus_(streamInfo) {
|
|
624
|
+
const Mp4Generator = shaka.util.Mp4Generator;
|
|
625
|
+
const dopsBox = Mp4Generator.box('dOps', streamInfo.audioConfig);
|
|
626
|
+
|
|
627
|
+
let boxName = 'Opus';
|
|
628
|
+
let sinfBox = new Uint8Array([]);
|
|
629
|
+
if (streamInfo.encrypted) {
|
|
630
|
+
sinfBox = this.sinf_(streamInfo);
|
|
631
|
+
boxName = 'enca';
|
|
632
|
+
}
|
|
633
|
+
return Mp4Generator.box(boxName,
|
|
634
|
+
this.audioStsd_(streamInfo), dopsBox, sinfBox);
|
|
635
|
+
}
|
|
636
|
+
|
|
614
637
|
/**
|
|
615
638
|
* Generate a MP4A box
|
|
616
639
|
*
|
package/lib/util/periods.js
CHANGED
|
@@ -45,6 +45,9 @@ shaka.util.PeriodCombiner = class {
|
|
|
45
45
|
/** @private {boolean} */
|
|
46
46
|
this.multiTypeVariantsAllowed_ = false;
|
|
47
47
|
|
|
48
|
+
/** @private {boolean} */
|
|
49
|
+
this.useStreamOnce_ = false;
|
|
50
|
+
|
|
48
51
|
/**
|
|
49
52
|
* The IDs of the periods we have already used to generate streams.
|
|
50
53
|
* This helps us identify the periods which have been added when a live
|
|
@@ -1008,6 +1011,12 @@ shaka.util.PeriodCombiner = class {
|
|
|
1008
1011
|
}
|
|
1009
1012
|
}
|
|
1010
1013
|
|
|
1014
|
+
// Remove just found stream if configured to, so possible future linear
|
|
1015
|
+
// searches can be faster.
|
|
1016
|
+
if (this.useStreamOnce_ && !shaka.util.PeriodCombiner.isDummy_(best)) {
|
|
1017
|
+
streams.delete(getKey(best));
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1011
1020
|
return best;
|
|
1012
1021
|
}
|
|
1013
1022
|
|
|
@@ -1042,11 +1051,21 @@ shaka.util.PeriodCombiner = class {
|
|
|
1042
1051
|
/**
|
|
1043
1052
|
* @param {boolean} allowed If set to true, multi-mimeType or multi-codec
|
|
1044
1053
|
* variants will be allowed.
|
|
1054
|
+
* @export
|
|
1045
1055
|
*/
|
|
1046
1056
|
setAllowMultiTypeVariants(allowed) {
|
|
1047
1057
|
this.multiTypeVariantsAllowed_ = allowed;
|
|
1048
1058
|
}
|
|
1049
1059
|
|
|
1060
|
+
/**
|
|
1061
|
+
* @param {boolean} useOnce if true, stream will be used only once in period
|
|
1062
|
+
* flattening algoritnm.
|
|
1063
|
+
* @export
|
|
1064
|
+
*/
|
|
1065
|
+
setUseStreamOnce(useOnce) {
|
|
1066
|
+
this.useStreamOnce_ = useOnce;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1050
1069
|
/**
|
|
1051
1070
|
* @param {T} outputStream An audio or video output stream
|
|
1052
1071
|
* @param {T} candidate A candidate stream to be combined with the output
|