shaka-player 4.4.3 → 4.5.0
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/release-please.yaml +2 -27
- package/CHANGELOG.md +64 -45
- package/README.md +16 -10
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +22 -5
- package/demo/common/assets.js +132 -49
- package/demo/config.js +192 -253
- package/demo/custom.js +39 -98
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +51 -123
- package/demo/search.js +22 -34
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/demo.compiled.debug.js +152 -178
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +152 -178
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +27 -24
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +22 -43
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +22 -43
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +507 -365
- package/dist/shaka-player.compiled.debug.d.ts +507 -365
- package/dist/shaka-player.compiled.debug.externs.js +205 -51
- package/dist/shaka-player.compiled.debug.js +541 -450
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +205 -51
- package/dist/shaka-player.compiled.js +1120 -1066
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +562 -410
- package/dist/shaka-player.ui.debug.d.ts +562 -410
- package/dist/shaka-player.ui.debug.externs.js +226 -51
- package/dist/shaka-player.ui.debug.js +606 -506
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +226 -51
- package/dist/shaka-player.ui.js +1266 -1207
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/ui-customization.md +4 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/manifest.js +10 -5
- package/externs/shaka/manifest_parser.js +7 -1
- package/externs/shaka/offline.js +4 -0
- package/externs/shaka/player.js +12 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +43 -3
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +828 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +75 -12
- package/lib/dash/mpd_utils.js +10 -6
- package/lib/dash/segment_base.js +13 -5
- package/lib/dash/segment_list.js +13 -5
- package/lib/dash/segment_template.js +43 -85
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_parser.js +44 -16
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +22 -11
- package/lib/media/adaptation_set_criteria.js +25 -7
- package/lib/media/media_source_engine.js +215 -27
- package/lib/media/segment_index.js +1 -1
- package/lib/media/segment_reference.js +7 -7
- package/lib/media/streaming_engine.js +33 -18
- package/lib/mss/mss_parser.js +1 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +3 -0
- package/lib/player.js +142 -72
- package/lib/routing/payload.js +5 -1
- package/lib/text/cue.js +15 -0
- package/lib/text/ttml_text_parser.js +17 -0
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +33 -20
- package/lib/transmuxer/h265.js +862 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
- package/lib/transmuxer/ts_transmuxer.js +160 -15
- package/lib/util/error.js +28 -9
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fake_event.js +3 -0
- package/lib/util/mp4_generator.js +4 -4
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +40 -0
- package/lib/util/player_configuration.js +8 -0
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +133 -217
- package/lib/util/ts_parser.js +226 -40
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +2 -1
- package/support.html +0 -1
- package/test/cast/cast_receiver_integration.js +47 -0
- package/test/codec_switching/codec_switching_integration.js +181 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +73 -0
- package/test/dash/dash_parser_live_unit.js +2 -0
- package/test/dash/dash_parser_manifest_unit.js +42 -0
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -0
- package/test/dash/dash_parser_segment_template_unit.js +2 -0
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +2 -0
- package/test/hls/hls_parser_unit.js +8 -6
- package/test/media/adaptation_set_criteria_unit.js +118 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/media_source_engine_unit.js +165 -1
- package/test/media/segment_index_unit.js +4 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/storage_integration.js +1 -4
- package/test/player_unit.js +102 -131
- package/test/routing/walker_unit.js +1 -0
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +8 -2
- package/test/test/util/manifest_generator.js +7 -3
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +7 -4
- package/test/text/ttml_text_parser_unit.js +52 -0
- package/test/text/vtt_text_parser_unit.js +103 -31
- package/test/transmuxer/transmuxer_integration.js +117 -0
- package/test/ui/ui_unit.js +3 -10
- package/test/util/stream_utils_unit.js +208 -74
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +8 -1
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +201 -0
- package/ui/ui.js +5 -2
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -288
- package/demo/locales/source.json +0 -1146
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
package/lib/cea/ts_cea_parser.js
CHANGED
|
@@ -49,10 +49,23 @@ shaka.cea.TsCeaParser = class {
|
|
|
49
49
|
return captionPackets;
|
|
50
50
|
}
|
|
51
51
|
const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
|
|
52
|
+
const codecs = tsParser.getCodecs();
|
|
52
53
|
const videoNalus = tsParser.getVideoNalus();
|
|
54
|
+
const validNaluTypes = [];
|
|
55
|
+
switch (codecs.video) {
|
|
56
|
+
case 'avc':
|
|
57
|
+
validNaluTypes.push(CeaUtils.H264_NALU_TYPE_SEI);
|
|
58
|
+
break;
|
|
59
|
+
case 'hvc':
|
|
60
|
+
validNaluTypes.push(CeaUtils.H265_PREFIX_NALU_TYPE_SEI);
|
|
61
|
+
validNaluTypes.push(CeaUtils.H265_SUFFIX_NALU_TYPE_SEI);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (!validNaluTypes.length) {
|
|
65
|
+
return captionPackets;
|
|
66
|
+
}
|
|
53
67
|
for (const nalu of videoNalus) {
|
|
54
|
-
if (nalu.type
|
|
55
|
-
nalu.time != null) {
|
|
68
|
+
if (validNaluTypes.includes(nalu.type) && nalu.time != null) {
|
|
56
69
|
for (const packet of this.seiProcessor_.process(nalu.data)) {
|
|
57
70
|
captionPackets.push({
|
|
58
71
|
packet: packet,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.config.CodecSwitchingStrategy');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @enum {string}
|
|
11
|
+
* @export
|
|
12
|
+
*/
|
|
13
|
+
shaka.config.CodecSwitchingStrategy = {
|
|
14
|
+
// Allow codec switching which will always involve reloading the
|
|
15
|
+
// `MediaSource`.
|
|
16
|
+
RELOAD: 'reload',
|
|
17
|
+
// Allow codec switching; determine if `SourceBuffer.changeType` is available
|
|
18
|
+
// and attempt to use this first, but fall back to reloading `MediaSource` if
|
|
19
|
+
// not available.
|
|
20
|
+
//
|
|
21
|
+
// Note: Some devices that support `SourceBuffer.changeType` can become stuck
|
|
22
|
+
// in a pause state.
|
|
23
|
+
SMOOTH: 'smooth',
|
|
24
|
+
};
|
|
@@ -39,6 +39,8 @@ shaka.dash.ContentProtection = class {
|
|
|
39
39
|
/** @type {!Array.<shaka.extern.DrmInfo>} */
|
|
40
40
|
let drmInfos = [];
|
|
41
41
|
let parsedNonCenc = [];
|
|
42
|
+
/** @type {?shaka.dash.ContentProtection.Aes128Info} */
|
|
43
|
+
let aes128Info = null;
|
|
42
44
|
|
|
43
45
|
// Get the default key ID; if there are multiple, they must all match.
|
|
44
46
|
const keyIds = new Set(parsed.map((element) => element.keyId));
|
|
@@ -53,6 +55,21 @@ shaka.dash.ContentProtection = class {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
if (!ignoreDrmInfo) {
|
|
58
|
+
const aes128Elements = parsed.filter((elem) => {
|
|
59
|
+
return elem.schemeUri == ContentProtection.Aes128Protection_;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (aes128Elements.length > 1) {
|
|
63
|
+
throw new shaka.util.Error(
|
|
64
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
65
|
+
shaka.util.Error.Category.MANIFEST,
|
|
66
|
+
shaka.util.Error.Code.DASH_CONFLICTING_AES_128);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (aes128Elements.length) {
|
|
70
|
+
aes128Info = ContentProtection.parseAes128_(aes128Elements[0]);
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
// Find the default key ID and init data. Create a new array of all the
|
|
57
74
|
// non-CENC elements.
|
|
58
75
|
parsedNonCenc = parsed.filter((elem) => {
|
|
@@ -62,7 +79,7 @@ shaka.dash.ContentProtection = class {
|
|
|
62
79
|
defaultInit = elem.init || defaultInit;
|
|
63
80
|
return false;
|
|
64
81
|
} else {
|
|
65
|
-
return
|
|
82
|
+
return elem.schemeUri != ContentProtection.Aes128Protection_;
|
|
66
83
|
}
|
|
67
84
|
});
|
|
68
85
|
|
|
@@ -80,7 +97,8 @@ shaka.dash.ContentProtection = class {
|
|
|
80
97
|
|
|
81
98
|
// If there are only CENC element(s) or ignoreDrmInfo flag is set, assume
|
|
82
99
|
// all key-systems are supported.
|
|
83
|
-
if (parsed.length &&
|
|
100
|
+
if (parsed.length && !aes128Info &&
|
|
101
|
+
(ignoreDrmInfo || !parsedNonCenc.length)) {
|
|
84
102
|
drmInfos = [];
|
|
85
103
|
|
|
86
104
|
for (const keySystem of Object.values(keySystemsByURI)) {
|
|
@@ -110,6 +128,7 @@ shaka.dash.ContentProtection = class {
|
|
|
110
128
|
defaultKeyId: defaultKeyId,
|
|
111
129
|
defaultInit: defaultInit,
|
|
112
130
|
drmInfos: drmInfos,
|
|
131
|
+
aes128Info: aes128Info,
|
|
113
132
|
firstRepresentation: true,
|
|
114
133
|
};
|
|
115
134
|
}
|
|
@@ -551,6 +570,79 @@ shaka.dash.ContentProtection = class {
|
|
|
551
570
|
init: (init.length > 0 ? init : null),
|
|
552
571
|
};
|
|
553
572
|
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Parses the given AES-128 ContentProtection element.
|
|
576
|
+
*
|
|
577
|
+
* @param {shaka.dash.ContentProtection.Element} element
|
|
578
|
+
* @return {?shaka.dash.ContentProtection.Aes128Info}
|
|
579
|
+
* @private
|
|
580
|
+
*/
|
|
581
|
+
static parseAes128_(element) {
|
|
582
|
+
// Check if the Web Crypto API is available.
|
|
583
|
+
if (!window.crypto || !window.crypto.subtle) {
|
|
584
|
+
shaka.log.alwaysWarn('Web Crypto API is not available to decrypt ' +
|
|
585
|
+
'AES-128. (Web Crypto only exists in secure origins like https)');
|
|
586
|
+
throw new shaka.util.Error(
|
|
587
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
588
|
+
shaka.util.Error.Category.MANIFEST,
|
|
589
|
+
shaka.util.Error.Code.NO_WEB_CRYPTO_API);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const namespace = 'urn:mpeg:dash:schema:sea:2012';
|
|
593
|
+
const segmentEncryption = shaka.util.XmlUtils.findChildNS(
|
|
594
|
+
element.node, namespace, 'SegmentEncryption');
|
|
595
|
+
|
|
596
|
+
if (!segmentEncryption) {
|
|
597
|
+
throw new shaka.util.Error(
|
|
598
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
599
|
+
shaka.util.Error.Category.MANIFEST,
|
|
600
|
+
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const aesSchemeIdUri = 'urn:mpeg:dash:sea:aes128-cbc:2013';
|
|
604
|
+
const segmentEncryptionSchemeIdUri =
|
|
605
|
+
segmentEncryption.getAttribute('schemeIdUri');
|
|
606
|
+
if (segmentEncryptionSchemeIdUri != aesSchemeIdUri) {
|
|
607
|
+
throw new shaka.util.Error(
|
|
608
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
609
|
+
shaka.util.Error.Category.MANIFEST,
|
|
610
|
+
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const cryptoPeriod = shaka.util.XmlUtils.findChildNS(
|
|
614
|
+
element.node, namespace, 'CryptoPeriod');
|
|
615
|
+
|
|
616
|
+
if (!cryptoPeriod) {
|
|
617
|
+
throw new shaka.util.Error(
|
|
618
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
619
|
+
shaka.util.Error.Category.MANIFEST,
|
|
620
|
+
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const ivHex = cryptoPeriod.getAttribute('IV');
|
|
624
|
+
const keyUri = cryptoPeriod.getAttribute('keyUriTemplate');
|
|
625
|
+
if (!ivHex || !keyUri) {
|
|
626
|
+
throw new shaka.util.Error(
|
|
627
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
628
|
+
shaka.util.Error.Category.MANIFEST,
|
|
629
|
+
shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Exclude 0x at the start of string.
|
|
633
|
+
const iv = shaka.util.Uint8ArrayUtils.fromHex(ivHex.substr(2));
|
|
634
|
+
if (iv.byteLength != 16) {
|
|
635
|
+
throw new shaka.util.Error(
|
|
636
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
637
|
+
shaka.util.Error.Category.MANIFEST,
|
|
638
|
+
shaka.util.Error.Code.AES_128_INVALID_IV_LENGTH);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return {
|
|
642
|
+
keyUri,
|
|
643
|
+
iv,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
554
646
|
};
|
|
555
647
|
|
|
556
648
|
/**
|
|
@@ -584,6 +676,7 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
|
|
|
584
676
|
* defaultKeyId: ?string,
|
|
585
677
|
* defaultInit: Array.<shaka.extern.InitDataOverride>,
|
|
586
678
|
* drmInfos: !Array.<shaka.extern.DrmInfo>,
|
|
679
|
+
* aes128Info: ?shaka.dash.ContentProtection.Aes128Info,
|
|
587
680
|
* firstRepresentation: boolean
|
|
588
681
|
* }}
|
|
589
682
|
*
|
|
@@ -599,6 +692,8 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
|
|
|
599
692
|
* is no default.
|
|
600
693
|
* @property {!Array.<shaka.extern.DrmInfo>} drmInfos
|
|
601
694
|
* The DrmInfo objects.
|
|
695
|
+
* @property {?shaka.dash.ContentProtection.Aes128Info} aes128Info
|
|
696
|
+
* The AES-128 key info.
|
|
602
697
|
* @property {boolean} firstRepresentation
|
|
603
698
|
* True when first parsed; changed to false after the first call to
|
|
604
699
|
* parseKeyIds. This is used to determine if a dummy key-system should be
|
|
@@ -607,6 +702,22 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
|
|
|
607
702
|
*/
|
|
608
703
|
shaka.dash.ContentProtection.Context;
|
|
609
704
|
|
|
705
|
+
/**
|
|
706
|
+
* @typedef {{
|
|
707
|
+
* keyUri: string,
|
|
708
|
+
* iv: !Uint8Array
|
|
709
|
+
* }}
|
|
710
|
+
*
|
|
711
|
+
* @description
|
|
712
|
+
* Contains information about the AES-128 keyUri and IV found at the
|
|
713
|
+
* AdaptationSet level.
|
|
714
|
+
*
|
|
715
|
+
* @property {string} method
|
|
716
|
+
* The keyUri in the manifest.
|
|
717
|
+
* @property {!Uint8Array} iv
|
|
718
|
+
* The IV in the manifest.
|
|
719
|
+
*/
|
|
720
|
+
shaka.dash.ContentProtection.Aes128Info;
|
|
610
721
|
|
|
611
722
|
/**
|
|
612
723
|
* @typedef {{
|
|
@@ -658,6 +769,13 @@ shaka.dash.ContentProtection.licenseUrlParsers_ = new Map()
|
|
|
658
769
|
shaka.dash.ContentProtection.MP4Protection_ =
|
|
659
770
|
'urn:mpeg:dash:mp4protection:2011';
|
|
660
771
|
|
|
772
|
+
/**
|
|
773
|
+
* @const {string}
|
|
774
|
+
* @private
|
|
775
|
+
*/
|
|
776
|
+
shaka.dash.ContentProtection.Aes128Protection_ =
|
|
777
|
+
'urn:mpeg:dash:sea:2012';
|
|
778
|
+
|
|
661
779
|
|
|
662
780
|
/**
|
|
663
781
|
* @const {string}
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -224,12 +224,10 @@ shaka.dash.DashParser = class {
|
|
|
224
224
|
const type = shaka.net.NetworkingEngine.AdvancedRequestType.MPD;
|
|
225
225
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
226
226
|
this.manifestUris_, this.config_.retryParameters);
|
|
227
|
-
const networkingEngine = this.playerInterface_.networkingEngine;
|
|
228
227
|
const startTime = Date.now();
|
|
229
|
-
const operation = networkingEngine.request(requestType, request, {type});
|
|
230
|
-
this.operationManager_.manage(operation);
|
|
231
228
|
|
|
232
|
-
const response = await
|
|
229
|
+
const response = await this.makeNetworkRequest_(
|
|
230
|
+
request, requestType, {type});
|
|
233
231
|
|
|
234
232
|
// Detect calls to stop().
|
|
235
233
|
if (!this.playerInterface_) {
|
|
@@ -1169,6 +1167,9 @@ shaka.dash.DashParser = class {
|
|
|
1169
1167
|
}
|
|
1170
1168
|
}
|
|
1171
1169
|
|
|
1170
|
+
const adaptationId = context.adaptationSet.id ||
|
|
1171
|
+
('__fake__' + this.globalId_++);
|
|
1172
|
+
|
|
1172
1173
|
for (const stream of streams) {
|
|
1173
1174
|
// Some DRM license providers require that we have a default
|
|
1174
1175
|
// key ID from the manifest in the wrapped license request.
|
|
@@ -1178,6 +1179,9 @@ shaka.dash.DashParser = class {
|
|
|
1178
1179
|
new Set([...drmInfo.keyIds, ...stream.keyIds]) :
|
|
1179
1180
|
drmInfo.keyIds || stream.keyIds;
|
|
1180
1181
|
}
|
|
1182
|
+
if (this.config_.dash.enableAudioGroups) {
|
|
1183
|
+
stream.groupId = adaptationId;
|
|
1184
|
+
}
|
|
1181
1185
|
}
|
|
1182
1186
|
|
|
1183
1187
|
const repIds = representations
|
|
@@ -1185,7 +1189,7 @@ shaka.dash.DashParser = class {
|
|
|
1185
1189
|
.filter(shaka.util.Functional.isNotNull);
|
|
1186
1190
|
|
|
1187
1191
|
return {
|
|
1188
|
-
id:
|
|
1192
|
+
id: adaptationId,
|
|
1189
1193
|
contentType: context.adaptationSet.contentType,
|
|
1190
1194
|
language: language,
|
|
1191
1195
|
main: main,
|
|
@@ -1250,21 +1254,61 @@ shaka.dash.DashParser = class {
|
|
|
1250
1254
|
const isImage = contentType == ContentType.IMAGE;
|
|
1251
1255
|
|
|
1252
1256
|
try {
|
|
1257
|
+
/** @type {shaka.extern.aes128Key|undefined} */
|
|
1258
|
+
let aes128Key = undefined;
|
|
1259
|
+
if (contentProtection.aes128Info) {
|
|
1260
|
+
const baseUris = context.representation.baseUris;
|
|
1261
|
+
const uris = shaka.util.ManifestParserUtils.resolveUris(
|
|
1262
|
+
baseUris, [contentProtection.aes128Info.keyUri]);
|
|
1263
|
+
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
|
1264
|
+
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1265
|
+
uris, this.config_.retryParameters);
|
|
1266
|
+
|
|
1267
|
+
aes128Key = {
|
|
1268
|
+
method: 'AES-128',
|
|
1269
|
+
iv: contentProtection.aes128Info.iv,
|
|
1270
|
+
firstMediaSequenceNumber: 0,
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
// Don't download the key object until the segment is parsed, to
|
|
1274
|
+
// avoid a startup delay for long manifests with lots of keys.
|
|
1275
|
+
aes128Key.fetchKey = async () => {
|
|
1276
|
+
const keyResponse =
|
|
1277
|
+
await this.makeNetworkRequest_(request, requestType);
|
|
1278
|
+
|
|
1279
|
+
// keyResponse.status is undefined when URI is
|
|
1280
|
+
// "data:text/plain;base64,"
|
|
1281
|
+
if (!keyResponse.data || keyResponse.data.byteLength != 16) {
|
|
1282
|
+
throw new shaka.util.Error(
|
|
1283
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
1284
|
+
shaka.util.Error.Category.MANIFEST,
|
|
1285
|
+
shaka.util.Error.Code.AES_128_INVALID_KEY_LENGTH);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
const algorithm = {
|
|
1289
|
+
name: 'AES-CBC',
|
|
1290
|
+
};
|
|
1291
|
+
aes128Key.cryptoKey = await window.crypto.subtle.importKey(
|
|
1292
|
+
'raw', keyResponse.data, algorithm, true, ['decrypt']);
|
|
1293
|
+
aes128Key.fetchKey = undefined; // No longer needed.
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1253
1296
|
const requestSegment = (uris, startByte, endByte, isInit) => {
|
|
1254
1297
|
return this.requestSegment_(uris, startByte, endByte, isInit);
|
|
1255
1298
|
};
|
|
1256
1299
|
if (context.representation.segmentBase) {
|
|
1257
1300
|
streamInfo = shaka.dash.SegmentBase.createStreamInfo(
|
|
1258
|
-
context, requestSegment);
|
|
1301
|
+
context, requestSegment, aes128Key);
|
|
1259
1302
|
} else if (context.representation.segmentList) {
|
|
1260
1303
|
streamInfo = shaka.dash.SegmentList.createStreamInfo(
|
|
1261
|
-
context, this.streamMap_);
|
|
1304
|
+
context, this.streamMap_, aes128Key);
|
|
1262
1305
|
} else if (context.representation.segmentTemplate) {
|
|
1263
1306
|
const hasManifest = !!this.manifest_;
|
|
1264
1307
|
|
|
1265
1308
|
streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
|
|
1266
1309
|
context, requestSegment, this.streamMap_, hasManifest,
|
|
1267
|
-
this.config_.dash.initialSegmentLimit, this.periodDurations_
|
|
1310
|
+
this.config_.dash.initialSegmentLimit, this.periodDurations_,
|
|
1311
|
+
aes128Key);
|
|
1268
1312
|
} else {
|
|
1269
1313
|
goog.asserts.assert(isText,
|
|
1270
1314
|
'Must have Segment* with non-text streams.');
|
|
@@ -1363,6 +1407,7 @@ shaka.dash.DashParser = class {
|
|
|
1363
1407
|
stream = {
|
|
1364
1408
|
id: this.globalId_++,
|
|
1365
1409
|
originalId: context.representation.id,
|
|
1410
|
+
groupId: null,
|
|
1366
1411
|
createSegmentIndex: () => Promise.resolve(),
|
|
1367
1412
|
closeSegmentIndex: () => {
|
|
1368
1413
|
if (stream.segmentIndex) {
|
|
@@ -1456,6 +1501,8 @@ shaka.dash.DashParser = class {
|
|
|
1456
1501
|
return;
|
|
1457
1502
|
}
|
|
1458
1503
|
|
|
1504
|
+
this.playerInterface_.onManifestUpdated();
|
|
1505
|
+
|
|
1459
1506
|
this.setUpdateTimer_(updateDelay);
|
|
1460
1507
|
}
|
|
1461
1508
|
|
|
@@ -1929,10 +1976,8 @@ shaka.dash.DashParser = class {
|
|
|
1929
1976
|
endByte,
|
|
1930
1977
|
this.config_.retryParameters);
|
|
1931
1978
|
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
this.operationManager_.manage(operation);
|
|
1935
|
-
const response = await operation.promise;
|
|
1979
|
+
const response = await this.makeNetworkRequest_(
|
|
1980
|
+
request, requestType, {type});
|
|
1936
1981
|
return response.data;
|
|
1937
1982
|
}
|
|
1938
1983
|
|
|
@@ -1958,6 +2003,24 @@ shaka.dash.DashParser = class {
|
|
|
1958
2003
|
// types well.
|
|
1959
2004
|
return mimeType.split('/')[0];
|
|
1960
2005
|
}
|
|
2006
|
+
|
|
2007
|
+
|
|
2008
|
+
/**
|
|
2009
|
+
* Create a networking request. This will manage the request using the
|
|
2010
|
+
* parser's operation manager.
|
|
2011
|
+
*
|
|
2012
|
+
* @param {shaka.extern.Request} request
|
|
2013
|
+
* @param {shaka.net.NetworkingEngine.RequestType} type
|
|
2014
|
+
* @param {shaka.extern.RequestContext=} context
|
|
2015
|
+
* @return {!Promise.<shaka.extern.Response>}
|
|
2016
|
+
* @private
|
|
2017
|
+
*/
|
|
2018
|
+
makeNetworkRequest_(request, type, context) {
|
|
2019
|
+
const op = this.playerInterface_.networkingEngine.request(
|
|
2020
|
+
type, request, context);
|
|
2021
|
+
this.operationManager_.manage(op);
|
|
2022
|
+
return op.promise;
|
|
2023
|
+
}
|
|
1961
2024
|
};
|
|
1962
2025
|
|
|
1963
2026
|
|
package/lib/dash/mpd_utils.js
CHANGED
|
@@ -30,7 +30,7 @@ shaka.dash.MpdUtils = class {
|
|
|
30
30
|
* @param {?string} representationId
|
|
31
31
|
* @param {?number} number
|
|
32
32
|
* @param {?number} bandwidth
|
|
33
|
-
* @param {?number} time
|
|
33
|
+
* @param {?(number|bigint)} time
|
|
34
34
|
* @return {string} A URI string.
|
|
35
35
|
* @see ISO/IEC 23009-1:2014 section 5.3.9.4.4
|
|
36
36
|
*/
|
|
@@ -71,11 +71,15 @@ shaka.dash.MpdUtils = class {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
if (name == 'Time') {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
if (typeof value != 'bigint') {
|
|
75
|
+
goog.asserts.assert(typeof value == 'number',
|
|
76
|
+
'Time value should be a number or bigint!');
|
|
77
|
+
if (Math.abs(value - Math.round(value)) >= 0.2) {
|
|
78
|
+
shaka.log.alwaysWarn(
|
|
79
|
+
'Calculated $Time$ values must be close to integers');
|
|
80
|
+
}
|
|
81
|
+
value = Math.round(value);
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
/** @type {string} */
|
package/lib/dash/segment_base.js
CHANGED
|
@@ -31,9 +31,10 @@ shaka.dash.SegmentBase = class {
|
|
|
31
31
|
*
|
|
32
32
|
* @param {shaka.dash.DashParser.Context} context
|
|
33
33
|
* @param {function(?shaka.dash.DashParser.InheritanceFrame):Element} callback
|
|
34
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
34
35
|
* @return {shaka.media.InitSegmentReference}
|
|
35
36
|
*/
|
|
36
|
-
static createInitSegment(context, callback) {
|
|
37
|
+
static createInitSegment(context, callback, aes128Key) {
|
|
37
38
|
const MpdUtils = shaka.dash.MpdUtils;
|
|
38
39
|
const XmlUtils = shaka.util.XmlUtils;
|
|
39
40
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
@@ -63,7 +64,13 @@ shaka.dash.SegmentBase = class {
|
|
|
63
64
|
const getUris = () => resolvedUris;
|
|
64
65
|
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
65
66
|
return new shaka.media.InitSegmentReference(
|
|
66
|
-
getUris,
|
|
67
|
+
getUris,
|
|
68
|
+
startByte,
|
|
69
|
+
endByte,
|
|
70
|
+
qualityInfo,
|
|
71
|
+
/* timescale= */ null,
|
|
72
|
+
/* segmentData= */ null,
|
|
73
|
+
aes128Key);
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
/**
|
|
@@ -71,9 +78,10 @@ shaka.dash.SegmentBase = class {
|
|
|
71
78
|
*
|
|
72
79
|
* @param {shaka.dash.DashParser.Context} context
|
|
73
80
|
* @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment
|
|
81
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
74
82
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
75
83
|
*/
|
|
76
|
-
static createStreamInfo(context, requestSegment) {
|
|
84
|
+
static createStreamInfo(context, requestSegment, aes128Key) {
|
|
77
85
|
goog.asserts.assert(context.representation.segmentBase,
|
|
78
86
|
'Should only be called with SegmentBase');
|
|
79
87
|
// Since SegmentBase does not need updates, simply treat any call as
|
|
@@ -95,8 +103,8 @@ shaka.dash.SegmentBase = class {
|
|
|
95
103
|
const scaledPresentationTimeOffset =
|
|
96
104
|
(unscaledPresentationTimeOffset / timescale) || 0;
|
|
97
105
|
|
|
98
|
-
const initSegmentReference =
|
|
99
|
-
|
|
106
|
+
const initSegmentReference = SegmentBase.createInitSegment(
|
|
107
|
+
context, SegmentBase.fromInheritance_, aes128Key);
|
|
100
108
|
|
|
101
109
|
// Throws an immediate error if the format is unsupported.
|
|
102
110
|
SegmentBase.checkSegmentIndexRangeSupport_(context, initSegmentReference);
|
package/lib/dash/segment_list.js
CHANGED
|
@@ -31,15 +31,16 @@ shaka.dash.SegmentList = class {
|
|
|
31
31
|
*
|
|
32
32
|
* @param {shaka.dash.DashParser.Context} context
|
|
33
33
|
* @param {!Object.<string, !shaka.extern.Stream>} streamMap
|
|
34
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
34
35
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
35
36
|
*/
|
|
36
|
-
static createStreamInfo(context, streamMap) {
|
|
37
|
+
static createStreamInfo(context, streamMap, aes128Key) {
|
|
37
38
|
goog.asserts.assert(context.representation.segmentList,
|
|
38
39
|
'Should only be called with SegmentList');
|
|
39
40
|
const SegmentList = shaka.dash.SegmentList;
|
|
40
41
|
|
|
41
42
|
const initSegmentReference = shaka.dash.SegmentBase.createInitSegment(
|
|
42
|
-
context, SegmentList.fromInheritance_);
|
|
43
|
+
context, SegmentList.fromInheritance_, aes128Key);
|
|
43
44
|
const info = SegmentList.parseSegmentListInfo_(context);
|
|
44
45
|
|
|
45
46
|
SegmentList.checkSegmentListInfo_(context, info);
|
|
@@ -59,7 +60,7 @@ shaka.dash.SegmentList = class {
|
|
|
59
60
|
const references = SegmentList.createSegmentReferences_(
|
|
60
61
|
context.periodInfo.start, context.periodInfo.duration,
|
|
61
62
|
info.startNumber, context.representation.baseUris, info,
|
|
62
|
-
initSegmentReference);
|
|
63
|
+
initSegmentReference, aes128Key);
|
|
63
64
|
|
|
64
65
|
const isNew = !segmentIndex;
|
|
65
66
|
if (segmentIndex) {
|
|
@@ -197,12 +198,13 @@ shaka.dash.SegmentList = class {
|
|
|
197
198
|
* @param {!Array.<string>} baseUris
|
|
198
199
|
* @param {shaka.dash.SegmentList.SegmentListInfo} info
|
|
199
200
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
201
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
200
202
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
201
203
|
* @private
|
|
202
204
|
*/
|
|
203
205
|
static createSegmentReferences_(
|
|
204
206
|
periodStart, periodDuration, startNumber, baseUris, info,
|
|
205
|
-
initSegmentReference) {
|
|
207
|
+
initSegmentReference, aes128Key) {
|
|
206
208
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
207
209
|
|
|
208
210
|
let max = info.mediaSegments.length;
|
|
@@ -257,7 +259,13 @@ shaka.dash.SegmentList = class {
|
|
|
257
259
|
segment.end,
|
|
258
260
|
initSegmentReference,
|
|
259
261
|
timestampOffset,
|
|
260
|
-
appendWindowStart, appendWindowEnd
|
|
262
|
+
appendWindowStart, appendWindowEnd,
|
|
263
|
+
/* partialReferences= */ [],
|
|
264
|
+
/* tilesLayout= */ '',
|
|
265
|
+
/* tileDuration= */ null,
|
|
266
|
+
/* syncTime= */ null,
|
|
267
|
+
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
268
|
+
aes128Key));
|
|
261
269
|
prevEndTime = endTime;
|
|
262
270
|
}
|
|
263
271
|
|