shaka-player 4.7.10 → 4.7.12
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/README.md +2 -4
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +4 -5
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +12 -10
- package/dist/shaka-player.compiled.debug.d.ts +12 -10
- package/dist/shaka-player.compiled.debug.externs.js +78 -64
- package/dist/shaka-player.compiled.debug.js +190 -183
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +78 -64
- package/dist/shaka-player.compiled.js +1122 -1115
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +12 -10
- package/dist/shaka-player.ui.debug.d.ts +12 -10
- package/dist/shaka-player.ui.debug.externs.js +78 -64
- package/dist/shaka-player.ui.debug.js +200 -193
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +78 -64
- package/dist/shaka-player.ui.js +1250 -1243
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/player.js +32 -19
- package/lib/abr/simple_abr_manager.js +21 -26
- package/lib/ads/ad_manager.js +1 -1
- package/lib/cast/cast_proxy.js +1 -3
- package/lib/cast/cast_sender.js +8 -11
- package/lib/cea/cea608_memory.js +1 -1
- package/lib/cea/ts_cea_parser.js +10 -1
- package/lib/dash/dash_parser.js +3 -0
- package/lib/deprecate/deprecate.js +1 -1
- package/lib/hls/hls_parser.js +40 -19
- package/lib/media/drm_engine.js +6 -3
- package/lib/media/manifest_parser.js +3 -2
- package/lib/media/media_source_engine.js +25 -12
- package/lib/media/presentation_timeline.js +23 -0
- package/lib/media/segment_utils.js +10 -1
- package/lib/player.js +19 -6
- package/lib/polyfill/media_capabilities.js +20 -1
- package/lib/polyfill/mediasource.js +35 -43
- package/lib/text/vtt_text_parser.js +53 -52
- package/lib/transmuxer/h264.js +3 -3
- package/lib/transmuxer/h265.js +3 -3
- package/lib/transmuxer/ts_transmuxer.js +42 -3
- package/lib/util/error.js +1 -0
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_parser.js +57 -0
- package/lib/util/platform.js +4 -0
- package/lib/util/ts_parser.js +101 -12
- package/package.json +2 -2
- package/ui/less/containers.less +1 -0
- package/lib/polyfill/storage_estimate.js +0 -57
package/externs/shaka/player.js
CHANGED
|
@@ -96,57 +96,70 @@ shaka.extern.StateChange;
|
|
|
96
96
|
* again.
|
|
97
97
|
*
|
|
98
98
|
* @property {number} width
|
|
99
|
-
* The width of the current video track.
|
|
99
|
+
* The width of the current video track. If nothing is loaded or the content
|
|
100
|
+
* is audio-only, NaN.
|
|
100
101
|
* @property {number} height
|
|
101
|
-
* The height of the current video track.
|
|
102
|
+
* The height of the current video track. If nothing is loaded or the content
|
|
103
|
+
* is audio-only, NaN.
|
|
102
104
|
* @property {number} streamBandwidth
|
|
103
105
|
* The bandwidth required for the current streams (total, in bit/sec).
|
|
104
|
-
* It takes into account the playbackrate.
|
|
106
|
+
* It takes into account the playbackrate. If nothing is loaded, NaN.
|
|
105
107
|
*
|
|
106
108
|
* @property {number} decodedFrames
|
|
107
|
-
* The total number of frames decoded by the Player.
|
|
108
|
-
*
|
|
109
|
+
* The total number of frames decoded by the Player. If not reported by the
|
|
110
|
+
* browser, NaN.
|
|
109
111
|
* @property {number} droppedFrames
|
|
110
|
-
* The total number of frames dropped by the Player.
|
|
111
|
-
*
|
|
112
|
+
* The total number of frames dropped by the Player. If not reported by the
|
|
113
|
+
* browser, NaN.
|
|
112
114
|
* @property {number} corruptedFrames
|
|
113
|
-
* The total number of corrupted frames dropped by the browser.
|
|
114
|
-
*
|
|
115
|
+
* The total number of corrupted frames dropped by the browser. If not
|
|
116
|
+
* reported by the browser, NaN.
|
|
115
117
|
* @property {number} estimatedBandwidth
|
|
116
|
-
* The current estimated network bandwidth (in bit/sec).
|
|
118
|
+
* The current estimated network bandwidth (in bit/sec). If no estimate
|
|
119
|
+
* available, NaN.
|
|
117
120
|
*
|
|
118
121
|
* @property {number} gapsJumped
|
|
119
122
|
* The total number of playback gaps jumped by the GapJumpingController.
|
|
123
|
+
* If nothing is loaded, NaN.
|
|
120
124
|
* @property {number} stallsDetected
|
|
121
125
|
* The total number of playback stalls detected by the StallDetector.
|
|
126
|
+
* If nothing is loaded, NaN.
|
|
122
127
|
*
|
|
123
128
|
* @property {number} completionPercent
|
|
124
129
|
* This is the greatest completion percent that the user has experienced in
|
|
125
|
-
* playback.
|
|
126
|
-
*
|
|
130
|
+
* playback. Also known as the "high water mark". If nothing is loaded, or
|
|
131
|
+
* the stream is live (and therefore indefinite), NaN.
|
|
127
132
|
* @property {number} loadLatency
|
|
128
133
|
* This is the number of seconds it took for the video element to have enough
|
|
129
134
|
* data to begin playback. This is measured from the time load() is called to
|
|
130
135
|
* the time the <code>'loadeddata'</code> event is fired by the media element.
|
|
136
|
+
* If nothing is loaded, NaN.
|
|
131
137
|
* @property {number} manifestTimeSeconds
|
|
132
138
|
* The amount of time it took to download and parse the manifest.
|
|
139
|
+
* If nothing is loaded, NaN.
|
|
133
140
|
* @property {number} drmTimeSeconds
|
|
134
141
|
* The amount of time it took to download the first drm key, and load that key
|
|
135
|
-
* into the drm system.
|
|
142
|
+
* into the drm system. If nothing is loaded or DRM is not in use, NaN.
|
|
136
143
|
* @property {number} playTime
|
|
137
|
-
* The total time spent in a playing state in seconds.
|
|
144
|
+
* The total time spent in a playing state in seconds. If nothing is loaded,
|
|
145
|
+
* NaN.
|
|
138
146
|
* @property {number} pauseTime
|
|
139
|
-
* The total time spent in a paused state in seconds.
|
|
147
|
+
* The total time spent in a paused state in seconds. If nothing is loaded,
|
|
148
|
+
* NaN.
|
|
140
149
|
* @property {number} bufferingTime
|
|
141
|
-
* The total time spent in a buffering state in seconds.
|
|
150
|
+
* The total time spent in a buffering state in seconds. If nothing is
|
|
151
|
+
* loaded, NaN.
|
|
142
152
|
* @property {number} licenseTime
|
|
143
|
-
* The time spent on license requests during this session in seconds
|
|
153
|
+
* The time spent on license requests during this session in seconds. If DRM
|
|
154
|
+
* is not in use, NaN.
|
|
144
155
|
* @property {number} liveLatency
|
|
145
156
|
* The time between the capturing of a frame and the end user having it
|
|
146
|
-
* displayed on their screen.
|
|
157
|
+
* displayed on their screen. If nothing is loaded or the content is VOD,
|
|
158
|
+
* NaN.
|
|
147
159
|
*
|
|
148
160
|
* @property {number} maxSegmentDuration
|
|
149
|
-
* The presentation's max segment duration in seconds
|
|
161
|
+
* The presentation's max segment duration in seconds. If nothing is loaded,
|
|
162
|
+
* NaN.
|
|
150
163
|
*
|
|
151
164
|
* @property {!Array.<shaka.extern.TrackChoice>} switchHistory
|
|
152
165
|
* A history of the stream changes.
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.abr.SimpleAbrManager');
|
|
8
8
|
|
|
9
|
-
goog.require('shaka.util.IReleasable');
|
|
10
9
|
goog.require('goog.asserts');
|
|
11
10
|
goog.require('shaka.abr.EwmaBandwidthEstimator');
|
|
12
11
|
goog.require('shaka.log');
|
|
12
|
+
goog.require('shaka.util.EventManager');
|
|
13
|
+
goog.require('shaka.util.IReleasable');
|
|
13
14
|
goog.require('shaka.util.StreamUtils');
|
|
14
15
|
goog.require('shaka.util.Timer');
|
|
15
16
|
|
|
@@ -50,30 +51,30 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
50
51
|
/** @private {shaka.abr.EwmaBandwidthEstimator} */
|
|
51
52
|
this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
|
|
52
53
|
|
|
53
|
-
/** @private {
|
|
54
|
-
this.
|
|
54
|
+
/** @private {!shaka.util.EventManager} */
|
|
55
|
+
this.eventManager_ = new shaka.util.EventManager();
|
|
55
56
|
|
|
56
57
|
// Some browsers implement the Network Information API, which allows
|
|
57
58
|
// retrieving information about a user's network connection. We listen
|
|
58
59
|
// to the change event to be able to make quick changes in case the type
|
|
59
60
|
// of connectivity changes.
|
|
60
61
|
if (navigator.connection && navigator.connection.addEventListener) {
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
this.eventManager_.listen(
|
|
63
|
+
/** @type {EventTarget} */(navigator.connection),
|
|
64
|
+
'change',
|
|
65
|
+
() => {
|
|
66
|
+
if (this.enabled_ && this.config_.useNetworkInformation) {
|
|
67
|
+
this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
|
|
68
|
+
if (this.config_) {
|
|
69
|
+
this.bandwidthEstimator_.configure(this.config_.advanced);
|
|
70
|
+
}
|
|
71
|
+
const chosenVariant = this.chooseVariant();
|
|
72
|
+
if (chosenVariant && navigator.onLine) {
|
|
73
|
+
this.switch_(chosenVariant, this.config_.clearBufferSwitch,
|
|
74
|
+
this.config_.safeMarginSwitch);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
/**
|
|
@@ -151,13 +152,7 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
151
152
|
*/
|
|
152
153
|
release() {
|
|
153
154
|
// stop() should already have been called for unload
|
|
154
|
-
|
|
155
|
-
if (navigator.connection && navigator.connection.removeEventListener) {
|
|
156
|
-
navigator.connection.removeEventListener(
|
|
157
|
-
'change', this.onNetworkInformationChange_);
|
|
158
|
-
this.onNetworkInformationChange_ = null;
|
|
159
|
-
}
|
|
160
|
-
|
|
155
|
+
this.eventManager_.release();
|
|
161
156
|
this.resizeObserverTimer_ = null;
|
|
162
157
|
}
|
|
163
158
|
|
package/lib/ads/ad_manager.js
CHANGED
|
@@ -656,7 +656,7 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
|
|
|
656
656
|
*/
|
|
657
657
|
getServerSideCuePoints() {
|
|
658
658
|
shaka.Deprecate.deprecateFeature(5,
|
|
659
|
-
'AdManager',
|
|
659
|
+
'AdManager.getServerSideCuePoints',
|
|
660
660
|
'Please use getCuePoints function.');
|
|
661
661
|
return this.getCuePoints();
|
|
662
662
|
}
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -188,12 +188,10 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
188
188
|
* @export
|
|
189
189
|
*/
|
|
190
190
|
async cast() {
|
|
191
|
-
const initState = this.getInitState_();
|
|
192
|
-
|
|
193
191
|
// TODO: transfer manually-selected tracks?
|
|
194
192
|
// TODO: transfer side-loaded text tracks?
|
|
195
193
|
|
|
196
|
-
await this.sender_.cast(
|
|
194
|
+
await this.sender_.cast();
|
|
197
195
|
if (!this.localPlayer_) {
|
|
198
196
|
// We've already been destroyed.
|
|
199
197
|
return;
|
package/lib/cast/cast_sender.js
CHANGED
|
@@ -261,12 +261,10 @@ shaka.cast.CastSender = class {
|
|
|
261
261
|
|
|
262
262
|
|
|
263
263
|
/**
|
|
264
|
-
* @param {shaka.cast.CastUtils.InitStateType} initState Video and player
|
|
265
|
-
* state to be sent to the receiver.
|
|
266
264
|
* @return {!Promise} Resolved when connected to a receiver. Rejected if the
|
|
267
265
|
* connection fails or is canceled by the user.
|
|
268
266
|
*/
|
|
269
|
-
async cast(
|
|
267
|
+
async cast() {
|
|
270
268
|
if (!this.apiReady_) {
|
|
271
269
|
throw new shaka.util.Error(
|
|
272
270
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
@@ -288,7 +286,7 @@ shaka.cast.CastSender = class {
|
|
|
288
286
|
|
|
289
287
|
this.castPromise_ = new shaka.util.PublicPromise();
|
|
290
288
|
chrome.cast.requestSession(
|
|
291
|
-
(session) => this.onSessionInitiated_(
|
|
289
|
+
(session) => this.onSessionInitiated_(session),
|
|
292
290
|
(error) => this.onConnectionError_(error));
|
|
293
291
|
await this.castPromise_;
|
|
294
292
|
}
|
|
@@ -303,10 +301,9 @@ shaka.cast.CastSender = class {
|
|
|
303
301
|
if (!this.isCasting_) {
|
|
304
302
|
return;
|
|
305
303
|
}
|
|
306
|
-
const initState = this.onInitStateRequired_();
|
|
307
304
|
|
|
308
305
|
chrome.cast.requestSession(
|
|
309
|
-
(session) => this.onSessionInitiated_(
|
|
306
|
+
(session) => this.onSessionInitiated_(session),
|
|
310
307
|
(error) => this.onConnectionError_(error));
|
|
311
308
|
}
|
|
312
309
|
|
|
@@ -401,12 +398,14 @@ shaka.cast.CastSender = class {
|
|
|
401
398
|
|
|
402
399
|
|
|
403
400
|
/**
|
|
404
|
-
* @param {shaka.cast.CastUtils.InitStateType} initState
|
|
405
401
|
* @param {chrome.cast.Session} session
|
|
406
402
|
* @private
|
|
407
403
|
*/
|
|
408
|
-
onSessionInitiated_(
|
|
404
|
+
onSessionInitiated_(session) {
|
|
409
405
|
shaka.log.debug('CastSender: onSessionInitiated');
|
|
406
|
+
|
|
407
|
+
const initState = this.onInitStateRequired_();
|
|
408
|
+
|
|
410
409
|
this.onSessionCreated_(session);
|
|
411
410
|
|
|
412
411
|
this.sendMessage_({
|
|
@@ -529,12 +528,10 @@ shaka.cast.CastSender = class {
|
|
|
529
528
|
onExistingSessionJoined_(session) {
|
|
530
529
|
shaka.log.debug('CastSender: onExistingSessionJoined');
|
|
531
530
|
|
|
532
|
-
const initState = this.onInitStateRequired_();
|
|
533
|
-
|
|
534
531
|
this.castPromise_ = new shaka.util.PublicPromise();
|
|
535
532
|
this.hasJoinedExistingSession_ = true;
|
|
536
533
|
|
|
537
|
-
this.onSessionInitiated_(
|
|
534
|
+
this.onSessionInitiated_(session);
|
|
538
535
|
}
|
|
539
536
|
|
|
540
537
|
|
package/lib/cea/cea608_memory.js
CHANGED
|
@@ -293,7 +293,7 @@ shaka.cea.Cea608Memory.CharSet.BasicNorthAmericanChars = new Map([
|
|
|
293
293
|
*/
|
|
294
294
|
shaka.cea.Cea608Memory.CharSet.SpecialNorthAmericanChars = new Map([
|
|
295
295
|
[0x30, '®'], [0x31, '°'], [0x32, '½'], [0x33, '¿'], [0x34, '™'], [0x35, '¢'],
|
|
296
|
-
[0x36, '£'], [0x37, '♪'], [0x38, 'à'], [0x39, '
|
|
296
|
+
[0x36, '£'], [0x37, '♪'], [0x38, 'à'], [0x39, ' '], [0x3a, 'è'], [0x3b, 'â'],
|
|
297
297
|
[0x3c, 'ê'], [0x3d, 'î'], [0x3e, 'ô'], [0x3f, 'û'],
|
|
298
298
|
]);
|
|
299
299
|
|
package/lib/cea/ts_cea_parser.js
CHANGED
|
@@ -26,6 +26,9 @@ shaka.cea.TsCeaParser = class {
|
|
|
26
26
|
* @const {!shaka.cea.SeiProcessor}
|
|
27
27
|
*/
|
|
28
28
|
this.seiProcessor_ = new shaka.cea.SeiProcessor();
|
|
29
|
+
|
|
30
|
+
/** @private {?shaka.util.TsParser} */
|
|
31
|
+
this.tsParser_ = null;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -41,6 +44,12 @@ shaka.cea.TsCeaParser = class {
|
|
|
41
44
|
parse(mediaSegment) {
|
|
42
45
|
const CeaUtils = shaka.cea.CeaUtils;
|
|
43
46
|
|
|
47
|
+
if (!this.tsParser_) {
|
|
48
|
+
this.tsParser_ = new shaka.util.TsParser();
|
|
49
|
+
} else {
|
|
50
|
+
this.tsParser_.clearData();
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
/** @type {!Array<!shaka.extern.ICeaParser.CaptionPacket>} **/
|
|
45
54
|
const captionPackets = [];
|
|
46
55
|
|
|
@@ -48,7 +57,7 @@ shaka.cea.TsCeaParser = class {
|
|
|
48
57
|
if (!shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
49
58
|
return captionPackets;
|
|
50
59
|
}
|
|
51
|
-
const tsParser =
|
|
60
|
+
const tsParser = this.tsParser_.parse(uint8ArrayData);
|
|
52
61
|
const codecs = tsParser.getCodecs();
|
|
53
62
|
const videoNalus = tsParser.getVideoNalus();
|
|
54
63
|
const validNaluTypes = [];
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -643,6 +643,9 @@ shaka.dash.DashParser = class {
|
|
|
643
643
|
// best latency
|
|
644
644
|
if (this.lowLatencyMode_) {
|
|
645
645
|
minBufferTime = 0;
|
|
646
|
+
const presentationDelay = suggestedPresentationDelay != null ?
|
|
647
|
+
suggestedPresentationDelay : this.config_.defaultPresentationDelay;
|
|
648
|
+
presentationTimeline.setDelay(presentationDelay);
|
|
646
649
|
}
|
|
647
650
|
|
|
648
651
|
// These steps are not done on manifest update.
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -32,6 +32,7 @@ goog.require('shaka.util.FakeEvent');
|
|
|
32
32
|
goog.require('shaka.util.LanguageUtils');
|
|
33
33
|
goog.require('shaka.util.ManifestParserUtils');
|
|
34
34
|
goog.require('shaka.util.MimeUtils');
|
|
35
|
+
goog.require('shaka.util.Networking');
|
|
35
36
|
goog.require('shaka.util.OperationManager');
|
|
36
37
|
goog.require('shaka.util.Pssh');
|
|
37
38
|
goog.require('shaka.media.SegmentUtils');
|
|
@@ -551,7 +552,7 @@ shaka.hls.HlsParser = class {
|
|
|
551
552
|
if (goog.DEBUG) {
|
|
552
553
|
const firstSequenceStartTime =
|
|
553
554
|
mediaSequenceToStartTime.values().next().value;
|
|
554
|
-
|
|
555
|
+
shaka.log.warning(
|
|
555
556
|
firstSequenceStartTime == segment0.startTime,
|
|
556
557
|
'Sequence number map is not ordered as expected!');
|
|
557
558
|
}
|
|
@@ -585,16 +586,18 @@ shaka.hls.HlsParser = class {
|
|
|
585
586
|
// Drop any earlier references.
|
|
586
587
|
const numSegmentsToDrop =
|
|
587
588
|
this.minSequenceNumber_ - streamInfo.firstSequenceNumber;
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
589
|
+
if (numSegmentsToDrop > 0) {
|
|
590
|
+
segmentIndex.dropFirstReferences(numSegmentsToDrop);
|
|
591
|
+
|
|
592
|
+
// Now adjust timestamps back to begin at 0.
|
|
593
|
+
const segmentN = segmentIndex.earliestReference();
|
|
594
|
+
if (segmentN) {
|
|
595
|
+
const streamOffset = -segmentN.startTime;
|
|
596
|
+
// Modify all SegmentReferences equally.
|
|
597
|
+
streamInfo.stream.segmentIndex.offset(streamOffset);
|
|
598
|
+
// Update other parts of streamInfo the same way.
|
|
599
|
+
this.offsetStreamInfo_(streamInfo, streamOffset);
|
|
600
|
+
}
|
|
598
601
|
}
|
|
599
602
|
}
|
|
600
603
|
}
|
|
@@ -909,8 +912,11 @@ shaka.hls.HlsParser = class {
|
|
|
909
912
|
playlist, middleSegment.tags, getUris);
|
|
910
913
|
this.mapTagToInitSegmentRefMap_.clear();
|
|
911
914
|
if (initSegmentRef) {
|
|
912
|
-
const initSegmentRequest = shaka.
|
|
913
|
-
initSegmentRef.getUris(),
|
|
915
|
+
const initSegmentRequest = shaka.util.Networking.createSegmentRequest(
|
|
916
|
+
initSegmentRef.getUris(),
|
|
917
|
+
initSegmentRef.getStartByte(),
|
|
918
|
+
initSegmentRef.getEndByte(),
|
|
919
|
+
this.config_.retryParameters);
|
|
914
920
|
const initType =
|
|
915
921
|
shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT;
|
|
916
922
|
const initResponse = await this.makeNetworkRequest_(
|
|
@@ -982,17 +988,17 @@ shaka.hls.HlsParser = class {
|
|
|
982
988
|
}
|
|
983
989
|
|
|
984
990
|
if (!this.presentationTimeline_.isStartTimeLocked()) {
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
991
|
+
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
992
|
+
if (!streamInfo.stream.segmentIndex) {
|
|
993
|
+
continue; // Not active.
|
|
994
|
+
}
|
|
989
995
|
if (streamInfo.type != 'audio' && streamInfo.type != 'video') {
|
|
990
996
|
continue;
|
|
991
997
|
}
|
|
992
998
|
const firstReference = streamInfo.stream.segmentIndex.get(0);
|
|
993
999
|
if (firstReference && firstReference.syncTime) {
|
|
994
1000
|
const syncTime = firstReference.syncTime;
|
|
995
|
-
this.presentationTimeline_.
|
|
1001
|
+
this.presentationTimeline_.setInitialProgramDateTime(syncTime);
|
|
996
1002
|
}
|
|
997
1003
|
}
|
|
998
1004
|
}
|
|
@@ -4130,7 +4136,22 @@ shaka.hls.HlsParser = class {
|
|
|
4130
4136
|
* @return {?shaka.extern.DrmInfo}
|
|
4131
4137
|
* @private
|
|
4132
4138
|
*/
|
|
4133
|
-
static identityDrmParser_(drmTag) {
|
|
4139
|
+
static identityDrmParser_(drmTag, mimeType) {
|
|
4140
|
+
if (mimeType == 'video/mp2t') {
|
|
4141
|
+
throw new shaka.util.Error(
|
|
4142
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4143
|
+
shaka.util.Error.Category.MANIFEST,
|
|
4144
|
+
shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4147
|
+
if (shaka.util.Platform.isMediaKeysPolyfilled()) {
|
|
4148
|
+
throw new shaka.util.Error(
|
|
4149
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4150
|
+
shaka.util.Error.Category.MANIFEST,
|
|
4151
|
+
shaka.util.Error.Code
|
|
4152
|
+
.HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED);
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4134
4155
|
const method = drmTag.getRequiredAttrValue('METHOD');
|
|
4135
4156
|
const VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR'];
|
|
4136
4157
|
if (!VALID_METHODS.includes(method)) {
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -697,9 +697,12 @@ shaka.media.DrmEngine = class {
|
|
|
697
697
|
initDataOverride.initDataType, initDataOverride.initData);
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
-
// If
|
|
701
|
-
// it will never get resolved.
|
|
702
|
-
|
|
700
|
+
// If there were no sessions to load, we need to resolve the promise right
|
|
701
|
+
// now or else it will never get resolved.
|
|
702
|
+
// We determine this by checking areAllSessionsLoaded_, rather than checking
|
|
703
|
+
// the number of initDatas, since the newInitData method can reject init
|
|
704
|
+
// datas in some circumstances.
|
|
705
|
+
if (this.areAllSessionsLoaded_()) {
|
|
703
706
|
this.allSessionsLoaded_.resolve();
|
|
704
707
|
}
|
|
705
708
|
|
|
@@ -28,7 +28,7 @@ shaka.media.ManifestParser = class {
|
|
|
28
28
|
*/
|
|
29
29
|
static registerParserByExtension(extension, parserFactory) {
|
|
30
30
|
shaka.Deprecate.deprecateFeature(5,
|
|
31
|
-
'ManifestParser',
|
|
31
|
+
'ManifestParser.registerParserByExtension',
|
|
32
32
|
'Please use an ManifestParser with registerParserByMime function.');
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -125,7 +125,8 @@ shaka.media.ManifestParser = class {
|
|
|
125
125
|
shaka.util.Error.Severity.CRITICAL,
|
|
126
126
|
shaka.util.Error.Category.MANIFEST,
|
|
127
127
|
shaka.util.Error.Code.UNABLE_TO_GUESS_MANIFEST_TYPE,
|
|
128
|
-
uri
|
|
128
|
+
uri,
|
|
129
|
+
mimeType);
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
|
|
@@ -151,6 +151,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
151
151
|
|
|
152
152
|
/** @private {?number} */
|
|
153
153
|
this.lastDuration_ = null;
|
|
154
|
+
|
|
155
|
+
/** @private {?shaka.util.TsParser} */
|
|
156
|
+
this.tsParser_ = null;
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
/**
|
|
@@ -392,6 +395,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
392
395
|
|
|
393
396
|
// This object is owned by Player
|
|
394
397
|
this.lcevcDec_ = null;
|
|
398
|
+
|
|
399
|
+
this.tsParser_ = null;
|
|
395
400
|
}
|
|
396
401
|
|
|
397
402
|
/**
|
|
@@ -442,6 +447,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
442
447
|
this.manifestType_ == shaka.media.ManifestParser.HLS &&
|
|
443
448
|
!this.ignoreManifestTimestampsInSegmentsMode_;
|
|
444
449
|
|
|
450
|
+
this.tsParser_ = null;
|
|
451
|
+
|
|
445
452
|
for (const contentType of streamsByType.keys()) {
|
|
446
453
|
const stream = streamsByType.get(contentType);
|
|
447
454
|
this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
@@ -460,10 +467,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
460
467
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
461
468
|
* @param {shaka.extern.Stream} stream
|
|
462
469
|
* @param {string} codecs
|
|
463
|
-
* @param {boolean=} forceTransmux
|
|
464
470
|
* @private
|
|
465
471
|
*/
|
|
466
|
-
initSourceBuffer_(contentType, stream, codecs
|
|
472
|
+
initSourceBuffer_(contentType, stream, codecs) {
|
|
467
473
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
468
474
|
|
|
469
475
|
goog.asserts.assert(
|
|
@@ -475,7 +481,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
475
481
|
if (contentType == ContentType.TEXT) {
|
|
476
482
|
this.reinitText(mimeType, this.sequenceMode_, stream.external);
|
|
477
483
|
} else {
|
|
478
|
-
let needTransmux = this.config_.forceTransmux
|
|
484
|
+
let needTransmux = this.config_.forceTransmux;
|
|
479
485
|
if (!shaka.media.Capabilities.isTypeSupported(mimeType) ||
|
|
480
486
|
(!this.sequenceMode_ &&
|
|
481
487
|
shaka.util.MimeUtils.RAW_FORMATS.includes(mimeType))) {
|
|
@@ -492,10 +498,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
492
498
|
ContentType.VIDEO, (codecs || '').split(','));
|
|
493
499
|
if (audioCodec && videoCodec) {
|
|
494
500
|
this.needSplitMuxedContent_ = true;
|
|
495
|
-
this.initSourceBuffer_(
|
|
496
|
-
|
|
497
|
-
this.initSourceBuffer_(
|
|
498
|
-
ContentType.VIDEO, stream, videoCodec, /* forceTransmux= */ true);
|
|
501
|
+
this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
|
|
502
|
+
this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
|
|
499
503
|
return;
|
|
500
504
|
}
|
|
501
505
|
const transmuxerPlugin =
|
|
@@ -789,7 +793,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
789
793
|
}
|
|
790
794
|
} else if (!mimeType.includes('/mp4') && !mimeType.includes('/webm') &&
|
|
791
795
|
shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
792
|
-
|
|
796
|
+
if (!this.tsParser_) {
|
|
797
|
+
this.tsParser_ = new shaka.util.TsParser();
|
|
798
|
+
} else {
|
|
799
|
+
this.tsParser_.clearData();
|
|
800
|
+
}
|
|
801
|
+
const tsParser = this.tsParser_.parse(uint8ArrayData);
|
|
793
802
|
const startTime = tsParser.getStartTime(contentType);
|
|
794
803
|
if (startTime != null) {
|
|
795
804
|
timestamp = startTime;
|
|
@@ -1177,6 +1186,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1177
1186
|
return;
|
|
1178
1187
|
}
|
|
1179
1188
|
|
|
1189
|
+
// Reset the promise in case the timestamp offset changed during
|
|
1190
|
+
// a period/discontinuity transition.
|
|
1191
|
+
if (contentType == ContentType.VIDEO) {
|
|
1192
|
+
this.textSequenceModeOffset_ = new shaka.util.PublicPromise();
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1180
1195
|
// Queue an abort() to help MSE splice together overlapping segments.
|
|
1181
1196
|
// We set appendWindowEnd when we change periods in DASH content, and the
|
|
1182
1197
|
// period transition may result in overlap.
|
|
@@ -1857,8 +1872,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1857
1872
|
let needTransmux = this.config_.forceTransmux;
|
|
1858
1873
|
if (!shaka.media.Capabilities.isTypeSupported(newMimeType) ||
|
|
1859
1874
|
(!this.sequenceMode_ &&
|
|
1860
|
-
shaka.util.MimeUtils.RAW_FORMATS.includes(newMimeType))
|
|
1861
|
-
codecs.includes(',')) {
|
|
1875
|
+
shaka.util.MimeUtils.RAW_FORMATS.includes(newMimeType))) {
|
|
1862
1876
|
needTransmux = true;
|
|
1863
1877
|
}
|
|
1864
1878
|
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
@@ -1939,8 +1953,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1939
1953
|
let needTransmux = this.config_.forceTransmux;
|
|
1940
1954
|
if (!shaka.media.Capabilities.isTypeSupported(newMimeType) ||
|
|
1941
1955
|
(!this.sequenceMode_ &&
|
|
1942
|
-
shaka.util.MimeUtils.RAW_FORMATS.includes(newMimeType))
|
|
1943
|
-
stream.codecs.includes(',')) {
|
|
1956
|
+
shaka.util.MimeUtils.RAW_FORMATS.includes(newMimeType))) {
|
|
1944
1957
|
needTransmux = true;
|
|
1945
1958
|
}
|
|
1946
1959
|
const newMimeTypeWithAllCodecs =
|
|
@@ -96,6 +96,9 @@ shaka.media.PresentationTimeline = class {
|
|
|
96
96
|
|
|
97
97
|
/** @private {boolean} */
|
|
98
98
|
this.startTimeLocked_ = false;
|
|
99
|
+
|
|
100
|
+
/** @private {?number} */
|
|
101
|
+
this.initialProgramDateTime_ = null;
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
|
|
@@ -339,6 +342,26 @@ shaka.media.PresentationTimeline = class {
|
|
|
339
342
|
}
|
|
340
343
|
|
|
341
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Sets the initial program date time.
|
|
347
|
+
*
|
|
348
|
+
* @param {number} initialProgramDateTime
|
|
349
|
+
* @export
|
|
350
|
+
*/
|
|
351
|
+
setInitialProgramDateTime(initialProgramDateTime) {
|
|
352
|
+
this.initialProgramDateTime_ = initialProgramDateTime;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @return {?number} The initial program date time in seconds.
|
|
358
|
+
* @export
|
|
359
|
+
*/
|
|
360
|
+
getInitialProgramDateTime() {
|
|
361
|
+
return this.initialProgramDateTime_;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
342
365
|
/**
|
|
343
366
|
* Gives PresentationTimeline a Stream's minimum segment start time.
|
|
344
367
|
*
|
|
@@ -55,6 +55,7 @@ shaka.media.SegmentUtils = class {
|
|
|
55
55
|
let hasVideo = false;
|
|
56
56
|
switch (tsCodecs.audio) {
|
|
57
57
|
case 'aac':
|
|
58
|
+
case 'aac-loas':
|
|
58
59
|
codecs.push('mp4a.40.2');
|
|
59
60
|
hasAudio = true;
|
|
60
61
|
break;
|
|
@@ -70,6 +71,10 @@ shaka.media.SegmentUtils = class {
|
|
|
70
71
|
codecs.push('ec-3');
|
|
71
72
|
hasAudio = true;
|
|
72
73
|
break;
|
|
74
|
+
case 'opus':
|
|
75
|
+
codecs.push('opus');
|
|
76
|
+
hasAudio = true;
|
|
77
|
+
break;
|
|
73
78
|
}
|
|
74
79
|
switch (tsCodecs.video) {
|
|
75
80
|
case 'avc':
|
|
@@ -88,6 +93,10 @@ shaka.media.SegmentUtils = class {
|
|
|
88
93
|
}
|
|
89
94
|
hasVideo = true;
|
|
90
95
|
break;
|
|
96
|
+
case 'av1':
|
|
97
|
+
codecs.push('av01.0.01M.08');
|
|
98
|
+
hasVideo = true;
|
|
99
|
+
break;
|
|
91
100
|
}
|
|
92
101
|
if (!codecs.length) {
|
|
93
102
|
return null;
|
|
@@ -256,7 +265,7 @@ shaka.media.SegmentUtils = class {
|
|
|
256
265
|
// This signals an encrypted sample, which we can go inside of to
|
|
257
266
|
// find the codec used.
|
|
258
267
|
// Note: If encrypted, you can only have audio or video, not both.
|
|
259
|
-
.box('enca', Mp4Parser.
|
|
268
|
+
.box('enca', Mp4Parser.audioSampleEntry)
|
|
260
269
|
.box('encv', Mp4Parser.visualSampleEntry)
|
|
261
270
|
.box('sinf', Mp4Parser.children)
|
|
262
271
|
.box('frma', (box) => {
|