shaka-player 4.8.2 → 4.8.4
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 +3 -3
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.debug.js +292 -287
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1051 -1049
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +308 -303
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1197 -1194
- package/dist/shaka-player.ui.map +3 -3
- package/externs/shaka/player.js +5 -2
- package/lib/cea/cea_decoder.js +3 -0
- package/lib/media/closed_caption_parser.js +7 -1
- package/lib/media/media_source_engine.js +5 -8
- package/lib/media/play_rate_controller.js +36 -8
- package/lib/media/segment_utils.js +1 -1
- package/lib/media/stall_detector.js +3 -0
- package/lib/player.js +36 -1
- package/lib/polyfill/media_capabilities.js +150 -133
- package/lib/transmuxer/ts_transmuxer.js +2 -24
- package/lib/util/platform.js +46 -13
- package/package.json +6 -1
package/externs/shaka/player.js
CHANGED
|
@@ -1519,11 +1519,14 @@ shaka.extern.AdsConfiguration;
|
|
|
1519
1519
|
* @property {boolean} enabled
|
|
1520
1520
|
* If true, enable adaptation by the current AbrManager. Defaults to true.
|
|
1521
1521
|
* @property {boolean} useNetworkInformation
|
|
1522
|
-
* If true, use Network Information API in the current AbrManager
|
|
1522
|
+
* If true, use the Network Information API in the current AbrManager, if it
|
|
1523
|
+
* is available in the browser environment. If the Network Information API is
|
|
1524
|
+
* used, Shaka Player will ignore the defaultBandwidthEstimate config.
|
|
1523
1525
|
* Defaults to true.
|
|
1524
1526
|
* @property {number} defaultBandwidthEstimate
|
|
1525
1527
|
* The default bandwidth estimate to use if there is not enough data, in
|
|
1526
|
-
* bit/sec.
|
|
1528
|
+
* bit/sec. Only used if useNetworkInformation is false, or if the Network
|
|
1529
|
+
* Information API is not available.
|
|
1527
1530
|
* @property {shaka.extern.Restrictions} restrictions
|
|
1528
1531
|
* The restrictions to apply to ABR decisions. These are "soft" restrictions.
|
|
1529
1532
|
* Any track that fails to meet these restrictions will not be selected
|
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
|
}
|
|
@@ -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
|
|
|
@@ -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
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.media.PlayRateController');
|
|
8
8
|
|
|
9
|
+
goog.require('goog.asserts');
|
|
9
10
|
goog.require('shaka.log');
|
|
10
11
|
goog.require('shaka.util.IReleasable');
|
|
11
12
|
goog.require('shaka.util.Timer');
|
|
@@ -27,6 +28,9 @@ shaka.media.PlayRateController = class {
|
|
|
27
28
|
/** @private {?shaka.media.PlayRateController.Harness} */
|
|
28
29
|
this.harness_ = harness;
|
|
29
30
|
|
|
31
|
+
/** @private {boolean} */
|
|
32
|
+
this.isBuffering_ = false;
|
|
33
|
+
|
|
30
34
|
/** @private {number} */
|
|
31
35
|
this.rate_ = this.harness_.getRate();
|
|
32
36
|
|
|
@@ -51,15 +55,25 @@ shaka.media.PlayRateController = class {
|
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
/**
|
|
54
|
-
*
|
|
58
|
+
* Sets the buffering flag, which controls the effective playback rate.
|
|
59
|
+
*
|
|
60
|
+
* @param {boolean} isBuffering If true, forces playback rate to 0 internally.
|
|
61
|
+
*/
|
|
62
|
+
setBuffering(isBuffering) {
|
|
63
|
+
this.isBuffering_ = isBuffering;
|
|
64
|
+
this.apply_();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set the playback rate. This rate will only be used as provided when the
|
|
69
|
+
* player is not buffering. You should never set the rate to 0.
|
|
55
70
|
*
|
|
56
71
|
* @param {number} rate
|
|
57
72
|
*/
|
|
58
73
|
set(rate) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
74
|
+
goog.asserts.assert(rate != 0, 'Should never set rate of 0 explicitly!');
|
|
75
|
+
this.rate_ = rate;
|
|
76
|
+
this.apply_();
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
/**
|
|
@@ -93,11 +107,14 @@ shaka.media.PlayRateController = class {
|
|
|
93
107
|
// Always stop the timer. We may not start it again.
|
|
94
108
|
this.timer_.stop();
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
/** @type {number} */
|
|
111
|
+
const rate = this.calculateCurrentRate_();
|
|
112
|
+
|
|
113
|
+
shaka.log.v1('Changing effective playback rate to', rate);
|
|
97
114
|
|
|
98
|
-
if (
|
|
115
|
+
if (rate >= 0) {
|
|
99
116
|
try {
|
|
100
|
-
this.applyRate_(
|
|
117
|
+
this.applyRate_(rate);
|
|
101
118
|
return;
|
|
102
119
|
} catch (e) {
|
|
103
120
|
// Fall through to the next clause.
|
|
@@ -117,6 +134,17 @@ shaka.media.PlayRateController = class {
|
|
|
117
134
|
this.applyRate_(0);
|
|
118
135
|
}
|
|
119
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Calculate the rate that the controller wants the media element to have
|
|
139
|
+
* based on the current state of the controller.
|
|
140
|
+
*
|
|
141
|
+
* @return {number}
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
calculateCurrentRate_() {
|
|
145
|
+
return this.isBuffering_ ? 0 : this.rate_;
|
|
146
|
+
}
|
|
147
|
+
|
|
120
148
|
/**
|
|
121
149
|
* If the new rate is different than the media element's playback rate, this
|
|
122
150
|
* will change the playback rate. If the rate does not need to change, it will
|
|
@@ -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
|
}
|
|
@@ -174,6 +174,9 @@ shaka.media.StallDetector.MediaElementImplementation = class {
|
|
|
174
174
|
if (this.mediaElement_.paused) {
|
|
175
175
|
return false;
|
|
176
176
|
}
|
|
177
|
+
if (this.mediaElement_.playbackRate == 0) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
177
180
|
|
|
178
181
|
// If we have don't have enough content, we are not stalled, we are
|
|
179
182
|
// buffering.
|
package/lib/player.js
CHANGED
|
@@ -622,6 +622,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
622
622
|
*/
|
|
623
623
|
this.playRateController_ = null;
|
|
624
624
|
|
|
625
|
+
// We use the buffering observer and timer to track when we move from having
|
|
626
|
+
// enough buffered content to not enough. They only exist when content has
|
|
627
|
+
// been loaded and are not re-used between loads.
|
|
628
|
+
/** @private {shaka.util.Timer} */
|
|
629
|
+
this.bufferPoller_ = null;
|
|
630
|
+
|
|
625
631
|
/** @private {shaka.media.BufferingObserver} */
|
|
626
632
|
this.bufferObserver_ = null;
|
|
627
633
|
|
|
@@ -709,6 +715,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
709
715
|
this.manifestFilterer_ = new shaka.media.ManifestFilterer(
|
|
710
716
|
this.config_, this.maxHwRes_, null);
|
|
711
717
|
|
|
718
|
+
/** @private {!Array.<shaka.media.PreloadManager>} */
|
|
719
|
+
this.createdPreloadManagers_ = [];
|
|
720
|
+
|
|
712
721
|
/** @private {shaka.util.Stats} */
|
|
713
722
|
this.stats_ = null;
|
|
714
723
|
|
|
@@ -875,6 +884,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
875
884
|
|
|
876
885
|
await detachPromise;
|
|
877
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
|
+
|
|
878
899
|
// Tear-down the event managers to ensure handlers stop firing.
|
|
879
900
|
if (this.globalEventManager_) {
|
|
880
901
|
this.globalEventManager_.release();
|
|
@@ -1228,6 +1249,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1228
1249
|
this.playheadObservers_ = null;
|
|
1229
1250
|
}
|
|
1230
1251
|
|
|
1252
|
+
if (this.bufferPoller_) {
|
|
1253
|
+
this.bufferPoller_.stop();
|
|
1254
|
+
this.bufferPoller_ = null;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1231
1257
|
// Stop the parser early. Since it is at the start of the pipeline, it
|
|
1232
1258
|
// should be start early to avoid is pushing new data downstream.
|
|
1233
1259
|
if (this.parser_) {
|
|
@@ -1961,6 +1987,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1961
1987
|
};
|
|
1962
1988
|
preloadManager = new shaka.media.PreloadManager(
|
|
1963
1989
|
assetUri, mimeType, startTimeOfLoad, startTime, playerInterface);
|
|
1990
|
+
this.createdPreloadManagers_.push(preloadManager);
|
|
1964
1991
|
return preloadManager;
|
|
1965
1992
|
}
|
|
1966
1993
|
|
|
@@ -3101,6 +3128,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3101
3128
|
!this.bufferObserver_,
|
|
3102
3129
|
'No buffering observer should exist before initialization.');
|
|
3103
3130
|
|
|
3131
|
+
goog.asserts.assert(
|
|
3132
|
+
!this.bufferPoller_,
|
|
3133
|
+
'No buffer timer should exist before initialization.');
|
|
3134
|
+
|
|
3104
3135
|
// Give dummy values, will be updated below.
|
|
3105
3136
|
this.bufferObserver_ = new shaka.media.BufferingObserver(1, 2);
|
|
3106
3137
|
|
|
@@ -3110,6 +3141,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3110
3141
|
this.updateBufferingSettings_(rebufferingGoal);
|
|
3111
3142
|
this.updateBufferState_();
|
|
3112
3143
|
|
|
3144
|
+
this.bufferPoller_ = new shaka.util.Timer(() => {
|
|
3145
|
+
this.pollBufferState_();
|
|
3146
|
+
}).tickEvery(/* seconds= */ 0.25);
|
|
3113
3147
|
this.loadEventManager_.listen(mediaElement, 'waiting',
|
|
3114
3148
|
(e) => this.pollBufferState_());
|
|
3115
3149
|
this.loadEventManager_.listen(mediaElement, 'stalled',
|
|
@@ -5833,6 +5867,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5833
5867
|
const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;
|
|
5834
5868
|
|
|
5835
5869
|
if (loaded) {
|
|
5870
|
+
this.playRateController_.setBuffering(isBuffering);
|
|
5836
5871
|
if (this.cmcdManager_) {
|
|
5837
5872
|
this.cmcdManager_.setBuffering(isBuffering);
|
|
5838
5873
|
}
|
|
@@ -7182,7 +7217,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7182
7217
|
* @export
|
|
7183
7218
|
*/
|
|
7184
7219
|
// eslint-disable-next-line no-useless-concat
|
|
7185
|
-
shaka.Player.version = 'v4.8.
|
|
7220
|
+
shaka.Player.version = 'v4.8.4' + '-uncompiled'; // x-release-please-version
|
|
7186
7221
|
|
|
7187
7222
|
// Initialize the deprecation system using the version string we just set
|
|
7188
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
|
}
|