shaka-player 4.11.13 → 4.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/dist/deps.js +8 -8
- package/dist/locales.js +35 -35
- package/dist/shaka-player.compiled.d.ts +36 -13
- package/dist/shaka-player.compiled.debug.d.ts +36 -13
- package/dist/shaka-player.compiled.debug.externs.js +46 -11
- package/dist/shaka-player.compiled.debug.js +543 -517
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +46 -11
- package/dist/shaka-player.compiled.js +1348 -1331
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +37 -14
- package/dist/shaka-player.ui.debug.d.ts +37 -14
- package/dist/shaka-player.ui.debug.externs.js +46 -11
- package/dist/shaka-player.ui.debug.js +629 -598
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +46 -11
- package/dist/shaka-player.ui.js +1624 -1603
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/ads.js +9 -0
- package/externs/shaka/manifest.js +26 -1
- package/externs/shaka/offline.js +8 -2
- package/externs/shaka/player.js +80 -28
- package/externs/shaka/text.js +9 -0
- package/lib/ads/ad_manager.js +6 -0
- package/lib/ads/ad_utils.js +1 -0
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/interstitial_ad.js +25 -4
- package/lib/ads/interstitial_ad_manager.js +67 -8
- package/lib/ads/media_tailor_ad.js +8 -0
- package/lib/ads/server_side_ad.js +8 -0
- package/lib/dash/content_protection.js +31 -0
- package/lib/dash/dash_parser.js +22 -12
- package/lib/hls/hls_parser.js +63 -49
- package/lib/media/adaptation_set.js +11 -17
- package/lib/media/adaptation_set_criteria.js +4 -9
- package/lib/media/drm_engine.js +3 -1
- package/lib/media/manifest_filterer.js +2 -1
- package/lib/media/media_source_engine.js +286 -20
- package/lib/media/playhead.js +3 -1
- package/lib/media/preload_manager.js +10 -7
- package/lib/media/segment_prefetch.js +32 -13
- package/lib/media/segment_reference.js +3 -3
- package/lib/media/streaming_engine.js +87 -261
- package/lib/mss/mss_parser.js +1 -0
- package/lib/offline/download_info.js +5 -1
- package/lib/offline/indexeddb/storage_mechanism.js +4 -3
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +4 -0
- package/lib/offline/storage.js +277 -5
- package/lib/player.js +224 -78
- package/lib/text/simple_text_displayer.js +7 -0
- package/lib/text/stub_text_displayer.js +7 -0
- package/lib/text/ui_text_displayer.js +12 -0
- package/lib/util/dom_utils.js +14 -0
- package/lib/util/error.js +5 -0
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +15 -0
- package/lib/util/player_configuration.js +11 -4
- package/lib/util/stream_utils.js +20 -1
- package/package.json +1 -1
- package/ui/ad_statistics_button.js +12 -0
- package/ui/controls.js +31 -7
- package/ui/externs/ui.js +8 -1
- package/ui/fullscreen_button.js +9 -0
- package/ui/locales/be.json +49 -0
- package/ui/mute_button.js +42 -11
- package/ui/skip_ad_button.js +16 -11
- package/ui/statistics_button.js +12 -0
- package/ui/ui.js +10 -5
|
@@ -27,7 +27,6 @@ goog.require('shaka.util.Destroyer');
|
|
|
27
27
|
goog.require('shaka.util.Error');
|
|
28
28
|
goog.require('shaka.util.FakeEvent');
|
|
29
29
|
goog.require('shaka.util.IDestroyable');
|
|
30
|
-
goog.require('shaka.util.Id3Utils');
|
|
31
30
|
goog.require('shaka.util.LanguageUtils');
|
|
32
31
|
goog.require('shaka.util.ManifestParserUtils');
|
|
33
32
|
goog.require('shaka.util.MimeUtils');
|
|
@@ -93,9 +92,6 @@ shaka.media.StreamingEngine = class {
|
|
|
93
92
|
/** @private {number} */
|
|
94
93
|
this.textStreamSequenceId_ = 0;
|
|
95
94
|
|
|
96
|
-
/** @private {boolean} */
|
|
97
|
-
this.parsedPrftEventRaised_ = false;
|
|
98
|
-
|
|
99
95
|
/**
|
|
100
96
|
* Maps a content type, e.g., 'audio', 'video', or 'text', to a MediaState.
|
|
101
97
|
*
|
|
@@ -628,6 +624,9 @@ shaka.media.StreamingEngine = class {
|
|
|
628
624
|
}
|
|
629
625
|
}
|
|
630
626
|
|
|
627
|
+
const shouldResetMediaSource =
|
|
628
|
+
mediaState.stream.isAudioMuxedInVideo != stream.isAudioMuxedInVideo;
|
|
629
|
+
|
|
631
630
|
mediaState.stream = stream;
|
|
632
631
|
mediaState.segmentIterator = null;
|
|
633
632
|
mediaState.adaptation = !!adaptation;
|
|
@@ -635,6 +634,11 @@ shaka.media.StreamingEngine = class {
|
|
|
635
634
|
const streamTag = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
636
635
|
shaka.log.debug('switch: switching to Stream ' + streamTag);
|
|
637
636
|
|
|
637
|
+
if (shouldResetMediaSource) {
|
|
638
|
+
this.resetMediaSource(/* force= */ true, /* clearBuffer= */ false);
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
638
642
|
if (clearBuffer) {
|
|
639
643
|
if (mediaState.clearingBuffer) {
|
|
640
644
|
// We are already going to clear the buffer, but make sure it is also
|
|
@@ -1319,6 +1323,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1319
1323
|
this.playerInterface_.mediaSourceEngine.clearSelectedClosedCaptionId();
|
|
1320
1324
|
}
|
|
1321
1325
|
|
|
1326
|
+
if (mediaState.stream.isAudioMuxedInVideo) {
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1322
1330
|
if (!this.playerInterface_.mediaSourceEngine.isStreamingAllowed() &&
|
|
1323
1331
|
mediaState.type != ContentType.TEXT) {
|
|
1324
1332
|
// It is not allowed to add segments yet, so we schedule an update to
|
|
@@ -2241,84 +2249,64 @@ shaka.media.StreamingEngine = class {
|
|
|
2241
2249
|
const hasClosedCaptions = stream.closedCaptions &&
|
|
2242
2250
|
stream.closedCaptions.size > 0;
|
|
2243
2251
|
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
stream.emsgSchemeIdUris.length > 0) ||
|
|
2247
|
-
this.config_.dispatchAllEmsgBoxes);
|
|
2248
|
-
const shouldParsePrftBox =
|
|
2249
|
-
(this.config_.parsePrftBox && !this.parsedPrftEventRaised_);
|
|
2250
|
-
|
|
2251
|
-
const isMP4 = stream.mimeType == 'video/mp4' ||
|
|
2252
|
-
stream.mimeType == 'audio/mp4';
|
|
2253
|
-
let timescale = null;
|
|
2254
|
-
if (reference.initSegmentReference) {
|
|
2255
|
-
timescale = reference.initSegmentReference.timescale;
|
|
2256
|
-
}
|
|
2257
|
-
const shouldFixTimestampOffset = isMP4 && timescale &&
|
|
2258
|
-
stream.type === shaka.util.ManifestParserUtils.ContentType.VIDEO &&
|
|
2259
|
-
this.manifest_.type == shaka.media.ManifestParser.DASH &&
|
|
2260
|
-
this.config_.shouldFixTimestampOffset;
|
|
2261
|
-
|
|
2262
|
-
if (hasEmsg || shouldParsePrftBox || shouldFixTimestampOffset) {
|
|
2263
|
-
parser = new shaka.util.Mp4Parser();
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
|
-
if (hasEmsg) {
|
|
2267
|
-
parser
|
|
2268
|
-
.fullBox(
|
|
2269
|
-
'emsg',
|
|
2270
|
-
(box) => this.parseEMSG_(
|
|
2271
|
-
reference, stream.emsgSchemeIdUris, box));
|
|
2272
|
-
}
|
|
2273
|
-
|
|
2274
|
-
if (shouldParsePrftBox) {
|
|
2275
|
-
parser
|
|
2276
|
-
.fullBox(
|
|
2277
|
-
'prft',
|
|
2278
|
-
(box) => this.parsePrft_(
|
|
2279
|
-
reference, box));
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
if (shouldFixTimestampOffset) {
|
|
2283
|
-
parser
|
|
2284
|
-
.box('moof', shaka.util.Mp4Parser.children)
|
|
2285
|
-
.box('traf', shaka.util.Mp4Parser.children)
|
|
2286
|
-
.fullBox('tfdt', async (box) => {
|
|
2287
|
-
goog.asserts.assert(
|
|
2288
|
-
box.version != null,
|
|
2289
|
-
'TFDT is a full box and should have a valid version.');
|
|
2290
|
-
|
|
2291
|
-
const parsedTFDT = shaka.util.Mp4BoxParsers.parseTFDTInaccurate(
|
|
2292
|
-
box.reader, box.version);
|
|
2293
|
-
|
|
2294
|
-
const baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
|
|
2295
|
-
|
|
2296
|
-
// In case the time is 0, it is not updated
|
|
2297
|
-
if (!baseMediaDecodeTime) {
|
|
2298
|
-
return;
|
|
2299
|
-
}
|
|
2300
|
-
goog.asserts.assert(typeof(timescale) == 'number',
|
|
2301
|
-
'Should be an number!');
|
|
2252
|
+
if (this.config_.shouldFixTimestampOffset) {
|
|
2253
|
+
let parser;
|
|
2302
2254
|
|
|
2303
|
-
|
|
2255
|
+
const isMP4 = stream.mimeType == 'video/mp4' ||
|
|
2256
|
+
stream.mimeType == 'audio/mp4';
|
|
2257
|
+
let timescale = null;
|
|
2258
|
+
if (reference.initSegmentReference) {
|
|
2259
|
+
timescale = reference.initSegmentReference.timescale;
|
|
2260
|
+
}
|
|
2261
|
+
const shouldFixTimestampOffset = isMP4 && timescale &&
|
|
2262
|
+
stream.type === shaka.util.ManifestParserUtils.ContentType.VIDEO &&
|
|
2263
|
+
this.manifest_.type == shaka.media.ManifestParser.DASH;
|
|
2304
2264
|
|
|
2305
|
-
|
|
2265
|
+
if (shouldFixTimestampOffset) {
|
|
2266
|
+
parser = new shaka.util.Mp4Parser();
|
|
2267
|
+
}
|
|
2306
2268
|
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
goog.asserts.assert(
|
|
2269
|
+
if (shouldFixTimestampOffset) {
|
|
2270
|
+
parser
|
|
2271
|
+
.box('moof', shaka.util.Mp4Parser.children)
|
|
2272
|
+
.box('traf', shaka.util.Mp4Parser.children)
|
|
2273
|
+
.fullBox('tfdt', async (box) => {
|
|
2274
|
+
goog.asserts.assert(
|
|
2275
|
+
box.version != null,
|
|
2276
|
+
'TFDT is a full box and should have a valid version.');
|
|
2277
|
+
|
|
2278
|
+
const parsedTFDT = shaka.util.Mp4BoxParsers.parseTFDTInaccurate(
|
|
2279
|
+
box.reader, box.version);
|
|
2280
|
+
|
|
2281
|
+
const baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
|
|
2282
|
+
|
|
2283
|
+
// In case the time is 0, it is not updated
|
|
2284
|
+
if (!baseMediaDecodeTime) {
|
|
2285
|
+
return;
|
|
2286
|
+
}
|
|
2287
|
+
goog.asserts.assert(typeof(timescale) == 'number',
|
|
2313
2288
|
'Should be an number!');
|
|
2314
|
-
await this.setProperties_(mediaState, scaledMediaDecodeTime,
|
|
2315
|
-
lastAppendWindowStart, lastAppendWindowEnd, reference);
|
|
2316
|
-
}
|
|
2317
|
-
});
|
|
2318
|
-
}
|
|
2319
2289
|
|
|
2320
|
-
|
|
2321
|
-
|
|
2290
|
+
const scaledMediaDecodeTime = -baseMediaDecodeTime / timescale;
|
|
2291
|
+
|
|
2292
|
+
const comparison1 = Number(mediaState.lastTimestampOffset) || 0;
|
|
2293
|
+
|
|
2294
|
+
if (comparison1 < scaledMediaDecodeTime) {
|
|
2295
|
+
const lastAppendWindowStart = mediaState.lastAppendWindowStart;
|
|
2296
|
+
const lastAppendWindowEnd = mediaState.lastAppendWindowEnd;
|
|
2297
|
+
goog.asserts.assert(typeof(lastAppendWindowStart) == 'number',
|
|
2298
|
+
'Should be an number!');
|
|
2299
|
+
goog.asserts.assert(typeof(lastAppendWindowEnd) == 'number',
|
|
2300
|
+
'Should be an number!');
|
|
2301
|
+
await this.setProperties_(mediaState, scaledMediaDecodeTime,
|
|
2302
|
+
lastAppendWindowStart, lastAppendWindowEnd, reference);
|
|
2303
|
+
}
|
|
2304
|
+
});
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
if (shouldFixTimestampOffset) {
|
|
2308
|
+
parser.parse(segment, /* partialOkay= */ false, isChunkedData);
|
|
2309
|
+
}
|
|
2322
2310
|
}
|
|
2323
2311
|
|
|
2324
2312
|
await this.evict_(mediaState, presentationTime);
|
|
@@ -2343,176 +2331,6 @@ shaka.media.StreamingEngine = class {
|
|
|
2343
2331
|
shaka.log.v2(logPrefix, 'appended media segment');
|
|
2344
2332
|
}
|
|
2345
2333
|
|
|
2346
|
-
|
|
2347
|
-
/**
|
|
2348
|
-
* Parse the EMSG box from a MP4 container.
|
|
2349
|
-
*
|
|
2350
|
-
* @param {!shaka.media.SegmentReference} reference
|
|
2351
|
-
* @param {?Array.<string>} emsgSchemeIdUris Array of emsg
|
|
2352
|
-
* scheme_id_uri for which emsg boxes should be parsed.
|
|
2353
|
-
* @param {!shaka.extern.ParsedBox} box
|
|
2354
|
-
* @private
|
|
2355
|
-
* https://dashif-documents.azurewebsites.net/Events/master/event.html#emsg-format
|
|
2356
|
-
* aligned(8) class DASHEventMessageBox
|
|
2357
|
-
* extends FullBox(‘emsg’, version, flags = 0){
|
|
2358
|
-
* if (version==0) {
|
|
2359
|
-
* string scheme_id_uri;
|
|
2360
|
-
* string value;
|
|
2361
|
-
* unsigned int(32) timescale;
|
|
2362
|
-
* unsigned int(32) presentation_time_delta;
|
|
2363
|
-
* unsigned int(32) event_duration;
|
|
2364
|
-
* unsigned int(32) id;
|
|
2365
|
-
* } else if (version==1) {
|
|
2366
|
-
* unsigned int(32) timescale;
|
|
2367
|
-
* unsigned int(64) presentation_time;
|
|
2368
|
-
* unsigned int(32) event_duration;
|
|
2369
|
-
* unsigned int(32) id;
|
|
2370
|
-
* string scheme_id_uri;
|
|
2371
|
-
* string value;
|
|
2372
|
-
* }
|
|
2373
|
-
* unsigned int(8) message_data[];
|
|
2374
|
-
*/
|
|
2375
|
-
parseEMSG_(reference, emsgSchemeIdUris, box) {
|
|
2376
|
-
let timescale;
|
|
2377
|
-
let id;
|
|
2378
|
-
let eventDuration;
|
|
2379
|
-
let schemeId;
|
|
2380
|
-
let startTime;
|
|
2381
|
-
let presentationTimeDelta;
|
|
2382
|
-
let value;
|
|
2383
|
-
|
|
2384
|
-
if (box.version === 0) {
|
|
2385
|
-
schemeId = box.reader.readTerminatedString();
|
|
2386
|
-
value = box.reader.readTerminatedString();
|
|
2387
|
-
timescale = box.reader.readUint32();
|
|
2388
|
-
presentationTimeDelta = box.reader.readUint32();
|
|
2389
|
-
eventDuration = box.reader.readUint32();
|
|
2390
|
-
id = box.reader.readUint32();
|
|
2391
|
-
startTime = reference.startTime + (presentationTimeDelta / timescale);
|
|
2392
|
-
} else {
|
|
2393
|
-
timescale = box.reader.readUint32();
|
|
2394
|
-
const pts = box.reader.readUint64();
|
|
2395
|
-
startTime = (pts / timescale) + reference.timestampOffset;
|
|
2396
|
-
presentationTimeDelta = startTime - reference.startTime;
|
|
2397
|
-
eventDuration = box.reader.readUint32();
|
|
2398
|
-
id = box.reader.readUint32();
|
|
2399
|
-
schemeId = box.reader.readTerminatedString();
|
|
2400
|
-
value = box.reader.readTerminatedString();
|
|
2401
|
-
}
|
|
2402
|
-
const messageData = box.reader.readBytes(
|
|
2403
|
-
box.reader.getLength() - box.reader.getPosition());
|
|
2404
|
-
|
|
2405
|
-
// See DASH sec. 5.10.3.3.1
|
|
2406
|
-
// If a DASH client detects an event message box with a scheme that is not
|
|
2407
|
-
// defined in MPD, the client is expected to ignore it.
|
|
2408
|
-
if ((emsgSchemeIdUris && emsgSchemeIdUris.includes(schemeId)) ||
|
|
2409
|
-
this.config_.dispatchAllEmsgBoxes) {
|
|
2410
|
-
// See DASH sec. 5.10.4.1
|
|
2411
|
-
// A special scheme in DASH used to signal manifest updates.
|
|
2412
|
-
if (schemeId == 'urn:mpeg:dash:event:2012') {
|
|
2413
|
-
this.playerInterface_.onManifestUpdate();
|
|
2414
|
-
} else {
|
|
2415
|
-
// All other schemes are dispatched as a general 'emsg' event.
|
|
2416
|
-
const endTime = startTime + (eventDuration / timescale);
|
|
2417
|
-
/** @type {shaka.extern.EmsgInfo} */
|
|
2418
|
-
const emsg = {
|
|
2419
|
-
startTime: startTime,
|
|
2420
|
-
endTime: endTime,
|
|
2421
|
-
schemeIdUri: schemeId,
|
|
2422
|
-
value: value,
|
|
2423
|
-
timescale: timescale,
|
|
2424
|
-
presentationTimeDelta: presentationTimeDelta,
|
|
2425
|
-
eventDuration: eventDuration,
|
|
2426
|
-
id: id,
|
|
2427
|
-
messageData: messageData,
|
|
2428
|
-
};
|
|
2429
|
-
|
|
2430
|
-
// Dispatch an event to notify the application about the emsg box.
|
|
2431
|
-
const eventName = shaka.util.FakeEvent.EventName.Emsg;
|
|
2432
|
-
const data = (new Map()).set('detail', emsg);
|
|
2433
|
-
const event = new shaka.util.FakeEvent(eventName, data);
|
|
2434
|
-
// A user can call preventDefault() on a cancelable event.
|
|
2435
|
-
event.cancelable = true;
|
|
2436
|
-
|
|
2437
|
-
this.playerInterface_.onEvent(event);
|
|
2438
|
-
|
|
2439
|
-
if (event.defaultPrevented) {
|
|
2440
|
-
// If the caller uses preventDefault() on the 'emsg' event, don't
|
|
2441
|
-
// process any further, and don't generate an ID3 'metadata' event
|
|
2442
|
-
// for the same data.
|
|
2443
|
-
return;
|
|
2444
|
-
}
|
|
2445
|
-
|
|
2446
|
-
// Additionally, ID3 events generate a 'metadata' event. This is a
|
|
2447
|
-
// pre-parsed version of the metadata blob already dispatched in the
|
|
2448
|
-
// 'emsg' event.
|
|
2449
|
-
if (schemeId == 'https://aomedia.org/emsg/ID3' ||
|
|
2450
|
-
schemeId == 'https://developer.apple.com/streaming/emsg-id3') {
|
|
2451
|
-
// See https://aomediacodec.github.io/id3-emsg/
|
|
2452
|
-
const frames = shaka.util.Id3Utils.getID3Frames(messageData);
|
|
2453
|
-
if (frames.length) {
|
|
2454
|
-
/** @private {shaka.extern.ID3Metadata} */
|
|
2455
|
-
const metadata = {
|
|
2456
|
-
cueTime: startTime,
|
|
2457
|
-
data: messageData,
|
|
2458
|
-
frames: frames,
|
|
2459
|
-
dts: startTime,
|
|
2460
|
-
pts: startTime,
|
|
2461
|
-
};
|
|
2462
|
-
this.playerInterface_.onMetadata(
|
|
2463
|
-
[metadata], /* offset= */ 0, endTime);
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
/**
|
|
2471
|
-
* Parse PRFT box.
|
|
2472
|
-
* @param {!shaka.media.SegmentReference} reference
|
|
2473
|
-
* @param {!shaka.extern.ParsedBox} box
|
|
2474
|
-
* @private
|
|
2475
|
-
*/
|
|
2476
|
-
parsePrft_(reference, box) {
|
|
2477
|
-
if (this.parsedPrftEventRaised_ ||
|
|
2478
|
-
!reference.initSegmentReference.timescale) {
|
|
2479
|
-
return;
|
|
2480
|
-
}
|
|
2481
|
-
goog.asserts.assert(
|
|
2482
|
-
box.version == 0 || box.version == 1,
|
|
2483
|
-
'PRFT version can only be 0 or 1');
|
|
2484
|
-
const parsed = shaka.util.Mp4BoxParsers.parsePRFTInaccurate(
|
|
2485
|
-
box.reader, box.version);
|
|
2486
|
-
|
|
2487
|
-
const timescale = reference.initSegmentReference.timescale;
|
|
2488
|
-
const wallClockTime = this.convertNtp(parsed.ntpTimestamp);
|
|
2489
|
-
const programStartDate = new Date(wallClockTime -
|
|
2490
|
-
(parsed.mediaTime / timescale) * 1000);
|
|
2491
|
-
const prftInfo = {
|
|
2492
|
-
wallClockTime,
|
|
2493
|
-
programStartDate,
|
|
2494
|
-
};
|
|
2495
|
-
|
|
2496
|
-
const eventName = shaka.util.FakeEvent.EventName.Prft;
|
|
2497
|
-
const data = (new Map()).set('detail', prftInfo);
|
|
2498
|
-
const event = new shaka.util.FakeEvent(
|
|
2499
|
-
eventName, data);
|
|
2500
|
-
this.playerInterface_.onEvent(event);
|
|
2501
|
-
this.parsedPrftEventRaised_ = true;
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
/**
|
|
2506
|
-
* Convert Ntp ntpTimeStamp to UTC Time
|
|
2507
|
-
*
|
|
2508
|
-
* @param {number} ntpTimeStamp
|
|
2509
|
-
* @return {number} utcTime
|
|
2510
|
-
*/
|
|
2511
|
-
convertNtp(ntpTimeStamp) {
|
|
2512
|
-
const start = new Date(Date.UTC(1900, 0, 1, 0, 0, 0));
|
|
2513
|
-
return new Date(start.getTime() + ntpTimeStamp).getTime();
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
2334
|
/**
|
|
2517
2335
|
* Evicts media to meet the max buffer behind limit.
|
|
2518
2336
|
*
|
|
@@ -2896,21 +2714,26 @@ shaka.media.StreamingEngine = class {
|
|
|
2896
2714
|
/**
|
|
2897
2715
|
* Reset Media Source
|
|
2898
2716
|
*
|
|
2717
|
+
* @param {boolean=} force
|
|
2899
2718
|
* @return {!Promise.<boolean>}
|
|
2900
2719
|
*/
|
|
2901
|
-
async resetMediaSource() {
|
|
2720
|
+
async resetMediaSource(force = false, clearBuffer = true) {
|
|
2902
2721
|
const now = (Date.now() / 1000);
|
|
2903
2722
|
const minTimeBetweenRecoveries = this.config_.minTimeBetweenRecoveries;
|
|
2904
|
-
if (!
|
|
2905
|
-
|
|
2906
|
-
|
|
2723
|
+
if (!force) {
|
|
2724
|
+
if (!this.config_.allowMediaSourceRecoveries ||
|
|
2725
|
+
(now - this.lastMediaSourceReset_) < minTimeBetweenRecoveries) {
|
|
2726
|
+
return false;
|
|
2727
|
+
}
|
|
2728
|
+
this.lastMediaSourceReset_ = now;
|
|
2907
2729
|
}
|
|
2908
|
-
this.lastMediaSourceReset_ = now;
|
|
2909
2730
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
2910
2731
|
const audioMediaState = this.mediaStates_.get(ContentType.AUDIO);
|
|
2911
2732
|
if (audioMediaState) {
|
|
2912
2733
|
audioMediaState.lastInitSegmentReference = null;
|
|
2913
|
-
|
|
2734
|
+
if (clearBuffer) {
|
|
2735
|
+
this.forceClearBuffer_(audioMediaState);
|
|
2736
|
+
}
|
|
2914
2737
|
this.abortOperations_(audioMediaState).catch(() => {});
|
|
2915
2738
|
if (audioMediaState.segmentIterator) {
|
|
2916
2739
|
audioMediaState.segmentIterator.resetToLastIndependent();
|
|
@@ -2919,7 +2742,9 @@ shaka.media.StreamingEngine = class {
|
|
|
2919
2742
|
const videoMediaState = this.mediaStates_.get(ContentType.VIDEO);
|
|
2920
2743
|
if (videoMediaState) {
|
|
2921
2744
|
videoMediaState.lastInitSegmentReference = null;
|
|
2922
|
-
|
|
2745
|
+
if (clearBuffer) {
|
|
2746
|
+
this.forceClearBuffer_(videoMediaState);
|
|
2747
|
+
}
|
|
2923
2748
|
this.abortOperations_(videoMediaState).catch(() => {});
|
|
2924
2749
|
if (videoMediaState.segmentIterator) {
|
|
2925
2750
|
videoMediaState.segmentIterator.resetToLastIndependent();
|
|
@@ -2937,6 +2762,14 @@ shaka.media.StreamingEngine = class {
|
|
|
2937
2762
|
streamsByType.set(ContentType.VIDEO, this.currentVariant_.video);
|
|
2938
2763
|
}
|
|
2939
2764
|
await this.playerInterface_.mediaSourceEngine.reset(streamsByType);
|
|
2765
|
+
if (videoMediaState &&
|
|
2766
|
+
!videoMediaState.performingUpdate && !videoMediaState.updateTimer) {
|
|
2767
|
+
this.scheduleUpdate_(videoMediaState, 0);
|
|
2768
|
+
}
|
|
2769
|
+
if (audioMediaState &&
|
|
2770
|
+
!audioMediaState.performingUpdate && !audioMediaState.updateTimer) {
|
|
2771
|
+
this.scheduleUpdate_(audioMediaState, 0);
|
|
2772
|
+
}
|
|
2940
2773
|
return true;
|
|
2941
2774
|
}
|
|
2942
2775
|
|
|
@@ -3006,13 +2839,11 @@ shaka.media.StreamingEngine = class {
|
|
|
3006
2839
|
* netEngine: shaka.net.NetworkingEngine,
|
|
3007
2840
|
* onError: function(!shaka.util.Error),
|
|
3008
2841
|
* onEvent: function(!Event),
|
|
3009
|
-
* onManifestUpdate: function(),
|
|
3010
2842
|
* onSegmentAppended: function(!shaka.media.SegmentReference,
|
|
3011
2843
|
* !shaka.extern.Stream),
|
|
3012
2844
|
* onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference),
|
|
3013
2845
|
* beforeAppendSegment: function(
|
|
3014
2846
|
* shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise,
|
|
3015
|
-
* onMetadata: !function(!Array.<shaka.extern.ID3Metadata>, number, ?number),
|
|
3016
2847
|
* disableStream: function(!shaka.extern.Stream, number):boolean
|
|
3017
2848
|
* }}
|
|
3018
2849
|
*
|
|
@@ -3033,8 +2864,6 @@ shaka.media.StreamingEngine = class {
|
|
|
3033
2864
|
* StreamingEngine.switch*() or StreamingEngine.seeked() to attempt recovery.
|
|
3034
2865
|
* @property {function(!Event)} onEvent
|
|
3035
2866
|
* Called when an event occurs that should be sent to the app.
|
|
3036
|
-
* @property {function()} onManifestUpdate
|
|
3037
|
-
* Called when an embedded 'emsg' box should trigger a manifest update.
|
|
3038
2867
|
* @property {function(!shaka.media.SegmentReference,
|
|
3039
2868
|
* !shaka.extern.Stream)} onSegmentAppended
|
|
3040
2869
|
* Called after a segment is successfully appended to a MediaSource.
|
|
@@ -3044,9 +2873,6 @@ shaka.media.StreamingEngine = class {
|
|
|
3044
2873
|
* @property {!function(shaka.util.ManifestParserUtils.ContentType,
|
|
3045
2874
|
* !BufferSource):Promise} beforeAppendSegment
|
|
3046
2875
|
* A function called just before appending to the source buffer.
|
|
3047
|
-
* @property
|
|
3048
|
-
* {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)} onMetadata
|
|
3049
|
-
* Called when an ID3 is found in a EMSG.
|
|
3050
2876
|
* @property {function(!shaka.extern.Stream, number):boolean} disableStream
|
|
3051
2877
|
* Called to temporarily disable a stream i.e. disabling all variant
|
|
3052
2878
|
* containing said stream.
|
package/lib/mss/mss_parser.js
CHANGED
|
@@ -45,7 +45,11 @@ shaka.offline.DownloadInfo = class {
|
|
|
45
45
|
static idForSegmentRef(ref) {
|
|
46
46
|
// Escape the URIs using encodeURI, to make sure that a weirdly formed URI
|
|
47
47
|
// cannot cause two unrelated refs to be considered equivalent.
|
|
48
|
-
|
|
48
|
+
const removeSprites = (uri) => {
|
|
49
|
+
return uri.split('#xywh=')[0];
|
|
50
|
+
};
|
|
51
|
+
return ref.getUris().map(
|
|
52
|
+
(uri) => '{' + encodeURI(removeSprites(uri)) + '}').join('') +
|
|
49
53
|
':' + ref.startByte + ':' + ref.endByte;
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -392,9 +392,10 @@ shaka.offline.indexeddb.StorageMechanism.SESSION_ID_STORE = 'session-ids';
|
|
|
392
392
|
shaka.offline.StorageMuxer.register(
|
|
393
393
|
'idb',
|
|
394
394
|
() => {
|
|
395
|
-
// Offline storage is not supported on the Chromecast or
|
|
396
|
-
// platforms.
|
|
397
|
-
if (shaka.util.Platform.isChromecast()
|
|
395
|
+
// Offline storage is not supported on the Chromecast Linux/Fuschia or
|
|
396
|
+
// Xbox One platforms.
|
|
397
|
+
if ((shaka.util.Platform.isChromecast() &&
|
|
398
|
+
!shaka.util.Platform.isAndroidCastDevice()) ||
|
|
398
399
|
shaka.util.Platform.isXboxOne()) {
|
|
399
400
|
return null;
|
|
400
401
|
}
|
|
@@ -182,6 +182,7 @@ shaka.offline.indexeddb.V1StorageCell = class
|
|
|
182
182
|
tilesLayout: undefined,
|
|
183
183
|
external: false,
|
|
184
184
|
fastSwitching: false,
|
|
185
|
+
isAudioMuxedInVideo: false,
|
|
185
186
|
};
|
|
186
187
|
}
|
|
187
188
|
|
|
@@ -214,6 +215,7 @@ shaka.offline.indexeddb.V1StorageCell = class
|
|
|
214
215
|
tilesLayout: '',
|
|
215
216
|
mimeType: null,
|
|
216
217
|
codecs: null,
|
|
218
|
+
thumbnailSprite: null,
|
|
217
219
|
};
|
|
218
220
|
}
|
|
219
221
|
|
|
@@ -131,6 +131,7 @@ shaka.offline.indexeddb.V2StorageCell = class
|
|
|
131
131
|
tilesLayout: undefined,
|
|
132
132
|
external: false,
|
|
133
133
|
fastSwitching: false,
|
|
134
|
+
isAudioMuxedInVideo: false,
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
137
|
|
|
@@ -158,6 +159,7 @@ shaka.offline.indexeddb.V2StorageCell = class
|
|
|
158
159
|
tilesLayout: '',
|
|
159
160
|
mimeType: null,
|
|
160
161
|
codecs: null,
|
|
162
|
+
thumbnailSprite: null,
|
|
161
163
|
};
|
|
162
164
|
}
|
|
163
165
|
};
|
|
@@ -221,6 +221,7 @@ shaka.offline.ManifestConverter = class {
|
|
|
221
221
|
fastSwitching: streamDB.fastSwitching,
|
|
222
222
|
fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
|
|
223
223
|
streamDB.mimeType, streamDB.codecs)]),
|
|
224
|
+
isAudioMuxedInVideo: false,
|
|
224
225
|
};
|
|
225
226
|
|
|
226
227
|
return stream;
|
|
@@ -255,6 +256,9 @@ shaka.offline.ManifestConverter = class {
|
|
|
255
256
|
segmentDB.tilesLayout || '');
|
|
256
257
|
ref.mimeType = segmentDB.mimeType || streamDB.mimeType || '';
|
|
257
258
|
ref.codecs = segmentDB.codecs || streamDB.codecs || '';
|
|
259
|
+
if (segmentDB.thumbnailSprite) {
|
|
260
|
+
ref.setThumbnailSprite(segmentDB.thumbnailSprite);
|
|
261
|
+
}
|
|
258
262
|
return ref;
|
|
259
263
|
}
|
|
260
264
|
|