shaka-player 4.4.0 → 4.4.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/.github/workflows/deflake.yaml +8 -5
- package/.github/workflows/release-please.yaml +64 -16
- package/.github/workflows/report-incremental-coverage.yaml +2 -2
- package/.github/workflows/shaka-bot-commands/command-help.sh +27 -0
- package/.github/workflows/shaka-bot-commands/command-test.sh +56 -0
- package/.github/workflows/shaka-bot-commands/lib.sh +83 -0
- package/.github/workflows/shaka-bot-commands/main.sh +51 -0
- package/.github/workflows/talk-to-shaka-bot.yaml +29 -0
- package/.github/workflows/update-issues.yaml +2 -1
- package/.github/workflows/validate-pr-title.yaml +3 -11
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTORS +1 -0
- package/demo/custom.js +5 -5
- package/dist/demo.compiled.debug.js +3 -3
- package/dist/demo.compiled.debug.map +1 -1
- package/dist/demo.compiled.js +3 -3
- package/dist/demo.compiled.map +1 -1
- package/dist/deps.js +2 -2
- package/dist/locales.js +32 -32
- package/dist/shaka-player.compiled.d.ts +18 -2
- package/dist/shaka-player.compiled.debug.d.ts +18 -2
- package/dist/shaka-player.compiled.debug.externs.js +38 -1
- package/dist/shaka-player.compiled.debug.js +289 -280
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +38 -1
- package/dist/shaka-player.compiled.js +944 -940
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +18 -2
- package/dist/shaka-player.ui.debug.d.ts +18 -2
- package/dist/shaka-player.ui.debug.externs.js +38 -1
- package/dist/shaka-player.ui.debug.js +352 -343
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +38 -1
- package/dist/shaka-player.ui.js +1037 -1034
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +8 -0
- package/docs/tutorials/faq.md +1 -1
- package/externs/shaka/namespace.js +2 -2
- package/externs/shaka/text.js +7 -0
- package/externs/shaka/transmuxer.js +2 -1
- package/lib/dash/segment_template.js +3 -0
- package/lib/hls/hls_parser.js +9 -4
- package/lib/media/media_source_engine.js +23 -3
- package/lib/mss/mss_parser.js +1 -0
- package/lib/player.js +8 -57
- 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 +0 -1
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +8 -1
- package/lib/text/ttml_text_parser.js +10 -1
- package/lib/text/ui_text_displayer.js +49 -3
- package/lib/text/vtt_text_parser.js +21 -5
- package/lib/transmuxer/aac_transmuxer.js +1 -1
- package/lib/transmuxer/ac3_transmuxer.js +1 -0
- package/lib/transmuxer/ec3_transmuxer.js +1 -0
- package/lib/transmuxer/mp3_transmuxer.js +1 -0
- package/lib/transmuxer/ts_transmuxer.js +84 -100
- package/lib/util/error.js +16 -10
- package/lib/util/mp4_generator.js +27 -20
- package/lib/util/player_configuration.js +2 -2
- package/lib/util/stream_utils.js +13 -11
- package/lib/util/ts_parser.js +137 -117
- package/package.json +2 -2
- package/test/hls/hls_parser_unit.js +12 -13
- package/test/media/media_source_engine_integration.js +2 -2
- package/test/mss/mss_player_integration.js +1 -1
- package/test/text/text_engine_unit.js +4 -2
- package/test/text/ttml_text_parser_unit.js +3 -4
- package/test/text/vtt_text_parser_unit.js +17 -2
- package/test/text/web_vtt_layout_integration.js +0 -1
- package/ui/language_utils.js +0 -15
|
@@ -159,7 +159,8 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
159
159
|
* @override
|
|
160
160
|
* @export
|
|
161
161
|
*/
|
|
162
|
-
transmux(data, stream, reference, duration) {
|
|
162
|
+
transmux(data, stream, reference, duration, contentType) {
|
|
163
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
163
164
|
if (!this.tsParser_) {
|
|
164
165
|
this.tsParser_ = new shaka.util.TsParser();
|
|
165
166
|
} else {
|
|
@@ -169,57 +170,46 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
169
170
|
|
|
170
171
|
const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
|
|
171
172
|
|
|
172
|
-
let timestamp = reference.endTime * 1000;
|
|
173
|
-
|
|
174
173
|
const tsParser = this.tsParser_.parse(uint8ArrayData);
|
|
175
|
-
const startTime = tsParser.getStartTime();
|
|
176
|
-
|
|
177
|
-
if (startTime.audio != null) {
|
|
178
|
-
timestamp = startTime.audio;
|
|
179
|
-
}
|
|
180
|
-
if (startTime.video != null) {
|
|
181
|
-
timestamp = startTime.video;
|
|
182
|
-
}
|
|
183
174
|
const streamInfos = [];
|
|
184
175
|
const codecs = tsParser.getCodecs();
|
|
185
176
|
try {
|
|
186
177
|
let streamInfo = null;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
switch (codecs.audio) {
|
|
199
|
-
case 'aac':
|
|
200
|
-
streamInfo =
|
|
201
|
-
this.getAacStreamInfo_(
|
|
202
|
-
tsParser, timestamp, stream, duration, isMuxed);
|
|
203
|
-
break;
|
|
204
|
-
case 'ac3':
|
|
205
|
-
streamInfo =
|
|
206
|
-
this.getAc3StreamInfo_(
|
|
207
|
-
tsParser, timestamp, stream, duration, isMuxed);
|
|
208
|
-
break;
|
|
209
|
-
case 'ec3':
|
|
210
|
-
streamInfo =
|
|
211
|
-
this.getEc3StreamInfo_(
|
|
212
|
-
tsParser, timestamp, stream, duration, isMuxed);
|
|
213
|
-
break;
|
|
214
|
-
case 'mp3':
|
|
215
|
-
streamInfo =
|
|
216
|
-
this.getMp3StreamInfo_(
|
|
217
|
-
tsParser, timestamp, stream, duration, isMuxed);
|
|
218
|
-
break;
|
|
178
|
+
if (contentType == ContentType.VIDEO) {
|
|
179
|
+
switch (codecs.video) {
|
|
180
|
+
case 'avc':
|
|
181
|
+
streamInfo =
|
|
182
|
+
this.getAvcStreamInfo_(tsParser, stream, duration);
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
if (streamInfo) {
|
|
186
|
+
streamInfos.push(streamInfo);
|
|
187
|
+
streamInfo = null;
|
|
188
|
+
}
|
|
219
189
|
}
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
190
|
+
if (contentType == ContentType.AUDIO) {
|
|
191
|
+
switch (codecs.audio) {
|
|
192
|
+
case 'aac':
|
|
193
|
+
streamInfo =
|
|
194
|
+
this.getAacStreamInfo_(tsParser, stream, duration);
|
|
195
|
+
break;
|
|
196
|
+
case 'ac3':
|
|
197
|
+
streamInfo =
|
|
198
|
+
this.getAc3StreamInfo_(tsParser, stream, duration);
|
|
199
|
+
break;
|
|
200
|
+
case 'ec3':
|
|
201
|
+
streamInfo =
|
|
202
|
+
this.getEc3StreamInfo_(tsParser, stream, duration);
|
|
203
|
+
break;
|
|
204
|
+
case 'mp3':
|
|
205
|
+
streamInfo =
|
|
206
|
+
this.getMp3StreamInfo_(tsParser, stream, duration);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
if (streamInfo) {
|
|
210
|
+
streamInfos.push(streamInfo);
|
|
211
|
+
streamInfo = null;
|
|
212
|
+
}
|
|
223
213
|
}
|
|
224
214
|
} catch (e) {
|
|
225
215
|
return Promise.reject(e);
|
|
@@ -250,21 +240,22 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
250
240
|
|
|
251
241
|
/**
|
|
252
242
|
* @param {shaka.util.TsParser} tsParser
|
|
253
|
-
* @param {number} timestamp
|
|
254
243
|
* @param {shaka.extern.Stream} stream
|
|
255
244
|
* @param {number} duration
|
|
256
|
-
* @param {boolean} isMuxed
|
|
257
245
|
* @return {shaka.util.Mp4Generator.StreamInfo}
|
|
258
246
|
* @private
|
|
259
247
|
*/
|
|
260
|
-
getAacStreamInfo_(tsParser,
|
|
248
|
+
getAacStreamInfo_(tsParser, stream, duration) {
|
|
261
249
|
const ADTS = shaka.transmuxer.ADTS;
|
|
250
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
262
251
|
|
|
263
252
|
/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
|
|
264
253
|
const samples = [];
|
|
265
254
|
|
|
266
255
|
let info;
|
|
267
256
|
|
|
257
|
+
let firstPts = null;
|
|
258
|
+
|
|
268
259
|
for (const audioData of tsParser.getAudioData()) {
|
|
269
260
|
const data = audioData.data;
|
|
270
261
|
if (!data) {
|
|
@@ -280,8 +271,9 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
280
271
|
}
|
|
281
272
|
stream.audioSamplingRate = info.sampleRate;
|
|
282
273
|
stream.channelsCount = info.channelCount;
|
|
283
|
-
|
|
284
|
-
|
|
274
|
+
if (firstPts == null && audioData.pts !== null) {
|
|
275
|
+
firstPts = audioData.pts;
|
|
276
|
+
}
|
|
285
277
|
while (offset < data.length) {
|
|
286
278
|
const header = ADTS.parseHeader(data, offset);
|
|
287
279
|
if (!header) {
|
|
@@ -313,7 +305,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
313
305
|
}
|
|
314
306
|
}
|
|
315
307
|
|
|
316
|
-
if (!info) {
|
|
308
|
+
if (!info || firstPts == null) {
|
|
317
309
|
throw new shaka.util.Error(
|
|
318
310
|
shaka.util.Error.Severity.CRITICAL,
|
|
319
311
|
shaka.util.Error.Category.MEDIA,
|
|
@@ -323,15 +315,12 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
323
315
|
/** @type {number} */
|
|
324
316
|
const sampleRate = info.sampleRate;
|
|
325
317
|
/** @type {number} */
|
|
326
|
-
const baseMediaDecodeTime =
|
|
318
|
+
const baseMediaDecodeTime = firstPts / timescale * sampleRate;
|
|
327
319
|
|
|
328
|
-
let id = stream.id;
|
|
329
|
-
if (isMuxed) {
|
|
330
|
-
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
|
|
331
|
-
}
|
|
332
320
|
return {
|
|
333
|
-
id: id,
|
|
321
|
+
id: stream.id,
|
|
334
322
|
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
|
|
323
|
+
codecs: info.codec,
|
|
335
324
|
encrypted: stream.encrypted && stream.drmInfos.length > 0,
|
|
336
325
|
timescale: sampleRate,
|
|
337
326
|
duration: duration,
|
|
@@ -350,15 +339,14 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
350
339
|
|
|
351
340
|
/**
|
|
352
341
|
* @param {shaka.util.TsParser} tsParser
|
|
353
|
-
* @param {number} timestamp
|
|
354
342
|
* @param {shaka.extern.Stream} stream
|
|
355
343
|
* @param {number} duration
|
|
356
|
-
* @param {boolean} isMuxed
|
|
357
344
|
* @return {shaka.util.Mp4Generator.StreamInfo}
|
|
358
345
|
* @private
|
|
359
346
|
*/
|
|
360
|
-
getAc3StreamInfo_(tsParser,
|
|
347
|
+
getAc3StreamInfo_(tsParser, stream, duration) {
|
|
361
348
|
const Ac3 = shaka.transmuxer.Ac3;
|
|
349
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
362
350
|
|
|
363
351
|
/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
|
|
364
352
|
const samples = [];
|
|
@@ -369,8 +357,13 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
369
357
|
/** @type {!Uint8Array} */
|
|
370
358
|
let audioConfig = new Uint8Array([]);
|
|
371
359
|
|
|
360
|
+
let firstPts = null;
|
|
361
|
+
|
|
372
362
|
for (const audioData of tsParser.getAudioData()) {
|
|
373
363
|
const data = audioData.data;
|
|
364
|
+
if (firstPts == null && audioData.pts !== null) {
|
|
365
|
+
firstPts = audioData.pts;
|
|
366
|
+
}
|
|
374
367
|
let offset = 0;
|
|
375
368
|
while (offset < data.length) {
|
|
376
369
|
const frame = Ac3.parseFrame(data, offset);
|
|
@@ -404,7 +397,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
404
397
|
}
|
|
405
398
|
}
|
|
406
399
|
|
|
407
|
-
if (sampleRate == 0 || audioConfig.byteLength == 0) {
|
|
400
|
+
if (sampleRate == 0 || audioConfig.byteLength == 0 || firstPts == null) {
|
|
408
401
|
throw new shaka.util.Error(
|
|
409
402
|
shaka.util.Error.Severity.CRITICAL,
|
|
410
403
|
shaka.util.Error.Category.MEDIA,
|
|
@@ -413,15 +406,12 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
413
406
|
|
|
414
407
|
|
|
415
408
|
/** @type {number} */
|
|
416
|
-
const baseMediaDecodeTime =
|
|
409
|
+
const baseMediaDecodeTime = firstPts / timescale * sampleRate;
|
|
417
410
|
|
|
418
|
-
let id = stream.id;
|
|
419
|
-
if (isMuxed) {
|
|
420
|
-
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
|
|
421
|
-
}
|
|
422
411
|
return {
|
|
423
|
-
id: id,
|
|
412
|
+
id: stream.id,
|
|
424
413
|
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
|
|
414
|
+
codecs: 'ac-3',
|
|
425
415
|
encrypted: stream.encrypted && stream.drmInfos.length > 0,
|
|
426
416
|
timescale: sampleRate,
|
|
427
417
|
duration: duration,
|
|
@@ -440,15 +430,14 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
440
430
|
|
|
441
431
|
/**
|
|
442
432
|
* @param {shaka.util.TsParser} tsParser
|
|
443
|
-
* @param {number} timestamp
|
|
444
433
|
* @param {shaka.extern.Stream} stream
|
|
445
434
|
* @param {number} duration
|
|
446
|
-
* @param {boolean} isMuxed
|
|
447
435
|
* @return {shaka.util.Mp4Generator.StreamInfo}
|
|
448
436
|
* @private
|
|
449
437
|
*/
|
|
450
|
-
getEc3StreamInfo_(tsParser,
|
|
438
|
+
getEc3StreamInfo_(tsParser, stream, duration) {
|
|
451
439
|
const Ec3 = shaka.transmuxer.Ec3;
|
|
440
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
452
441
|
|
|
453
442
|
/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
|
|
454
443
|
const samples = [];
|
|
@@ -459,8 +448,13 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
459
448
|
/** @type {!Uint8Array} */
|
|
460
449
|
let audioConfig = new Uint8Array([]);
|
|
461
450
|
|
|
451
|
+
let firstPts = null;
|
|
452
|
+
|
|
462
453
|
for (const audioData of tsParser.getAudioData()) {
|
|
463
454
|
const data = audioData.data;
|
|
455
|
+
if (firstPts == null && audioData.pts !== null) {
|
|
456
|
+
firstPts = audioData.pts;
|
|
457
|
+
}
|
|
464
458
|
let offset = 0;
|
|
465
459
|
while (offset < data.length) {
|
|
466
460
|
const frame = Ec3.parseFrame(data, offset);
|
|
@@ -494,7 +488,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
494
488
|
}
|
|
495
489
|
}
|
|
496
490
|
|
|
497
|
-
if (sampleRate == 0 || audioConfig.byteLength == 0) {
|
|
491
|
+
if (sampleRate == 0 || audioConfig.byteLength == 0 || firstPts == null) {
|
|
498
492
|
throw new shaka.util.Error(
|
|
499
493
|
shaka.util.Error.Severity.CRITICAL,
|
|
500
494
|
shaka.util.Error.Category.MEDIA,
|
|
@@ -503,15 +497,12 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
503
497
|
|
|
504
498
|
|
|
505
499
|
/** @type {number} */
|
|
506
|
-
const baseMediaDecodeTime =
|
|
500
|
+
const baseMediaDecodeTime = firstPts / timescale * sampleRate;
|
|
507
501
|
|
|
508
|
-
let id = stream.id;
|
|
509
|
-
if (isMuxed) {
|
|
510
|
-
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
|
|
511
|
-
}
|
|
512
502
|
return {
|
|
513
|
-
id: id,
|
|
503
|
+
id: stream.id,
|
|
514
504
|
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
|
|
505
|
+
codecs: 'ec-3',
|
|
515
506
|
encrypted: stream.encrypted && stream.drmInfos.length > 0,
|
|
516
507
|
timescale: sampleRate,
|
|
517
508
|
duration: duration,
|
|
@@ -530,26 +521,30 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
530
521
|
|
|
531
522
|
/**
|
|
532
523
|
* @param {shaka.util.TsParser} tsParser
|
|
533
|
-
* @param {number} timestamp
|
|
534
524
|
* @param {shaka.extern.Stream} stream
|
|
535
525
|
* @param {number} duration
|
|
536
|
-
* @param {boolean} isMuxed
|
|
537
526
|
* @return {shaka.util.Mp4Generator.StreamInfo}
|
|
538
527
|
* @private
|
|
539
528
|
*/
|
|
540
|
-
getMp3StreamInfo_(tsParser,
|
|
529
|
+
getMp3StreamInfo_(tsParser, stream, duration) {
|
|
541
530
|
const MpegAudio = shaka.transmuxer.MpegAudio;
|
|
531
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
542
532
|
|
|
543
533
|
/** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
|
|
544
534
|
const samples = [];
|
|
545
535
|
|
|
546
536
|
let firstHeader;
|
|
547
537
|
|
|
538
|
+
let firstPts = null;
|
|
539
|
+
|
|
548
540
|
for (const audioData of tsParser.getAudioData()) {
|
|
549
541
|
const data = audioData.data;
|
|
550
542
|
if (!data) {
|
|
551
543
|
continue;
|
|
552
544
|
}
|
|
545
|
+
if (firstPts == null && audioData.pts !== null) {
|
|
546
|
+
firstPts = audioData.pts;
|
|
547
|
+
}
|
|
553
548
|
let offset = 0;
|
|
554
549
|
while (offset < data.length) {
|
|
555
550
|
const header = MpegAudio.parseHeader(data, offset);
|
|
@@ -579,7 +574,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
579
574
|
offset += header.frameLength;
|
|
580
575
|
}
|
|
581
576
|
}
|
|
582
|
-
if (!firstHeader) {
|
|
577
|
+
if (!firstHeader || firstPts == null) {
|
|
583
578
|
throw new shaka.util.Error(
|
|
584
579
|
shaka.util.Error.Severity.CRITICAL,
|
|
585
580
|
shaka.util.Error.Category.MEDIA,
|
|
@@ -588,15 +583,12 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
588
583
|
/** @type {number} */
|
|
589
584
|
const sampleRate = firstHeader.sampleRate;
|
|
590
585
|
/** @type {number} */
|
|
591
|
-
const baseMediaDecodeTime =
|
|
586
|
+
const baseMediaDecodeTime = firstPts / timescale * sampleRate;
|
|
592
587
|
|
|
593
|
-
let id = stream.id;
|
|
594
|
-
if (isMuxed) {
|
|
595
|
-
id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
|
|
596
|
-
}
|
|
597
588
|
return {
|
|
598
|
-
id: id,
|
|
589
|
+
id: stream.id,
|
|
599
590
|
type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
|
|
591
|
+
codecs: 'mp3',
|
|
600
592
|
encrypted: stream.encrypted && stream.drmInfos.length > 0,
|
|
601
593
|
timescale: sampleRate,
|
|
602
594
|
duration: duration,
|
|
@@ -615,13 +607,12 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
615
607
|
|
|
616
608
|
/**
|
|
617
609
|
* @param {shaka.util.TsParser} tsParser
|
|
618
|
-
* @param {number} timestamp
|
|
619
610
|
* @param {shaka.extern.Stream} stream
|
|
620
611
|
* @param {number} duration
|
|
621
612
|
* @return {shaka.util.Mp4Generator.StreamInfo}
|
|
622
613
|
* @private
|
|
623
614
|
*/
|
|
624
|
-
getAvcStreamInfo_(tsParser,
|
|
615
|
+
getAvcStreamInfo_(tsParser, stream, duration) {
|
|
625
616
|
const H264 = shaka.transmuxer.H264;
|
|
626
617
|
const timescale = shaka.util.TsParser.Timescale;
|
|
627
618
|
|
|
@@ -632,9 +623,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
632
623
|
let baseMediaDecodeTime = null;
|
|
633
624
|
|
|
634
625
|
let nalus = [];
|
|
635
|
-
const videoData = tsParser.getVideoData()
|
|
636
|
-
return pes.pts != null && pes.dts != null;
|
|
637
|
-
});
|
|
626
|
+
const videoData = tsParser.getVideoData();
|
|
638
627
|
for (let i = 0; i < videoData.length; i++) {
|
|
639
628
|
const pes = videoData[i];
|
|
640
629
|
let nextPes;
|
|
@@ -647,7 +636,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
647
636
|
if (!frame) {
|
|
648
637
|
continue;
|
|
649
638
|
}
|
|
650
|
-
if (baseMediaDecodeTime == null
|
|
639
|
+
if (baseMediaDecodeTime == null) {
|
|
651
640
|
baseMediaDecodeTime = pes.dts;
|
|
652
641
|
}
|
|
653
642
|
let duration;
|
|
@@ -686,6 +675,7 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
686
675
|
return {
|
|
687
676
|
id: stream.id,
|
|
688
677
|
type: shaka.util.ManifestParserUtils.ContentType.VIDEO,
|
|
678
|
+
codecs: 'avc1',
|
|
689
679
|
encrypted: stream.encrypted && stream.drmInfos.length > 0,
|
|
690
680
|
timescale: timescale,
|
|
691
681
|
duration: duration,
|
|
@@ -725,12 +715,6 @@ shaka.transmuxer.TsTransmuxer.SUPPORTED_VIDEO_CODECS_ = [
|
|
|
725
715
|
'avc',
|
|
726
716
|
];
|
|
727
717
|
|
|
728
|
-
/**
|
|
729
|
-
* @private
|
|
730
|
-
* @const {number}
|
|
731
|
-
*/
|
|
732
|
-
shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_ = 128;
|
|
733
|
-
|
|
734
718
|
|
|
735
719
|
shaka.transmuxer.TransmuxerEngine.registerTransmuxer(
|
|
736
720
|
'video/mp2t',
|
package/lib/util/error.js
CHANGED
|
@@ -63,8 +63,11 @@ shaka.util.Error = class {
|
|
|
63
63
|
*/
|
|
64
64
|
this.handled = false;
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// A basic message for compiled mode.
|
|
67
|
+
let formattedMessage = 'Shaka Error ' + this.code;
|
|
67
68
|
if (goog.DEBUG) {
|
|
69
|
+
// This improves the formatting of Errors in failure messages in the
|
|
70
|
+
// tests in debug mode.
|
|
68
71
|
let categoryName = 'UNKNOWN';
|
|
69
72
|
let codeName = 'UNKNOWN';
|
|
70
73
|
|
|
@@ -79,17 +82,20 @@ shaka.util.Error = class {
|
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
* <i>(Only available in uncompiled mode.)</i>
|
|
85
|
-
*
|
|
86
|
-
* @const {string}
|
|
87
|
-
* @exportDoc
|
|
88
|
-
*/
|
|
89
|
-
this.message = 'Shaka Error ' + categoryName + '.' + codeName +
|
|
90
|
-
' (' + this.data.toString() + ')';
|
|
85
|
+
formattedMessage = 'Shaka Error ' + categoryName + '.' + codeName +
|
|
86
|
+
' (' + this.data.toString() + ')';
|
|
91
87
|
}
|
|
92
88
|
|
|
89
|
+
/**
|
|
90
|
+
* In compiled mode, contains a basic message string with the error code.
|
|
91
|
+
* In uncompiled and debug modes, contains a human-readable version of the
|
|
92
|
+
* category and code as enums.
|
|
93
|
+
*
|
|
94
|
+
* @const {string}
|
|
95
|
+
* @exportDoc
|
|
96
|
+
*/
|
|
97
|
+
this.message = formattedMessage;
|
|
98
|
+
|
|
93
99
|
if (shaka.util.Error.createStack) {
|
|
94
100
|
try {
|
|
95
101
|
throw new Error(this.message || 'Shaka Error');
|
|
@@ -55,7 +55,7 @@ shaka.util.Mp4Generator = class {
|
|
|
55
55
|
return Mp4Generator.box('moov',
|
|
56
56
|
this.mvhd_(firstStreamInfo),
|
|
57
57
|
traks,
|
|
58
|
-
this.mvex_(
|
|
58
|
+
this.mvex_(),
|
|
59
59
|
this.pssh_(firstStreamInfo));
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -130,9 +130,14 @@ shaka.util.Mp4Generator = class {
|
|
|
130
130
|
*/
|
|
131
131
|
tkhd_(streamInfo) {
|
|
132
132
|
const Mp4Generator = shaka.util.Mp4Generator;
|
|
133
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
133
134
|
const id = streamInfo.id + 1;
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
let width = streamInfo.stream.width || 0;
|
|
136
|
+
let height = streamInfo.stream.height || 0;
|
|
137
|
+
if (streamInfo.type == ContentType.AUDIO) {
|
|
138
|
+
width = 0;
|
|
139
|
+
height = 0;
|
|
140
|
+
}
|
|
136
141
|
const duration = streamInfo.duration * streamInfo.timescale;
|
|
137
142
|
const upperWordDuration =
|
|
138
143
|
Math.floor(duration / (Mp4Generator.UINT32_MAX_ + 1));
|
|
@@ -295,24 +300,18 @@ shaka.util.Mp4Generator = class {
|
|
|
295
300
|
let bytes = new Uint8Array([]);
|
|
296
301
|
switch (streamInfo.type) {
|
|
297
302
|
case ContentType.VIDEO:
|
|
298
|
-
if (streamInfo.
|
|
299
|
-
streamInfo.stream.codecs.includes('avc3.')) {
|
|
303
|
+
if (streamInfo.codecs.includes('avc1')) {
|
|
300
304
|
bytes = this.avc1_(streamInfo);
|
|
301
|
-
} else if (streamInfo.
|
|
302
|
-
streamInfo.stream.codecs.includes('hvc1.')) {
|
|
305
|
+
} else if (streamInfo.codecs.includes('hvc1')) {
|
|
303
306
|
bytes = this.hvc1_(streamInfo);
|
|
304
307
|
}
|
|
305
308
|
break;
|
|
306
309
|
case ContentType.AUDIO:
|
|
307
|
-
if (streamInfo.
|
|
308
|
-
streamInfo.stream.codecs.includes('mp3') ||
|
|
309
|
-
streamInfo.stream.codecs.includes('mp4a.40.34')) {
|
|
310
|
+
if (streamInfo.codecs.includes('mp3')) {
|
|
310
311
|
bytes = this.mp3_(streamInfo);
|
|
311
|
-
} else if (streamInfo.
|
|
312
|
-
streamInfo.stream.codecs.includes('ac-3')) {
|
|
312
|
+
} else if (streamInfo.codecs.includes('ac-3')) {
|
|
313
313
|
bytes = this.ac3_(streamInfo);
|
|
314
|
-
} else if (streamInfo.
|
|
315
|
-
streamInfo.stream.codecs.includes('ec-3')) {
|
|
314
|
+
} else if (streamInfo.codecs.includes('ec-3')) {
|
|
316
315
|
bytes = this.ec3_(streamInfo);
|
|
317
316
|
} else {
|
|
318
317
|
bytes = this.mp4a_(streamInfo);
|
|
@@ -630,7 +629,7 @@ shaka.util.Mp4Generator = class {
|
|
|
630
629
|
const audioSamplingRate = streamInfo.stream.audioSamplingRate || 44100;
|
|
631
630
|
|
|
632
631
|
const audioCodec = shaka.util.ManifestParserUtils.guessCodecs(
|
|
633
|
-
ContentType.AUDIO, streamInfo.
|
|
632
|
+
ContentType.AUDIO, streamInfo.codecs.split(','));
|
|
634
633
|
|
|
635
634
|
const samplingFrequencyIndex = {
|
|
636
635
|
96000: 0x0,
|
|
@@ -689,13 +688,16 @@ shaka.util.Mp4Generator = class {
|
|
|
689
688
|
/**
|
|
690
689
|
* Generate a MVEX box
|
|
691
690
|
*
|
|
692
|
-
* @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
|
|
693
691
|
* @return {!Uint8Array}
|
|
694
692
|
* @private
|
|
695
693
|
*/
|
|
696
|
-
mvex_(
|
|
694
|
+
mvex_() {
|
|
697
695
|
const Mp4Generator = shaka.util.Mp4Generator;
|
|
698
|
-
|
|
696
|
+
let trexs = new Uint8Array([]);
|
|
697
|
+
for (const streamInfo of this.streamInfos_) {
|
|
698
|
+
trexs = shaka.util.Uint8ArrayUtils.concat(trexs, this.trex_(streamInfo));
|
|
699
|
+
}
|
|
700
|
+
return Mp4Generator.box('mvex', trexs);
|
|
699
701
|
}
|
|
700
702
|
|
|
701
703
|
/**
|
|
@@ -765,8 +767,8 @@ shaka.util.Mp4Generator = class {
|
|
|
765
767
|
* @private
|
|
766
768
|
*/
|
|
767
769
|
frma_(streamInfo) {
|
|
768
|
-
const codec = streamInfo.
|
|
769
|
-
0, streamInfo.
|
|
770
|
+
const codec = streamInfo.codecs.substring(
|
|
771
|
+
0, streamInfo.codecs.indexOf('.'));
|
|
770
772
|
const Mp4Generator = shaka.util.Mp4Generator;
|
|
771
773
|
const codecNumber = this.stringToCharCode_(codec);
|
|
772
774
|
const bytes = new Uint8Array([
|
|
@@ -1290,6 +1292,7 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
|
|
|
1290
1292
|
* @typedef {{
|
|
1291
1293
|
* id: number,
|
|
1292
1294
|
* type: string,
|
|
1295
|
+
* codecs: string,
|
|
1293
1296
|
* encrypted: boolean,
|
|
1294
1297
|
* timescale: number,
|
|
1295
1298
|
* duration: number,
|
|
@@ -1304,6 +1307,10 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
|
|
|
1304
1307
|
* A unique ID
|
|
1305
1308
|
* @property {string} type
|
|
1306
1309
|
* Indicate the content type: 'video' or 'audio'.
|
|
1310
|
+
* @property {string} codecs
|
|
1311
|
+
* <i>Defaults to '' (i.e., unknown / not needed).</i> <br>
|
|
1312
|
+
* The Stream's codecs, e.g., 'avc1.4d4015' or 'vp9'<br>
|
|
1313
|
+
* See {@link https://tools.ietf.org/html/rfc6381}
|
|
1307
1314
|
* @property {boolean} encrypted
|
|
1308
1315
|
* Indicate if the stream is encrypted.
|
|
1309
1316
|
* @property {number} timescale
|
|
@@ -71,8 +71,8 @@ shaka.util.PlayerConfiguration = class {
|
|
|
71
71
|
persistentSessionOnlinePlayback: false,
|
|
72
72
|
persistentSessionsMetadata: [],
|
|
73
73
|
initDataTransform: (initData, initDataType, drmInfo) => {
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
if (shaka.util.Platform.isMediaKeysPolyfilled() &&
|
|
75
|
+
initDataType == 'skd') {
|
|
76
76
|
const cert = drmInfo.serverCertificate;
|
|
77
77
|
const contentId =
|
|
78
78
|
shaka.util.FairPlayUtils.defaultGetContentId(initData);
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -1543,22 +1543,23 @@ shaka.util.StreamUtils = class {
|
|
|
1543
1543
|
|
|
1544
1544
|
/**
|
|
1545
1545
|
* Chooses streams according to the given config.
|
|
1546
|
+
* Works both for Stream and Track types due to their similarities.
|
|
1546
1547
|
*
|
|
1547
|
-
* @param {!Array
|
|
1548
|
+
* @param {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>} streams
|
|
1548
1549
|
* @param {string} preferredLanguage
|
|
1549
1550
|
* @param {string} preferredRole
|
|
1550
1551
|
* @param {boolean} preferredForced
|
|
1551
|
-
* @return {!Array
|
|
1552
|
+
* @return {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>}
|
|
1552
1553
|
*/
|
|
1553
1554
|
static filterStreamsByLanguageAndRole(
|
|
1554
1555
|
streams, preferredLanguage, preferredRole, preferredForced) {
|
|
1555
1556
|
const LanguageUtils = shaka.util.LanguageUtils;
|
|
1556
1557
|
|
|
1557
|
-
/** @type {!Array
|
|
1558
|
+
/** @type {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>} */
|
|
1558
1559
|
let chosen = streams;
|
|
1559
1560
|
|
|
1560
1561
|
// Start with the set of primary streams.
|
|
1561
|
-
/** @type {!Array
|
|
1562
|
+
/** @type {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>} */
|
|
1562
1563
|
const primary = streams.filter((stream) => {
|
|
1563
1564
|
return stream.primary;
|
|
1564
1565
|
});
|
|
@@ -1598,7 +1599,7 @@ shaka.util.StreamUtils = class {
|
|
|
1598
1599
|
|
|
1599
1600
|
// Now refine the choice based on role preference.
|
|
1600
1601
|
if (preferredRole) {
|
|
1601
|
-
const roleMatches = shaka.util.StreamUtils.
|
|
1602
|
+
const roleMatches = shaka.util.StreamUtils.filterStreamsByRole_(
|
|
1602
1603
|
chosen, preferredRole);
|
|
1603
1604
|
if (roleMatches.length) {
|
|
1604
1605
|
return roleMatches;
|
|
@@ -1626,20 +1627,21 @@ shaka.util.StreamUtils = class {
|
|
|
1626
1627
|
if (!allRoles.length) {
|
|
1627
1628
|
return chosen;
|
|
1628
1629
|
}
|
|
1629
|
-
return shaka.util.StreamUtils.
|
|
1630
|
+
return shaka.util.StreamUtils.filterStreamsByRole_(chosen, allRoles[0]);
|
|
1630
1631
|
}
|
|
1631
1632
|
|
|
1632
1633
|
|
|
1633
1634
|
/**
|
|
1634
|
-
* Filter
|
|
1635
|
+
* Filter Streams by role.
|
|
1636
|
+
* Works both for Stream and Track types due to their similarities.
|
|
1635
1637
|
*
|
|
1636
|
-
* @param {!Array
|
|
1638
|
+
* @param {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>} streams
|
|
1637
1639
|
* @param {string} preferredRole
|
|
1638
|
-
* @return {!Array
|
|
1640
|
+
* @return {!Array<!shaka.extern.Stream>|!Array<!shaka.extern.Track>}
|
|
1639
1641
|
* @private
|
|
1640
1642
|
*/
|
|
1641
|
-
static
|
|
1642
|
-
return
|
|
1643
|
+
static filterStreamsByRole_(streams, preferredRole) {
|
|
1644
|
+
return streams.filter((stream) => {
|
|
1643
1645
|
return stream.roles.includes(preferredRole);
|
|
1644
1646
|
});
|
|
1645
1647
|
}
|