shaka-player 4.9.34 → 4.9.36
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/README.md +9 -3
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +6 -6
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.externs.js +4 -3
- package/dist/shaka-player.compiled.debug.js +445 -427
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +4 -3
- package/dist/shaka-player.compiled.js +1254 -1240
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.dash.d.ts +4099 -0
- package/dist/shaka-player.dash.debug.d.ts +4099 -0
- package/dist/shaka-player.dash.debug.externs.js +4188 -0
- package/dist/shaka-player.dash.debug.js +2161 -0
- package/dist/shaka-player.dash.debug.map +8 -0
- package/dist/shaka-player.dash.externs.js +4188 -0
- package/dist/shaka-player.dash.js +1007 -0
- package/dist/shaka-player.dash.map +8 -0
- package/dist/shaka-player.hls.d.ts +4196 -0
- package/dist/shaka-player.hls.debug.d.ts +4196 -0
- package/dist/shaka-player.hls.debug.externs.js +4403 -0
- package/dist/shaka-player.hls.debug.js +2243 -0
- package/dist/shaka-player.hls.debug.map +8 -0
- package/dist/shaka-player.hls.externs.js +4403 -0
- package/dist/shaka-player.hls.js +1076 -0
- package/dist/shaka-player.hls.map +8 -0
- package/dist/shaka-player.ui.d.ts +1 -0
- package/dist/shaka-player.ui.debug.d.ts +1 -0
- package/dist/shaka-player.ui.debug.externs.js +4 -3
- package/dist/shaka-player.ui.debug.js +472 -454
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +4 -3
- package/dist/shaka-player.ui.js +1495 -1484
- package/dist/shaka-player.ui.map +3 -3
- package/externs/shaka/player.js +8 -4
- package/lib/cast/cast_proxy.js +48 -10
- package/lib/cea/cea708_service.js +20 -2
- package/lib/cea/dtvcc_packet_builder.js +15 -0
- package/lib/dash/dash_parser.js +24 -13
- package/lib/dash/mpd_utils.js +7 -4
- package/lib/dash/segment_template.js +74 -56
- package/lib/hls/hls_parser.js +5 -4
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/content_workarounds.js +110 -72
- package/lib/media/drm_engine.js +72 -11
- package/lib/media/gap_jumping_controller.js +14 -1
- package/lib/media/media_source_engine.js +29 -11
- package/lib/media/region_timeline.js +4 -3
- package/lib/media/segment_utils.js +28 -16
- package/lib/media/streaming_engine.js +38 -12
- package/lib/net/http_fetch_plugin.js +1 -1
- package/lib/net/http_plugin_utils.js +4 -1
- package/lib/net/networking_engine.js +8 -0
- package/lib/net/networking_utils.js +1 -0
- package/lib/player.js +109 -37
- package/lib/polyfill/patchedmediakeys_apple.js +21 -0
- package/lib/text/cue.js +6 -2
- package/lib/text/mp4_ttml_parser.js +94 -6
- package/lib/text/ui_text_displayer.js +35 -4
- package/lib/transmuxer/ac3_transmuxer.js +6 -1
- package/lib/util/config_utils.js +13 -3
- package/lib/util/drm_utils.js +8 -0
- package/lib/util/error.js +6 -0
- package/lib/util/mp4_generator.js +19 -4
- package/lib/util/periods.js +4 -2
- package/lib/util/platform.js +60 -12
- package/lib/util/player_configuration.js +13 -2
- package/lib/util/stream_utils.js +18 -0
- package/lib/util/tXml.js +3 -2
- package/package.json +3 -3
- package/ui/controls.js +2 -6
- package/ui/less/thumbnails.less +1 -0
- package/ui/statistics_button.js +3 -1
- package/ui/ui.js +44 -35
package/externs/shaka/player.js
CHANGED
|
@@ -1204,7 +1204,8 @@ shaka.extern.MssManifestConfiguration;
|
|
|
1204
1204
|
* A default <code>presentationDelay</code> value.
|
|
1205
1205
|
* For DASH, it's a default <code>presentationDelay</code> value if
|
|
1206
1206
|
* <code>suggestedPresentationDelay</code> is missing in the MPEG DASH
|
|
1207
|
-
* manifest. The default value is <code>1.5 *
|
|
1207
|
+
* manifest. The default value is the lower of <code>1.5 *
|
|
1208
|
+
* minBufferTime</code> and <code>segmentAvailabilityDuration</code> if not
|
|
1208
1209
|
* configured or set as 0.
|
|
1209
1210
|
* For HLS, the default value is 3 segments duration if not configured or
|
|
1210
1211
|
* set as 0.
|
|
@@ -1483,9 +1484,12 @@ shaka.extern.ManifestConfiguration;
|
|
|
1483
1484
|
* <code>vodDynamicPlaybackRateLowBufferRate</code>.
|
|
1484
1485
|
* Defaults to <code>0.5</code>.
|
|
1485
1486
|
* @property {boolean} infiniteLiveStreamDuration
|
|
1486
|
-
* If <code>true</code>, the media source
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
1487
|
+
* If <code>true</code>, the media source duration of livestreams will be set
|
|
1488
|
+
* to <code>Infinity</code>. Otherwise, it will be set to a high but
|
|
1489
|
+
* non-infinite number (2^32).
|
|
1490
|
+
* <br>
|
|
1491
|
+
* Defaults to <code>false</code> except on Safari 17 or above whose default
|
|
1492
|
+
* value is <code>true</code>.
|
|
1489
1493
|
* @property {number} preloadNextUrlWindow
|
|
1490
1494
|
* The window of time at the end of the presentation to begin preloading the
|
|
1491
1495
|
* next URL, such as one specified by a urn:mpeg:dash:chaining:2016 element
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -81,17 +81,21 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
81
81
|
this.compiledToExternNames_ = new Map();
|
|
82
82
|
|
|
83
83
|
/** @private {shaka.cast.CastSender} */
|
|
84
|
-
this.sender_ =
|
|
85
|
-
receiverAppId,
|
|
86
|
-
() => this.onCastStatusChanged_(),
|
|
87
|
-
() => this.onFirstCastStateUpdate_(),
|
|
88
|
-
(targetName, event) => this.onRemoteEvent_(targetName, event),
|
|
89
|
-
() => this.onResumeLocal_(),
|
|
90
|
-
() => this.getInitState_(),
|
|
91
|
-
androidReceiverCompatible);
|
|
92
|
-
|
|
84
|
+
this.sender_ = null;
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
if (window.chrome) {
|
|
87
|
+
this.sender_ = new shaka.cast.CastSender(
|
|
88
|
+
receiverAppId,
|
|
89
|
+
() => this.onCastStatusChanged_(),
|
|
90
|
+
() => this.onFirstCastStateUpdate_(),
|
|
91
|
+
(targetName, event) => this.onRemoteEvent_(targetName, event),
|
|
92
|
+
() => this.onResumeLocal_(),
|
|
93
|
+
() => this.getInitState_(),
|
|
94
|
+
androidReceiverCompatible);
|
|
95
|
+
this.init_();
|
|
96
|
+
} else {
|
|
97
|
+
this.initWithoutSender_();
|
|
98
|
+
}
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
/**
|
|
@@ -163,6 +167,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
163
167
|
* @export
|
|
164
168
|
*/
|
|
165
169
|
canCast() {
|
|
170
|
+
if (!this.sender_) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
166
173
|
return this.sender_.apiReady() && this.sender_.hasReceivers();
|
|
167
174
|
}
|
|
168
175
|
|
|
@@ -171,6 +178,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
171
178
|
* @export
|
|
172
179
|
*/
|
|
173
180
|
isCasting() {
|
|
181
|
+
if (!this.sender_) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
174
184
|
return this.sender_.isCasting();
|
|
175
185
|
}
|
|
176
186
|
|
|
@@ -179,6 +189,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
179
189
|
* @export
|
|
180
190
|
*/
|
|
181
191
|
receiverName() {
|
|
192
|
+
if (!this.sender_) {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
182
195
|
return this.sender_.receiverName();
|
|
183
196
|
}
|
|
184
197
|
|
|
@@ -188,6 +201,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
188
201
|
* @export
|
|
189
202
|
*/
|
|
190
203
|
async cast() {
|
|
204
|
+
if (!this.sender_) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
191
207
|
// TODO: transfer manually-selected tracks?
|
|
192
208
|
// TODO: transfer side-loaded text tracks?
|
|
193
209
|
|
|
@@ -208,6 +224,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
208
224
|
* @export
|
|
209
225
|
*/
|
|
210
226
|
setAppData(appData) {
|
|
227
|
+
if (!this.sender_) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
211
230
|
this.sender_.setAppData(appData);
|
|
212
231
|
}
|
|
213
232
|
|
|
@@ -216,6 +235,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
216
235
|
* @export
|
|
217
236
|
*/
|
|
218
237
|
suggestDisconnect() {
|
|
238
|
+
if (!this.sender_) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
219
241
|
this.sender_.showDisconnectDialog();
|
|
220
242
|
}
|
|
221
243
|
|
|
@@ -224,6 +246,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
224
246
|
* @export
|
|
225
247
|
*/
|
|
226
248
|
forceDisconnect() {
|
|
249
|
+
if (!this.sender_) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
227
252
|
this.sender_.forceDisconnect();
|
|
228
253
|
}
|
|
229
254
|
|
|
@@ -243,6 +268,10 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
243
268
|
this.receiverAppId_ = newAppId;
|
|
244
269
|
this.androidReceiverCompatible_ = newCastAndroidReceiver;
|
|
245
270
|
|
|
271
|
+
if (!this.sender_) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
246
275
|
// Destroy the old sender
|
|
247
276
|
this.sender_.forceDisconnect();
|
|
248
277
|
await this.sender_.destroy();
|
|
@@ -262,6 +291,15 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
262
291
|
this.sender_.init();
|
|
263
292
|
}
|
|
264
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Initialize the Proxies without Cast sender.
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
initWithoutSender_() {
|
|
299
|
+
this.videoProxy_ = /** @type {Object} */(this.localVideo_);
|
|
300
|
+
this.playerProxy_ = /** @type {Object} */(this.localPlayer_);
|
|
301
|
+
}
|
|
302
|
+
|
|
265
303
|
/**
|
|
266
304
|
* Initialize the Proxies and the Cast sender.
|
|
267
305
|
* @private
|
|
@@ -60,7 +60,7 @@ shaka.cea.Cea708Service = class {
|
|
|
60
60
|
// Control codes are in 1 of 4 logical groups:
|
|
61
61
|
// CL (C0, C2), CR (C1, C3), GL (G0, G2), GR (G1, G2).
|
|
62
62
|
if (controlCode >= 0x00 && controlCode <= 0x1f) {
|
|
63
|
-
return this.handleC0_(controlCode, pts);
|
|
63
|
+
return this.handleC0_(dtvccPacket, controlCode, pts);
|
|
64
64
|
} else if (controlCode >= 0x80 && controlCode <= 0x9f) {
|
|
65
65
|
return this.handleC1_(dtvccPacket, controlCode, pts);
|
|
66
66
|
} else if (controlCode >= 0x1000 && controlCode <= 0x101f) {
|
|
@@ -153,17 +153,35 @@ shaka.cea.Cea708Service = class {
|
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* Handles C0 group data.
|
|
156
|
+
* @param {!shaka.cea.DtvccPacket} dtvccPacket
|
|
156
157
|
* @param {number} controlCode
|
|
157
158
|
* @param {number} pts
|
|
158
159
|
* @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
|
|
159
160
|
* @private
|
|
160
161
|
*/
|
|
161
|
-
handleC0_(controlCode, pts) {
|
|
162
|
+
handleC0_(dtvccPacket, controlCode, pts) {
|
|
162
163
|
// All these commands pertain to the current window, so ensure it exists.
|
|
163
164
|
if (!this.currentWindow_) {
|
|
164
165
|
return null;
|
|
165
166
|
}
|
|
166
167
|
|
|
168
|
+
if (controlCode == 0x18) {
|
|
169
|
+
const firstByte = dtvccPacket.readByte().value;
|
|
170
|
+
const secondByte = dtvccPacket.readByte().value;
|
|
171
|
+
|
|
172
|
+
const toHexString = (byteArray) => {
|
|
173
|
+
return byteArray.map((byte) => {
|
|
174
|
+
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
|
175
|
+
}).join('');
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const unicode = toHexString([firstByte, secondByte]);
|
|
179
|
+
// Takes a unicode hex string and creates a single character.
|
|
180
|
+
const char = String.fromCharCode(parseInt(unicode, 16));
|
|
181
|
+
this.currentWindow_.setCharacter(char);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
167
185
|
const window = this.currentWindow_;
|
|
168
186
|
let parsedClosedCaption = null;
|
|
169
187
|
|
|
@@ -161,6 +161,21 @@ shaka.cea.DtvccPacket = class {
|
|
|
161
161
|
}
|
|
162
162
|
this.pos_ += numBlocks;
|
|
163
163
|
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Rewinds the provided number of blocks in the buffer.
|
|
167
|
+
* @param {number} numBlocks
|
|
168
|
+
* @throws {!shaka.util.Error}
|
|
169
|
+
*/
|
|
170
|
+
rewind(numBlocks) {
|
|
171
|
+
if (this.pos_ - numBlocks < 0) {
|
|
172
|
+
throw new shaka.util.Error(
|
|
173
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
174
|
+
shaka.util.Error.Category.TEXT,
|
|
175
|
+
shaka.util.Error.Code.BUFFER_READ_OUT_OF_BOUNDS);
|
|
176
|
+
}
|
|
177
|
+
this.pos_ -= numBlocks;
|
|
178
|
+
}
|
|
164
179
|
};
|
|
165
180
|
|
|
166
181
|
/**
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -645,10 +645,11 @@ shaka.dash.DashParser = class {
|
|
|
645
645
|
// that the complex logic of multi-Period eviction and period-flattening
|
|
646
646
|
// is correct. See also:
|
|
647
647
|
// https://github.com/shaka-project/shaka-player/issues/3169#issuecomment-823580634
|
|
648
|
+
const availabilityStart =
|
|
649
|
+
presentationTimeline.getSegmentAvailabilityStart();
|
|
648
650
|
for (const stream of Object.values(this.streamMap_)) {
|
|
649
651
|
if (stream.segmentIndex) {
|
|
650
|
-
stream.segmentIndex.evict(
|
|
651
|
-
presentationTimeline.getSegmentAvailabilityStart());
|
|
652
|
+
stream.segmentIndex.evict(availabilityStart);
|
|
652
653
|
}
|
|
653
654
|
}
|
|
654
655
|
} else {
|
|
@@ -657,18 +658,28 @@ shaka.dash.DashParser = class {
|
|
|
657
658
|
// feasible choices for the value. Nothing older than
|
|
658
659
|
// timeShiftBufferDepth is still available, and anything less than
|
|
659
660
|
// minBufferTime will cause buffering issues.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
661
|
+
let delay = 0;
|
|
662
|
+
if (suggestedPresentationDelay != null) {
|
|
663
|
+
// 1. If a suggestedPresentationDelay is provided by the manifest, that
|
|
664
|
+
// will be used preferentially.
|
|
665
|
+
// This is given a minimum bound of segmentAvailabilityDuration.
|
|
666
|
+
// Content providers should provide a suggestedPresentationDelay
|
|
667
|
+
// whenever possible to optimize the live streaming experience.
|
|
668
|
+
delay = Math.min(
|
|
669
|
+
suggestedPresentationDelay,
|
|
670
|
+
segmentAvailabilityDuration || Infinity);
|
|
671
|
+
} else if (this.config_.defaultPresentationDelay > 0) {
|
|
672
|
+
// 2. If the developer provides a value for
|
|
673
|
+
// "manifest.defaultPresentationDelay", that is used as a fallback.
|
|
674
|
+
delay = this.config_.defaultPresentationDelay;
|
|
675
|
+
} else {
|
|
676
|
+
// 3. Otherwise, we default to the lower of segmentAvailabilityDuration
|
|
677
|
+
// and 1.5 * minBufferTime. This is fairly conservative.
|
|
678
|
+
delay = Math.min(
|
|
679
|
+
minBufferTime * 1.5, segmentAvailabilityDuration || Infinity);
|
|
680
|
+
}
|
|
669
681
|
presentationTimeline = new shaka.media.PresentationTimeline(
|
|
670
|
-
presentationStartTime,
|
|
671
|
-
this.config_.dash.autoCorrectDrift);
|
|
682
|
+
presentationStartTime, delay, this.config_.dash.autoCorrectDrift);
|
|
672
683
|
}
|
|
673
684
|
|
|
674
685
|
presentationTimeline.setStatic(mpdType == 'static');
|
package/lib/dash/mpd_utils.js
CHANGED
|
@@ -279,10 +279,9 @@ shaka.dash.MpdUtils = class {
|
|
|
279
279
|
|
|
280
280
|
const durationStr =
|
|
281
281
|
MpdUtils.inheritAttribute(context, callback, 'duration');
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
282
|
+
const unscaledSegmentDuration = TXml.parsePositiveInt(durationStr || '');
|
|
283
|
+
const segmentDuration = unscaledSegmentDuration ?
|
|
284
|
+
unscaledSegmentDuration / timescale : null;
|
|
286
285
|
|
|
287
286
|
const startNumberStr =
|
|
288
287
|
MpdUtils.inheritAttribute(context, callback, 'startNumber');
|
|
@@ -309,6 +308,7 @@ shaka.dash.MpdUtils = class {
|
|
|
309
308
|
(unscaledPresentationTimeOffset / timescale) || 0;
|
|
310
309
|
return {
|
|
311
310
|
timescale: timescale,
|
|
311
|
+
unscaledSegmentDuration: unscaledSegmentDuration,
|
|
312
312
|
segmentDuration: segmentDuration,
|
|
313
313
|
startNumber: startNumber,
|
|
314
314
|
scaledPresentationTimeOffset: scaledPresentationTimeOffset,
|
|
@@ -564,6 +564,7 @@ shaka.dash.MpdUtils = class {
|
|
|
564
564
|
/**
|
|
565
565
|
* @typedef {{
|
|
566
566
|
* timescale: number,
|
|
567
|
+
* unscaledSegmentDuration: ?number,
|
|
567
568
|
* segmentDuration: ?number,
|
|
568
569
|
* startNumber: number,
|
|
569
570
|
* scaledPresentationTimeOffset: number,
|
|
@@ -576,6 +577,8 @@ shaka.dash.MpdUtils = class {
|
|
|
576
577
|
*
|
|
577
578
|
* @property {number} timescale
|
|
578
579
|
* The time-scale of the representation.
|
|
580
|
+
* @property {?number} unscaledSegmentDuration
|
|
581
|
+
* The duration of the segments in timescale units, if given.
|
|
579
582
|
* @property {?number} segmentDuration
|
|
580
583
|
* The duration of the segments in seconds, if given.
|
|
581
584
|
* @property {number} startNumber
|
|
@@ -121,24 +121,6 @@ shaka.dash.SegmentTemplate = class {
|
|
|
121
121
|
|
|
122
122
|
shaka.log.debug(`New manifest ${periodStart} - ${periodEnd}`);
|
|
123
123
|
|
|
124
|
-
/* When to fit segments. All refactors should honor/update this table:
|
|
125
|
-
*
|
|
126
|
-
* | dynamic | infinite | last | should | notes |
|
|
127
|
-
* | | period | period | fit | |
|
|
128
|
-
* | ------- | -------- | ------ | ------ | ------------------------- |
|
|
129
|
-
* | F | F | X | T | typical VOD |
|
|
130
|
-
* | F | T | X | X | impossible: infinite VOD |
|
|
131
|
-
* | T | F | F | T | typical live, old period |
|
|
132
|
-
* | T | F | T | F | typical IPR |
|
|
133
|
-
* | T | T | F | X | impossible: old, infinite |
|
|
134
|
-
* | T | T | T | F | typical live, new period |
|
|
135
|
-
*/
|
|
136
|
-
|
|
137
|
-
// We never fit the final period of dynamic content, which could be
|
|
138
|
-
// infinite live (with no limit to fit to) or IPR (which would expand the
|
|
139
|
-
// most recent segment to the end of the presentation).
|
|
140
|
-
const shouldFit = !(context.dynamic && context.periodInfo.isLastPeriod);
|
|
141
|
-
|
|
142
124
|
if (!segmentIndex) {
|
|
143
125
|
shaka.log.debug(`Creating TSI with end ${periodEnd}`);
|
|
144
126
|
segmentIndex = new TimelineSegmentIndex(
|
|
@@ -149,14 +131,13 @@ shaka.dash.SegmentTemplate = class {
|
|
|
149
131
|
periodStart,
|
|
150
132
|
periodEnd,
|
|
151
133
|
initSegmentReference,
|
|
152
|
-
shouldFit,
|
|
153
134
|
aesKey,
|
|
154
135
|
context.representation.segmentSequenceCadence,
|
|
155
136
|
);
|
|
156
137
|
} else {
|
|
157
138
|
const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
|
|
158
139
|
tsi.appendTemplateInfo(
|
|
159
|
-
info, periodStart, periodEnd,
|
|
140
|
+
info, periodStart, periodEnd, initSegmentReference);
|
|
160
141
|
|
|
161
142
|
const availabilityStart =
|
|
162
143
|
context.presentationTimeline.getSegmentAvailabilityStart();
|
|
@@ -166,7 +147,9 @@ shaka.dash.SegmentTemplate = class {
|
|
|
166
147
|
if (info.timeline &&
|
|
167
148
|
context.adaptationSet.contentType !== 'image' &&
|
|
168
149
|
context.adaptationSet.contentType !== 'text') {
|
|
169
|
-
const
|
|
150
|
+
const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
|
|
151
|
+
// getTimeline is the info.timeline but fitted to the period.
|
|
152
|
+
const timeline = tsi.getTimeline();
|
|
170
153
|
context.presentationTimeline.notifyTimeRange(
|
|
171
154
|
timeline,
|
|
172
155
|
periodStart);
|
|
@@ -184,7 +167,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
184
167
|
if (segmentIndex instanceof shaka.dash.TimelineSegmentIndex &&
|
|
185
168
|
segmentIndex.isEmpty()) {
|
|
186
169
|
segmentIndex.appendTemplateInfo(info, periodStart,
|
|
187
|
-
periodEnd,
|
|
170
|
+
periodEnd, initSegmentReference);
|
|
188
171
|
}
|
|
189
172
|
return Promise.resolve(segmentIndex);
|
|
190
173
|
},
|
|
@@ -258,6 +241,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
258
241
|
context, SegmentTemplate.fromInheritance_, 'index');
|
|
259
242
|
|
|
260
243
|
return {
|
|
244
|
+
unscaledSegmentDuration: segmentInfo.unscaledSegmentDuration,
|
|
261
245
|
segmentDuration: segmentInfo.segmentDuration,
|
|
262
246
|
timescale: segmentInfo.timescale,
|
|
263
247
|
startNumber: segmentInfo.startNumber,
|
|
@@ -304,10 +288,12 @@ shaka.dash.SegmentTemplate = class {
|
|
|
304
288
|
if (info.indexTemplate) {
|
|
305
289
|
shaka.log.info('Using the index URL template by default.');
|
|
306
290
|
info.timeline = null;
|
|
291
|
+
info.unscaledSegmentDuration = null;
|
|
307
292
|
info.segmentDuration = null;
|
|
308
293
|
} else {
|
|
309
294
|
goog.asserts.assert(info.timeline, 'There should be a timeline');
|
|
310
295
|
shaka.log.info('Using the SegmentTimeline by default.');
|
|
296
|
+
info.unscaledSegmentDuration = null;
|
|
311
297
|
info.segmentDuration = null;
|
|
312
298
|
}
|
|
313
299
|
}
|
|
@@ -399,7 +385,6 @@ shaka.dash.SegmentTemplate = class {
|
|
|
399
385
|
segmentDuration != null, 'Segment duration must not be null!');
|
|
400
386
|
|
|
401
387
|
const startNumber = info.startNumber;
|
|
402
|
-
const timescale = info.timescale;
|
|
403
388
|
|
|
404
389
|
const template = info.mediaTemplate;
|
|
405
390
|
const bandwidth = context.bandwidth || null;
|
|
@@ -482,20 +467,18 @@ shaka.dash.SegmentTemplate = class {
|
|
|
482
467
|
const positionWithinPeriod = position - startNumber;
|
|
483
468
|
const segmentPeriodTime = positionWithinPeriod * segmentDuration;
|
|
484
469
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
info.scaledPresentationTimeOffset;
|
|
470
|
+
const unscaledSegmentDuration = info.unscaledSegmentDuration;
|
|
471
|
+
goog.asserts.assert(unscaledSegmentDuration != null,
|
|
472
|
+
'Segment duration must not be null!');
|
|
489
473
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
};
|
|
474
|
+
// The original media timestamp from the timeline is what is expected in
|
|
475
|
+
// the $Time$ template. (Or based on duration, in this case.) It should
|
|
476
|
+
// not be adjusted with presentationTimeOffset or the Period start.
|
|
477
|
+
let timeReplacement = positionWithinPeriod * unscaledSegmentDuration;
|
|
478
|
+
if ('BigInt' in window && timeReplacement > Number.MAX_SAFE_INTEGER) {
|
|
479
|
+
timeReplacement =
|
|
480
|
+
BigInt(positionWithinPeriod) * BigInt(unscaledSegmentDuration);
|
|
481
|
+
}
|
|
499
482
|
|
|
500
483
|
// Relative to the presentation.
|
|
501
484
|
const segmentStart = segmentPeriodTime + periodStart;
|
|
@@ -509,6 +492,13 @@ shaka.dash.SegmentTemplate = class {
|
|
|
509
492
|
goog.asserts.assert(segmentStart < segmentEnd,
|
|
510
493
|
'Generated a segment outside of the period!');
|
|
511
494
|
|
|
495
|
+
const getUris = () => {
|
|
496
|
+
const mediaUri = MpdUtils.fillUriTemplate(
|
|
497
|
+
template, id, position, /* subNumber= */ null, bandwidth,
|
|
498
|
+
timeReplacement);
|
|
499
|
+
return ManifestParserUtils.resolveUris(getBaseUris(), [mediaUri]);
|
|
500
|
+
};
|
|
501
|
+
|
|
512
502
|
const ref = new shaka.media.SegmentReference(
|
|
513
503
|
segmentStart,
|
|
514
504
|
segmentEnd,
|
|
@@ -661,38 +651,42 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
661
651
|
* @param {number} periodStart
|
|
662
652
|
* @param {number} periodEnd
|
|
663
653
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
664
|
-
* @param {boolean} shouldFit
|
|
665
654
|
* @param {shaka.extern.aesKey|undefined} aesKey
|
|
666
655
|
* @param {number} segmentSequenceCadence
|
|
667
656
|
*/
|
|
668
657
|
constructor(templateInfo, representationId, bandwidth, getBaseUris,
|
|
669
|
-
periodStart, periodEnd, initSegmentReference,
|
|
658
|
+
periodStart, periodEnd, initSegmentReference,
|
|
670
659
|
aesKey, segmentSequenceCadence) {
|
|
671
660
|
super([]);
|
|
672
661
|
|
|
673
662
|
/** @private {?shaka.dash.SegmentTemplate.SegmentTemplateInfo} */
|
|
674
663
|
this.templateInfo_ = templateInfo;
|
|
664
|
+
|
|
675
665
|
/** @private {?string} */
|
|
676
666
|
this.representationId_ = representationId;
|
|
667
|
+
|
|
677
668
|
/** @private {number} */
|
|
678
669
|
this.bandwidth_ = bandwidth;
|
|
679
|
-
|
|
670
|
+
|
|
671
|
+
/** @private {function(): Array<string>} */
|
|
680
672
|
this.getBaseUris_ = getBaseUris;
|
|
673
|
+
|
|
681
674
|
/** @private {number} */
|
|
682
675
|
this.periodStart_ = periodStart;
|
|
676
|
+
|
|
683
677
|
/** @private {number} */
|
|
684
678
|
this.periodEnd_ = periodEnd;
|
|
679
|
+
|
|
685
680
|
/** @private {shaka.media.InitSegmentReference} */
|
|
686
681
|
this.initSegmentReference_ = initSegmentReference;
|
|
682
|
+
|
|
687
683
|
/** @private {shaka.extern.aesKey|undefined} */
|
|
688
684
|
this.aesKey_ = aesKey;
|
|
685
|
+
|
|
689
686
|
/** @private {number} */
|
|
690
687
|
this.segmentSequenceCadence_ = segmentSequenceCadence;
|
|
691
688
|
|
|
692
|
-
|
|
693
|
-
if (shouldFit) {
|
|
694
|
-
this.fitTimeline();
|
|
695
|
-
}
|
|
689
|
+
this.fitTimeline();
|
|
696
690
|
}
|
|
697
691
|
|
|
698
692
|
/**
|
|
@@ -760,11 +754,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
760
754
|
* @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info
|
|
761
755
|
* @param {number} periodStart
|
|
762
756
|
* @param {number} periodEnd
|
|
763
|
-
* @param {boolean} shouldFit
|
|
764
757
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
765
758
|
*/
|
|
766
|
-
appendTemplateInfo(info, periodStart, periodEnd,
|
|
767
|
-
initSegmentReference) {
|
|
759
|
+
appendTemplateInfo(info, periodStart, periodEnd, initSegmentReference) {
|
|
768
760
|
this.updateInitSegmentReference(initSegmentReference);
|
|
769
761
|
if (!this.templateInfo_) {
|
|
770
762
|
this.templateInfo_ = info;
|
|
@@ -798,9 +790,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
798
790
|
}
|
|
799
791
|
}
|
|
800
792
|
|
|
801
|
-
|
|
802
|
-
this.fitTimeline();
|
|
803
|
-
}
|
|
793
|
+
this.fitTimeline();
|
|
804
794
|
}
|
|
805
795
|
|
|
806
796
|
/**
|
|
@@ -845,14 +835,19 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
845
835
|
return;
|
|
846
836
|
}
|
|
847
837
|
const timeline = this.templateInfo_.timeline;
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
838
|
+
goog.asserts.assert(timeline, 'Timeline should be non-null!');
|
|
839
|
+
const newTimeline = [];
|
|
840
|
+
for (const range of timeline) {
|
|
841
|
+
if (range.start >= this.periodEnd_) {
|
|
842
|
+
// Starts after end of period.
|
|
843
|
+
} else if (range.end <= 0) {
|
|
844
|
+
// Ends before start of period.
|
|
852
845
|
} else {
|
|
853
|
-
|
|
846
|
+
// Usable.
|
|
847
|
+
newTimeline.push(range);
|
|
854
848
|
}
|
|
855
849
|
}
|
|
850
|
+
this.templateInfo_.timeline = newTimeline;
|
|
856
851
|
|
|
857
852
|
this.evict(this.periodStart_);
|
|
858
853
|
|
|
@@ -862,6 +857,19 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
862
857
|
// find/get() methods whenever possible.
|
|
863
858
|
}
|
|
864
859
|
|
|
860
|
+
/**
|
|
861
|
+
* Get the current timeline
|
|
862
|
+
* @return {!Array<shaka.media.PresentationTimeline.TimeRange>}
|
|
863
|
+
*/
|
|
864
|
+
getTimeline() {
|
|
865
|
+
if (!this.templateInfo_) {
|
|
866
|
+
return [];
|
|
867
|
+
}
|
|
868
|
+
const timeline = this.templateInfo_.timeline;
|
|
869
|
+
goog.asserts.assert(timeline, 'Timeline should be non-null!');
|
|
870
|
+
return timeline;
|
|
871
|
+
}
|
|
872
|
+
|
|
865
873
|
/**
|
|
866
874
|
* @override
|
|
867
875
|
*/
|
|
@@ -925,8 +933,15 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
925
933
|
if (!ref) {
|
|
926
934
|
const range = this.templateInfo_.timeline[correctedPosition];
|
|
927
935
|
const segmentReplacement = range.segmentPosition;
|
|
928
|
-
|
|
929
|
-
|
|
936
|
+
|
|
937
|
+
// The original media timestamp from the timeline is what is expected in
|
|
938
|
+
// the $Time$ template. It should not be adjusted with
|
|
939
|
+
// presentationTimeOffset or the Period start, but
|
|
940
|
+
// unscaledPresentationTimeOffset was already subtracted from the times
|
|
941
|
+
// in timeline.
|
|
942
|
+
const timeReplacement = range.unscaledStart +
|
|
943
|
+
this.templateInfo_.unscaledPresentationTimeOffset;
|
|
944
|
+
|
|
930
945
|
const timestampOffset = this.periodStart_ -
|
|
931
946
|
this.templateInfo_.scaledPresentationTimeOffset;
|
|
932
947
|
const trueSegmentEnd = this.periodStart_ + range.end;
|
|
@@ -1068,6 +1083,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
1068
1083
|
/**
|
|
1069
1084
|
* @typedef {{
|
|
1070
1085
|
* timescale: number,
|
|
1086
|
+
* unscaledSegmentDuration: ?number,
|
|
1071
1087
|
* segmentDuration: ?number,
|
|
1072
1088
|
* startNumber: number,
|
|
1073
1089
|
* scaledPresentationTimeOffset: number,
|
|
@@ -1084,6 +1100,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
1084
1100
|
*
|
|
1085
1101
|
* @property {number} timescale
|
|
1086
1102
|
* The time-scale of the representation.
|
|
1103
|
+
* @property {?number} unscaledSegmentDuration
|
|
1104
|
+
* The duration of the segments in seconds, in timescale units.
|
|
1087
1105
|
* @property {?number} segmentDuration
|
|
1088
1106
|
* The duration of the segments in seconds, if given.
|
|
1089
1107
|
* @property {number} startNumber
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -1013,7 +1013,8 @@ shaka.hls.HlsParser = class {
|
|
|
1013
1013
|
|
|
1014
1014
|
if (extension == 'ts' || contentMimeType == 'video/mp2t') {
|
|
1015
1015
|
const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromTs(
|
|
1016
|
-
response.data, this.config_.disableAudio, this.config_.disableVideo
|
|
1016
|
+
response.data, this.config_.disableAudio, this.config_.disableVideo,
|
|
1017
|
+
this.config_.disableText);
|
|
1017
1018
|
if (basicInfo) {
|
|
1018
1019
|
return basicInfo;
|
|
1019
1020
|
}
|
|
@@ -1023,7 +1024,7 @@ shaka.hls.HlsParser = class {
|
|
|
1023
1024
|
contentMimeType == 'audio/mp4' ||
|
|
1024
1025
|
contentMimeType == 'video/iso.segment') {
|
|
1025
1026
|
const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
|
|
1026
|
-
initData, response.data);
|
|
1027
|
+
initData, response.data, this.config_.disableText);
|
|
1027
1028
|
if (basicInfo) {
|
|
1028
1029
|
return basicInfo;
|
|
1029
1030
|
}
|
|
@@ -4311,7 +4312,7 @@ shaka.hls.HlsParser = class {
|
|
|
4311
4312
|
shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
|
|
4312
4313
|
}
|
|
4313
4314
|
|
|
4314
|
-
if (shaka.util.Platform.isMediaKeysPolyfilled()) {
|
|
4315
|
+
if (shaka.util.Platform.isMediaKeysPolyfilled('apple')) {
|
|
4315
4316
|
throw new shaka.util.Error(
|
|
4316
4317
|
shaka.util.Error.Severity.CRITICAL,
|
|
4317
4318
|
shaka.util.Error.Category.MANIFEST,
|
|
@@ -4451,7 +4452,7 @@ shaka.hls.HlsParser = class {
|
|
|
4451
4452
|
shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
|
|
4452
4453
|
}
|
|
4453
4454
|
|
|
4454
|
-
if (shaka.util.Platform.isMediaKeysPolyfilled()) {
|
|
4455
|
+
if (shaka.util.Platform.isMediaKeysPolyfilled('apple')) {
|
|
4455
4456
|
throw new shaka.util.Error(
|
|
4456
4457
|
shaka.util.Error.Severity.CRITICAL,
|
|
4457
4458
|
shaka.util.Error.Category.MANIFEST,
|