shaka-player 4.3.12 → 4.3.13
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/CHANGELOG.md +21 -0
- package/demo/common/asset.js +5 -0
- package/demo/common/assets.js +16 -1
- package/demo/common/message_ids.js +1 -0
- package/demo/locales/en.json +1 -0
- package/demo/locales/source.json +4 -0
- package/demo/main.js +1 -1
- package/dist/demo.compiled.debug.js +55 -53
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +55 -53
- package/dist/demo.compiled.map +3 -3
- package/dist/locales.js +27 -27
- package/dist/receiver.compiled.debug.js +24 -22
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +24 -22
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.externs.js +6 -4
- package/dist/shaka-player.compiled.debug.js +87 -89
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +6 -4
- package/dist/shaka-player.compiled.js +340 -338
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +1 -1
- package/dist/shaka-player.ui.debug.d.ts +1 -1
- package/dist/shaka-player.ui.debug.externs.js +6 -4
- package/dist/shaka-player.ui.debug.js +235 -237
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +6 -4
- package/dist/shaka-player.ui.js +510 -508
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/offline.md +1 -1
- package/lib/dash/dash_parser.js +4 -1
- package/lib/hls/hls_parser.js +60 -24
- package/lib/media/segment_reference.js +11 -5
- package/lib/media/streaming_engine.js +15 -25
- package/lib/player.js +1 -1
- package/lib/text/vtt_text_parser.js +2 -2
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/ts_parser.js +3 -3
- package/package.json +1 -1
- package/test/dash/dash_parser_manifest_unit.js +5 -0
- package/test/dash/dash_parser_segment_base_unit.js +5 -0
- package/test/dash/dash_parser_segment_list_unit.js +21 -17
- package/test/dash/dash_parser_segment_template_unit.js +5 -0
- package/test/hls/hls_live_unit.js +33 -0
- package/test/hls/hls_parser_unit.js +2 -57
- package/test/test/util/dash_parser_util.js +16 -7
- package/test/text/vtt_text_parser_unit.js +2 -17
- package/test/util/ts_parser_unit.js +1 -1
package/lib/dash/dash_parser.js
CHANGED
|
@@ -522,7 +522,10 @@ shaka.dash.DashParser = class {
|
|
|
522
522
|
// Just update the variants and text streams, which may change as periods
|
|
523
523
|
// are added or removed.
|
|
524
524
|
this.manifest_.variants = this.periodCombiner_.getVariants();
|
|
525
|
-
|
|
525
|
+
const textStreams = this.periodCombiner_.getTextStreams();
|
|
526
|
+
if (textStreams.length > 0) {
|
|
527
|
+
this.manifest_.textStreams = textStreams;
|
|
528
|
+
}
|
|
526
529
|
this.manifest_.imageStreams = this.periodCombiner_.getImageStreams();
|
|
527
530
|
|
|
528
531
|
// Re-filter the manifest. This will check any configured restrictions on
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -774,7 +774,7 @@ shaka.hls.HlsParser = class {
|
|
|
774
774
|
// enough info here to determine the presentation type and duration.
|
|
775
775
|
if (playlist.type == shaka.hls.PlaylistType.MEDIA) {
|
|
776
776
|
if (this.isLive_()) {
|
|
777
|
-
this.changePresentationTimelineToLive_();
|
|
777
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
778
778
|
const delay = this.updatePlaylistDelay_;
|
|
779
779
|
this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay);
|
|
780
780
|
}
|
|
@@ -1440,7 +1440,14 @@ shaka.hls.HlsParser = class {
|
|
|
1440
1440
|
for (const tag of closedCaptionsTags) {
|
|
1441
1441
|
goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
|
|
1442
1442
|
'Should only be called on media tags!');
|
|
1443
|
-
const
|
|
1443
|
+
const languageValue = tag.getAttributeValue('LANGUAGE');
|
|
1444
|
+
let language = this.getLanguage_(tag);
|
|
1445
|
+
if (!languageValue) {
|
|
1446
|
+
const nameValue = tag.getAttributeValue('NAME');
|
|
1447
|
+
if (nameValue) {
|
|
1448
|
+
language = nameValue;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1444
1451
|
|
|
1445
1452
|
// The GROUP-ID value is a quoted-string that specifies the group to which
|
|
1446
1453
|
// the Rendition belongs.
|
|
@@ -1449,7 +1456,9 @@ shaka.hls.HlsParser = class {
|
|
|
1449
1456
|
// The value of INSTREAM-ID is a quoted-string that specifies a Rendition
|
|
1450
1457
|
// within the segments in the Media Playlist. This attribute is REQUIRED
|
|
1451
1458
|
// if the TYPE attribute is CLOSED-CAPTIONS.
|
|
1452
|
-
|
|
1459
|
+
// We need replace SERVICE string by our internal svc string.
|
|
1460
|
+
const instreamId = tag.getRequiredAttrValue('INSTREAM-ID')
|
|
1461
|
+
.replace('SERVICE', 'svc');
|
|
1453
1462
|
if (!this.groupIdToClosedCaptionsMap_.get(groupId)) {
|
|
1454
1463
|
this.groupIdToClosedCaptionsMap_.set(groupId, new Map());
|
|
1455
1464
|
}
|
|
@@ -1709,7 +1718,7 @@ shaka.hls.HlsParser = class {
|
|
|
1709
1718
|
if (this.isLive_() && !wasLive) {
|
|
1710
1719
|
// Now that we know that the presentation is live, convert the timeline
|
|
1711
1720
|
// to live.
|
|
1712
|
-
this.changePresentationTimelineToLive_();
|
|
1721
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
1713
1722
|
}
|
|
1714
1723
|
|
|
1715
1724
|
// Copy values from the real stream info to our initial one.
|
|
@@ -2323,9 +2332,10 @@ shaka.hls.HlsParser = class {
|
|
|
2323
2332
|
}
|
|
2324
2333
|
|
|
2325
2334
|
/**
|
|
2335
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2326
2336
|
* @private
|
|
2327
2337
|
*/
|
|
2328
|
-
changePresentationTimelineToLive_() {
|
|
2338
|
+
changePresentationTimelineToLive_(playlist) {
|
|
2329
2339
|
// The live edge will be calculated from segments, so we don't need to
|
|
2330
2340
|
// set a presentation start time. We will assert later that this is
|
|
2331
2341
|
// working as expected.
|
|
@@ -2346,8 +2356,12 @@ shaka.hls.HlsParser = class {
|
|
|
2346
2356
|
} else if (this.lowLatencyPresentationDelay_) {
|
|
2347
2357
|
presentationDelay = this.lowLatencyPresentationDelay_;
|
|
2348
2358
|
} else {
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2359
|
+
const playlistSegments = playlist.segments.length;
|
|
2360
|
+
let delaySegments = this.config_.hls.liveSegmentsDelay;
|
|
2361
|
+
if (delaySegments > (playlistSegments - 2)) {
|
|
2362
|
+
delaySegments = Math.max(1, playlistSegments - 2);
|
|
2363
|
+
}
|
|
2364
|
+
presentationDelay = this.maxTargetDuration_ * delaySegments;
|
|
2351
2365
|
}
|
|
2352
2366
|
|
|
2353
2367
|
this.presentationTimeline_.setPresentationStartTime(0);
|
|
@@ -2357,13 +2371,13 @@ shaka.hls.HlsParser = class {
|
|
|
2357
2371
|
|
|
2358
2372
|
/**
|
|
2359
2373
|
* Get the InitSegmentReference for a segment if it has a EXT-X-MAP tag.
|
|
2360
|
-
* @param {
|
|
2374
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2361
2375
|
* @param {!Array.<!shaka.hls.Tag>} tags Segment tags
|
|
2362
2376
|
* @param {!Map.<string, string>} variables
|
|
2363
2377
|
* @return {shaka.media.InitSegmentReference}
|
|
2364
2378
|
* @private
|
|
2365
2379
|
*/
|
|
2366
|
-
getInitSegmentReference_(
|
|
2380
|
+
getInitSegmentReference_(playlist, tags, variables) {
|
|
2367
2381
|
/** @type {?shaka.hls.Tag} */
|
|
2368
2382
|
const mapTag = shaka.hls.Utils.getFirstTagWithName(tags, 'EXT-X-MAP');
|
|
2369
2383
|
|
|
@@ -2374,7 +2388,7 @@ shaka.hls.HlsParser = class {
|
|
|
2374
2388
|
const verbatimInitSegmentUri = mapTag.getRequiredAttrValue('URI');
|
|
2375
2389
|
const absoluteInitSegmentUri = this.variableSubstitution_(
|
|
2376
2390
|
shaka.hls.Utils.constructAbsoluteUri(
|
|
2377
|
-
|
|
2391
|
+
playlist.absoluteUri, verbatimInitSegmentUri),
|
|
2378
2392
|
variables);
|
|
2379
2393
|
|
|
2380
2394
|
const mapTagKey = [
|
|
@@ -2382,8 +2396,18 @@ shaka.hls.HlsParser = class {
|
|
|
2382
2396
|
mapTag.getAttributeValue('BYTERANGE', ''),
|
|
2383
2397
|
].join('-');
|
|
2384
2398
|
if (!this.mapTagToInitSegmentRefMap_.has(mapTagKey)) {
|
|
2399
|
+
/** @type {shaka.extern.HlsAes128Key|undefined} */
|
|
2400
|
+
let aes128Key = undefined;
|
|
2401
|
+
for (const tag of tags) {
|
|
2402
|
+
if (tag.name == 'EXT-X-KEY') {
|
|
2403
|
+
if (tag.getRequiredAttrValue('METHOD') == 'AES-128' &&
|
|
2404
|
+
tag.id < mapTag.id) {
|
|
2405
|
+
aes128Key = this.parseAES128DrmTag_(tag, playlist);
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2385
2409
|
const initSegmentRef = this.createInitSegmentReference_(
|
|
2386
|
-
absoluteInitSegmentUri, mapTag);
|
|
2410
|
+
absoluteInitSegmentUri, mapTag, aes128Key);
|
|
2387
2411
|
this.mapTagToInitSegmentRefMap_.set(mapTagKey, initSegmentRef);
|
|
2388
2412
|
}
|
|
2389
2413
|
return this.mapTagToInitSegmentRefMap_.get(mapTagKey);
|
|
@@ -2394,10 +2418,11 @@ shaka.hls.HlsParser = class {
|
|
|
2394
2418
|
* playlist.
|
|
2395
2419
|
* @param {string} absoluteInitSegmentUri
|
|
2396
2420
|
* @param {!shaka.hls.Tag} mapTag EXT-X-MAP
|
|
2421
|
+
* @param {shaka.extern.HlsAes128Key=} aes128Key
|
|
2397
2422
|
* @return {!shaka.media.InitSegmentReference}
|
|
2398
2423
|
* @private
|
|
2399
2424
|
*/
|
|
2400
|
-
createInitSegmentReference_(absoluteInitSegmentUri, mapTag) {
|
|
2425
|
+
createInitSegmentReference_(absoluteInitSegmentUri, mapTag, aes128Key) {
|
|
2401
2426
|
let startByte = 0;
|
|
2402
2427
|
let endByte = null;
|
|
2403
2428
|
const byterange = mapTag.getAttributeValue('BYTERANGE');
|
|
@@ -2408,12 +2433,25 @@ shaka.hls.HlsParser = class {
|
|
|
2408
2433
|
const byteLength = Number(blocks[0]);
|
|
2409
2434
|
startByte = Number(blocks[1]);
|
|
2410
2435
|
endByte = startByte + byteLength - 1;
|
|
2436
|
+
|
|
2437
|
+
if (aes128Key) {
|
|
2438
|
+
// MAP segment encrypted with method 'AES-128', when served with
|
|
2439
|
+
// HTTP Range, has the unencrypted size specified in the range.
|
|
2440
|
+
// See: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
|
2441
|
+
const length = (endByte + 1) - startByte;
|
|
2442
|
+
if (length % 16) {
|
|
2443
|
+
endByte += (16 - (length % 16));
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2411
2446
|
}
|
|
2412
2447
|
|
|
2413
2448
|
const initSegmentRef = new shaka.media.InitSegmentReference(
|
|
2414
2449
|
() => [absoluteInitSegmentUri],
|
|
2415
2450
|
startByte,
|
|
2416
|
-
endByte
|
|
2451
|
+
endByte,
|
|
2452
|
+
/* mediaQuality= */ null,
|
|
2453
|
+
/* timescale= */ null,
|
|
2454
|
+
aes128Key);
|
|
2417
2455
|
return initSegmentRef;
|
|
2418
2456
|
}
|
|
2419
2457
|
|
|
@@ -2427,15 +2465,13 @@ shaka.hls.HlsParser = class {
|
|
|
2427
2465
|
* @param {!Map.<string, string>} variables
|
|
2428
2466
|
* @param {string} absoluteMediaPlaylistUri
|
|
2429
2467
|
* @param {string} type
|
|
2430
|
-
* @param {number} timestampOffset
|
|
2431
2468
|
* @param {shaka.extern.HlsAes128Key=} hlsAes128Key
|
|
2432
2469
|
* @return {shaka.media.SegmentReference}
|
|
2433
2470
|
* @private
|
|
2434
2471
|
*/
|
|
2435
2472
|
createSegmentReference_(
|
|
2436
2473
|
initSegmentReference, previousReference, hlsSegment, startTime,
|
|
2437
|
-
variables, absoluteMediaPlaylistUri, type,
|
|
2438
|
-
hlsAes128Key) {
|
|
2474
|
+
variables, absoluteMediaPlaylistUri, type, hlsAes128Key) {
|
|
2439
2475
|
const tags = hlsSegment.tags;
|
|
2440
2476
|
const absoluteSegmentUri = this.variableSubstitution_(
|
|
2441
2477
|
hlsSegment.absoluteUri, variables);
|
|
@@ -2539,7 +2575,7 @@ shaka.hls.HlsParser = class {
|
|
|
2539
2575
|
pStartByte,
|
|
2540
2576
|
pEndByte,
|
|
2541
2577
|
initSegmentReference,
|
|
2542
|
-
/* timestampOffset= */ 0,
|
|
2578
|
+
/* timestampOffset= */ 0,
|
|
2543
2579
|
/* appendWindowStart= */ 0,
|
|
2544
2580
|
/* appendWindowEnd= */ Infinity,
|
|
2545
2581
|
/* partialReferences= */ [],
|
|
@@ -2571,8 +2607,11 @@ shaka.hls.HlsParser = class {
|
|
|
2571
2607
|
return null;
|
|
2572
2608
|
}
|
|
2573
2609
|
endTime = startTime + duration;
|
|
2574
|
-
} else {
|
|
2610
|
+
} else if (partialSegmentRefs.length) {
|
|
2575
2611
|
endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
|
|
2612
|
+
} else {
|
|
2613
|
+
// Skip segments without duration and without partialsegments
|
|
2614
|
+
return null;
|
|
2576
2615
|
}
|
|
2577
2616
|
|
|
2578
2617
|
// If the segment has EXT-X-BYTERANGE tag, set the start byte and end byte
|
|
@@ -2612,7 +2651,7 @@ shaka.hls.HlsParser = class {
|
|
|
2612
2651
|
startByte,
|
|
2613
2652
|
endByte,
|
|
2614
2653
|
initSegmentReference,
|
|
2615
|
-
timestampOffset
|
|
2654
|
+
/* timestampOffset= */ 0,
|
|
2616
2655
|
/* appendWindowStart= */ 0,
|
|
2617
2656
|
/* appendWindowEnd= */ Infinity,
|
|
2618
2657
|
partialSegmentRefs,
|
|
@@ -2697,7 +2736,6 @@ shaka.hls.HlsParser = class {
|
|
|
2697
2736
|
const references = [];
|
|
2698
2737
|
|
|
2699
2738
|
let previousReference = null;
|
|
2700
|
-
let lastDiscontinuityStartTime = firstStartTime;
|
|
2701
2739
|
|
|
2702
2740
|
for (let i = 0; i < hlsSegments.length; i++) {
|
|
2703
2741
|
const item = hlsSegments[i];
|
|
@@ -2709,7 +2747,6 @@ shaka.hls.HlsParser = class {
|
|
|
2709
2747
|
item.tags, 'EXT-X-DISCONTINUITY');
|
|
2710
2748
|
if (discontinuityTag) {
|
|
2711
2749
|
discontinuitySequence++;
|
|
2712
|
-
lastDiscontinuityStartTime = startTime;
|
|
2713
2750
|
}
|
|
2714
2751
|
|
|
2715
2752
|
// Apply new AES-128 tags as you see them, keeping a running total.
|
|
@@ -2725,8 +2762,8 @@ shaka.hls.HlsParser = class {
|
|
|
2725
2762
|
|
|
2726
2763
|
mediaSequenceToStartTime.set(position, startTime);
|
|
2727
2764
|
|
|
2728
|
-
initSegmentRef = this.getInitSegmentReference_(playlist.
|
|
2729
|
-
|
|
2765
|
+
initSegmentRef = this.getInitSegmentReference_(playlist, item.tags,
|
|
2766
|
+
variables);
|
|
2730
2767
|
|
|
2731
2768
|
// If the stream is low latency and the user has not configured the
|
|
2732
2769
|
// lowLatencyMode, but if it has been configured to activate the
|
|
@@ -2748,7 +2785,6 @@ shaka.hls.HlsParser = class {
|
|
|
2748
2785
|
variables,
|
|
2749
2786
|
playlist.absoluteUri,
|
|
2750
2787
|
type,
|
|
2751
|
-
lastDiscontinuityStartTime,
|
|
2752
2788
|
hlsAes128Key);
|
|
2753
2789
|
|
|
2754
2790
|
if (reference) {
|
|
@@ -27,11 +27,14 @@ shaka.media.InitSegmentReference = class {
|
|
|
27
27
|
* @param {?number} endByte The offset from the start of the resource
|
|
28
28
|
* to the end of the segment, inclusive. A value of null indicates that the
|
|
29
29
|
* segment extends to the end of the resource.
|
|
30
|
-
* @param {null|shaka.extern.MediaQualityInfo=} mediaQuality Information
|
|
31
|
-
* the quality of the media associated with this init segment.
|
|
32
|
-
* @param {number=} timescale
|
|
30
|
+
* @param {(null|shaka.extern.MediaQualityInfo)=} mediaQuality Information
|
|
31
|
+
* about the quality of the media associated with this init segment.
|
|
32
|
+
* @param {(null|number)=} timescale
|
|
33
|
+
* @param {?shaka.extern.HlsAes128Key=} aes128Key
|
|
34
|
+
* The segment's AES-128-CBC full segment encryption key and iv.
|
|
33
35
|
*/
|
|
34
|
-
constructor(uris, startByte, endByte, mediaQuality = null, timescale
|
|
36
|
+
constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
|
|
37
|
+
aes128Key = null) {
|
|
35
38
|
/** @type {function():!Array.<string>} */
|
|
36
39
|
this.getUris = uris;
|
|
37
40
|
|
|
@@ -44,8 +47,11 @@ shaka.media.InitSegmentReference = class {
|
|
|
44
47
|
/** @const {shaka.extern.MediaQualityInfo|null} */
|
|
45
48
|
this.mediaQuality = mediaQuality;
|
|
46
49
|
|
|
47
|
-
/** @type {number|
|
|
50
|
+
/** @type {number|null} */
|
|
48
51
|
this.timescale = timescale;
|
|
52
|
+
|
|
53
|
+
/** @type {?shaka.extern.HlsAes128Key} */
|
|
54
|
+
this.hlsAes128Key = aes128Key;
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
/**
|
|
@@ -1357,16 +1357,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1357
1357
|
'ReadableStream is not supported by the browser.');
|
|
1358
1358
|
}
|
|
1359
1359
|
const fetchSegment = this.fetch_(mediaState, reference);
|
|
1360
|
-
|
|
1360
|
+
const result = await fetchSegment;
|
|
1361
1361
|
this.destroyer_.ensureNotDestroyed();
|
|
1362
1362
|
if (this.fatalError_) {
|
|
1363
1363
|
return;
|
|
1364
1364
|
}
|
|
1365
|
-
if (reference.hlsAes128Key) {
|
|
1366
|
-
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
|
|
1367
|
-
result = await this.aes128Decrypt_(result, reference, iter);
|
|
1368
|
-
}
|
|
1369
|
-
this.destroyer_.ensureNotDestroyed();
|
|
1370
1365
|
|
|
1371
1366
|
// If the text stream gets switched between fetch_() and append_(), the
|
|
1372
1367
|
// new text parser is initialized, but the new init segment is not
|
|
@@ -1450,13 +1445,13 @@ shaka.media.StreamingEngine = class {
|
|
|
1450
1445
|
|
|
1451
1446
|
/**
|
|
1452
1447
|
* @param {!BufferSource} rawResult
|
|
1453
|
-
* @param {
|
|
1448
|
+
* @param {shaka.extern.HlsAes128Key} aes128Key
|
|
1454
1449
|
* @param {!shaka.media.SegmentIterator} iter
|
|
1455
1450
|
* @return {!Promise.<!BufferSource>} finalResult
|
|
1456
1451
|
* @private
|
|
1457
1452
|
*/
|
|
1458
|
-
async aes128Decrypt_(rawResult,
|
|
1459
|
-
const key =
|
|
1453
|
+
async aes128Decrypt_(rawResult, aes128Key, iter) {
|
|
1454
|
+
const key = aes128Key;
|
|
1460
1455
|
if (!key.cryptoKey) {
|
|
1461
1456
|
goog.asserts.assert(key.fetchKey, 'If AES-128 cryptoKey was not ' +
|
|
1462
1457
|
'preloaded, fetchKey function should be provided');
|
|
@@ -1693,10 +1688,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1693
1688
|
}
|
|
1694
1689
|
}
|
|
1695
1690
|
|
|
1696
|
-
const lastDiscontinuitySequence =
|
|
1697
|
-
mediaState.lastSegmentReference ?
|
|
1698
|
-
mediaState.lastSegmentReference.discontinuitySequence : null;
|
|
1699
1691
|
if (this.manifest_.sequenceMode) {
|
|
1692
|
+
const lastDiscontinuitySequence =
|
|
1693
|
+
mediaState.lastSegmentReference ?
|
|
1694
|
+
mediaState.lastSegmentReference.discontinuitySequence : null;
|
|
1700
1695
|
// Across discontinuity bounds, we should resync timestamps for
|
|
1701
1696
|
// sequence mode playbacks. The next segment appended should
|
|
1702
1697
|
// land at its theoretical timestamp from the segment index.
|
|
@@ -1706,18 +1701,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1706
1701
|
operations.push(this.playerInterface_.mediaSourceEngine.resync(
|
|
1707
1702
|
mediaState.type, reference.startTime));
|
|
1708
1703
|
}
|
|
1709
|
-
} else {
|
|
1710
|
-
// In segments mode, we need to resync to set the timestampOffset
|
|
1711
|
-
// to the start of the current discontinuity sequence. This is
|
|
1712
|
-
// because individual discontinuity sequences may have internal
|
|
1713
|
-
// timestamps that overlap, so we adjust the timestampOffset to avoid
|
|
1714
|
-
// having the SourceBuffer get overwritten.
|
|
1715
|
-
if (reference.discontinuitySequence != lastDiscontinuitySequence) {
|
|
1716
|
-
operations.push(
|
|
1717
|
-
this.playerInterface_.mediaSourceEngine.resync(
|
|
1718
|
-
mediaState.type,
|
|
1719
|
-
reference.timestampOffset));
|
|
1720
|
-
}
|
|
1721
1704
|
}
|
|
1722
1705
|
|
|
1723
1706
|
await Promise.all(operations);
|
|
@@ -2104,7 +2087,14 @@ shaka.media.StreamingEngine = class {
|
|
|
2104
2087
|
mediaState.operation = op;
|
|
2105
2088
|
const response = await op.promise;
|
|
2106
2089
|
mediaState.operation = null;
|
|
2107
|
-
|
|
2090
|
+
|
|
2091
|
+
let result = response.data;
|
|
2092
|
+
if (reference.hlsAes128Key) {
|
|
2093
|
+
const iter = mediaState.segmentIterator;
|
|
2094
|
+
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
|
|
2095
|
+
result = await this.aes128Decrypt_(result, reference.hlsAes128Key, iter);
|
|
2096
|
+
}
|
|
2097
|
+
return result;
|
|
2108
2098
|
}
|
|
2109
2099
|
|
|
2110
2100
|
|
package/lib/player.js
CHANGED
|
@@ -6971,7 +6971,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6971
6971
|
* @define {string} A version number taken from git at compile time.
|
|
6972
6972
|
* @export
|
|
6973
6973
|
*/
|
|
6974
|
-
shaka.Player.version = 'v4.3.
|
|
6974
|
+
shaka.Player.version = 'v4.3.13-uncompiled';
|
|
6975
6975
|
|
|
6976
6976
|
// Initialize the deprecation system using the version string we just set
|
|
6977
6977
|
// on the player.
|
|
@@ -403,6 +403,8 @@ shaka.text.VttTextParser = class {
|
|
|
403
403
|
cue = new shaka.text.Cue(start, end, '');
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
VttTextParser.parseCueStyles(payload, cue, styles);
|
|
407
|
+
|
|
406
408
|
// Parse optional settings.
|
|
407
409
|
parser.skipWhitespace();
|
|
408
410
|
let word = parser.readWord();
|
|
@@ -416,8 +418,6 @@ shaka.text.VttTextParser = class {
|
|
|
416
418
|
word = parser.readWord();
|
|
417
419
|
}
|
|
418
420
|
|
|
419
|
-
VttTextParser.parseCueStyles(payload, cue, styles);
|
|
420
|
-
|
|
421
421
|
if (id != null) {
|
|
422
422
|
cue.id = id;
|
|
423
423
|
}
|
package/lib/util/cmcd_manager.js
CHANGED
|
@@ -331,12 +331,17 @@ shaka.util.CmcdManager = class {
|
|
|
331
331
|
* @private
|
|
332
332
|
*/
|
|
333
333
|
getObjectTypeFromMimeType_(mimeType) {
|
|
334
|
-
switch (mimeType) {
|
|
334
|
+
switch (mimeType.toLowerCase()) {
|
|
335
335
|
case 'video/webm':
|
|
336
336
|
case 'video/mp4':
|
|
337
|
+
case 'video/mpeg':
|
|
338
|
+
case 'video/mp2t':
|
|
337
339
|
return shaka.util.CmcdManager.ObjectType.MUXED;
|
|
338
340
|
|
|
339
341
|
case 'application/x-mpegurl':
|
|
342
|
+
case 'application/vnd.apple.mpegurl':
|
|
343
|
+
case 'application/dash+xml':
|
|
344
|
+
case 'video/vnd.mpeg.dash.mpd':
|
|
340
345
|
return shaka.util.CmcdManager.ObjectType.MANIFEST;
|
|
341
346
|
|
|
342
347
|
default:
|
|
@@ -29,13 +29,19 @@ shaka.util.ManifestParserUtils = class {
|
|
|
29
29
|
return baseUris;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
if (baseUris.length == 1 && relativeUris.length == 1) {
|
|
33
|
+
const baseUri = new goog.Uri(baseUris[0]);
|
|
34
|
+
const relativeUri = new goog.Uri(relativeUris[0]);
|
|
35
|
+
return [baseUri.resolve(relativeUri).toString()];
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
const relativeAsGoog = relativeUris.map((uri) => new goog.Uri(uri));
|
|
33
39
|
// Resolve each URI relative to each base URI, creating an Array of Arrays.
|
|
34
40
|
// Then flatten the Arrays into a single Array.
|
|
35
|
-
return baseUris.map((uri) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
return baseUris.map((uri) => {
|
|
42
|
+
const base = new goog.Uri(uri);
|
|
43
|
+
return relativeAsGoog.map((i) => base.resolve(i).toString());
|
|
44
|
+
}).reduce(Functional.collapseArrays, []);
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
|
package/lib/util/ts_parser.js
CHANGED
|
@@ -122,15 +122,15 @@ shaka.util.TsParser = class {
|
|
|
122
122
|
// for example
|
|
123
123
|
// NOTE this is only the PID of the track as found in TS,
|
|
124
124
|
// but we are not using this for MP4 track IDs.
|
|
125
|
-
if (
|
|
125
|
+
if (parsedPIDs.video != -1) {
|
|
126
126
|
this.videoPid_ = parsedPIDs.video;
|
|
127
127
|
this.videoCodec_ = parsedPIDs.videoCodec;
|
|
128
128
|
}
|
|
129
|
-
if (
|
|
129
|
+
if (parsedPIDs.audio != -1) {
|
|
130
130
|
this.audioPid_ = parsedPIDs.audio;
|
|
131
131
|
this.audioCodec_ = parsedPIDs.audioCodec;
|
|
132
132
|
}
|
|
133
|
-
if (
|
|
133
|
+
if (parsedPIDs.id3 != -1) {
|
|
134
134
|
this.id3Pid_ = parsedPIDs.id3;
|
|
135
135
|
}
|
|
136
136
|
|
package/package.json
CHANGED
|
@@ -43,6 +43,11 @@ describe('DashParser SegmentBase', () => {
|
|
|
43
43
|
};
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
// Dash parser stop is synchronous.
|
|
48
|
+
parser.stop();
|
|
49
|
+
});
|
|
50
|
+
|
|
46
51
|
it('requests init data for WebM', async () => {
|
|
47
52
|
const source = [
|
|
48
53
|
'<MPD mediaPresentationDuration="PT75S">',
|
|
@@ -351,24 +351,28 @@ describe('DashParser SegmentList', () => {
|
|
|
351
351
|
updateDuration: () => {},
|
|
352
352
|
newDrmInfo: (stream) => {},
|
|
353
353
|
};
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
354
|
+
try {
|
|
355
|
+
const manifest = await dashParser.start('dummy://foo', playerInterface);
|
|
356
|
+
const stream = manifest.variants[0].video;
|
|
357
|
+
await stream.createSegmentIndex();
|
|
358
|
+
goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
|
|
358
359
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
360
|
+
// Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
|
|
361
|
+
// doesn't reproduce this issue. We want to use Array.from which uses
|
|
362
|
+
// the iterator.
|
|
363
|
+
const expected = [
|
|
364
|
+
ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
|
|
365
|
+
ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
|
|
366
|
+
ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
|
|
366
367
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
368
|
+
ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
|
|
369
|
+
ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
|
|
370
|
+
ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
|
|
371
|
+
];
|
|
372
|
+
const actual = Array.from(stream.segmentIndex);
|
|
373
|
+
expect(actual).toEqual(expected);
|
|
374
|
+
} finally {
|
|
375
|
+
dashParser.stop();
|
|
376
|
+
}
|
|
373
377
|
});
|
|
374
378
|
});
|
|
@@ -501,10 +501,43 @@ describe('HlsParser live', () => {
|
|
|
501
501
|
|
|
502
502
|
it('sets 3 times target duration as presentation delay if not configured',
|
|
503
503
|
async () => {
|
|
504
|
+
const media = [
|
|
505
|
+
'#EXTM3U\n',
|
|
506
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
507
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
508
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
509
|
+
'#EXTINF:2,\n',
|
|
510
|
+
'main.mp4\n',
|
|
511
|
+
'#EXTINF:2,\n',
|
|
512
|
+
'main.mp4\n',
|
|
513
|
+
'#EXTINF:2,\n',
|
|
514
|
+
'main.mp4\n',
|
|
515
|
+
'#EXTINF:2,\n',
|
|
516
|
+
'main.mp4\n',
|
|
517
|
+
'#EXTINF:2,\n',
|
|
518
|
+
'main.mp4\n',
|
|
519
|
+
'#EXTINF:2,\n',
|
|
520
|
+
'main.mp4\n',
|
|
521
|
+
].join('');
|
|
504
522
|
const manifest = await testInitialManifest(master, media);
|
|
505
523
|
expect(manifest.presentationTimeline.getDelay()).toBe(15);
|
|
506
524
|
});
|
|
507
525
|
|
|
526
|
+
it('sets 1 times target duration as presentation delay if there are not enough segments', async () => { // eslint-disable-line max-len
|
|
527
|
+
const media = [
|
|
528
|
+
'#EXTM3U\n',
|
|
529
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
530
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
531
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
532
|
+
'#EXTINF:2,\n',
|
|
533
|
+
'main.mp4\n',
|
|
534
|
+
'#EXTINF:2,\n',
|
|
535
|
+
'main.mp4\n',
|
|
536
|
+
].join('');
|
|
537
|
+
const manifest = await testInitialManifest(master, media);
|
|
538
|
+
expect(manifest.presentationTimeline.getDelay()).toBe(5);
|
|
539
|
+
});
|
|
540
|
+
|
|
508
541
|
it('sets presentation delay for low latency mode', async () => {
|
|
509
542
|
const mediaWithLowLatency = [
|
|
510
543
|
'#EXTM3U\n',
|