shaka-player 4.8.3 → 4.8.5
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/AUTHORS +1 -0
- package/CONTRIBUTORS +1 -0
- package/dist/deps.js +2 -2
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +351 -345
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +813 -811
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +361 -355
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +864 -861
- package/dist/shaka-player.ui.map +3 -3
- package/externs/ima.js +2 -0
- package/lib/ads/client_side_ad_manager.js +5 -3
- package/lib/cea/cea_decoder.js +3 -0
- package/lib/hls/hls_parser.js +19 -10
- package/lib/media/closed_caption_parser.js +7 -1
- package/lib/media/media_source_engine.js +6 -9
- package/lib/media/segment_utils.js +1 -1
- package/lib/player.js +17 -1
- package/lib/polyfill/media_capabilities.js +150 -133
- package/lib/transmuxer/ts_transmuxer.js +6 -24
- package/lib/util/platform.js +46 -12
- package/lib/util/stream_utils.js +24 -11
- package/package.json +6 -1
package/externs/ima.js
CHANGED
|
@@ -63,16 +63,17 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
63
63
|
|
|
64
64
|
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true);
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
/** @private {!google.ima.AdDisplayContainer} */
|
|
67
|
+
this.adDisplayContainer_ = new google.ima.AdDisplayContainer(
|
|
67
68
|
this.adContainer_,
|
|
68
69
|
this.video_);
|
|
69
70
|
|
|
70
71
|
// TODO: IMA: Must be done as the result of a user action on mobile
|
|
71
|
-
|
|
72
|
+
this.adDisplayContainer_.initialize();
|
|
72
73
|
|
|
73
74
|
// IMA: This instance should be re-used for the entire lifecycle of
|
|
74
75
|
// the page.
|
|
75
|
-
this.adsLoader_ = new google.ima.AdsLoader(
|
|
76
|
+
this.adsLoader_ = new google.ima.AdsLoader(this.adDisplayContainer_);
|
|
76
77
|
|
|
77
78
|
this.adsLoader_.getSettings().setPlayerType('shaka-player');
|
|
78
79
|
this.adsLoader_.getSettings().setPlayerVersion(shaka.Player.version);
|
|
@@ -176,6 +177,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
176
177
|
this.imaAdsManager_.destroy();
|
|
177
178
|
}
|
|
178
179
|
this.adsLoader_.destroy();
|
|
180
|
+
this.adDisplayContainer_.destroy();
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
/**
|
package/lib/cea/cea_decoder.js
CHANGED
|
@@ -97,6 +97,7 @@ shaka.cea.CeaDecoder = class {
|
|
|
97
97
|
* @override
|
|
98
98
|
*/
|
|
99
99
|
clear() {
|
|
100
|
+
shaka.log.debug('Clearing CEA decoder');
|
|
100
101
|
this.badFrames_ = 0;
|
|
101
102
|
this.cea608DataArray_ = [];
|
|
102
103
|
this.cea708DataArray_ = [];
|
|
@@ -113,6 +114,7 @@ shaka.cea.CeaDecoder = class {
|
|
|
113
114
|
* Resets the decoder.
|
|
114
115
|
*/
|
|
115
116
|
reset() {
|
|
117
|
+
shaka.log.debug('Resetting CEA decoder');
|
|
116
118
|
this.currentField1Channel_ = 0;
|
|
117
119
|
this.currentField2Channel_ = 0;
|
|
118
120
|
for (const stream of this.cea608ModeToStream_.values()) {
|
|
@@ -128,6 +130,7 @@ shaka.cea.CeaDecoder = class {
|
|
|
128
130
|
*/
|
|
129
131
|
extract(userDataSeiMessage, pts) {
|
|
130
132
|
if (this.waitingForFirstPacket_) {
|
|
133
|
+
shaka.log.debug('Setting first pts value to', pts);
|
|
131
134
|
for (const stream of this.cea608ModeToStream_.values()) {
|
|
132
135
|
stream.firstPts(pts);
|
|
133
136
|
}
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -928,13 +928,12 @@ shaka.hls.HlsParser = class {
|
|
|
928
928
|
if (!playlist.segments.length) {
|
|
929
929
|
return defaultBasicInfo;
|
|
930
930
|
}
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
const middleSegmentUris = shaka.hls.Utils.constructSegmentUris(
|
|
931
|
+
const firstSegment = playlist.segments[0];
|
|
932
|
+
const firstSegmentUris = shaka.hls.Utils.constructSegmentUris(
|
|
934
933
|
getUris(),
|
|
935
|
-
|
|
936
|
-
const
|
|
937
|
-
const parsedUri = new goog.Uri(
|
|
934
|
+
firstSegment.verbatimSegmentUri);
|
|
935
|
+
const firstSegmentUri = firstSegmentUris[0];
|
|
936
|
+
const parsedUri = new goog.Uri(firstSegmentUri);
|
|
938
937
|
const extension = parsedUri.getPath().split('.').pop();
|
|
939
938
|
const rawMimeType = HlsParser.RAW_FORMATS_TO_MIME_TYPES_[extension];
|
|
940
939
|
if (rawMimeType) {
|
|
@@ -946,7 +945,7 @@ shaka.hls.HlsParser = class {
|
|
|
946
945
|
|
|
947
946
|
let initData = null;
|
|
948
947
|
const initSegmentRef = this.getInitSegmentReference_(
|
|
949
|
-
playlist,
|
|
948
|
+
playlist, firstSegment.tags, getUris);
|
|
950
949
|
this.mapTagToInitSegmentRefMap_.clear();
|
|
951
950
|
if (initSegmentRef) {
|
|
952
951
|
const initSegmentRequest = shaka.util.Networking.createSegmentRequest(
|
|
@@ -961,8 +960,17 @@ shaka.hls.HlsParser = class {
|
|
|
961
960
|
initData = initResponse.data;
|
|
962
961
|
}
|
|
963
962
|
|
|
964
|
-
|
|
965
|
-
|
|
963
|
+
let startByte = 0;
|
|
964
|
+
let endByte = null;
|
|
965
|
+
const byterangeTag = shaka.hls.Utils.getFirstTagWithName(
|
|
966
|
+
firstSegment.tags, 'EXT-X-BYTERANGE');
|
|
967
|
+
if (byterangeTag) {
|
|
968
|
+
[startByte, endByte] = this.parseByteRange_(
|
|
969
|
+
/* previousReference= */ null, byterangeTag.value);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
const segmentRequest = shaka.util.Networking.createSegmentRequest(
|
|
973
|
+
firstSegmentUris, startByte, endByte, this.config_.retryParameters);
|
|
966
974
|
const type = shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
|
|
967
975
|
const response = await this.makeNetworkRequest_(
|
|
968
976
|
segmentRequest, requestType, {type});
|
|
@@ -980,7 +988,8 @@ shaka.hls.HlsParser = class {
|
|
|
980
988
|
return basicInfo;
|
|
981
989
|
}
|
|
982
990
|
} else if (extension == 'mp4' || extension == 'cmfv' ||
|
|
983
|
-
extension == 'm4s' ||
|
|
991
|
+
extension == 'm4s' || extension == 'fmp4' ||
|
|
992
|
+
contentMimeType == 'video/mp4' ||
|
|
984
993
|
contentMimeType == 'audio/mp4' ||
|
|
985
994
|
contentMimeType == 'video/iso.segment') {
|
|
986
995
|
const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
|
|
@@ -9,6 +9,7 @@ goog.provide('shaka.media.IClosedCaptionParser');
|
|
|
9
9
|
|
|
10
10
|
goog.require('shaka.cea.DummyCaptionDecoder');
|
|
11
11
|
goog.require('shaka.cea.DummyCeaParser');
|
|
12
|
+
goog.require('shaka.log');
|
|
12
13
|
goog.require('shaka.util.BufferUtils');
|
|
13
14
|
|
|
14
15
|
|
|
@@ -22,7 +23,8 @@ goog.require('shaka.util.BufferUtils');
|
|
|
22
23
|
*/
|
|
23
24
|
shaka.media.IClosedCaptionParser = class {
|
|
24
25
|
/**
|
|
25
|
-
* Initialize the caption parser. This should be called
|
|
26
|
+
* Initialize the caption parser. This should be called whenever new init
|
|
27
|
+
* segment arrives.
|
|
26
28
|
* @param {BufferSource} initSegment
|
|
27
29
|
*/
|
|
28
30
|
init(initSegment) {}
|
|
@@ -88,6 +90,10 @@ shaka.media.ClosedCaptionParser = class {
|
|
|
88
90
|
* @override
|
|
89
91
|
*/
|
|
90
92
|
init(initSegment) {
|
|
93
|
+
shaka.log.debug('Passing new init segment to CEA parser');
|
|
94
|
+
// Reset underlying decoder when new init segment arrives
|
|
95
|
+
// to clear stored pts values.
|
|
96
|
+
this.reset();
|
|
91
97
|
this.ceaParser_.init(initSegment);
|
|
92
98
|
}
|
|
93
99
|
|
|
@@ -280,7 +280,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
280
280
|
if (contentType == ContentType.VIDEO) {
|
|
281
281
|
codecs = StreamUtils.getCorrectVideoCodecs(codecs);
|
|
282
282
|
} else if (contentType == ContentType.AUDIO) {
|
|
283
|
-
codecs = StreamUtils.getCorrectAudioCodecs(codecs);
|
|
283
|
+
codecs = StreamUtils.getCorrectAudioCodecs(codecs, mimeType);
|
|
284
284
|
}
|
|
285
285
|
const extendedMimeType = MimeUtils.getExtendedType(
|
|
286
286
|
stream, mimeType, codecs);
|
|
@@ -347,14 +347,11 @@ shaka.media.MediaSourceEngine = class {
|
|
|
347
347
|
|
|
348
348
|
const support = {};
|
|
349
349
|
for (const type of testMimeTypes) {
|
|
350
|
-
if (shaka.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
support[type] = shaka.media.Capabilities.isTypeSupported(type) ||
|
|
356
|
-
shaka.transmuxer.TransmuxerEngine.isSupported(type);
|
|
357
|
-
}
|
|
350
|
+
if (shaka.text.TextEngine.isTypeSupported(type)) {
|
|
351
|
+
support[type] = true;
|
|
352
|
+
} else if (shaka.util.Platform.supportsMediaSource()) {
|
|
353
|
+
support[type] = shaka.media.Capabilities.isTypeSupported(type) ||
|
|
354
|
+
shaka.transmuxer.TransmuxerEngine.isSupported(type);
|
|
358
355
|
} else {
|
|
359
356
|
support[type] = shaka.util.Platform.supportsMediaType(type);
|
|
360
357
|
}
|
|
@@ -470,7 +470,7 @@ shaka.media.SegmentUtils = class {
|
|
|
470
470
|
if (!dolbyVision) {
|
|
471
471
|
return codecs;
|
|
472
472
|
}
|
|
473
|
-
const type = `video/mp4; codecs="${dolbyVision}"
|
|
473
|
+
const type = `video/mp4; codecs="${dolbyVision}"`;
|
|
474
474
|
if (shaka.media.Capabilities.isTypeSupported(type)) {
|
|
475
475
|
return [dolbyVision];
|
|
476
476
|
}
|
package/lib/player.js
CHANGED
|
@@ -715,6 +715,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
715
715
|
this.manifestFilterer_ = new shaka.media.ManifestFilterer(
|
|
716
716
|
this.config_, this.maxHwRes_, null);
|
|
717
717
|
|
|
718
|
+
/** @private {!Array.<shaka.media.PreloadManager>} */
|
|
719
|
+
this.createdPreloadManagers_ = [];
|
|
720
|
+
|
|
718
721
|
/** @private {shaka.util.Stats} */
|
|
719
722
|
this.stats_ = null;
|
|
720
723
|
|
|
@@ -881,6 +884,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
881
884
|
|
|
882
885
|
await detachPromise;
|
|
883
886
|
|
|
887
|
+
// A PreloadManager can only be used with the Player instance that created
|
|
888
|
+
// it, so all PreloadManagers this Player has created are now useless.
|
|
889
|
+
// Destroy any remaining managers now, to help prevent memory leaks.
|
|
890
|
+
const preloadManagerDestroys = [];
|
|
891
|
+
for (const preloadManager of this.createdPreloadManagers_) {
|
|
892
|
+
if (!preloadManager.isDestroyed()) {
|
|
893
|
+
preloadManagerDestroys.push(preloadManager.destroy());
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
this.createdPreloadManagers_ = [];
|
|
897
|
+
await Promise.all(preloadManagerDestroys);
|
|
898
|
+
|
|
884
899
|
// Tear-down the event managers to ensure handlers stop firing.
|
|
885
900
|
if (this.globalEventManager_) {
|
|
886
901
|
this.globalEventManager_.release();
|
|
@@ -1972,6 +1987,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1972
1987
|
};
|
|
1973
1988
|
preloadManager = new shaka.media.PreloadManager(
|
|
1974
1989
|
assetUri, mimeType, startTimeOfLoad, startTime, playerInterface);
|
|
1990
|
+
this.createdPreloadManagers_.push(preloadManager);
|
|
1975
1991
|
return preloadManager;
|
|
1976
1992
|
}
|
|
1977
1993
|
|
|
@@ -7201,7 +7217,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7201
7217
|
* @export
|
|
7202
7218
|
*/
|
|
7203
7219
|
// eslint-disable-next-line no-useless-concat
|
|
7204
|
-
shaka.Player.version = 'v4.8.
|
|
7220
|
+
shaka.Player.version = 'v4.8.5' + '-uncompiled'; // x-release-please-version
|
|
7205
7221
|
|
|
7206
7222
|
// Initialize the deprecation system using the version string we just set
|
|
7207
7223
|
// on the player.
|
|
@@ -88,6 +88,7 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
88
88
|
* @private
|
|
89
89
|
*/
|
|
90
90
|
static async decodingInfo_(mediaDecodingConfig) {
|
|
91
|
+
/** @type {!MediaCapabilitiesDecodingInfo} */
|
|
91
92
|
const res = {
|
|
92
93
|
supported: false,
|
|
93
94
|
powerEfficient: true,
|
|
@@ -96,60 +97,26 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
96
97
|
configuration: mediaDecodingConfig,
|
|
97
98
|
};
|
|
98
99
|
|
|
99
|
-
if (!mediaDecodingConfig) {
|
|
100
|
-
return res;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
100
|
const videoConfig = mediaDecodingConfig['video'];
|
|
104
101
|
const audioConfig = mediaDecodingConfig['audio'];
|
|
105
102
|
|
|
106
|
-
const Capabilities = shaka.media.Capabilities;
|
|
107
|
-
|
|
108
103
|
if (mediaDecodingConfig.type == 'media-source') {
|
|
109
104
|
if (!shaka.util.Platform.supportsMediaSource()) {
|
|
110
105
|
return res;
|
|
111
106
|
}
|
|
112
|
-
|
|
113
|
-
// the stream is supported.
|
|
114
|
-
// Cast platforms will additionally check canDisplayType(), which
|
|
115
|
-
// accepts extended MIME type parameters.
|
|
116
|
-
// See: https://github.com/shaka-project/shaka-player/issues/4726
|
|
107
|
+
|
|
117
108
|
if (videoConfig) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
|
|
122
|
-
} else if (shaka.util.Platform.isTizen()) {
|
|
123
|
-
let extendedType = videoConfig.contentType;
|
|
124
|
-
if (videoConfig.width && videoConfig.height) {
|
|
125
|
-
extendedType += `; width=${videoConfig.width}`;
|
|
126
|
-
extendedType += `; height=${videoConfig.height}`;
|
|
127
|
-
}
|
|
128
|
-
if (videoConfig.framerate) {
|
|
129
|
-
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
130
|
-
}
|
|
131
|
-
if (videoConfig.bitrate) {
|
|
132
|
-
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
133
|
-
}
|
|
134
|
-
isSupported = Capabilities.isTypeSupported(extendedType);
|
|
135
|
-
} else {
|
|
136
|
-
isSupported = Capabilities.isTypeSupported(videoConfig.contentType);
|
|
137
|
-
}
|
|
109
|
+
const isSupported =
|
|
110
|
+
await shaka.polyfill.MediaCapabilities.checkVideoSupport_(
|
|
111
|
+
videoConfig);
|
|
138
112
|
if (!isSupported) {
|
|
139
113
|
return res;
|
|
140
114
|
}
|
|
141
115
|
}
|
|
142
116
|
|
|
143
117
|
if (audioConfig) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
audioConfig.spatialRendering) {
|
|
147
|
-
const extendedType =
|
|
148
|
-
audioConfig.contentType + '; spatialRendering=true';
|
|
149
|
-
isSupported = Capabilities.isTypeSupported(extendedType);
|
|
150
|
-
} else {
|
|
151
|
-
isSupported = Capabilities.isTypeSupported(audioConfig.contentType);
|
|
152
|
-
}
|
|
118
|
+
const isSupported =
|
|
119
|
+
shaka.polyfill.MediaCapabilities.checkAudioSupport_(audioConfig);
|
|
153
120
|
if (!isSupported) {
|
|
154
121
|
return res;
|
|
155
122
|
}
|
|
@@ -178,122 +145,172 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
178
145
|
if (!mediaDecodingConfig.keySystemConfiguration) {
|
|
179
146
|
// The variant is supported if it's unencrypted.
|
|
180
147
|
res.supported = true;
|
|
181
|
-
return
|
|
148
|
+
return res;
|
|
182
149
|
} else {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (mediaCapkeySystemConfig.audio) {
|
|
194
|
-
let capability = {
|
|
195
|
-
robustness: mediaCapkeySystemConfig.audio.robustness || '',
|
|
196
|
-
contentType: mediaDecodingConfig.audio.contentType,
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// Some Tizen devices seem to misreport AC-3 support, but correctly
|
|
200
|
-
// report EC-3 support. So query EC-3 as a fallback for AC-3.
|
|
201
|
-
// See https://github.com/shaka-project/shaka-player/issues/2989 for
|
|
202
|
-
// details.
|
|
203
|
-
if (shaka.util.Platform.isTizen() &&
|
|
204
|
-
mediaDecodingConfig.audio.contentType.includes('codecs="ac-3"')) {
|
|
205
|
-
capability = {
|
|
206
|
-
robustness: capability.robustness,
|
|
207
|
-
contentType: 'audio/mp4; codecs="ec-3"',
|
|
208
|
-
};
|
|
209
|
-
}
|
|
150
|
+
const mcapKeySystemConfig = mediaDecodingConfig.keySystemConfiguration;
|
|
151
|
+
const keySystemAccess =
|
|
152
|
+
await shaka.polyfill.MediaCapabilities.checkDrmSupport_(
|
|
153
|
+
videoConfig, audioConfig, mcapKeySystemConfig);
|
|
154
|
+
if (keySystemAccess) {
|
|
155
|
+
res.supported = true;
|
|
156
|
+
res.keySystemAccess = keySystemAccess;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
210
159
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
robustness: capability.robustness,
|
|
214
|
-
contentType: capability.contentType,
|
|
215
|
-
encryptionScheme: mediaCapkeySystemConfig.audio.encryptionScheme,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
160
|
+
return res;
|
|
161
|
+
}
|
|
218
162
|
|
|
219
|
-
|
|
163
|
+
/**
|
|
164
|
+
* @param {!VideoConfiguration} videoConfig The 'video' field of the
|
|
165
|
+
* MediaDecodingConfiguration.
|
|
166
|
+
* @return {!Promise<boolean>}
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
static async checkVideoSupport_(videoConfig) {
|
|
170
|
+
// Use 'shaka.media.Capabilities.isTypeSupported' to check if
|
|
171
|
+
// the stream is supported.
|
|
172
|
+
// Cast platforms will additionally check canDisplayType(), which
|
|
173
|
+
// accepts extended MIME type parameters.
|
|
174
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4726
|
|
175
|
+
if (shaka.util.Platform.isChromecast()) {
|
|
176
|
+
const isSupported =
|
|
177
|
+
await shaka.polyfill.MediaCapabilities.canCastDisplayType_(
|
|
178
|
+
videoConfig);
|
|
179
|
+
return isSupported;
|
|
180
|
+
} else if (shaka.util.Platform.isTizen()) {
|
|
181
|
+
let extendedType = videoConfig.contentType;
|
|
182
|
+
if (videoConfig.width && videoConfig.height) {
|
|
183
|
+
extendedType += `; width=${videoConfig.width}`;
|
|
184
|
+
extendedType += `; height=${videoConfig.height}`;
|
|
220
185
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
};
|
|
227
|
-
if (mediaCapkeySystemConfig.video.encryptionScheme) {
|
|
228
|
-
capability = {
|
|
229
|
-
robustness: capability.robustness,
|
|
230
|
-
contentType: capability.contentType,
|
|
231
|
-
encryptionScheme: mediaCapkeySystemConfig.video.encryptionScheme,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
videoCapabilities.push(capability);
|
|
186
|
+
if (videoConfig.framerate) {
|
|
187
|
+
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
188
|
+
}
|
|
189
|
+
if (videoConfig.bitrate) {
|
|
190
|
+
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
235
191
|
}
|
|
192
|
+
return shaka.media.Capabilities.isTypeSupported(extendedType);
|
|
193
|
+
}
|
|
194
|
+
return shaka.media.Capabilities.isTypeSupported(videoConfig.contentType);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @param {!AudioConfiguration} audioConfig The 'audio' field of the
|
|
199
|
+
* MediaDecodingConfiguration.
|
|
200
|
+
* @return {boolean}
|
|
201
|
+
* @private
|
|
202
|
+
*/
|
|
203
|
+
static checkAudioSupport_(audioConfig) {
|
|
204
|
+
let extendedType = audioConfig.contentType;
|
|
205
|
+
if (shaka.util.Platform.isChromecast() && audioConfig.spatialRendering) {
|
|
206
|
+
extendedType += '; spatialRendering=true';
|
|
207
|
+
}
|
|
208
|
+
return shaka.media.Capabilities.isTypeSupported(extendedType);
|
|
209
|
+
}
|
|
236
210
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
211
|
+
/**
|
|
212
|
+
* @param {VideoConfiguration} videoConfig The 'video' field of the
|
|
213
|
+
* MediaDecodingConfiguration.
|
|
214
|
+
* @param {AudioConfiguration} audioConfig The 'audio' field of the
|
|
215
|
+
* MediaDecodingConfiguration.
|
|
216
|
+
* @param {!MediaCapabilitiesKeySystemConfiguration} mcapKeySystemConfig The
|
|
217
|
+
* 'keySystemConfiguration' field of the MediaDecodingConfiguration.
|
|
218
|
+
* @return {Promise<MediaKeySystemAccess>}
|
|
219
|
+
* @private
|
|
220
|
+
*/
|
|
221
|
+
static async checkDrmSupport_(videoConfig, audioConfig, mcapKeySystemConfig) {
|
|
222
|
+
const audioCapabilities = [];
|
|
223
|
+
const videoCapabilities = [];
|
|
224
|
+
|
|
225
|
+
if (mcapKeySystemConfig.audio) {
|
|
226
|
+
const capability = {
|
|
227
|
+
robustness: mcapKeySystemConfig.audio.robustness || '',
|
|
228
|
+
contentType: audioConfig.contentType,
|
|
243
229
|
};
|
|
244
230
|
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
231
|
+
// Some Tizen devices seem to misreport AC-3 support, but correctly
|
|
232
|
+
// report EC-3 support. So query EC-3 as a fallback for AC-3.
|
|
233
|
+
// See https://github.com/shaka-project/shaka-player/issues/2989 for
|
|
234
|
+
// details.
|
|
235
|
+
if (shaka.util.Platform.isTizen() &&
|
|
236
|
+
audioConfig.contentType.includes('codecs="ac-3"')) {
|
|
237
|
+
capability.contentType = 'audio/mp4; codecs="ec-3"';
|
|
249
238
|
}
|
|
250
|
-
|
|
251
|
-
|
|
239
|
+
|
|
240
|
+
if (mcapKeySystemConfig.audio.encryptionScheme) {
|
|
241
|
+
capability.encryptionScheme =
|
|
242
|
+
mcapKeySystemConfig.audio.encryptionScheme;
|
|
252
243
|
}
|
|
253
244
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
.memoizedMediaKeySystemAccessRequests_) {
|
|
266
|
-
keySystemAccess = shaka.polyfill.MediaCapabilities
|
|
267
|
-
.memoizedMediaKeySystemAccessRequests_[cacheKey];
|
|
268
|
-
} else {
|
|
269
|
-
keySystemAccess = await navigator.requestMediaKeySystemAccess(
|
|
270
|
-
mediaCapkeySystemConfig.keySystem, [mediaKeySystemConfig]);
|
|
271
|
-
shaka.polyfill.MediaCapabilities
|
|
272
|
-
.memoizedMediaKeySystemAccessRequests_[cacheKey] =
|
|
273
|
-
keySystemAccess;
|
|
274
|
-
}
|
|
275
|
-
} catch (e) {
|
|
276
|
-
shaka.log.info('navigator.requestMediaKeySystemAccess failed.');
|
|
245
|
+
audioCapabilities.push(capability);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (mcapKeySystemConfig.video) {
|
|
249
|
+
const capability = {
|
|
250
|
+
robustness: mcapKeySystemConfig.video.robustness || '',
|
|
251
|
+
contentType: videoConfig.contentType,
|
|
252
|
+
};
|
|
253
|
+
if (mcapKeySystemConfig.video.encryptionScheme) {
|
|
254
|
+
capability.encryptionScheme =
|
|
255
|
+
mcapKeySystemConfig.video.encryptionScheme;
|
|
277
256
|
}
|
|
257
|
+
videoCapabilities.push(capability);
|
|
258
|
+
}
|
|
278
259
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
260
|
+
/** @type {MediaKeySystemConfiguration} */
|
|
261
|
+
const mediaKeySystemConfig = {
|
|
262
|
+
initDataTypes: [mcapKeySystemConfig.initDataType],
|
|
263
|
+
distinctiveIdentifier: mcapKeySystemConfig.distinctiveIdentifier,
|
|
264
|
+
persistentState: mcapKeySystemConfig.persistentState,
|
|
265
|
+
sessionTypes: mcapKeySystemConfig.sessionTypes,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Only add audio / video capabilities if they have valid data.
|
|
269
|
+
// Otherwise the query will fail.
|
|
270
|
+
if (audioCapabilities.length) {
|
|
271
|
+
mediaKeySystemConfig.audioCapabilities = audioCapabilities;
|
|
272
|
+
}
|
|
273
|
+
if (videoCapabilities.length) {
|
|
274
|
+
mediaKeySystemConfig.videoCapabilities = videoCapabilities;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const cacheKey = shaka.polyfill.MediaCapabilities
|
|
278
|
+
.generateKeySystemCacheKey_(
|
|
279
|
+
videoConfig ? videoConfig.contentType : '',
|
|
280
|
+
audioConfig ? audioConfig.contentType : '',
|
|
281
|
+
mcapKeySystemConfig.keySystem);
|
|
282
|
+
|
|
283
|
+
/** @type {MediaKeySystemAccess} */
|
|
284
|
+
let keySystemAccess = null;
|
|
285
|
+
try {
|
|
286
|
+
if (cacheKey in shaka.polyfill.MediaCapabilities
|
|
287
|
+
.memoizedMediaKeySystemAccessRequests_) {
|
|
288
|
+
keySystemAccess = shaka.polyfill.MediaCapabilities
|
|
289
|
+
.memoizedMediaKeySystemAccessRequests_[cacheKey];
|
|
290
|
+
} else {
|
|
291
|
+
keySystemAccess = await navigator.requestMediaKeySystemAccess(
|
|
292
|
+
mcapKeySystemConfig.keySystem, [mediaKeySystemConfig]);
|
|
293
|
+
shaka.polyfill.MediaCapabilities
|
|
294
|
+
.memoizedMediaKeySystemAccessRequests_[cacheKey] =
|
|
295
|
+
keySystemAccess;
|
|
282
296
|
}
|
|
297
|
+
} catch (e) {
|
|
298
|
+
shaka.log.info('navigator.requestMediaKeySystemAccess failed.');
|
|
283
299
|
}
|
|
284
300
|
|
|
285
|
-
return
|
|
301
|
+
return keySystemAccess;
|
|
286
302
|
}
|
|
287
303
|
|
|
288
304
|
/**
|
|
289
305
|
* Checks if the given media parameters of the video or audio streams are
|
|
290
306
|
* supported by the Cast platform.
|
|
291
307
|
* @param {!VideoConfiguration} videoConfig The 'video' field of the
|
|
292
|
-
*
|
|
293
|
-
* @return {boolean} `true` when the stream can be displayed on a
|
|
308
|
+
* MediaDecodingConfiguration.
|
|
309
|
+
* @return {!Promise<boolean>} `true` when the stream can be displayed on a
|
|
310
|
+
* Cast device.
|
|
294
311
|
* @private
|
|
295
312
|
*/
|
|
296
|
-
static canCastDisplayType_(videoConfig) {
|
|
313
|
+
static async canCastDisplayType_(videoConfig) {
|
|
297
314
|
if (!(window.cast &&
|
|
298
315
|
cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
299
316
|
shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
|
|
@@ -321,7 +338,7 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
321
338
|
result = shaka.polyfill.MediaCapabilities
|
|
322
339
|
.memoizedCanDisplayTypeRequests_[displayType];
|
|
323
340
|
} else {
|
|
324
|
-
result = cast.__platform__.canDisplayType(displayType);
|
|
341
|
+
result = await cast.__platform__.canDisplayType(displayType);
|
|
325
342
|
shaka.polyfill.MediaCapabilities
|
|
326
343
|
.memoizedCanDisplayTypeRequests_[displayType] = result;
|
|
327
344
|
}
|
|
@@ -22,6 +22,7 @@ goog.require('shaka.util.Id3Utils');
|
|
|
22
22
|
goog.require('shaka.util.ManifestParserUtils');
|
|
23
23
|
goog.require('shaka.util.MimeUtils');
|
|
24
24
|
goog.require('shaka.util.Mp4Generator');
|
|
25
|
+
goog.require('shaka.util.StreamUtils');
|
|
25
26
|
goog.require('shaka.util.TsParser');
|
|
26
27
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
27
28
|
|
|
@@ -143,13 +144,17 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
143
144
|
convertCodecs(contentType, mimeType) {
|
|
144
145
|
if (this.isTsContainer_(mimeType)) {
|
|
145
146
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
147
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
146
148
|
// The replace it's necessary because Firefox(the only browser that
|
|
147
149
|
// supports MP3 in MP4) only support the MP3 codec with the mp3 string.
|
|
148
150
|
// MediaSource.isTypeSupported('audio/mp4; codecs="mp4a.40.34"') -> false
|
|
149
151
|
// MediaSource.isTypeSupported('audio/mp4; codecs="mp3"') -> true
|
|
150
152
|
const codecs = shaka.util.MimeUtils.getCodecs(mimeType)
|
|
151
153
|
.replace('mp4a.40.34', 'mp3').split(',')
|
|
152
|
-
.map(
|
|
154
|
+
.map((codecs) => {
|
|
155
|
+
return StreamUtils.getCorrectAudioCodecs(codecs, 'audio/mp4');
|
|
156
|
+
})
|
|
157
|
+
.map(StreamUtils.getCorrectVideoCodecs).join(',');
|
|
153
158
|
if (contentType == ContentType.AUDIO) {
|
|
154
159
|
return `audio/mp4; codecs="${codecs}"`;
|
|
155
160
|
}
|
|
@@ -159,29 +164,6 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
|
|
162
|
-
/**
|
|
163
|
-
* @param {string} codec
|
|
164
|
-
* @return {string}
|
|
165
|
-
* @private
|
|
166
|
-
*/
|
|
167
|
-
getCorrectVideoCodecs_(codec) {
|
|
168
|
-
if (codec.includes('avc1')) {
|
|
169
|
-
// Convert avc1 codec string from RFC-4281 to RFC-6381 for
|
|
170
|
-
// MediaSource.isTypeSupported
|
|
171
|
-
// Example, convert avc1.66.30 to avc1.42001e (0x42 == 66 and 0x1e == 30)
|
|
172
|
-
const avcdata = codec.split('.');
|
|
173
|
-
if (avcdata.length == 3) {
|
|
174
|
-
let result = avcdata.shift() + '.';
|
|
175
|
-
result += parseInt(avcdata.shift(), 10).toString(16);
|
|
176
|
-
result +=
|
|
177
|
-
('000' + parseInt(avcdata.shift(), 10).toString(16)).slice(-4);
|
|
178
|
-
return result;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return codec;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
167
|
/**
|
|
186
168
|
* @override
|
|
187
169
|
* @export
|