shaka-player 4.9.8 → 4.9.9
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/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +273 -271
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1183 -1182
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +308 -306
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1428 -1427
- package/dist/shaka-player.ui.map +3 -3
- package/lib/cea/mp4_cea_parser.js +67 -31
- package/lib/hls/hls_parser.js +30 -17
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/segment_utils.js +8 -1
- package/lib/media/streaming_engine.js +4 -1
- package/lib/player.js +1 -1
- package/lib/util/mp4_box_parsers.js +36 -0
- package/package.json +1 -1
|
@@ -164,53 +164,62 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
164
164
|
/** @type {!Array<!shaka.extern.ICeaParser.CaptionPacket>} **/
|
|
165
165
|
const captionPackets = [];
|
|
166
166
|
|
|
167
|
-
// Fields that are found in MOOF boxes
|
|
168
|
-
let defaultSampleDuration = this.defaultSampleDuration_;
|
|
169
|
-
let defaultSampleSize = this.defaultSampleSize_;
|
|
170
167
|
let moofOffset = 0;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
let
|
|
174
|
-
let timescale = shaka.cea.CeaUtils.DEFAULT_TIMESCALE_VALUE;
|
|
168
|
+
|
|
169
|
+
/** @type {!Array<!shaka.cea.Mp4CeaParser.ParsedTRAF>} */
|
|
170
|
+
let parsedTRAFs = [];
|
|
175
171
|
|
|
176
172
|
new Mp4Parser()
|
|
177
173
|
.box('moof', (box) => {
|
|
178
174
|
moofOffset = box.start;
|
|
179
|
-
//
|
|
180
|
-
|
|
175
|
+
// traf box parsing is reset on each moof.
|
|
176
|
+
parsedTRAFs = [];
|
|
177
|
+
Mp4Parser.children(box);
|
|
178
|
+
})
|
|
179
|
+
.box('traf', (box) => {
|
|
180
|
+
parsedTRAFs.push({
|
|
181
|
+
baseMediaDecodeTime: null,
|
|
182
|
+
defaultSampleDuration: this.defaultSampleDuration_,
|
|
183
|
+
defaultSampleSize: this.defaultSampleSize_,
|
|
184
|
+
parsedTRUNs: [],
|
|
185
|
+
timescale: shaka.cea.CeaUtils.DEFAULT_TIMESCALE_VALUE,
|
|
186
|
+
});
|
|
181
187
|
Mp4Parser.children(box);
|
|
182
188
|
})
|
|
183
|
-
.box('traf', Mp4Parser.children)
|
|
184
189
|
.fullBox('trun', (box) => {
|
|
185
190
|
goog.asserts.assert(
|
|
186
|
-
box.version != null && box.flags!=null,
|
|
191
|
+
box.version != null && box.flags != null,
|
|
187
192
|
'TRUN is a full box and should have a valid version & flags.');
|
|
188
193
|
|
|
194
|
+
const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
|
|
195
|
+
|
|
189
196
|
const parsedTRUN = shaka.util.Mp4BoxParsers.parseTRUN(
|
|
190
197
|
box.reader, box.version, box.flags);
|
|
191
|
-
parsedTRUNs.push(parsedTRUN);
|
|
198
|
+
lastTRAF.parsedTRUNs.push(parsedTRUN);
|
|
192
199
|
})
|
|
193
200
|
.fullBox('tfhd', (box) => {
|
|
194
201
|
goog.asserts.assert(
|
|
195
202
|
box.flags != null,
|
|
196
203
|
'TFHD is a full box and should have valid flags.');
|
|
197
204
|
|
|
205
|
+
const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
|
|
206
|
+
|
|
198
207
|
const parsedTFHD = shaka.util.Mp4BoxParsers.parseTFHD(
|
|
199
208
|
box.reader, box.flags);
|
|
200
209
|
|
|
201
210
|
// If specified, defaultSampleDuration and defaultSampleSize
|
|
202
211
|
// override the ones specified in the TREX box
|
|
203
|
-
defaultSampleDuration = parsedTFHD.defaultSampleDuration ||
|
|
212
|
+
lastTRAF.defaultSampleDuration = parsedTFHD.defaultSampleDuration ||
|
|
204
213
|
this.defaultSampleDuration_;
|
|
205
214
|
|
|
206
|
-
defaultSampleSize = parsedTFHD.defaultSampleSize ||
|
|
215
|
+
lastTRAF.defaultSampleSize = parsedTFHD.defaultSampleSize ||
|
|
207
216
|
this.defaultSampleSize_;
|
|
208
217
|
|
|
209
218
|
const trackId = parsedTFHD.trackId;
|
|
210
219
|
|
|
211
220
|
// Get the timescale from the track Id
|
|
212
221
|
if (this.trackIdToTimescale_.has(trackId)) {
|
|
213
|
-
timescale = this.trackIdToTimescale_.get(trackId);
|
|
222
|
+
lastTRAF.timescale = this.trackIdToTimescale_.get(trackId);
|
|
214
223
|
}
|
|
215
224
|
})
|
|
216
225
|
.fullBox('tfdt', (box) => {
|
|
@@ -218,27 +227,37 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
218
227
|
box.version != null,
|
|
219
228
|
'TFDT is a full box and should have a valid version.');
|
|
220
229
|
|
|
230
|
+
const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
|
|
231
|
+
|
|
221
232
|
const parsedTFDT = shaka.util.Mp4BoxParsers.parseTFDTInaccurate(
|
|
222
233
|
box.reader, box.version);
|
|
223
234
|
|
|
224
|
-
baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
|
|
235
|
+
lastTRAF.baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
|
|
225
236
|
})
|
|
226
237
|
.box('mdat', (box) => {
|
|
227
|
-
if (baseMediaDecodeTime === null) {
|
|
228
|
-
// This field should have been populated by the Base Media Decode
|
|
229
|
-
// Time in the tfdt box.
|
|
230
|
-
shaka.log.alwaysWarn(
|
|
231
|
-
'Unable to find base media decode time for CEA captions!');
|
|
232
|
-
throw new shaka.util.Error(
|
|
233
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
234
|
-
shaka.util.Error.Category.TEXT,
|
|
235
|
-
shaka.util.Error.Code.INVALID_MP4_CEA);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
238
|
const offset = moofOffset - box.start - 8;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
const initialPosition = box.reader.getPosition();
|
|
240
|
+
for (const parsedTRAF of parsedTRAFs) {
|
|
241
|
+
if (parsedTRAF.baseMediaDecodeTime === null) {
|
|
242
|
+
// This field should have been populated by the Base Media Decode
|
|
243
|
+
// Time in the tfdt box.
|
|
244
|
+
shaka.log.alwaysWarn(
|
|
245
|
+
'Unable to find base media decode time for CEA captions!');
|
|
246
|
+
throw new shaka.util.Error(
|
|
247
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
248
|
+
shaka.util.Error.Category.TEXT,
|
|
249
|
+
shaka.util.Error.Code.INVALID_MP4_CEA);
|
|
250
|
+
}
|
|
251
|
+
box.reader.seek(initialPosition);
|
|
252
|
+
this.parseMdat_(box.reader,
|
|
253
|
+
parsedTRAF.baseMediaDecodeTime,
|
|
254
|
+
parsedTRAF.timescale,
|
|
255
|
+
parsedTRAF.defaultSampleDuration,
|
|
256
|
+
parsedTRAF.defaultSampleSize,
|
|
257
|
+
offset,
|
|
258
|
+
parsedTRAF.parsedTRUNs,
|
|
259
|
+
captionPackets);
|
|
260
|
+
}
|
|
242
261
|
})
|
|
243
262
|
.parse(mediaSegment, /* partialOkay= */ false);
|
|
244
263
|
|
|
@@ -315,7 +334,7 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
315
334
|
timeOffset = sampleData[sampleIndex].sampleCompositionTimeOffset || 0;
|
|
316
335
|
}
|
|
317
336
|
|
|
318
|
-
const pts = (time + timeOffset)/timescale;
|
|
337
|
+
const pts = (time + timeOffset) / timescale;
|
|
319
338
|
for (const packet of this.seiProcessor_
|
|
320
339
|
.process(reader.readBytes(naluSize - naluHeaderSize))) {
|
|
321
340
|
captionPackets.push({
|
|
@@ -384,5 +403,22 @@ shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = {
|
|
|
384
403
|
'dvhe': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
385
404
|
};
|
|
386
405
|
|
|
406
|
+
/**
|
|
407
|
+
* @typedef {{
|
|
408
|
+
* baseMediaDecodeTime: ?number,
|
|
409
|
+
* defaultSampleDuration: number,
|
|
410
|
+
* defaultSampleSize: number,
|
|
411
|
+
* parsedTRUNs: !Array<shaka.util.ParsedTRUNBox>,
|
|
412
|
+
* timescale: number
|
|
413
|
+
* }}
|
|
414
|
+
*
|
|
415
|
+
* @property {?number} baseMediaDecodeTime
|
|
416
|
+
* @property {number} defaultSampleDuration
|
|
417
|
+
* @property {number} defaultSampleSize
|
|
418
|
+
* @property {!Array<shaka.util.ParsedTRUNBox>} parsedTRUNs
|
|
419
|
+
* @property {?number} timescale
|
|
420
|
+
*/
|
|
421
|
+
shaka.cea.Mp4CeaParser.ParsedTRAF;
|
|
422
|
+
|
|
387
423
|
shaka.media.ClosedCaptionParser.registerParser('video/mp4',
|
|
388
424
|
() => new shaka.cea.Mp4CeaParser());
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -2319,24 +2319,32 @@ shaka.hls.HlsParser = class {
|
|
|
2319
2319
|
this.config_.hls.disableCodecGuessing) ||
|
|
2320
2320
|
(this.needsClosedCaptionsDetection_ && type == ContentType.VIDEO &&
|
|
2321
2321
|
!this.config_.hls.disableClosedCaptionsDetection)) {
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
type === basicInfo.type, 'Media types should match!');
|
|
2329
|
-
|
|
2330
|
-
if (basicInfo.closedCaptions.size && (!closedCaptions ||
|
|
2331
|
-
closedCaptions.size != basicInfo.closedCaptions.size)) {
|
|
2332
|
-
closedCaptions = basicInfo.closedCaptions;
|
|
2333
|
-
closedCaptionsUpdated = true;
|
|
2322
|
+
let canRequestBasicInfo = playlist.segments.length > 0;
|
|
2323
|
+
if (canRequestBasicInfo) {
|
|
2324
|
+
const segment = playlist.segments[0];
|
|
2325
|
+
if (shaka.hls.Utils.getFirstTagWithName(segment.tags, 'EXT-X-GAP')) {
|
|
2326
|
+
canRequestBasicInfo = false;
|
|
2327
|
+
}
|
|
2334
2328
|
}
|
|
2329
|
+
if (canRequestBasicInfo) {
|
|
2330
|
+
this.needsClosedCaptionsDetection_ = false;
|
|
2331
|
+
const basicInfo = await this.getMediaPlaylistBasicInfo_(
|
|
2332
|
+
playlist, getUris, mediaVariables);
|
|
2333
|
+
|
|
2334
|
+
goog.asserts.assert(
|
|
2335
|
+
type === basicInfo.type, 'Media types should match!');
|
|
2336
|
+
|
|
2337
|
+
if (basicInfo.closedCaptions.size && (!closedCaptions ||
|
|
2338
|
+
closedCaptions.size != basicInfo.closedCaptions.size)) {
|
|
2339
|
+
closedCaptions = basicInfo.closedCaptions;
|
|
2340
|
+
closedCaptionsUpdated = true;
|
|
2341
|
+
}
|
|
2335
2342
|
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2343
|
+
if (!this.codecInfoInManifest_ &&
|
|
2344
|
+
this.config_.hls.disableCodecGuessing) {
|
|
2345
|
+
mimeType = basicInfo.mimeType;
|
|
2346
|
+
codecs = basicInfo.codecs;
|
|
2347
|
+
}
|
|
2340
2348
|
}
|
|
2341
2349
|
}
|
|
2342
2350
|
|
|
@@ -3944,9 +3952,14 @@ shaka.hls.HlsParser = class {
|
|
|
3944
3952
|
'Playlist should have segments!');
|
|
3945
3953
|
const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
|
|
3946
3954
|
|
|
3955
|
+
const middleSegment = playlist.segments[middleSegmentIdx];
|
|
3956
|
+
if (shaka.hls.Utils.getFirstTagWithName(middleSegment.tags, 'EXT-X-GAP')) {
|
|
3957
|
+
return this.guessMimeTypeFallback_(contentType);
|
|
3958
|
+
}
|
|
3959
|
+
|
|
3947
3960
|
const middleSegmentUris = shaka.hls.Utils.constructSegmentUris(
|
|
3948
3961
|
getUris(),
|
|
3949
|
-
|
|
3962
|
+
middleSegment.verbatimSegmentUri,
|
|
3950
3963
|
variables);
|
|
3951
3964
|
|
|
3952
3965
|
const parsedUri = new goog.Uri(middleSegmentUris[0]);
|
|
@@ -140,7 +140,7 @@ shaka.media.SegmentUtils = class {
|
|
|
140
140
|
const SegmentUtils = shaka.media.SegmentUtils;
|
|
141
141
|
|
|
142
142
|
const audioCodecs = [];
|
|
143
|
-
|
|
143
|
+
let videoCodecs = [];
|
|
144
144
|
|
|
145
145
|
let hasAudio = false;
|
|
146
146
|
let hasVideo = false;
|
|
@@ -360,6 +360,13 @@ shaka.media.SegmentUtils = class {
|
|
|
360
360
|
})
|
|
361
361
|
|
|
362
362
|
.box('colr', (box) => {
|
|
363
|
+
videoCodecs = videoCodecs.map((codec) => {
|
|
364
|
+
if (codec.startsWith('av01.')) {
|
|
365
|
+
return shaka.util.Mp4BoxParsers.updateAV1CodecWithCOLRBox(
|
|
366
|
+
codec, box.reader);
|
|
367
|
+
}
|
|
368
|
+
return codec;
|
|
369
|
+
});
|
|
363
370
|
const {videoRange, colorGamut} =
|
|
364
371
|
shaka.util.Mp4BoxParsers.parseCOLR(box.reader);
|
|
365
372
|
realVideoRange = videoRange;
|
|
@@ -2691,7 +2691,10 @@ shaka.media.StreamingEngine = class {
|
|
|
2691
2691
|
}
|
|
2692
2692
|
|
|
2693
2693
|
// First fire an error event.
|
|
2694
|
-
|
|
2694
|
+
if (!error.handled ||
|
|
2695
|
+
error.code != shaka.util.Error.Code.SEGMENT_MISSING) {
|
|
2696
|
+
this.playerInterface_.onError(error);
|
|
2697
|
+
}
|
|
2695
2698
|
|
|
2696
2699
|
// If the error was not handled by the application, call the failure
|
|
2697
2700
|
// callback.
|
package/lib/player.js
CHANGED
|
@@ -7459,7 +7459,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7459
7459
|
* @export
|
|
7460
7460
|
*/
|
|
7461
7461
|
// eslint-disable-next-line no-useless-concat
|
|
7462
|
-
shaka.Player.version = 'v4.9.
|
|
7462
|
+
shaka.Player.version = 'v4.9.9' + '-uncompiled'; // x-release-please-version
|
|
7463
7463
|
|
|
7464
7464
|
// Initialize the deprecation system using the version string we just set
|
|
7465
7465
|
// on the player.
|
|
@@ -604,6 +604,42 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
604
604
|
};
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
+
/**
|
|
608
|
+
* Parses AV1 codec string with COLR box information.
|
|
609
|
+
*
|
|
610
|
+
* AV1 codec info: https://aomediacodec.github.io/av1-isobmff/#codecsparam
|
|
611
|
+
*
|
|
612
|
+
* @param {string} codec
|
|
613
|
+
* @param {!shaka.util.DataViewReader} reader
|
|
614
|
+
* @return {string}
|
|
615
|
+
*/
|
|
616
|
+
static updateAV1CodecWithCOLRBox(codec, reader) {
|
|
617
|
+
const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
|
|
618
|
+
const initialPosition = reader.getPosition();
|
|
619
|
+
const data = reader.readBytes(4);
|
|
620
|
+
let colorType = '';
|
|
621
|
+
colorType += String.fromCharCode(data[0]);
|
|
622
|
+
colorType += String.fromCharCode(data[1]);
|
|
623
|
+
colorType += String.fromCharCode(data[2]);
|
|
624
|
+
colorType += String.fromCharCode(data[3]);
|
|
625
|
+
if (colorType === 'nclx') {
|
|
626
|
+
const colorPrimaries = reader.readUint16();
|
|
627
|
+
const transferCharacteristics = reader.readUint16();
|
|
628
|
+
const matrixCoefficients = reader.readUint16();
|
|
629
|
+
const videoFullRangeFlag = reader.readUint8() >> 7;
|
|
630
|
+
const codecParts = codec.split('.');
|
|
631
|
+
if (codecParts.length == 10) {
|
|
632
|
+
codecParts[6] = Mp4BoxParsers.addLeadingZero_(colorPrimaries);
|
|
633
|
+
codecParts[7] = Mp4BoxParsers.addLeadingZero_(transferCharacteristics);
|
|
634
|
+
codecParts[8] = Mp4BoxParsers.addLeadingZero_(matrixCoefficients);
|
|
635
|
+
codecParts[9] = String(videoFullRangeFlag);
|
|
636
|
+
codec = codecParts.join('.');
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
reader.seek(initialPosition);
|
|
640
|
+
return codec;
|
|
641
|
+
}
|
|
642
|
+
|
|
607
643
|
/**
|
|
608
644
|
* Convert a number to hex
|
|
609
645
|
* @param {number} x
|