shaka-player 4.4.1 → 4.4.3
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 +47 -7
- package/.github/workflows/shaka-bot-commands/command-test.sh +1 -1
- package/CHANGELOG.md +43 -0
- package/CONTRIBUTORS +1 -0
- package/demo/common/asset.js +5 -0
- package/demo/common/assets.js +20 -5
- package/demo/common/message_ids.js +1 -1
- package/demo/custom.js +5 -5
- package/demo/locales/en.json +2 -1
- package/demo/locales/source.json +5 -1
- package/demo/main.js +1 -1
- package/demo/search.js +3 -3
- package/dist/demo.compiled.debug.js +75 -73
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +75 -73
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +2 -2
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +38 -36
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +38 -36
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +533 -296
- package/dist/shaka-player.compiled.debug.d.ts +533 -296
- package/dist/shaka-player.compiled.debug.externs.js +308 -1
- package/dist/shaka-player.compiled.debug.js +280 -265
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +308 -1
- package/dist/shaka-player.compiled.js +1037 -1027
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +577 -340
- package/dist/shaka-player.ui.debug.d.ts +577 -340
- package/dist/shaka-player.ui.debug.externs.js +308 -1
- package/dist/shaka-player.ui.debug.js +341 -326
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +308 -1
- package/dist/shaka-player.ui.js +1149 -1141
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +8 -0
- package/docs/tutorials/faq.md +1 -1
- package/docs/tutorials/offline.md +1 -1
- package/externs/shaka/text.js +7 -0
- package/lib/dash/dash_parser.js +4 -1
- package/lib/dash/segment_template.js +3 -0
- package/lib/hls/hls_parser.js +68 -28
- package/lib/media/media_source_engine.js +1 -1
- package/lib/media/segment_index.js +4 -4
- package/lib/media/segment_reference.js +6 -1
- package/lib/media/streaming_engine.js +14 -24
- package/lib/player.js +8 -57
- package/lib/text/cue.js +47 -47
- 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/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 +19 -3
- package/lib/transmuxer/ts_transmuxer.js +44 -43
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/error.js +16 -10
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/platform.js +14 -0
- package/lib/util/player_configuration.js +2 -2
- package/lib/util/stream_utils.js +13 -11
- package/lib/util/ts_parser.js +73 -16
- package/package.json +2 -2
- package/test/dash/dash_parser_manifest_unit.js +5 -0
- package/test/dash/dash_parser_segment_base_unit.js +5 -0
- package/test/dash/dash_parser_segment_list_unit.js +21 -17
- package/test/dash/dash_parser_segment_template_unit.js +47 -0
- package/test/hls/hls_live_unit.js +33 -0
- package/test/hls/hls_parser_unit.js +2 -57
- package/test/test/util/dash_parser_util.js +16 -7
- package/test/text/text_engine_unit.js +4 -2
- package/test/text/ttml_text_parser_unit.js +3 -4
- package/test/text/web_vtt_layout_integration.js +0 -1
- package/test/transmuxer/transmuxer_integration.js +4 -4
- package/test/util/ts_parser_unit.js +1 -1
- package/ui/language_utils.js +0 -15
|
@@ -232,3 +232,11 @@ player.getNetworkingEngine()
|
|
|
232
232
|
player.configure('drm.initDataTransform',
|
|
233
233
|
FairPlayUtils.expressplayInitDataTransform);
|
|
234
234
|
```
|
|
235
|
+
|
|
236
|
+
#### Nagra (legacy Apple Media Keys)
|
|
237
|
+
|
|
238
|
+
For integration with Nagra the following can be used:
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
shaka.polyfill.PatchedMediaKeysApple.install();
|
|
242
|
+
```
|
package/docs/tutorials/faq.md
CHANGED
|
@@ -153,7 +153,7 @@ In other environments, for example Electron, it is appropriate.
|
|
|
153
153
|
In those cases, before Shaka Player loads a manifest, you can register the
|
|
154
154
|
existing http plugin for `file://` requests:
|
|
155
155
|
```js
|
|
156
|
-
shaka.net.NetworkingEngine.registerScheme('file', shaka.net.HttpXHRPlugin);
|
|
156
|
+
shaka.net.NetworkingEngine.registerScheme('file', shaka.net.HttpXHRPlugin.parse);
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
<hr>
|
package/externs/shaka/text.js
CHANGED
package/lib/dash/dash_parser.js
CHANGED
|
@@ -533,7 +533,10 @@ shaka.dash.DashParser = class {
|
|
|
533
533
|
// Just update the variants and text streams, which may change as periods
|
|
534
534
|
// are added or removed.
|
|
535
535
|
this.manifest_.variants = this.periodCombiner_.getVariants();
|
|
536
|
-
|
|
536
|
+
const textStreams = this.periodCombiner_.getTextStreams();
|
|
537
|
+
if (textStreams.length > 0) {
|
|
538
|
+
this.manifest_.textStreams = textStreams;
|
|
539
|
+
}
|
|
537
540
|
this.manifest_.imageStreams = this.periodCombiner_.getImageStreams();
|
|
538
541
|
|
|
539
542
|
// Re-filter the manifest. This will check any configured restrictions on
|
|
@@ -868,6 +868,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
868
868
|
.unscaledPresentationTimeOffset + range.unscaledStart;
|
|
869
869
|
|
|
870
870
|
const createUrisCb = () => {
|
|
871
|
+
if (!this.templateInfo_) {
|
|
872
|
+
return [];
|
|
873
|
+
}
|
|
871
874
|
return shaka.dash.TimelineSegmentIndex
|
|
872
875
|
.createUris_(
|
|
873
876
|
this.templateInfo_.mediaTemplate,
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -787,7 +787,7 @@ shaka.hls.HlsParser = class {
|
|
|
787
787
|
// enough info here to determine the presentation type and duration.
|
|
788
788
|
if (playlist.type == shaka.hls.PlaylistType.MEDIA) {
|
|
789
789
|
if (this.isLive_()) {
|
|
790
|
-
this.changePresentationTimelineToLive_();
|
|
790
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
791
791
|
const delay = this.getUpdatePlaylistDelay_();
|
|
792
792
|
this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay);
|
|
793
793
|
}
|
|
@@ -856,7 +856,7 @@ shaka.hls.HlsParser = class {
|
|
|
856
856
|
|
|
857
857
|
let segmentUris = [firstSegment.absoluteUri];
|
|
858
858
|
const initSegmentRef = this.getInitSegmentReference_(
|
|
859
|
-
playlist
|
|
859
|
+
playlist, firstSegment.tags, new Map());
|
|
860
860
|
if (initSegmentRef) {
|
|
861
861
|
segmentUris = initSegmentRef.getUris();
|
|
862
862
|
}
|
|
@@ -900,6 +900,7 @@ shaka.hls.HlsParser = class {
|
|
|
900
900
|
const uint8ArrayData = shaka.util.BufferUtils.toUint8(response.data);
|
|
901
901
|
const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
|
|
902
902
|
const tsCodecs = tsParser.getCodecs();
|
|
903
|
+
const videoInfo = tsParser.getVideoInfo();
|
|
903
904
|
const codecs = [];
|
|
904
905
|
let hasAudio = false;
|
|
905
906
|
let hasVideo = false;
|
|
@@ -923,7 +924,11 @@ shaka.hls.HlsParser = class {
|
|
|
923
924
|
}
|
|
924
925
|
switch (tsCodecs.video) {
|
|
925
926
|
case 'avc':
|
|
926
|
-
|
|
927
|
+
if (videoInfo.codec) {
|
|
928
|
+
codecs.push(videoInfo.codec);
|
|
929
|
+
} else {
|
|
930
|
+
codecs.push('avc1.42E01E');
|
|
931
|
+
}
|
|
927
932
|
hasVideo = true;
|
|
928
933
|
break;
|
|
929
934
|
case 'hvc':
|
|
@@ -935,14 +940,13 @@ shaka.hls.HlsParser = class {
|
|
|
935
940
|
return null;
|
|
936
941
|
}
|
|
937
942
|
const onlyAudio = hasAudio && !hasVideo;
|
|
938
|
-
const videoResolution = tsParser.getVideoResolution();
|
|
939
943
|
return {
|
|
940
944
|
type: onlyAudio ? 'audio' : 'video',
|
|
941
945
|
mimeType: 'video/mp2t',
|
|
942
946
|
codecs: codecs.join(', '),
|
|
943
947
|
language: null,
|
|
944
|
-
height:
|
|
945
|
-
width:
|
|
948
|
+
height: videoInfo.height,
|
|
949
|
+
width: videoInfo.width,
|
|
946
950
|
channelCount: null,
|
|
947
951
|
sampleRate: null,
|
|
948
952
|
};
|
|
@@ -1777,7 +1781,13 @@ shaka.hls.HlsParser = class {
|
|
|
1777
1781
|
goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
|
|
1778
1782
|
'Should only be called on media tags!');
|
|
1779
1783
|
const languageValue = tag.getAttributeValue('LANGUAGE');
|
|
1780
|
-
|
|
1784
|
+
let language = this.getLanguage_(languageValue);
|
|
1785
|
+
if (!languageValue) {
|
|
1786
|
+
const nameValue = tag.getAttributeValue('NAME');
|
|
1787
|
+
if (nameValue) {
|
|
1788
|
+
language = nameValue;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1781
1791
|
|
|
1782
1792
|
// The GROUP-ID value is a quoted-string that specifies the group to which
|
|
1783
1793
|
// the Rendition belongs.
|
|
@@ -1786,7 +1796,9 @@ shaka.hls.HlsParser = class {
|
|
|
1786
1796
|
// The value of INSTREAM-ID is a quoted-string that specifies a Rendition
|
|
1787
1797
|
// within the segments in the Media Playlist. This attribute is REQUIRED
|
|
1788
1798
|
// if the TYPE attribute is CLOSED-CAPTIONS.
|
|
1789
|
-
|
|
1799
|
+
// We need replace SERVICE string by our internal svc string.
|
|
1800
|
+
const instreamId = tag.getRequiredAttrValue('INSTREAM-ID')
|
|
1801
|
+
.replace('SERVICE', 'svc');
|
|
1790
1802
|
if (!this.groupIdToClosedCaptionsMap_.get(groupId)) {
|
|
1791
1803
|
this.groupIdToClosedCaptionsMap_.set(groupId, new Map());
|
|
1792
1804
|
}
|
|
@@ -2050,7 +2062,7 @@ shaka.hls.HlsParser = class {
|
|
|
2050
2062
|
if (this.isLive_() && !wasLive) {
|
|
2051
2063
|
// Now that we know that the presentation is live, convert the timeline
|
|
2052
2064
|
// to live.
|
|
2053
|
-
this.changePresentationTimelineToLive_();
|
|
2065
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
2054
2066
|
}
|
|
2055
2067
|
|
|
2056
2068
|
// Copy values from the real stream info to our initial one.
|
|
@@ -2766,9 +2778,10 @@ shaka.hls.HlsParser = class {
|
|
|
2766
2778
|
|
|
2767
2779
|
|
|
2768
2780
|
/**
|
|
2781
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2769
2782
|
* @private
|
|
2770
2783
|
*/
|
|
2771
|
-
changePresentationTimelineToLive_() {
|
|
2784
|
+
changePresentationTimelineToLive_(playlist) {
|
|
2772
2785
|
// The live edge will be calculated from segments, so we don't need to
|
|
2773
2786
|
// set a presentation start time. We will assert later that this is
|
|
2774
2787
|
// working as expected.
|
|
@@ -2791,8 +2804,12 @@ shaka.hls.HlsParser = class {
|
|
|
2791
2804
|
} else if (this.presentationDelay_) {
|
|
2792
2805
|
presentationDelay = this.presentationDelay_;
|
|
2793
2806
|
} else {
|
|
2794
|
-
const
|
|
2795
|
-
|
|
2807
|
+
const playlistSegments = playlist.segments.length;
|
|
2808
|
+
let delaySegments = this.config_.hls.liveSegmentsDelay;
|
|
2809
|
+
if (delaySegments > (playlistSegments - 2)) {
|
|
2810
|
+
delaySegments = Math.max(1, playlistSegments - 2);
|
|
2811
|
+
}
|
|
2812
|
+
presentationDelay = this.maxTargetDuration_ * delaySegments;
|
|
2796
2813
|
}
|
|
2797
2814
|
|
|
2798
2815
|
this.presentationTimeline_.setPresentationStartTime(0);
|
|
@@ -2802,13 +2819,13 @@ shaka.hls.HlsParser = class {
|
|
|
2802
2819
|
|
|
2803
2820
|
/**
|
|
2804
2821
|
* Get the InitSegmentReference for a segment if it has a EXT-X-MAP tag.
|
|
2805
|
-
* @param {
|
|
2822
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2806
2823
|
* @param {!Array.<!shaka.hls.Tag>} tags Segment tags
|
|
2807
2824
|
* @param {!Map.<string, string>} variables
|
|
2808
2825
|
* @return {shaka.media.InitSegmentReference}
|
|
2809
2826
|
* @private
|
|
2810
2827
|
*/
|
|
2811
|
-
getInitSegmentReference_(
|
|
2828
|
+
getInitSegmentReference_(playlist, tags, variables) {
|
|
2812
2829
|
/** @type {?shaka.hls.Tag} */
|
|
2813
2830
|
const mapTag = shaka.hls.Utils.getFirstTagWithName(tags, 'EXT-X-MAP');
|
|
2814
2831
|
|
|
@@ -2819,7 +2836,7 @@ shaka.hls.HlsParser = class {
|
|
|
2819
2836
|
const verbatimInitSegmentUri = mapTag.getRequiredAttrValue('URI');
|
|
2820
2837
|
const absoluteInitSegmentUri = this.variableSubstitution_(
|
|
2821
2838
|
shaka.hls.Utils.constructAbsoluteUri(
|
|
2822
|
-
|
|
2839
|
+
playlist.absoluteUri, verbatimInitSegmentUri),
|
|
2823
2840
|
variables);
|
|
2824
2841
|
|
|
2825
2842
|
const mapTagKey = [
|
|
@@ -2827,8 +2844,18 @@ shaka.hls.HlsParser = class {
|
|
|
2827
2844
|
mapTag.getAttributeValue('BYTERANGE', ''),
|
|
2828
2845
|
].join('-');
|
|
2829
2846
|
if (!this.mapTagToInitSegmentRefMap_.has(mapTagKey)) {
|
|
2847
|
+
/** @type {shaka.extern.HlsAes128Key|undefined} */
|
|
2848
|
+
let aes128Key = undefined;
|
|
2849
|
+
for (const tag of tags) {
|
|
2850
|
+
if (tag.name == 'EXT-X-KEY') {
|
|
2851
|
+
if (tag.getRequiredAttrValue('METHOD') == 'AES-128' &&
|
|
2852
|
+
tag.id < mapTag.id) {
|
|
2853
|
+
aes128Key = this.parseAES128DrmTag_(tag, playlist);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2830
2857
|
const initSegmentRef = this.createInitSegmentReference_(
|
|
2831
|
-
absoluteInitSegmentUri, mapTag);
|
|
2858
|
+
absoluteInitSegmentUri, mapTag, aes128Key);
|
|
2832
2859
|
this.mapTagToInitSegmentRefMap_.set(mapTagKey, initSegmentRef);
|
|
2833
2860
|
}
|
|
2834
2861
|
return this.mapTagToInitSegmentRefMap_.get(mapTagKey);
|
|
@@ -2839,10 +2866,11 @@ shaka.hls.HlsParser = class {
|
|
|
2839
2866
|
* playlist.
|
|
2840
2867
|
* @param {string} absoluteInitSegmentUri
|
|
2841
2868
|
* @param {!shaka.hls.Tag} mapTag EXT-X-MAP
|
|
2869
|
+
* @param {shaka.extern.HlsAes128Key=} aes128Key
|
|
2842
2870
|
* @return {!shaka.media.InitSegmentReference}
|
|
2843
2871
|
* @private
|
|
2844
2872
|
*/
|
|
2845
|
-
createInitSegmentReference_(absoluteInitSegmentUri, mapTag) {
|
|
2873
|
+
createInitSegmentReference_(absoluteInitSegmentUri, mapTag, aes128Key) {
|
|
2846
2874
|
let startByte = 0;
|
|
2847
2875
|
let endByte = null;
|
|
2848
2876
|
const byterange = mapTag.getAttributeValue('BYTERANGE');
|
|
@@ -2853,12 +2881,26 @@ shaka.hls.HlsParser = class {
|
|
|
2853
2881
|
const byteLength = Number(blocks[0]);
|
|
2854
2882
|
startByte = Number(blocks[1]);
|
|
2855
2883
|
endByte = startByte + byteLength - 1;
|
|
2884
|
+
|
|
2885
|
+
if (aes128Key) {
|
|
2886
|
+
// MAP segment encrypted with method 'AES-128', when served with
|
|
2887
|
+
// HTTP Range, has the unencrypted size specified in the range.
|
|
2888
|
+
// See: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
|
2889
|
+
const length = (endByte + 1) - startByte;
|
|
2890
|
+
if (length % 16) {
|
|
2891
|
+
endByte += (16 - (length % 16));
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2856
2894
|
}
|
|
2857
2895
|
|
|
2858
2896
|
const initSegmentRef = new shaka.media.InitSegmentReference(
|
|
2859
2897
|
() => [absoluteInitSegmentUri],
|
|
2860
2898
|
startByte,
|
|
2861
|
-
endByte
|
|
2899
|
+
endByte,
|
|
2900
|
+
/* mediaQuality= */ null,
|
|
2901
|
+
/* timescale= */ null,
|
|
2902
|
+
/* segmentData= */ null,
|
|
2903
|
+
aes128Key);
|
|
2862
2904
|
return initSegmentRef;
|
|
2863
2905
|
}
|
|
2864
2906
|
|
|
@@ -2873,15 +2915,13 @@ shaka.hls.HlsParser = class {
|
|
|
2873
2915
|
* @param {string} absoluteMediaPlaylistUri
|
|
2874
2916
|
* @param {string} type
|
|
2875
2917
|
* @param {string} mimeType
|
|
2876
|
-
* @param {number} timestampOffset
|
|
2877
2918
|
* @param {shaka.extern.HlsAes128Key=} hlsAes128Key
|
|
2878
2919
|
* @return {shaka.media.SegmentReference}
|
|
2879
2920
|
* @private
|
|
2880
2921
|
*/
|
|
2881
2922
|
createSegmentReference_(
|
|
2882
2923
|
initSegmentReference, previousReference, hlsSegment, startTime,
|
|
2883
|
-
variables, absoluteMediaPlaylistUri, type, mimeType,
|
|
2884
|
-
hlsAes128Key) {
|
|
2924
|
+
variables, absoluteMediaPlaylistUri, type, mimeType, hlsAes128Key) {
|
|
2885
2925
|
const tags = hlsSegment.tags;
|
|
2886
2926
|
const extinfTag =
|
|
2887
2927
|
shaka.hls.Utils.getFirstTagWithName(tags, 'EXTINF');
|
|
@@ -3018,7 +3058,7 @@ shaka.hls.HlsParser = class {
|
|
|
3018
3058
|
pStartByte,
|
|
3019
3059
|
pEndByte,
|
|
3020
3060
|
initSegmentReference,
|
|
3021
|
-
/* timestampOffset= */ 0,
|
|
3061
|
+
/* timestampOffset= */ 0,
|
|
3022
3062
|
/* appendWindowStart= */ 0,
|
|
3023
3063
|
/* appendWindowEnd= */ Infinity,
|
|
3024
3064
|
/* partialReferences= */ [],
|
|
@@ -3063,8 +3103,11 @@ shaka.hls.HlsParser = class {
|
|
|
3063
3103
|
return null;
|
|
3064
3104
|
}
|
|
3065
3105
|
endTime = startTime + duration;
|
|
3066
|
-
} else {
|
|
3106
|
+
} else if (partialSegmentRefs.length) {
|
|
3067
3107
|
endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
|
|
3108
|
+
} else {
|
|
3109
|
+
// Skip segments without duration and without partialsegments
|
|
3110
|
+
return null;
|
|
3068
3111
|
}
|
|
3069
3112
|
|
|
3070
3113
|
if (segmentWithByteRangeOptimization) {
|
|
@@ -3127,7 +3170,7 @@ shaka.hls.HlsParser = class {
|
|
|
3127
3170
|
startByte,
|
|
3128
3171
|
endByte,
|
|
3129
3172
|
initSegmentReference,
|
|
3130
|
-
timestampOffset
|
|
3173
|
+
/* timestampOffset= */ 0,
|
|
3131
3174
|
/* appendWindowStart= */ 0,
|
|
3132
3175
|
/* appendWindowEnd= */ Infinity,
|
|
3133
3176
|
partialSegmentRefs,
|
|
@@ -3226,7 +3269,6 @@ shaka.hls.HlsParser = class {
|
|
|
3226
3269
|
const references = [];
|
|
3227
3270
|
|
|
3228
3271
|
let previousReference = null;
|
|
3229
|
-
let lastDiscontinuityStartTime = firstStartTime;
|
|
3230
3272
|
|
|
3231
3273
|
/** @type {!Array.<{bitrate: number, duration: number}>} */
|
|
3232
3274
|
const bitrates = [];
|
|
@@ -3241,7 +3283,6 @@ shaka.hls.HlsParser = class {
|
|
|
3241
3283
|
item.tags, 'EXT-X-DISCONTINUITY');
|
|
3242
3284
|
if (discontinuityTag) {
|
|
3243
3285
|
discontinuitySequence++;
|
|
3244
|
-
lastDiscontinuityStartTime = startTime;
|
|
3245
3286
|
}
|
|
3246
3287
|
|
|
3247
3288
|
// Apply new AES-128 tags as you see them, keeping a running total.
|
|
@@ -3257,7 +3298,7 @@ shaka.hls.HlsParser = class {
|
|
|
3257
3298
|
|
|
3258
3299
|
mediaSequenceToStartTime.set(position, startTime);
|
|
3259
3300
|
|
|
3260
|
-
initSegmentRef = this.getInitSegmentReference_(playlist
|
|
3301
|
+
initSegmentRef = this.getInitSegmentReference_(playlist,
|
|
3261
3302
|
item.tags, variables);
|
|
3262
3303
|
|
|
3263
3304
|
// If the stream is low latency and the user has not configured the
|
|
@@ -3281,7 +3322,6 @@ shaka.hls.HlsParser = class {
|
|
|
3281
3322
|
playlist.absoluteUri,
|
|
3282
3323
|
type,
|
|
3283
3324
|
mimeType,
|
|
3284
|
-
lastDiscontinuityStartTime,
|
|
3285
3325
|
hlsAes128Key);
|
|
3286
3326
|
|
|
3287
3327
|
if (reference) {
|
|
@@ -492,7 +492,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
492
492
|
this.textEngine_ = new shaka.text.TextEngine(this.textDisplayer_);
|
|
493
493
|
}
|
|
494
494
|
this.textEngine_.initParser(mimeType, sequenceMode,
|
|
495
|
-
external || this.segmentRelativeVttTiming_);
|
|
495
|
+
external || this.segmentRelativeVttTiming_, this.manifestType_);
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
/**
|
|
@@ -708,7 +708,7 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
numPassedInEarlierIndexes += index.numEvicted_ +
|
|
711
|
-
index.
|
|
711
|
+
index.getNumReferences();
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
return null;
|
|
@@ -732,9 +732,9 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
732
732
|
return reference;
|
|
733
733
|
}
|
|
734
734
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
sawSegments = sawSegments ||
|
|
735
|
+
const num = index.getNumReferences();
|
|
736
|
+
numPassedInEarlierIndexes += index.numEvicted_ + num;
|
|
737
|
+
sawSegments = sawSegments || num != 0;
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
return null;
|
|
@@ -32,9 +32,11 @@ shaka.media.InitSegmentReference = class {
|
|
|
32
32
|
* the quality of the media associated with this init segment.
|
|
33
33
|
* @param {(null|number)=} timescale
|
|
34
34
|
* @param {(null|BufferSource)=} segmentData
|
|
35
|
+
* @param {?shaka.extern.HlsAes128Key=} aes128Key
|
|
36
|
+
* The segment's AES-128-CBC full segment encryption key and iv.
|
|
35
37
|
*/
|
|
36
38
|
constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
|
|
37
|
-
segmentData = null) {
|
|
39
|
+
segmentData = null, aes128Key = null) {
|
|
38
40
|
/** @type {function():!Array.<string>} */
|
|
39
41
|
this.getUris = uris;
|
|
40
42
|
|
|
@@ -52,6 +54,9 @@ shaka.media.InitSegmentReference = class {
|
|
|
52
54
|
|
|
53
55
|
/** @type {BufferSource|null} */
|
|
54
56
|
this.segmentData = segmentData;
|
|
57
|
+
|
|
58
|
+
/** @type {?shaka.extern.HlsAes128Key} */
|
|
59
|
+
this.hlsAes128Key = aes128Key;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
/**
|
|
@@ -1409,15 +1409,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1409
1409
|
'ReadableStream is not supported by the browser.');
|
|
1410
1410
|
}
|
|
1411
1411
|
const fetchSegment = this.fetch_(mediaState, reference);
|
|
1412
|
-
|
|
1412
|
+
const result = await fetchSegment;
|
|
1413
1413
|
this.destroyer_.ensureNotDestroyed();
|
|
1414
1414
|
if (this.fatalError_) {
|
|
1415
1415
|
return;
|
|
1416
1416
|
}
|
|
1417
|
-
if (reference.hlsAes128Key) {
|
|
1418
|
-
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
|
|
1419
|
-
result = await this.aes128Decrypt_(result, reference, iter);
|
|
1420
|
-
}
|
|
1421
1417
|
this.destroyer_.ensureNotDestroyed();
|
|
1422
1418
|
|
|
1423
1419
|
// If the text stream gets switched between fetch_() and append_(), the
|
|
@@ -1502,13 +1498,13 @@ shaka.media.StreamingEngine = class {
|
|
|
1502
1498
|
|
|
1503
1499
|
/**
|
|
1504
1500
|
* @param {!BufferSource} rawResult
|
|
1505
|
-
* @param {
|
|
1501
|
+
* @param {shaka.extern.HlsAes128Key} aes128Key
|
|
1506
1502
|
* @param {!shaka.media.SegmentIterator} iter
|
|
1507
1503
|
* @return {!Promise.<!BufferSource>} finalResult
|
|
1508
1504
|
* @private
|
|
1509
1505
|
*/
|
|
1510
|
-
async aes128Decrypt_(rawResult,
|
|
1511
|
-
const key =
|
|
1506
|
+
async aes128Decrypt_(rawResult, aes128Key, iter) {
|
|
1507
|
+
const key = aes128Key;
|
|
1512
1508
|
if (!key.cryptoKey) {
|
|
1513
1509
|
goog.asserts.assert(key.fetchKey, 'If AES-128 cryptoKey was not ' +
|
|
1514
1510
|
'preloaded, fetchKey function should be provided');
|
|
@@ -1818,10 +1814,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1818
1814
|
}
|
|
1819
1815
|
}
|
|
1820
1816
|
|
|
1821
|
-
const lastDiscontinuitySequence =
|
|
1822
|
-
mediaState.lastSegmentReference ?
|
|
1823
|
-
mediaState.lastSegmentReference.discontinuitySequence : null;
|
|
1824
1817
|
if (this.manifest_.sequenceMode) {
|
|
1818
|
+
const lastDiscontinuitySequence =
|
|
1819
|
+
mediaState.lastSegmentReference ?
|
|
1820
|
+
mediaState.lastSegmentReference.discontinuitySequence : null;
|
|
1825
1821
|
// Across discontinuity bounds, we should resync timestamps for
|
|
1826
1822
|
// sequence mode playbacks. The next segment appended should
|
|
1827
1823
|
// land at its theoretical timestamp from the segment index.
|
|
@@ -1831,18 +1827,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1831
1827
|
operations.push(this.playerInterface_.mediaSourceEngine.resync(
|
|
1832
1828
|
mediaState.type, reference.startTime));
|
|
1833
1829
|
}
|
|
1834
|
-
} else if (this.manifest_.ignoreManifestTimestampsInSegmentsMode) {
|
|
1835
|
-
// In segments mode, we need to resync to set the timestampOffset
|
|
1836
|
-
// to the start of the current discontinuity sequence. This is
|
|
1837
|
-
// because individual discontinuity sequences may have internal
|
|
1838
|
-
// timestamps that overlap, so we adjust the timestampOffset to avoid
|
|
1839
|
-
// having the SourceBuffer get overwritten.
|
|
1840
|
-
if (reference.discontinuitySequence != lastDiscontinuitySequence) {
|
|
1841
|
-
operations.push(
|
|
1842
|
-
this.playerInterface_.mediaSourceEngine.resync(
|
|
1843
|
-
mediaState.type,
|
|
1844
|
-
reference.timestampOffset));
|
|
1845
|
-
}
|
|
1846
1830
|
}
|
|
1847
1831
|
|
|
1848
1832
|
await Promise.all(operations);
|
|
@@ -2200,7 +2184,13 @@ shaka.media.StreamingEngine = class {
|
|
|
2200
2184
|
mediaState.operation = op;
|
|
2201
2185
|
const response = await op.promise;
|
|
2202
2186
|
mediaState.operation = null;
|
|
2203
|
-
|
|
2187
|
+
let result = response.data;
|
|
2188
|
+
if (reference.hlsAes128Key) {
|
|
2189
|
+
const iter = mediaState.segmentIterator;
|
|
2190
|
+
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
|
|
2191
|
+
result = await this.aes128Decrypt_(result, reference.hlsAes128Key, iter);
|
|
2192
|
+
}
|
|
2193
|
+
return result;
|
|
2204
2194
|
}
|
|
2205
2195
|
|
|
2206
2196
|
/**
|
package/lib/player.js
CHANGED
|
@@ -2663,16 +2663,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2663
2663
|
return;
|
|
2664
2664
|
}
|
|
2665
2665
|
|
|
2666
|
-
this.selectAudioLanguage(preferredAudioLanguage);
|
|
2667
|
-
|
|
2668
2666
|
const preferredVariantRole = this.config_.preferredVariantRole;
|
|
2669
|
-
|
|
2670
|
-
// If the user has not selected a role preference, the previous match is
|
|
2671
|
-
// selected.
|
|
2672
|
-
if (preferredVariantRole == '') {
|
|
2673
|
-
return;
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
2667
|
this.selectAudioLanguage(preferredAudioLanguage, preferredVariantRole);
|
|
2677
2668
|
}
|
|
2678
2669
|
|
|
@@ -2683,7 +2674,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2683
2674
|
*/
|
|
2684
2675
|
setupPreferredTextOnSrc_() {
|
|
2685
2676
|
const preferredTextLanguage = this.config_.preferredTextLanguage;
|
|
2686
|
-
const preferForcedSubs = this.config_.preferForcedSubs;
|
|
2687
2677
|
|
|
2688
2678
|
// If the user has not selected a preference, the browser preference is
|
|
2689
2679
|
// left.
|
|
@@ -2691,16 +2681,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2691
2681
|
return;
|
|
2692
2682
|
}
|
|
2693
2683
|
|
|
2694
|
-
this.
|
|
2695
|
-
|
|
2684
|
+
const preferForcedSubs = this.config_.preferForcedSubs;
|
|
2696
2685
|
const preferredTextRole = this.config_.preferredTextRole;
|
|
2697
2686
|
|
|
2698
|
-
// If the user has not selected a role preference, the previous match is
|
|
2699
|
-
// selected.
|
|
2700
|
-
if (preferredTextRole == '') {
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
|
|
2704
2687
|
this.selectTextLanguage(preferredTextLanguage, preferredTextRole,
|
|
2705
2688
|
preferForcedSubs);
|
|
2706
2689
|
}
|
|
@@ -4199,8 +4182,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4199
4182
|
* @export
|
|
4200
4183
|
*/
|
|
4201
4184
|
selectAudioLanguage(language, role, channelsCount = 0, safeMargin = 0) {
|
|
4202
|
-
const LanguageUtils = shaka.util.LanguageUtils;
|
|
4203
|
-
|
|
4204
4185
|
if (this.manifest_ && this.playhead_) {
|
|
4205
4186
|
this.currentAdaptationSetCriteria_ =
|
|
4206
4187
|
new shaka.media.PreferenceBasedCriteria(language, role || '',
|
|
@@ -4238,33 +4219,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4238
4219
|
// If we haven't switched yet, just use ABR to find a new track.
|
|
4239
4220
|
this.chooseVariantAndSwitch_();
|
|
4240
4221
|
} else if (this.video_ && this.video_.audioTracks) {
|
|
4241
|
-
const
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
let languageAndRoleMatch = null;
|
|
4246
|
-
|
|
4247
|
-
for (const audioTrack of audioTracks) {
|
|
4248
|
-
const track = shaka.util.StreamUtils.html5AudioTrackToTrack(audioTrack);
|
|
4249
|
-
|
|
4250
|
-
if (LanguageUtils.normalize(track.language) == selectedLanguage) {
|
|
4251
|
-
languageMatch = audioTrack;
|
|
4252
|
-
|
|
4253
|
-
if (role) {
|
|
4254
|
-
if (track.roles.includes(role)) {
|
|
4255
|
-
languageAndRoleMatch = audioTrack;
|
|
4256
|
-
}
|
|
4257
|
-
} else { // no role
|
|
4258
|
-
if (track.roles.length == 0) {
|
|
4259
|
-
languageAndRoleMatch = audioTrack;
|
|
4260
|
-
}
|
|
4261
|
-
}
|
|
4262
|
-
}
|
|
4263
|
-
}
|
|
4264
|
-
if (languageAndRoleMatch) {
|
|
4265
|
-
this.switchHtml5Track_(languageAndRoleMatch);
|
|
4266
|
-
} else if (languageMatch) {
|
|
4267
|
-
this.switchHtml5Track_(languageMatch);
|
|
4222
|
+
const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole(
|
|
4223
|
+
this.getVariantTracks(), language, role || '', false)[0];
|
|
4224
|
+
if (track) {
|
|
4225
|
+
this.selectVariantTrack(track);
|
|
4268
4226
|
}
|
|
4269
4227
|
}
|
|
4270
4228
|
}
|
|
@@ -4280,8 +4238,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4280
4238
|
* @export
|
|
4281
4239
|
*/
|
|
4282
4240
|
selectTextLanguage(language, role, forced = false) {
|
|
4283
|
-
const LanguageUtils = shaka.util.LanguageUtils;
|
|
4284
|
-
|
|
4285
4241
|
if (this.manifest_ && this.playhead_) {
|
|
4286
4242
|
this.currentTextLanguage_ = language;
|
|
4287
4243
|
this.currentTextRole_ = role || '';
|
|
@@ -4302,13 +4258,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4302
4258
|
}
|
|
4303
4259
|
}
|
|
4304
4260
|
} else {
|
|
4305
|
-
const
|
|
4306
|
-
|
|
4307
|
-
const track = this.getTextTracks().find((t) => {
|
|
4308
|
-
return LanguageUtils.normalize(t.language) == selectedLanguage &&
|
|
4309
|
-
(!role || t.roles.includes(role)) && t.forced == forced;
|
|
4310
|
-
});
|
|
4311
|
-
|
|
4261
|
+
const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole(
|
|
4262
|
+
this.getTextTracks(), language, role || '', forced)[0];
|
|
4312
4263
|
if (track) {
|
|
4313
4264
|
this.selectTextTrack(track);
|
|
4314
4265
|
}
|
|
@@ -7224,7 +7175,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7224
7175
|
* @define {string} A version number taken from git at compile time.
|
|
7225
7176
|
* @export
|
|
7226
7177
|
*/
|
|
7227
|
-
shaka.Player.version = 'v4.4.
|
|
7178
|
+
shaka.Player.version = 'v4.4.3-uncompiled';
|
|
7228
7179
|
|
|
7229
7180
|
// Initialize the deprecation system using the version string we just set
|
|
7230
7181
|
// on the player.
|