shaka-player 4.7.11 → 4.7.13
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/README.md +2 -4
- package/dist/deps.js +6 -7
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.d.ts +14 -12
- package/dist/shaka-player.compiled.debug.d.ts +14 -12
- package/dist/shaka-player.compiled.debug.externs.js +78 -64
- package/dist/shaka-player.compiled.debug.js +321 -312
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +78 -64
- package/dist/shaka-player.compiled.js +1167 -1153
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +14 -12
- package/dist/shaka-player.ui.debug.d.ts +14 -12
- package/dist/shaka-player.ui.debug.externs.js +78 -64
- package/dist/shaka-player.ui.debug.js +443 -434
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +78 -64
- package/dist/shaka-player.ui.js +1319 -1305
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/manifest.js +11 -1
- package/externs/shaka/offline.js +7 -1
- package/externs/shaka/player.js +32 -19
- package/lib/abr/simple_abr_manager.js +21 -26
- package/lib/cast/cast_proxy.js +1 -3
- package/lib/cast/cast_sender.js +8 -11
- package/lib/cea/cea608_memory.js +1 -1
- package/lib/cea/ts_cea_parser.js +10 -1
- package/lib/dash/dash_parser.js +13 -3
- package/lib/dash/segment_base.js +8 -1
- package/lib/dash/segment_list.js +24 -18
- package/lib/dash/segment_template.js +21 -2
- package/lib/hls/hls_parser.js +36 -17
- package/lib/media/drm_engine.js +6 -3
- package/lib/media/media_source_engine.js +96 -33
- package/lib/media/playhead.js +3 -3
- package/lib/media/presentation_timeline.js +23 -0
- package/lib/media/segment_index.js +21 -20
- package/lib/media/segment_utils.js +10 -1
- package/lib/media/streaming_engine.js +2 -14
- package/lib/mss/mss_parser.js +4 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +10 -3
- package/lib/offline/storage.js +2 -0
- package/lib/player.js +30 -4
- package/lib/polyfill/media_capabilities.js +20 -1
- package/lib/polyfill/mediasource.js +37 -14
- package/lib/text/vtt_text_parser.js +51 -51
- package/lib/transmuxer/h264.js +3 -3
- package/lib/transmuxer/h265.js +3 -3
- package/lib/transmuxer/ts_transmuxer.js +42 -3
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mime_utils.js +10 -5
- package/lib/util/mp4_parser.js +57 -0
- package/lib/util/periods.js +5 -37
- package/lib/util/platform.js +4 -0
- package/lib/util/stream_utils.js +334 -271
- package/lib/util/ts_parser.js +99 -10
- package/package.json +1 -1
- package/lib/polyfill/storage_estimate.js +0 -57
package/lib/util/stream_utils.js
CHANGED
|
@@ -364,115 +364,122 @@ shaka.util.StreamUtils = class {
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
368
|
+
|
|
369
|
+
manifest.variants = manifest.variants.filter((variant) => {
|
|
370
|
+
const supported = StreamUtils.checkVariantSupported_(variant, keySystem);
|
|
371
|
+
// Filter out all unsupported variants.
|
|
372
|
+
if (!supported) {
|
|
373
|
+
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
374
|
+
StreamUtils.getVariantSummaryString_(variant));
|
|
375
|
+
}
|
|
376
|
+
return supported;
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @param {!shaka.extern.Variant} variant
|
|
383
|
+
* @param {?string} keySystem
|
|
384
|
+
* @return {boolean}
|
|
385
|
+
* @private
|
|
386
|
+
*/
|
|
387
|
+
static checkVariantSupported_(variant, keySystem) {
|
|
367
388
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
368
389
|
const Capabilities = shaka.media.Capabilities;
|
|
369
390
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
370
391
|
const MimeUtils = shaka.util.MimeUtils;
|
|
371
392
|
const StreamUtils = shaka.util.StreamUtils;
|
|
372
|
-
const isXboxOne = shaka.util.Platform.isXboxOne();
|
|
373
393
|
|
|
394
|
+
const isXboxOne = shaka.util.Platform.isXboxOne();
|
|
374
395
|
const isFirefoxAndroid = shaka.util.Platform.isFirefox() &&
|
|
375
396
|
shaka.util.Platform.isAndroid();
|
|
376
397
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const videoHeight = (video && video.height) || 0;
|
|
382
|
-
|
|
383
|
-
// See: https://github.com/shaka-project/shaka-player/issues/3380
|
|
384
|
-
// Note: it makes sense to drop early
|
|
385
|
-
if (isXboxOne && video &&
|
|
386
|
-
(videoWidth > 1920 || videoHeight > 1080) &&
|
|
387
|
-
(video.codecs.includes('avc1.') || video.codecs.includes('avc3.'))
|
|
388
|
-
) {
|
|
389
|
-
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
390
|
-
StreamUtils.getVariantSummaryString_(variant));
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
if (video) {
|
|
395
|
-
let videoCodecs = StreamUtils.getCorrectVideoCodecs_(video.codecs);
|
|
396
|
-
// For multiplexed streams. Here we must check the audio of the
|
|
397
|
-
// stream to see if it is compatible.
|
|
398
|
-
if (video.codecs.includes(',')) {
|
|
399
|
-
const allCodecs = video.codecs.split(',');
|
|
400
|
-
|
|
401
|
-
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
402
|
-
ContentType.VIDEO, allCodecs);
|
|
403
|
-
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
404
|
-
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
405
|
-
ContentType.AUDIO, allCodecs);
|
|
406
|
-
audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
|
|
398
|
+
// See: https://github.com/shaka-project/shaka-player/issues/3860
|
|
399
|
+
const video = variant.video;
|
|
400
|
+
const videoWidth = (video && video.width) || 0;
|
|
401
|
+
const videoHeight = (video && video.height) || 0;
|
|
407
402
|
|
|
408
|
-
|
|
409
|
-
|
|
403
|
+
// See: https://github.com/shaka-project/shaka-player/issues/3380
|
|
404
|
+
// Note: it makes sense to drop early
|
|
405
|
+
if (isXboxOne && video && (videoWidth > 1920 || videoHeight > 1080) &&
|
|
406
|
+
(video.codecs.includes('avc1.') || video.codecs.includes('avc3.'))) {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
410
409
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
410
|
+
if (video) {
|
|
411
|
+
let videoCodecs = StreamUtils.getCorrectVideoCodecs(video.codecs);
|
|
412
|
+
// For multiplexed streams. Here we must check the audio of the
|
|
413
|
+
// stream to see if it is compatible.
|
|
414
|
+
if (video.codecs.includes(',')) {
|
|
415
|
+
const allCodecs = video.codecs.split(',');
|
|
414
416
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
417
|
+
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
418
|
+
ContentType.VIDEO, allCodecs);
|
|
419
|
+
videoCodecs = StreamUtils.getCorrectVideoCodecs(videoCodecs);
|
|
420
|
+
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
421
|
+
ContentType.AUDIO, allCodecs);
|
|
422
|
+
audioCodecs = StreamUtils.getCorrectAudioCodecs(audioCodecs);
|
|
418
423
|
|
|
419
|
-
const
|
|
420
|
-
video.mimeType,
|
|
424
|
+
const audioFullType = MimeUtils.getFullOrConvertedType(
|
|
425
|
+
video.mimeType, audioCodecs, ContentType.AUDIO);
|
|
421
426
|
|
|
422
|
-
if (!Capabilities.isTypeSupported(
|
|
427
|
+
if (!Capabilities.isTypeSupported(audioFullType)) {
|
|
423
428
|
return false;
|
|
424
429
|
}
|
|
425
430
|
|
|
426
431
|
// Update the codec string with the (possibly) converted codecs.
|
|
427
|
-
|
|
432
|
+
videoCodecs = [videoCodecs, audioCodecs].join(',');
|
|
428
433
|
}
|
|
429
434
|
|
|
430
|
-
const
|
|
435
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
436
|
+
video.mimeType, videoCodecs, ContentType.VIDEO);
|
|
431
437
|
|
|
432
|
-
|
|
433
|
-
// It seems that Firefox Android reports that it supports
|
|
434
|
-
// Opus + Widevine, but it is not actually supported.
|
|
435
|
-
// It makes sense to drop early.
|
|
436
|
-
if (isFirefoxAndroid && audio && audio.encrypted &&
|
|
437
|
-
audio.codecs.toLowerCase().includes('opus')) {
|
|
438
|
-
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
439
|
-
StreamUtils.getVariantSummaryString_(variant));
|
|
438
|
+
if (!Capabilities.isTypeSupported(fullType)) {
|
|
440
439
|
return false;
|
|
441
440
|
}
|
|
442
441
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
audio.mimeType, codecs, ContentType.AUDIO);
|
|
442
|
+
// Update the codec string with the (possibly) converted codecs.
|
|
443
|
+
video.codecs = videoCodecs;
|
|
444
|
+
}
|
|
447
445
|
|
|
448
|
-
|
|
449
|
-
return false;
|
|
450
|
-
}
|
|
446
|
+
const audio = variant.audio;
|
|
451
447
|
|
|
452
|
-
|
|
453
|
-
|
|
448
|
+
// See: https://github.com/shaka-project/shaka-player/issues/6111
|
|
449
|
+
// It seems that Firefox Android reports that it supports
|
|
450
|
+
// Opus + Widevine, but it is not actually supported.
|
|
451
|
+
// It makes sense to drop early.
|
|
452
|
+
if (isFirefoxAndroid && audio && audio.encrypted &&
|
|
453
|
+
audio.codecs.toLowerCase().includes('opus')) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (audio) {
|
|
458
|
+
const codecs = StreamUtils.getCorrectAudioCodecs(audio.codecs);
|
|
459
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
460
|
+
audio.mimeType, codecs, ContentType.AUDIO);
|
|
461
|
+
|
|
462
|
+
if (!Capabilities.isTypeSupported(fullType)) {
|
|
463
|
+
return false;
|
|
454
464
|
}
|
|
455
465
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
+
// Update the codec string with the (possibly) converted codecs.
|
|
467
|
+
audio.codecs = codecs;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return variant.decodingInfos.some((decodingInfo) => {
|
|
471
|
+
if (!decodingInfo.supported) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
if (keySystem) {
|
|
475
|
+
const keySystemAccess = decodingInfo.keySystemAccess;
|
|
476
|
+
if (keySystemAccess) {
|
|
477
|
+
if (keySystemAccess.keySystem != keySystem) {
|
|
478
|
+
return false;
|
|
466
479
|
}
|
|
467
480
|
}
|
|
468
|
-
return true;
|
|
469
|
-
});
|
|
470
|
-
// Filter out all unsupported variants.
|
|
471
|
-
if (!supported) {
|
|
472
|
-
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
473
|
-
StreamUtils.getVariantSummaryString_(variant));
|
|
474
481
|
}
|
|
475
|
-
return
|
|
482
|
+
return true;
|
|
476
483
|
});
|
|
477
484
|
}
|
|
478
485
|
|
|
@@ -516,51 +523,69 @@ shaka.util.StreamUtils = class {
|
|
|
516
523
|
* and assigns it to the given variant.
|
|
517
524
|
* If that query has been done before, instead return a cached result.
|
|
518
525
|
* @param {!shaka.extern.Variant} variant
|
|
519
|
-
* @param {!MediaDecodingConfiguration}
|
|
526
|
+
* @param {!Array.<!MediaDecodingConfiguration>} decodingConfigs
|
|
520
527
|
* @private
|
|
521
528
|
*/
|
|
522
|
-
static async getDecodingInfosForVariant_(variant,
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
// overall variant compatibility.
|
|
539
|
-
const results = await shaka.util.StreamUtils
|
|
540
|
-
.checkEachDecodingConfigCombination_(decodingConfig);
|
|
541
|
-
if (results && results.length) {
|
|
542
|
-
/** @type {?MediaCapabilitiesDecodingInfo} */
|
|
543
|
-
let overallResult = null;
|
|
544
|
-
for (const result of results) {
|
|
545
|
-
if (!overallResult) {
|
|
546
|
-
overallResult = result;
|
|
547
|
-
} else {
|
|
548
|
-
overallResult.supported =
|
|
549
|
-
overallResult.supported && result.supported;
|
|
550
|
-
overallResult.powerEfficient =
|
|
551
|
-
overallResult.powerEfficient && result.powerEfficient;
|
|
552
|
-
overallResult.smooth = overallResult.smooth && result.smooth;
|
|
553
|
-
if (!result.keySystemAccess) {
|
|
554
|
-
overallResult.keySystemAccess = null;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (overallResult) {
|
|
559
|
-
cache[cacheKey] = overallResult;
|
|
560
|
-
variant.decodingInfos.push(overallResult);
|
|
529
|
+
static async getDecodingInfosForVariant_(variant, decodingConfigs) {
|
|
530
|
+
/**
|
|
531
|
+
* @param {?MediaCapabilitiesDecodingInfo} a
|
|
532
|
+
* @param {!MediaCapabilitiesDecodingInfo} b
|
|
533
|
+
* @return {!MediaCapabilitiesDecodingInfo}
|
|
534
|
+
*/
|
|
535
|
+
const merge = (a, b) => {
|
|
536
|
+
if (!a) {
|
|
537
|
+
return b;
|
|
538
|
+
} else {
|
|
539
|
+
const res = shaka.util.ObjectUtils.cloneObject(a);
|
|
540
|
+
res.supported = a.supported && b.supported;
|
|
541
|
+
res.powerEfficient = a.powerEfficient && b.powerEfficient;
|
|
542
|
+
res.smooth = a.smooth && b.smooth;
|
|
543
|
+
if (b.keySystemAccess && !res.keySystemAccess) {
|
|
544
|
+
res.keySystemAccess = b.keySystemAccess;
|
|
561
545
|
}
|
|
546
|
+
return res;
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
551
|
+
/** @type {?MediaCapabilitiesDecodingInfo} */
|
|
552
|
+
let finalResult = null;
|
|
553
|
+
const promises = [];
|
|
554
|
+
for (const decodingConfig of decodingConfigs) {
|
|
555
|
+
const cacheKey =
|
|
556
|
+
StreamUtils.alphabeticalKeyOrderStringify_(decodingConfig);
|
|
557
|
+
|
|
558
|
+
const cache = StreamUtils.decodingConfigCache_;
|
|
559
|
+
if (cache[cacheKey]) {
|
|
560
|
+
shaka.log.v2('Using cached results of mediaCapabilities.decodingInfo',
|
|
561
|
+
'for key', cacheKey);
|
|
562
|
+
finalResult = merge(finalResult, cache[cacheKey]);
|
|
563
|
+
} else {
|
|
564
|
+
// Do a final pass-over of the decoding config: if a given stream has
|
|
565
|
+
// multiple codecs, that suggests that it switches between those codecs
|
|
566
|
+
// at points of the go-through.
|
|
567
|
+
// mediaCapabilities by itself will report "not supported" when you
|
|
568
|
+
// put in multiple different codecs, so each has to be checked
|
|
569
|
+
// individually. So check each and take the worst result, to determine
|
|
570
|
+
// overall variant compatibility.
|
|
571
|
+
promises.push(StreamUtils
|
|
572
|
+
.checkEachDecodingConfigCombination_(decodingConfig).then((res) => {
|
|
573
|
+
/** @type {?MediaCapabilitiesDecodingInfo} */
|
|
574
|
+
let acc = null;
|
|
575
|
+
for (const result of (res || [])) {
|
|
576
|
+
acc = merge(acc, result);
|
|
577
|
+
}
|
|
578
|
+
if (acc) {
|
|
579
|
+
cache[cacheKey] = acc;
|
|
580
|
+
finalResult = merge(finalResult, acc);
|
|
581
|
+
}
|
|
582
|
+
}));
|
|
562
583
|
}
|
|
563
584
|
}
|
|
585
|
+
await Promise.all(promises);
|
|
586
|
+
if (finalResult) {
|
|
587
|
+
variant.decodingInfos.push(finalResult);
|
|
588
|
+
}
|
|
564
589
|
}
|
|
565
590
|
|
|
566
591
|
/**
|
|
@@ -634,10 +659,12 @@ shaka.util.StreamUtils = class {
|
|
|
634
659
|
for (const preferredKeySystem of preferredKeySystems) {
|
|
635
660
|
let keySystemSatisfied = false;
|
|
636
661
|
for (const variant of variants) {
|
|
637
|
-
/** @type {!Array.<!MediaDecodingConfiguration
|
|
662
|
+
/** @type {!Array.<!Array.<!MediaDecodingConfiguration>>} */
|
|
638
663
|
const decodingConfigs = shaka.util.StreamUtils.getDecodingConfigs_(
|
|
639
664
|
variant, usePersistentLicenses, srcEquals)
|
|
640
|
-
.filter((
|
|
665
|
+
.filter((configs) => {
|
|
666
|
+
// All configs in a batch will have the same keySystem.
|
|
667
|
+
const config = configs[0];
|
|
641
668
|
const keySystem = config.keySystemConfiguration &&
|
|
642
669
|
config.keySystemConfiguration.keySystem;
|
|
643
670
|
return keySystem === preferredKeySystem;
|
|
@@ -646,10 +673,10 @@ shaka.util.StreamUtils = class {
|
|
|
646
673
|
// The reason we are performing this await in a loop rather than
|
|
647
674
|
// batching into a `promise.all` is performance related.
|
|
648
675
|
// https://github.com/shaka-project/shaka-player/pull/4708#discussion_r1022581178
|
|
649
|
-
for (const
|
|
676
|
+
for (const configs of decodingConfigs) {
|
|
650
677
|
// eslint-disable-next-line no-await-in-loop
|
|
651
678
|
await shaka.util.StreamUtils.getDecodingInfosForVariant_(
|
|
652
|
-
variant,
|
|
679
|
+
variant, configs);
|
|
653
680
|
}
|
|
654
681
|
if (variant.decodingInfos.length) {
|
|
655
682
|
keySystemSatisfied = true;
|
|
@@ -662,10 +689,12 @@ shaka.util.StreamUtils = class {
|
|
|
662
689
|
} // for (const preferredKeySystem of preferredKeySystems)
|
|
663
690
|
|
|
664
691
|
for (const variant of variants) {
|
|
665
|
-
/** @type {!Array.<!MediaDecodingConfiguration
|
|
692
|
+
/** @type {!Array.<!Array.<!MediaDecodingConfiguration>>} */
|
|
666
693
|
const decodingConfigs = shaka.util.StreamUtils.getDecodingConfigs_(
|
|
667
694
|
variant, usePersistentLicenses, srcEquals)
|
|
668
|
-
.filter((
|
|
695
|
+
.filter((configs) => {
|
|
696
|
+
// All configs in a batch will have the same keySystem.
|
|
697
|
+
const config = configs[0];
|
|
669
698
|
const keySystem = config.keySystemConfiguration &&
|
|
670
699
|
config.keySystemConfiguration.keySystem;
|
|
671
700
|
// Avoid checking preferred systems twice.
|
|
@@ -675,22 +704,24 @@ shaka.util.StreamUtils = class {
|
|
|
675
704
|
// The reason we are performing this await in a loop rather than
|
|
676
705
|
// batching into a `promise.all` is performance related.
|
|
677
706
|
// https://github.com/shaka-project/shaka-player/pull/4708#discussion_r1022581178
|
|
678
|
-
for (const
|
|
707
|
+
for (const configs of decodingConfigs) {
|
|
679
708
|
// eslint-disable-next-line no-await-in-loop
|
|
680
709
|
await shaka.util.StreamUtils.getDecodingInfosForVariant_(
|
|
681
|
-
variant,
|
|
710
|
+
variant, configs);
|
|
682
711
|
}
|
|
683
712
|
}
|
|
684
713
|
}
|
|
685
714
|
|
|
686
715
|
|
|
687
716
|
/**
|
|
688
|
-
* Generate a MediaDecodingConfiguration
|
|
689
|
-
* results for each variant.
|
|
717
|
+
* Generate a batch of MediaDecodingConfiguration objects to get the
|
|
718
|
+
* decodingInfo results for each variant.
|
|
719
|
+
* Each batch shares the same DRM information, and represents the various
|
|
720
|
+
* fullMimeType combinations of the streams.
|
|
690
721
|
* @param {!shaka.extern.Variant} variant
|
|
691
722
|
* @param {boolean} usePersistentLicenses
|
|
692
723
|
* @param {boolean} srcEquals
|
|
693
|
-
* @return {!Array.<!MediaDecodingConfiguration
|
|
724
|
+
* @return {!Array.<!Array.<!MediaDecodingConfiguration>>}
|
|
694
725
|
* @private
|
|
695
726
|
*/
|
|
696
727
|
static getDecodingConfigs_(variant, usePersistentLicenses, srcEquals) {
|
|
@@ -702,87 +733,118 @@ shaka.util.StreamUtils = class {
|
|
|
702
733
|
const MimeUtils = shaka.util.MimeUtils;
|
|
703
734
|
const StreamUtils = shaka.util.StreamUtils;
|
|
704
735
|
|
|
705
|
-
|
|
706
|
-
const
|
|
707
|
-
type: srcEquals ? 'file' : 'media-source',
|
|
708
|
-
};
|
|
709
|
-
|
|
736
|
+
const videoConfigs = [];
|
|
737
|
+
const audioConfigs = [];
|
|
710
738
|
if (video) {
|
|
711
|
-
|
|
739
|
+
for (const fullMimeType of video.fullMimeTypes) {
|
|
740
|
+
let videoCodecs = MimeUtils.getCodecs(fullMimeType);
|
|
712
741
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
742
|
+
// For multiplexed streams with audio+video codecs, the config should
|
|
743
|
+
// have AudioConfiguration and VideoConfiguration.
|
|
744
|
+
// We ignore the multiplexed audio when there is normal audio also.
|
|
745
|
+
if (videoCodecs.includes(',') && !audio) {
|
|
746
|
+
const allCodecs = videoCodecs.split(',');
|
|
717
747
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
748
|
+
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
749
|
+
ContentType.VIDEO, allCodecs);
|
|
721
750
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
751
|
+
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
752
|
+
ContentType.AUDIO, allCodecs);
|
|
753
|
+
audioCodecs = StreamUtils.getCorrectAudioCodecs(audioCodecs);
|
|
725
754
|
|
|
726
|
-
|
|
727
|
-
|
|
755
|
+
const audioFullType = MimeUtils.getFullOrConvertedType(
|
|
756
|
+
MimeUtils.getBasicType(fullMimeType), audioCodecs,
|
|
757
|
+
ContentType.AUDIO);
|
|
758
|
+
|
|
759
|
+
audioConfigs.push({
|
|
760
|
+
contentType: audioFullType,
|
|
761
|
+
channels: 2,
|
|
762
|
+
bitrate: variant.bandwidth || 1,
|
|
763
|
+
samplerate: 1,
|
|
764
|
+
spatialRendering: false,
|
|
765
|
+
});
|
|
766
|
+
}
|
|
728
767
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
768
|
+
videoCodecs = StreamUtils.getCorrectVideoCodecs(videoCodecs);
|
|
769
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
770
|
+
MimeUtils.getBasicType(fullMimeType), videoCodecs,
|
|
771
|
+
ContentType.VIDEO);
|
|
772
|
+
|
|
773
|
+
// VideoConfiguration
|
|
774
|
+
const videoConfig = {
|
|
775
|
+
contentType: fullType,
|
|
776
|
+
|
|
777
|
+
// NOTE: Some decoders strictly check the width and height fields and
|
|
778
|
+
// won't decode smaller than 64x64. So if we don't have this info (as
|
|
779
|
+
// is the case in some of our simpler tests), assume a 64x64
|
|
780
|
+
// resolution to fill in this required field for MediaCapabilities.
|
|
781
|
+
//
|
|
782
|
+
// This became an issue specifically on Firefox on M1 Macs.
|
|
783
|
+
width: video.width || 64,
|
|
784
|
+
height: video.height || 64,
|
|
785
|
+
|
|
786
|
+
bitrate: video.bandwidth || variant.bandwidth || 1,
|
|
787
|
+
// framerate must be greater than 0, otherwise the config is invalid.
|
|
788
|
+
framerate: video.frameRate || 1,
|
|
735
789
|
};
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
// is the case in some of our simpler tests), assume a 64x64 resolution
|
|
749
|
-
// to fill in this required field for MediaCapabilities.
|
|
750
|
-
//
|
|
751
|
-
// This became an issue specifically on Firefox on M1 Macs.
|
|
752
|
-
width: video.width || 64,
|
|
753
|
-
height: video.height || 64,
|
|
754
|
-
|
|
755
|
-
bitrate: video.bandwidth || variant.bandwidth || 1,
|
|
756
|
-
// framerate must be greater than 0, otherwise the config is invalid.
|
|
757
|
-
framerate: video.frameRate || 1,
|
|
758
|
-
};
|
|
759
|
-
if (video.hdr) {
|
|
760
|
-
switch (video.hdr) {
|
|
761
|
-
case 'SDR':
|
|
762
|
-
mediaDecodingConfig.video.transferFunction = 'srgb';
|
|
763
|
-
break;
|
|
764
|
-
case 'PQ':
|
|
765
|
-
mediaDecodingConfig.video.transferFunction = 'pq';
|
|
766
|
-
break;
|
|
767
|
-
case 'HLG':
|
|
768
|
-
mediaDecodingConfig.video.transferFunction = 'hlg';
|
|
769
|
-
break;
|
|
790
|
+
if (video.hdr) {
|
|
791
|
+
switch (video.hdr) {
|
|
792
|
+
case 'SDR':
|
|
793
|
+
videoConfig.transferFunction = 'srgb';
|
|
794
|
+
break;
|
|
795
|
+
case 'PQ':
|
|
796
|
+
videoConfig.transferFunction = 'pq';
|
|
797
|
+
break;
|
|
798
|
+
case 'HLG':
|
|
799
|
+
videoConfig.transferFunction = 'hlg';
|
|
800
|
+
break;
|
|
801
|
+
}
|
|
770
802
|
}
|
|
803
|
+
videoConfigs.push(videoConfig);
|
|
771
804
|
}
|
|
772
805
|
}
|
|
773
806
|
if (audio) {
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
807
|
+
for (const fullMimeType of audio.fullMimeTypes) {
|
|
808
|
+
const codecs = StreamUtils.getCorrectAudioCodecs(MimeUtils.getCodecs(
|
|
809
|
+
fullMimeType));
|
|
810
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
811
|
+
MimeUtils.getBasicType(fullMimeType), codecs, ContentType.AUDIO);
|
|
812
|
+
|
|
813
|
+
// AudioConfiguration
|
|
814
|
+
audioConfigs.push({
|
|
815
|
+
contentType: fullType,
|
|
816
|
+
channels: audio.channelsCount || 2,
|
|
817
|
+
bitrate: audio.bandwidth || variant.bandwidth || 1,
|
|
818
|
+
samplerate: audio.audioSamplingRate || 1,
|
|
819
|
+
spatialRendering: audio.spatialAudio,
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
}
|
|
777
823
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
824
|
+
// Generate each combination of video and audio config as a separate
|
|
825
|
+
// MediaDecodingConfiguration, inside the main "batch".
|
|
826
|
+
/** @type {!Array.<!MediaDecodingConfiguration>} */
|
|
827
|
+
const mediaDecodingConfigBatch = [];
|
|
828
|
+
if (videoConfigs.length == 0) {
|
|
829
|
+
videoConfigs.push(null);
|
|
830
|
+
}
|
|
831
|
+
if (audioConfigs.length == 0) {
|
|
832
|
+
audioConfigs.push(null);
|
|
833
|
+
}
|
|
834
|
+
for (const videoConfig of videoConfigs) {
|
|
835
|
+
for (const audioConfig of audioConfigs) {
|
|
836
|
+
/** @type {!MediaDecodingConfiguration} */
|
|
837
|
+
const mediaDecodingConfig = {
|
|
838
|
+
type: srcEquals ? 'file' : 'media-source',
|
|
839
|
+
};
|
|
840
|
+
if (videoConfig) {
|
|
841
|
+
mediaDecodingConfig.video = videoConfig;
|
|
842
|
+
}
|
|
843
|
+
if (audioConfig) {
|
|
844
|
+
mediaDecodingConfig.audio = audioConfig;
|
|
845
|
+
}
|
|
846
|
+
mediaDecodingConfigBatch.push(mediaDecodingConfig);
|
|
847
|
+
}
|
|
786
848
|
}
|
|
787
849
|
|
|
788
850
|
const videoDrmInfos = variant.video ? variant.video.drmInfos : [];
|
|
@@ -791,7 +853,7 @@ shaka.util.StreamUtils = class {
|
|
|
791
853
|
|
|
792
854
|
// Return a list containing the mediaDecodingConfig for unencrypted variant.
|
|
793
855
|
if (!allDrmInfos.length) {
|
|
794
|
-
return [
|
|
856
|
+
return [mediaDecodingConfigBatch];
|
|
795
857
|
}
|
|
796
858
|
|
|
797
859
|
// A list of MediaDecodingConfiguration objects created for the variant.
|
|
@@ -813,83 +875,87 @@ shaka.util.StreamUtils = class {
|
|
|
813
875
|
usePersistentLicenses ? ['persistent-license'] : ['temporary'];
|
|
814
876
|
|
|
815
877
|
for (const keySystem of drmInfoByKeySystems.keys()) {
|
|
816
|
-
|
|
817
|
-
const
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
initDataTypes
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
878
|
+
const modifiedMediaDecodingConfigBatch = [];
|
|
879
|
+
for (const base of mediaDecodingConfigBatch) {
|
|
880
|
+
// Create a copy of the mediaDecodingConfig.
|
|
881
|
+
const config = /** @type {!MediaDecodingConfiguration} */
|
|
882
|
+
(Object.assign({}, base));
|
|
883
|
+
|
|
884
|
+
const drmInfos = drmInfoByKeySystems.get(keySystem);
|
|
885
|
+
|
|
886
|
+
/** @type {!MediaCapabilitiesKeySystemConfiguration} */
|
|
887
|
+
const keySystemConfig = {
|
|
888
|
+
keySystem: keySystem,
|
|
889
|
+
initDataType: 'cenc',
|
|
890
|
+
persistentState: persistentState,
|
|
891
|
+
distinctiveIdentifier: 'optional',
|
|
892
|
+
sessionTypes: sessionTypes,
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
for (const info of drmInfos) {
|
|
896
|
+
if (info.initData && info.initData.length) {
|
|
897
|
+
const initDataTypes = new Set();
|
|
898
|
+
for (const initData of info.initData) {
|
|
899
|
+
initDataTypes.add(initData.initDataType);
|
|
900
|
+
}
|
|
901
|
+
if (initDataTypes.size > 1) {
|
|
902
|
+
shaka.log.v2('DrmInfo contains more than one initDataType,',
|
|
903
|
+
'and we use the initDataType of the first initData.',
|
|
904
|
+
info);
|
|
905
|
+
}
|
|
906
|
+
keySystemConfig.initDataType = info.initData[0].initDataType;
|
|
841
907
|
}
|
|
842
|
-
keySystemConfig.initDataType = info.initData[0].initDataType;
|
|
843
|
-
}
|
|
844
908
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
909
|
+
if (info.distinctiveIdentifierRequired) {
|
|
910
|
+
keySystemConfig.distinctiveIdentifier = 'required';
|
|
911
|
+
}
|
|
912
|
+
if (info.persistentStateRequired) {
|
|
913
|
+
keySystemConfig.persistentState = 'required';
|
|
914
|
+
}
|
|
915
|
+
if (info.sessionType) {
|
|
916
|
+
keySystemConfig.sessionTypes = [info.sessionType];
|
|
917
|
+
}
|
|
854
918
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
919
|
+
if (audio) {
|
|
920
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
921
|
+
if (info.audioRobustness != '') {
|
|
922
|
+
if (!keySystemConfig.audio) {
|
|
923
|
+
// KeySystemTrackConfiguration
|
|
924
|
+
keySystemConfig.audio = {
|
|
925
|
+
robustness: info.audioRobustness,
|
|
926
|
+
};
|
|
927
|
+
} else {
|
|
928
|
+
keySystemConfig.audio.robustness =
|
|
929
|
+
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
930
|
+
}
|
|
931
|
+
} else if (!keySystemConfig.audio) {
|
|
859
932
|
// KeySystemTrackConfiguration
|
|
860
|
-
keySystemConfig.audio = {
|
|
861
|
-
robustness: info.audioRobustness,
|
|
862
|
-
};
|
|
863
|
-
} else {
|
|
864
|
-
keySystemConfig.audio.robustness =
|
|
865
|
-
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
933
|
+
keySystemConfig.audio = {};
|
|
866
934
|
}
|
|
867
|
-
} else if (!keySystemConfig.audio) {
|
|
868
|
-
// KeySystemTrackConfiguration
|
|
869
|
-
keySystemConfig.audio = {};
|
|
870
935
|
}
|
|
871
|
-
}
|
|
872
936
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
937
|
+
if (video) {
|
|
938
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
939
|
+
if (info.videoRobustness != '') {
|
|
940
|
+
if (!keySystemConfig.video) {
|
|
941
|
+
// KeySystemTrackConfiguration
|
|
942
|
+
keySystemConfig.video = {
|
|
943
|
+
robustness: info.videoRobustness,
|
|
944
|
+
};
|
|
945
|
+
} else {
|
|
946
|
+
keySystemConfig.video.robustness =
|
|
947
|
+
keySystemConfig.video.robustness || info.videoRobustness;
|
|
948
|
+
}
|
|
949
|
+
} else if (!keySystemConfig.video) {
|
|
877
950
|
// KeySystemTrackConfiguration
|
|
878
|
-
keySystemConfig.video = {
|
|
879
|
-
robustness: info.videoRobustness,
|
|
880
|
-
};
|
|
881
|
-
} else {
|
|
882
|
-
keySystemConfig.video.robustness =
|
|
883
|
-
keySystemConfig.video.robustness || info.videoRobustness;
|
|
951
|
+
keySystemConfig.video = {};
|
|
884
952
|
}
|
|
885
|
-
} else if (!keySystemConfig.video) {
|
|
886
|
-
// KeySystemTrackConfiguration
|
|
887
|
-
keySystemConfig.video = {};
|
|
888
953
|
}
|
|
889
954
|
}
|
|
955
|
+
config.keySystemConfiguration = keySystemConfig;
|
|
956
|
+
modifiedMediaDecodingConfigBatch.push(config);
|
|
890
957
|
}
|
|
891
|
-
|
|
892
|
-
configs.push(config);
|
|
958
|
+
configs.push(modifiedMediaDecodingConfigBatch);
|
|
893
959
|
}
|
|
894
960
|
return configs;
|
|
895
961
|
}
|
|
@@ -900,9 +966,8 @@ shaka.util.StreamUtils = class {
|
|
|
900
966
|
* for MediaSource.isTypeSupported.
|
|
901
967
|
* @param {string} codecs
|
|
902
968
|
* @return {string}
|
|
903
|
-
* @private
|
|
904
969
|
*/
|
|
905
|
-
static
|
|
970
|
+
static getCorrectAudioCodecs(codecs) {
|
|
906
971
|
// According to RFC 6381 section 3.3, 'fLaC' is actually the correct
|
|
907
972
|
// codec string. We still need to map it to 'flac', as some browsers
|
|
908
973
|
// currently don't support 'fLaC', while 'flac' is supported by most
|
|
@@ -926,9 +991,8 @@ shaka.util.StreamUtils = class {
|
|
|
926
991
|
* for MediaSource.isTypeSupported.
|
|
927
992
|
* @param {string} codec
|
|
928
993
|
* @return {string}
|
|
929
|
-
* @private
|
|
930
994
|
*/
|
|
931
|
-
static
|
|
995
|
+
static getCorrectVideoCodecs(codec) {
|
|
932
996
|
if (codec.includes('avc1')) {
|
|
933
997
|
// Convert avc1 codec string from RFC-4281 to RFC-6381 for
|
|
934
998
|
// MediaSource.isTypeSupported
|
|
@@ -1390,8 +1454,6 @@ shaka.util.StreamUtils = class {
|
|
|
1390
1454
|
* @return {shaka.extern.Track}
|
|
1391
1455
|
*/
|
|
1392
1456
|
static html5TextTrackToTrack(textTrack) {
|
|
1393
|
-
const CLOSED_CAPTION_MIMETYPE =
|
|
1394
|
-
shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE;
|
|
1395
1457
|
const StreamUtils = shaka.util.StreamUtils;
|
|
1396
1458
|
|
|
1397
1459
|
/** @type {shaka.extern.Track} */
|
|
@@ -1400,7 +1462,8 @@ shaka.util.StreamUtils = class {
|
|
|
1400
1462
|
track.type = 'text';
|
|
1401
1463
|
track.originalTextId = textTrack.id;
|
|
1402
1464
|
if (textTrack.kind == 'captions') {
|
|
1403
|
-
|
|
1465
|
+
// See: https://github.com/shaka-project/shaka-player/issues/6233
|
|
1466
|
+
track.mimeType = 'unknown';
|
|
1404
1467
|
}
|
|
1405
1468
|
if (textTrack.kind == 'subtitles') {
|
|
1406
1469
|
track.mimeType = 'text/vtt';
|