shaka-player 4.3.0 → 4.3.1
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/build-and-test.yaml +7 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTORS +1 -0
- package/conditional/dummy_cast_proxy.js +120 -0
- package/dist/demo.compiled.debug.js +104 -110
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +104 -110
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +8 -6
- package/dist/locales.js +28 -28
- package/dist/receiver.compiled.debug.js +54 -60
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +54 -60
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +19 -2
- package/dist/shaka-player.compiled.debug.d.ts +19 -2
- package/dist/shaka-player.compiled.debug.externs.js +102 -80
- package/dist/shaka-player.compiled.debug.js +632 -628
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +102 -80
- package/dist/shaka-player.compiled.js +903 -900
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +19 -2
- package/dist/shaka-player.ui.debug.d.ts +19 -2
- package/dist/shaka-player.ui.debug.externs.js +102 -80
- package/dist/shaka-player.ui.debug.js +681 -678
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +102 -80
- package/dist/shaka-player.ui.js +1033 -1031
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/welcome.md +2 -2
- package/externs/shaka/mp4_parser.js +3 -0
- package/externs/shaka/player.js +2 -1
- package/lib/cea/cea708_window.js +2 -2
- package/lib/cea/mp4_cea_parser.js +37 -16
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +37 -19
- package/lib/media/content_workarounds.js +12 -0
- package/lib/media/media_source_capabilities.js +36 -0
- package/lib/media/media_source_engine.js +12 -7
- package/lib/media/transmuxer.js +6 -4
- package/lib/player.js +5 -5
- package/lib/polyfill/abort_controller.js +143 -0
- package/lib/polyfill/media_capabilities.js +65 -11
- package/lib/polyfill/patchedmediakeys_apple.js +33 -28
- package/lib/text/ttml_text_parser.js +32 -7
- package/lib/text/ui_text_displayer.js +17 -0
- package/lib/util/mp4_box_parsers.js +24 -0
- package/lib/util/mp4_parser.js +35 -0
- package/lib/util/player_configuration.js +10 -3
- package/lib/util/stream_utils.js +35 -13
- package/package.json +4 -4
- package/shaka-player.uncompiled.js +1 -0
- package/test/ads/ad_manager_unit.js +3 -1
- package/test/dash/dash_parser_manifest_unit.js +1 -0
- package/test/hls/hls_parser_unit.js +132 -0
- package/test/media/drm_engine_unit.js +11 -1
- package/test/media/media_source_engine_integration.js +78 -2
- package/test/polyfill/media_capabilities_unit.js +259 -0
- package/test/polyfill/patchedmediakeys_apple_unit.js +6 -0
- package/test/test/util/stream_generator.js +212 -8
- package/test/test/util/test_scheme.js +4 -3
- package/test/test/util/util.js +3 -2
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/ttml_text_parser_unit.js +119 -86
- package/test/text/ui_text_displayer_unit.js +76 -0
- package/test/util/stream_utils_unit.js +18 -0
- package/test/util/xml_utils_unit.js +6 -1
- package/third_party/closure-uri/uri.js +1 -1
- package/ui/controls.js +45 -36
|
@@ -29,8 +29,8 @@ You can build Shaka on Linux, Windows, or Mac.
|
|
|
29
29
|
To get the sources and compile the library, you will need:
|
|
30
30
|
* {@link https://git-scm.com/downloads Git v1.9+}
|
|
31
31
|
* {@link https://www.python.org/downloads/ Python v2.7 or v3.5+}
|
|
32
|
-
* {@link https://java.com/en/download/ Java Runtime Environment
|
|
33
|
-
* {@link https://nodejs.org/en/download/ NodeJS
|
|
32
|
+
* {@link https://java.com/en/download/ Java Runtime Environment v14+}
|
|
33
|
+
* {@link https://nodejs.org/en/download/ NodeJS v14+}
|
|
34
34
|
* A local web server, such as {@link https://httpd.apache.org/ Apache}
|
|
35
35
|
* _NOTE: A local web server is required because browsers place restrictions
|
|
36
36
|
on applications from file:/// URLs._
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @typedef {{
|
|
14
|
+
* name: string,
|
|
14
15
|
* parser: !shaka.util.Mp4Parser,
|
|
15
16
|
* partialOkay: boolean,
|
|
16
17
|
* start: number,
|
|
@@ -21,6 +22,8 @@
|
|
|
21
22
|
* has64BitSize: boolean
|
|
22
23
|
* }}
|
|
23
24
|
*
|
|
25
|
+
* @property {string} name
|
|
26
|
+
* The box name, a 4-character string (fourcc).
|
|
24
27
|
* @property {!shaka.util.Mp4Parser} parser
|
|
25
28
|
* The parser that parsed this box. The parser can be used to parse child
|
|
26
29
|
* boxes where the configuration of the current parser is needed to parsed
|
package/externs/shaka/player.js
CHANGED
|
@@ -131,7 +131,8 @@ shaka.extern.StateChange;
|
|
|
131
131
|
* @property {number} manifestTimeSeconds
|
|
132
132
|
* The amount of time it took to download and parse the manifest.
|
|
133
133
|
* @property {number} drmTimeSeconds
|
|
134
|
-
* The amount of time it took to download the first drm key
|
|
134
|
+
* The amount of time it took to download the first drm key, and load that key
|
|
135
|
+
* into the drm system.
|
|
135
136
|
* @property {number} playTime
|
|
136
137
|
* The total time spent in a playing state in seconds.
|
|
137
138
|
* @property {number} pauseTime
|
package/lib/cea/cea708_window.js
CHANGED
|
@@ -420,7 +420,7 @@ shaka.cea.Cea708Window.TextJustification = {
|
|
|
420
420
|
shaka.cea.Cea708Window.MAX_COLS = 42;
|
|
421
421
|
|
|
422
422
|
/**
|
|
423
|
-
* Maximum of
|
|
423
|
+
* Maximum of 16 rows that can be indexed from 0 to 15.
|
|
424
424
|
* @private @const {number}
|
|
425
425
|
*/
|
|
426
|
-
shaka.cea.Cea708Window.MAX_ROWS =
|
|
426
|
+
shaka.cea.Cea708Window.MAX_ROWS = 16;
|
|
@@ -66,14 +66,7 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
66
66
|
const trackIds = [];
|
|
67
67
|
const timescales = [];
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
// bitstream format. It makes the list of codec-signalling boxes below
|
|
71
|
-
// more compact and readable.
|
|
72
|
-
const bitstreamFormatSetter = (format) => {
|
|
73
|
-
return (box) => {
|
|
74
|
-
this.bitstreamFormat_ = format;
|
|
75
|
-
};
|
|
76
|
-
};
|
|
69
|
+
const codecBoxParser = (box) => this.setBitstreamFormat_(box.name);
|
|
77
70
|
|
|
78
71
|
new Mp4Parser()
|
|
79
72
|
.box('moov', Mp4Parser.children)
|
|
@@ -108,14 +101,21 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
108
101
|
.fullBox('stsd', Mp4Parser.sampleDescription)
|
|
109
102
|
|
|
110
103
|
// These are the various boxes that signal a codec.
|
|
111
|
-
|
|
112
|
-
.box('
|
|
113
|
-
.box('
|
|
114
|
-
.box('
|
|
115
|
-
.box('
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
.box('avc1', codecBoxParser)
|
|
105
|
+
.box('avc3', codecBoxParser)
|
|
106
|
+
.box('hev1', codecBoxParser)
|
|
107
|
+
.box('hvc1', codecBoxParser)
|
|
108
|
+
.box('dvh1', codecBoxParser)
|
|
109
|
+
.box('dvhe', codecBoxParser)
|
|
110
|
+
|
|
111
|
+
// This signals an encrypted sample, which we can go inside of to find
|
|
112
|
+
// the codec used.
|
|
113
|
+
.box('encv', Mp4Parser.visualSampleEntry)
|
|
114
|
+
.box('sinf', Mp4Parser.children)
|
|
115
|
+
.box('frma', (box) => {
|
|
116
|
+
const {codec} = shaka.util.Mp4BoxParsers.parseFRMA(box.reader);
|
|
117
|
+
this.setBitstreamFormat_(codec);
|
|
118
|
+
})
|
|
119
119
|
|
|
120
120
|
.parse(initSegment, /* partialOkay= */ true);
|
|
121
121
|
|
|
@@ -338,6 +338,16 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @param {string} codec A fourcc for a codec.
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
setBitstreamFormat_(codec) {
|
|
347
|
+
if (codec in shaka.cea.Mp4CeaParser.CodecBitstreamMap_) {
|
|
348
|
+
this.bitstreamFormat_ = shaka.cea.Mp4CeaParser.CodecBitstreamMap_[codec];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
341
351
|
};
|
|
342
352
|
|
|
343
353
|
/** @enum {number} */
|
|
@@ -346,3 +356,14 @@ shaka.cea.Mp4CeaParser.BitstreamFormat = {
|
|
|
346
356
|
H264: 1,
|
|
347
357
|
H265: 2,
|
|
348
358
|
};
|
|
359
|
+
|
|
360
|
+
/** @private {Object.<string, shaka.cea.Mp4CeaParser.BitstreamFormat>} */
|
|
361
|
+
shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = {
|
|
362
|
+
'avc1': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
|
|
363
|
+
'avc3': shaka.cea.Mp4CeaParser.BitstreamFormat.H264,
|
|
364
|
+
'hev1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
365
|
+
'hvc1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
366
|
+
// Dobly vision is also H265.
|
|
367
|
+
'dvh1': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
368
|
+
'dvhe': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
|
|
369
|
+
};
|
|
@@ -67,7 +67,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
67
67
|
},
|
|
68
68
|
};
|
|
69
69
|
} else if (info.segmentDuration) {
|
|
70
|
-
if (!isUpdate) {
|
|
70
|
+
if (!isUpdate && context.adaptationSet.contentType !== 'image') {
|
|
71
71
|
context.presentationTimeline.notifyMaxSegmentDuration(
|
|
72
72
|
info.segmentDuration);
|
|
73
73
|
context.presentationTimeline.notifyMinSegmentStartTime(
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -618,9 +618,23 @@ shaka.hls.HlsParser = class {
|
|
|
618
618
|
if (playlist.segments.length) {
|
|
619
619
|
const parsedUri = new goog.Uri(playlist.segments[0].absoluteUri);
|
|
620
620
|
const extension = parsedUri.getPath().split('.').pop();
|
|
621
|
-
|
|
621
|
+
let mimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_[extension];
|
|
622
622
|
if (mimeType) {
|
|
623
623
|
fullMimeType = mimeType;
|
|
624
|
+
} else if (extension === 'ts') {
|
|
625
|
+
// TODO: Fetch one segment a use the TsParser to analize if there is
|
|
626
|
+
// video, audio or both.
|
|
627
|
+
} else if (extension === 'mp4') {
|
|
628
|
+
// TODO: Fetch one segment a use the Mp4Parser to analize if there is
|
|
629
|
+
// video, audio or both.
|
|
630
|
+
} else if (HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_[extension]) {
|
|
631
|
+
mimeType = HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
632
|
+
const defaultAudioCodec = this.config_.hls.defaultAudioCodec;
|
|
633
|
+
fullMimeType = `${mimeType}; codecs="${defaultAudioCodec}"`;
|
|
634
|
+
} else if (HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_[extension]) {
|
|
635
|
+
mimeType = HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
636
|
+
const defaultVideoCodec = this.config_.hls.defaultVideoCodec;
|
|
637
|
+
fullMimeType = `${mimeType}; codecs="${defaultVideoCodec}"`;
|
|
624
638
|
}
|
|
625
639
|
}
|
|
626
640
|
|
|
@@ -1123,7 +1137,7 @@ shaka.hls.HlsParser = class {
|
|
|
1123
1137
|
shaka.log.debug('Guessing audio-only.');
|
|
1124
1138
|
type = ContentType.AUDIO;
|
|
1125
1139
|
ignoreStream = true;
|
|
1126
|
-
} else if (res.video.length) {
|
|
1140
|
+
} else if (res.video.length && !res.audio.length) {
|
|
1127
1141
|
// There are associated video streams. Assume this is audio.
|
|
1128
1142
|
shaka.log.debug('Guessing audio-only.');
|
|
1129
1143
|
type = ContentType.AUDIO;
|
|
@@ -1677,9 +1691,10 @@ shaka.hls.HlsParser = class {
|
|
|
1677
1691
|
stream.encrypted = realStream.encrypted;
|
|
1678
1692
|
stream.drmInfos = realStream.drmInfos;
|
|
1679
1693
|
stream.keyIds = realStream.keyIds;
|
|
1680
|
-
stream.kind = realStream.kind;
|
|
1681
|
-
stream.roles = realStream.roles;
|
|
1682
1694
|
stream.mimeType = realStream.mimeType;
|
|
1695
|
+
if (shaka.media.MediaSourceEngine.RAW_FORMATS.includes(stream.mimeType)) {
|
|
1696
|
+
stream.codecs = '';
|
|
1697
|
+
}
|
|
1683
1698
|
|
|
1684
1699
|
// Since we lazy-loaded this content, the player may need to create new
|
|
1685
1700
|
// sessions for the DRM info in this stream.
|
|
@@ -1694,6 +1709,10 @@ shaka.hls.HlsParser = class {
|
|
|
1694
1709
|
// To aid manifest filtering, assume before loading that all video
|
|
1695
1710
|
// renditions have the same MIME type. (And likewise for audio.)
|
|
1696
1711
|
otherStreamInfo.stream.mimeType = realStream.mimeType;
|
|
1712
|
+
if (shaka.media.MediaSourceEngine.RAW_FORMATS
|
|
1713
|
+
.includes(otherStreamInfo.stream.mimeType)) {
|
|
1714
|
+
otherStreamInfo.stream.codecs = '';
|
|
1715
|
+
}
|
|
1697
1716
|
}
|
|
1698
1717
|
}
|
|
1699
1718
|
}
|
|
@@ -1923,23 +1942,20 @@ shaka.hls.HlsParser = class {
|
|
|
1923
1942
|
|
|
1924
1943
|
const mediaSequenceToStartTime = this.isLive_() ?
|
|
1925
1944
|
this.mediaSequenceToStartTimeByType_.get(type) : new Map();
|
|
1945
|
+
const prevLowLatencyMode = this.lowLatencyMode_;
|
|
1926
1946
|
const segments = this.createSegments_(verbatimMediaPlaylistUri, playlist,
|
|
1927
1947
|
type, mimeType, mediaSequenceToStartTime, mediaVariables);
|
|
1928
1948
|
|
|
1949
|
+
// This happens when autoLowLatencyMode is true, so we need set the
|
|
1950
|
+
// correct lowLatencyPresentationDelay_
|
|
1951
|
+
if (prevLowLatencyMode != this.lowLatencyMode_) {
|
|
1952
|
+
this.determinePresentationType_(playlist);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1929
1955
|
const lastEndTime = segments[segments.length - 1].endTime;
|
|
1930
1956
|
/** @type {!shaka.media.SegmentIndex} */
|
|
1931
1957
|
const segmentIndex = new shaka.media.SegmentIndex(segments);
|
|
1932
1958
|
|
|
1933
|
-
const kind = (type == shaka.util.ManifestParserUtils.ContentType.TEXT) ?
|
|
1934
|
-
shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE : undefined;
|
|
1935
|
-
|
|
1936
|
-
const roles = [];
|
|
1937
|
-
if (characteristics) {
|
|
1938
|
-
for (const characteristic of characteristics.split(',')) {
|
|
1939
|
-
roles.push(characteristic);
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
1959
|
const serverControlTag = shaka.hls.Utils.getFirstTagWithName(
|
|
1944
1960
|
playlist.tags, 'EXT-X-SERVER-CONTROL');
|
|
1945
1961
|
const canSkipSegments = serverControlTag ?
|
|
@@ -1951,8 +1967,6 @@ shaka.hls.HlsParser = class {
|
|
|
1951
1967
|
stream.encrypted = encrypted;
|
|
1952
1968
|
stream.drmInfos = drmInfos;
|
|
1953
1969
|
stream.keyIds = keyIds;
|
|
1954
|
-
stream.kind = kind;
|
|
1955
|
-
stream.roles = roles;
|
|
1956
1970
|
stream.mimeType = mimeType;
|
|
1957
1971
|
|
|
1958
1972
|
return {
|
|
@@ -2002,7 +2016,8 @@ shaka.hls.HlsParser = class {
|
|
|
2002
2016
|
segmentIndex: null,
|
|
2003
2017
|
mimeType,
|
|
2004
2018
|
codecs,
|
|
2005
|
-
kind:
|
|
2019
|
+
kind: (type == shaka.util.ManifestParserUtils.ContentType.TEXT) ?
|
|
2020
|
+
shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE : undefined,
|
|
2006
2021
|
encrypted: false,
|
|
2007
2022
|
drmInfos: [],
|
|
2008
2023
|
keyIds: new Set(),
|
|
@@ -2018,7 +2033,7 @@ shaka.hls.HlsParser = class {
|
|
|
2018
2033
|
width: undefined,
|
|
2019
2034
|
height: undefined,
|
|
2020
2035
|
bandwidth: undefined,
|
|
2021
|
-
roles: [],
|
|
2036
|
+
roles: characteristics ? characteristics.split(',') : [],
|
|
2022
2037
|
forced,
|
|
2023
2038
|
channelsCount,
|
|
2024
2039
|
audioSamplingRate: null,
|
|
@@ -2156,8 +2171,11 @@ shaka.hls.HlsParser = class {
|
|
|
2156
2171
|
shaka.util.Error.Code.HLS_AES_128_INVALID_KEY_LENGTH);
|
|
2157
2172
|
}
|
|
2158
2173
|
|
|
2174
|
+
const algorithm = {
|
|
2175
|
+
name: 'AES-CBC',
|
|
2176
|
+
};
|
|
2159
2177
|
keyInfo.cryptoKey = await window.crypto.subtle.importKey(
|
|
2160
|
-
'raw', keyResponse.data,
|
|
2178
|
+
'raw', keyResponse.data, algorithm, true, ['decrypt']);
|
|
2161
2179
|
keyInfo.fetchKey = undefined; // No longer needed.
|
|
2162
2180
|
};
|
|
2163
2181
|
|
|
@@ -69,6 +69,18 @@ shaka.media.ContentWorkarounds = class {
|
|
|
69
69
|
})
|
|
70
70
|
.fullBox('encv', onEncryptionMetadataBox)
|
|
71
71
|
.fullBox('enca', onEncryptionMetadataBox)
|
|
72
|
+
.fullBox('hev1', (box) => {
|
|
73
|
+
boxesToModify.push({
|
|
74
|
+
box,
|
|
75
|
+
newType: ContentWorkarounds.BOX_TYPE_ENCV_,
|
|
76
|
+
});
|
|
77
|
+
})
|
|
78
|
+
.fullBox('hvc1', (box) => {
|
|
79
|
+
boxesToModify.push({
|
|
80
|
+
box,
|
|
81
|
+
newType: ContentWorkarounds.BOX_TYPE_ENCV_,
|
|
82
|
+
});
|
|
83
|
+
})
|
|
72
84
|
.fullBox('avc1', (box) => {
|
|
73
85
|
boxesToModify.push({
|
|
74
86
|
box,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.media.Capabilities');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @summary
|
|
11
|
+
* This is for capturing all media source capabilities on current platform.
|
|
12
|
+
* And this is for static check and can not be constructed.
|
|
13
|
+
*/
|
|
14
|
+
shaka.media.Capabilities = class {
|
|
15
|
+
/**
|
|
16
|
+
* Cache browser engine call to improve performance on some poor platforms
|
|
17
|
+
*
|
|
18
|
+
* @param {string} type
|
|
19
|
+
* @return {boolean}
|
|
20
|
+
*/
|
|
21
|
+
static isTypeSupported(type) {
|
|
22
|
+
const supportMap = shaka.media.Capabilities.MediaSourceTypeSupportMap;
|
|
23
|
+
if (supportMap.has(type)) {
|
|
24
|
+
return supportMap.get(type);
|
|
25
|
+
}
|
|
26
|
+
const currentSupport = MediaSource.isTypeSupported(type);
|
|
27
|
+
supportMap.set(type, currentSupport);
|
|
28
|
+
return currentSupport;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Public it for unit test, and developer could also check the support map.
|
|
34
|
+
* @type {!Map.<string, boolean>}
|
|
35
|
+
*/
|
|
36
|
+
shaka.media.Capabilities.MediaSourceTypeSupportMap = new Map();
|
|
@@ -8,6 +8,7 @@ goog.provide('shaka.media.MediaSourceEngine');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
+
goog.require('shaka.media.Capabilities');
|
|
11
12
|
goog.require('shaka.media.ContentWorkarounds');
|
|
12
13
|
goog.require('shaka.media.ClosedCaptionParser');
|
|
13
14
|
goog.require('shaka.media.IClosedCaptionParser');
|
|
@@ -175,7 +176,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
175
176
|
stream.mimeType, stream.codecs);
|
|
176
177
|
const extendedMimeType = shaka.util.MimeUtils.getExtendedType(stream);
|
|
177
178
|
return shaka.text.TextEngine.isTypeSupported(fullMimeType) ||
|
|
178
|
-
|
|
179
|
+
shaka.media.Capabilities.isTypeSupported(extendedMimeType) ||
|
|
179
180
|
shaka.media.Transmuxer.isSupported(fullMimeType, stream.type);
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -231,7 +232,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
231
232
|
if (shaka.text.TextEngine.isTypeSupported(type)) {
|
|
232
233
|
support[type] = true;
|
|
233
234
|
} else {
|
|
234
|
-
support[type] =
|
|
235
|
+
support[type] = shaka.media.Capabilities.isTypeSupported(type) ||
|
|
235
236
|
shaka.media.Transmuxer.isSupported(type);
|
|
236
237
|
}
|
|
237
238
|
} else {
|
|
@@ -365,7 +366,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
365
366
|
if (contentType == ContentType.TEXT) {
|
|
366
367
|
this.reinitText(mimeType, sequenceMode);
|
|
367
368
|
} else {
|
|
368
|
-
if ((forceTransmux ||
|
|
369
|
+
if ((forceTransmux ||
|
|
370
|
+
!shaka.media.Capabilities.isTypeSupported(mimeType)) &&
|
|
369
371
|
shaka.media.Transmuxer.isSupported(mimeType, contentType)) {
|
|
370
372
|
this.transmuxers_[contentType] =
|
|
371
373
|
new shaka.media.Transmuxer(mimeType);
|
|
@@ -586,11 +588,14 @@ shaka.media.MediaSourceEngine = class {
|
|
|
586
588
|
mimeType = this.transmuxers_[contentType].getOrginalMimeType();
|
|
587
589
|
}
|
|
588
590
|
if (shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
+
const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
|
|
592
|
+
// The SourceBuffer timestampOffset may or may not be set yet, so this is
|
|
593
|
+
// the timestamp offset that would eventually compute for this segment
|
|
594
|
+
// either way.
|
|
595
|
+
const timestampOffset =
|
|
596
|
+
reference.startTime - (tsParser.getStartTime()[contentType] || 0);
|
|
597
|
+
const metadata = tsParser.getMetadata();
|
|
591
598
|
if (metadata.length) {
|
|
592
|
-
const timestampOffset =
|
|
593
|
-
this.sourceBuffers_[contentType].timestampOffset;
|
|
594
599
|
this.onMetadata_(metadata, timestampOffset,
|
|
595
600
|
reference ? reference.endTime : null);
|
|
596
601
|
}
|
package/lib/media/transmuxer.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.media.Transmuxer');
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
|
+
goog.require('shaka.media.Capabilities');
|
|
10
11
|
goog.require('shaka.util.BufferUtils');
|
|
11
12
|
goog.require('shaka.util.Error');
|
|
12
13
|
goog.require('shaka.util.IDestroyable');
|
|
@@ -74,6 +75,7 @@ shaka.media.Transmuxer = class {
|
|
|
74
75
|
*/
|
|
75
76
|
static isSupported(mimeType, contentType) {
|
|
76
77
|
const Transmuxer = shaka.media.Transmuxer;
|
|
78
|
+
const Capabilities = shaka.media.Capabilities;
|
|
77
79
|
|
|
78
80
|
const isTs = Transmuxer.isTsContainer_(mimeType);
|
|
79
81
|
const isAac = Transmuxer.isAacContainer_(mimeType);
|
|
@@ -83,11 +85,11 @@ shaka.media.Transmuxer = class {
|
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
if (isAac) {
|
|
86
|
-
return
|
|
88
|
+
return Capabilities.isTypeSupported(Transmuxer.convertAacCodecs_());
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
if (contentType) {
|
|
90
|
-
return
|
|
92
|
+
return Capabilities.isTypeSupported(
|
|
91
93
|
Transmuxer.convertTsCodecs_(contentType, mimeType));
|
|
92
94
|
}
|
|
93
95
|
|
|
@@ -95,8 +97,8 @@ shaka.media.Transmuxer = class {
|
|
|
95
97
|
|
|
96
98
|
const audioMime = Transmuxer.convertTsCodecs_(ContentType.AUDIO, mimeType);
|
|
97
99
|
const videoMime = Transmuxer.convertTsCodecs_(ContentType.VIDEO, mimeType);
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
+
return Capabilities.isTypeSupported(audioMime) ||
|
|
101
|
+
Capabilities.isTypeSupported(videoMime);
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
|
package/lib/player.js
CHANGED
|
@@ -2160,15 +2160,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2160
2160
|
// Unless the user has already picked a variant, anyway, by calling
|
|
2161
2161
|
// selectVariantTrack before this loading stage.
|
|
2162
2162
|
let initialVariant = null;
|
|
2163
|
-
const
|
|
2164
|
-
if (!
|
|
2163
|
+
const activeVariant = this.streamingEngine_.getCurrentVariant();
|
|
2164
|
+
if (!activeVariant) {
|
|
2165
2165
|
initialVariant = this.chooseVariant_();
|
|
2166
2166
|
goog.asserts.assert(initialVariant, 'Must choose an initial variant!');
|
|
2167
2167
|
}
|
|
2168
2168
|
|
|
2169
2169
|
// Lazy-load the stream, so we will have enough info to make the playhead.
|
|
2170
2170
|
const createSegmentIndexPromises = [];
|
|
2171
|
-
const toLazyLoad =
|
|
2171
|
+
const toLazyLoad = activeVariant || initialVariant;
|
|
2172
2172
|
for (const stream of [toLazyLoad.video, toLazyLoad.audio]) {
|
|
2173
2173
|
if (stream && !stream.segmentIndex) {
|
|
2174
2174
|
createSegmentIndexPromises.push(stream.createSegmentIndex());
|
|
@@ -2189,7 +2189,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2189
2189
|
this.startBufferManagement_(rebufferThreshold);
|
|
2190
2190
|
|
|
2191
2191
|
// Now we can switch to the initial variant.
|
|
2192
|
-
if (!
|
|
2192
|
+
if (!activeVariant) {
|
|
2193
2193
|
goog.asserts.assert(initialVariant,
|
|
2194
2194
|
'Must have choosen an initial variant!');
|
|
2195
2195
|
|
|
@@ -6974,7 +6974,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6974
6974
|
* @define {string} A version number taken from git at compile time.
|
|
6975
6975
|
* @export
|
|
6976
6976
|
*/
|
|
6977
|
-
shaka.Player.version = 'v4.3.
|
|
6977
|
+
shaka.Player.version = 'v4.3.1-uncompiled';
|
|
6978
6978
|
|
|
6979
6979
|
// Initialize the deprecation system using the version string we just set
|
|
6980
6980
|
// on the player.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.polyfill.AbortController');
|
|
8
|
+
|
|
9
|
+
goog.require('shaka.polyfill');
|
|
10
|
+
goog.require('shaka.util.FakeEvent');
|
|
11
|
+
goog.require('shaka.util.FakeEventTarget');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @summary A polyfill for systems that do not implement AbortController.
|
|
15
|
+
* This is used both with the fetch API for HTTP requests and inside the HLS
|
|
16
|
+
* parser.
|
|
17
|
+
* @export
|
|
18
|
+
* @extends AbortController
|
|
19
|
+
*/
|
|
20
|
+
shaka.polyfill.AbortController = class {
|
|
21
|
+
/**
|
|
22
|
+
* Install the polyfill if needed.
|
|
23
|
+
* @export
|
|
24
|
+
*/
|
|
25
|
+
static install() {
|
|
26
|
+
if (window.AbortController) {
|
|
27
|
+
// Not needed.
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
window.AbortController = shaka.polyfill.AbortController;
|
|
32
|
+
window.AbortSignal = shaka.polyfill.AbortController.AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** */
|
|
36
|
+
constructor() {
|
|
37
|
+
/** @private {!shaka.polyfill.AbortController.AbortSignal} */
|
|
38
|
+
this.signal_ = new shaka.polyfill.AbortController.AbortSignal();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @override
|
|
43
|
+
* @suppress {const|duplicate} Since the original is defined as "const", we
|
|
44
|
+
* need this suppression to override it.
|
|
45
|
+
*/
|
|
46
|
+
get signal() {
|
|
47
|
+
return this.signal_;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {*=} reason
|
|
52
|
+
* @override
|
|
53
|
+
*/
|
|
54
|
+
abort(reason) {
|
|
55
|
+
this.signal_.doAbort_(reason);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @summary A polyfill for AbortSignal, part of the AbortController API.
|
|
61
|
+
* @implements {AbortSignal}
|
|
62
|
+
*/
|
|
63
|
+
shaka.polyfill.AbortController.AbortSignal =
|
|
64
|
+
class extends shaka.util.FakeEventTarget {
|
|
65
|
+
/** */
|
|
66
|
+
constructor() {
|
|
67
|
+
super();
|
|
68
|
+
|
|
69
|
+
/** @private {boolean} */
|
|
70
|
+
this.aborted_ = false;
|
|
71
|
+
|
|
72
|
+
/** @private {*} */
|
|
73
|
+
this.reason_ = undefined;
|
|
74
|
+
|
|
75
|
+
/** @type {?function(!Event)} */
|
|
76
|
+
this.onabort = null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @override */
|
|
80
|
+
get aborted() {
|
|
81
|
+
return this.aborted_;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @return {*} */
|
|
85
|
+
get reason() {
|
|
86
|
+
return this.reason_;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {*} reason
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
doAbort_(reason) {
|
|
94
|
+
if (this.aborted_) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.aborted_ = true;
|
|
99
|
+
this.reason_ = reason;
|
|
100
|
+
if (this.reason_ === undefined) {
|
|
101
|
+
// This is equivalent to a native implementation.
|
|
102
|
+
this.reason_ = new DOMException(
|
|
103
|
+
'signal is aborted without reason', 'AbortError');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// According to MDN:
|
|
107
|
+
// "Event type - A generic Event with no added properties."
|
|
108
|
+
const event = new shaka.util.FakeEvent('abort');
|
|
109
|
+
if (this.onabort) {
|
|
110
|
+
this.onabort(event);
|
|
111
|
+
}
|
|
112
|
+
this.dispatchEvent(event);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {*=} reason
|
|
118
|
+
* @return {!AbortSignal}
|
|
119
|
+
*/
|
|
120
|
+
static abort(reason) {
|
|
121
|
+
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
122
|
+
signal.doAbort_(reason);
|
|
123
|
+
return signal;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {number} timeMs
|
|
128
|
+
* @return {!AbortSignal}
|
|
129
|
+
*/
|
|
130
|
+
static timeout(timeMs) {
|
|
131
|
+
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
132
|
+
|
|
133
|
+
window.setTimeout(() => {
|
|
134
|
+
// This is equivalent to a native implementation.
|
|
135
|
+
signal.doAbort_(new DOMException('signal timed out', 'TimeoutError'));
|
|
136
|
+
}, timeMs);
|
|
137
|
+
|
|
138
|
+
return signal;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
shaka.polyfill.register(shaka.polyfill.AbortController.install);
|