shaka-player 4.4.2 → 4.5.0
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/.github/workflows/release-please.yaml +2 -27
- package/CHANGELOG.md +67 -25
- package/README.md +16 -10
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +27 -5
- package/demo/common/assets.js +150 -52
- package/demo/config.js +192 -253
- package/demo/custom.js +39 -98
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +52 -124
- package/demo/search.js +23 -35
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/demo.compiled.debug.js +187 -211
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +187 -211
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +27 -24
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +42 -61
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +42 -61
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.externs.js +475 -51
- package/dist/shaka-player.compiled.debug.js +576 -480
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +475 -51
- package/dist/shaka-player.compiled.js +1117 -1056
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +783 -410
- package/dist/shaka-player.ui.debug.d.ts +783 -410
- package/dist/shaka-player.ui.debug.externs.js +496 -51
- package/dist/shaka-player.ui.debug.js +647 -542
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +496 -51
- package/dist/shaka-player.ui.js +1260 -1194
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +1 -1
- package/docs/tutorials/ui-customization.md +4 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/manifest.js +10 -5
- package/externs/shaka/manifest_parser.js +7 -1
- package/externs/shaka/offline.js +4 -0
- package/externs/shaka/player.js +12 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +43 -3
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +828 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +79 -13
- package/lib/dash/mpd_utils.js +10 -6
- package/lib/dash/segment_base.js +13 -5
- package/lib/dash/segment_list.js +13 -5
- package/lib/dash/segment_template.js +43 -85
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_parser.js +101 -37
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +22 -11
- package/lib/media/adaptation_set_criteria.js +25 -7
- package/lib/media/media_source_engine.js +215 -27
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_reference.js +10 -5
- package/lib/media/streaming_engine.js +44 -39
- package/lib/mss/mss_parser.js +1 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +3 -0
- package/lib/player.js +142 -72
- package/lib/routing/payload.js +5 -1
- package/lib/text/cue.js +62 -47
- package/lib/text/ttml_text_parser.js +17 -0
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +35 -22
- package/lib/transmuxer/h265.js +862 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
- package/lib/transmuxer/ts_transmuxer.js +160 -15
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/error.js +28 -9
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fake_event.js +3 -0
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/mp4_generator.js +4 -4
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +54 -0
- package/lib/util/player_configuration.js +8 -0
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +133 -217
- package/lib/util/ts_parser.js +229 -43
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +2 -1
- package/support.html +0 -1
- package/test/cast/cast_receiver_integration.js +47 -0
- package/test/codec_switching/codec_switching_integration.js +181 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +73 -0
- package/test/dash/dash_parser_live_unit.js +2 -0
- package/test/dash/dash_parser_manifest_unit.js +47 -0
- package/test/dash/dash_parser_segment_base_unit.js +7 -0
- package/test/dash/dash_parser_segment_list_unit.js +23 -17
- package/test/dash/dash_parser_segment_template_unit.js +49 -0
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +35 -0
- package/test/hls/hls_parser_unit.js +8 -61
- package/test/media/adaptation_set_criteria_unit.js +118 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/media_source_engine_unit.js +165 -1
- package/test/media/segment_index_unit.js +4 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/storage_integration.js +1 -4
- package/test/player_unit.js +102 -131
- package/test/routing/walker_unit.js +1 -0
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +20 -7
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +8 -2
- package/test/test/util/manifest_generator.js +7 -3
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +7 -4
- package/test/text/ttml_text_parser_unit.js +52 -0
- package/test/text/vtt_text_parser_unit.js +105 -48
- package/test/transmuxer/transmuxer_integration.js +121 -4
- package/test/ui/ui_unit.js +3 -10
- package/test/util/stream_utils_unit.js +208 -74
- package/test/util/ts_parser_unit.js +1 -1
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +8 -1
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +201 -0
- package/ui/ui.js +5 -2
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -287
- package/demo/locales/source.json +0 -1142
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
|
@@ -36,17 +36,19 @@ shaka.dash.SegmentTemplate = class {
|
|
|
36
36
|
* @param {number} segmentLimit The maximum number of segments to generate for
|
|
37
37
|
* a SegmentTemplate with fixed duration.
|
|
38
38
|
* @param {!Object.<string, number>} periodDurationMap
|
|
39
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
39
40
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
40
41
|
*/
|
|
41
42
|
static createStreamInfo(
|
|
42
43
|
context, requestSegment, streamMap, isUpdate, segmentLimit,
|
|
43
|
-
periodDurationMap) {
|
|
44
|
+
periodDurationMap, aes128Key) {
|
|
44
45
|
goog.asserts.assert(context.representation.segmentTemplate,
|
|
45
46
|
'Should only be called with SegmentTemplate');
|
|
46
47
|
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
47
48
|
const TimelineSegmentIndex = shaka.dash.TimelineSegmentIndex;
|
|
48
49
|
|
|
49
|
-
const initSegmentReference =
|
|
50
|
+
const initSegmentReference =
|
|
51
|
+
SegmentTemplate.createInitSegment_(context, aes128Key);
|
|
50
52
|
|
|
51
53
|
/** @type {shaka.dash.SegmentTemplate.SegmentTemplateInfo} */
|
|
52
54
|
const info = SegmentTemplate.parseSegmentTemplateInfo_(context);
|
|
@@ -82,7 +84,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
82
84
|
generateSegmentIndex: () => {
|
|
83
85
|
return SegmentTemplate.generateSegmentIndexFromDuration_(
|
|
84
86
|
shallowCopyOfContext, info, segmentLimit, initSegmentReference,
|
|
85
|
-
periodDurationMap);
|
|
87
|
+
periodDurationMap, aes128Key);
|
|
86
88
|
},
|
|
87
89
|
};
|
|
88
90
|
} else {
|
|
@@ -134,6 +136,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
134
136
|
periodEnd,
|
|
135
137
|
initSegmentReference,
|
|
136
138
|
shouldFit,
|
|
139
|
+
aes128Key,
|
|
137
140
|
);
|
|
138
141
|
} else {
|
|
139
142
|
const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
|
|
@@ -299,11 +302,13 @@ shaka.dash.SegmentTemplate = class {
|
|
|
299
302
|
* @param {number} segmentLimit The maximum number of segments to generate.
|
|
300
303
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
301
304
|
* @param {!Object.<string, number>} periodDurationMap
|
|
305
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
302
306
|
* @return {!Promise.<shaka.media.SegmentIndex>}
|
|
303
307
|
* @private
|
|
304
308
|
*/
|
|
305
309
|
static generateSegmentIndexFromDuration_(
|
|
306
|
-
context, info, segmentLimit, initSegmentReference, periodDurationMap
|
|
310
|
+
context, info, segmentLimit, initSegmentReference, periodDurationMap,
|
|
311
|
+
aes128Key) {
|
|
307
312
|
goog.asserts.assert(info.mediaTemplate,
|
|
308
313
|
'There should be a media template with duration');
|
|
309
314
|
|
|
@@ -419,9 +424,12 @@ shaka.dash.SegmentTemplate = class {
|
|
|
419
424
|
info.scaledPresentationTimeOffset;
|
|
420
425
|
|
|
421
426
|
const getUris = () => {
|
|
427
|
+
let time = segmentMediaTime * timescale;
|
|
428
|
+
if ('BigInt' in window && time > Number.MAX_SAFE_INTEGER) {
|
|
429
|
+
time = BigInt(segmentMediaTime) * BigInt(timescale);
|
|
430
|
+
}
|
|
422
431
|
const mediaUri = MpdUtils.fillUriTemplate(
|
|
423
|
-
template, id, position, bandwidth,
|
|
424
|
-
segmentMediaTime * timescale);
|
|
432
|
+
template, id, position, bandwidth, time);
|
|
425
433
|
return ManifestParserUtils.resolveUris(baseUris, [mediaUri]);
|
|
426
434
|
};
|
|
427
435
|
|
|
@@ -446,7 +454,13 @@ shaka.dash.SegmentTemplate = class {
|
|
|
446
454
|
initSegmentReference,
|
|
447
455
|
timestampOffset,
|
|
448
456
|
/* appendWindowStart= */ periodStart,
|
|
449
|
-
/* appendWindowEnd= */ getPeriodEnd()
|
|
457
|
+
/* appendWindowEnd= */ getPeriodEnd(),
|
|
458
|
+
/* partialReferences= */ [],
|
|
459
|
+
/* tilesLayout= */ '',
|
|
460
|
+
/* tileDuration= */ null,
|
|
461
|
+
/* syncTime= */ null,
|
|
462
|
+
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
463
|
+
aes128Key);
|
|
450
464
|
// This is necessary information for thumbnail streams:
|
|
451
465
|
ref.trueEndTime = trueSegmentEnd;
|
|
452
466
|
return ref;
|
|
@@ -505,87 +519,15 @@ shaka.dash.SegmentTemplate = class {
|
|
|
505
519
|
return Promise.resolve(segmentIndex);
|
|
506
520
|
}
|
|
507
521
|
|
|
508
|
-
/**
|
|
509
|
-
* Creates segment references from a timeline.
|
|
510
|
-
*
|
|
511
|
-
* @param {shaka.dash.DashParser.Context} context
|
|
512
|
-
* @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info
|
|
513
|
-
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
514
|
-
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
515
|
-
* @private
|
|
516
|
-
*/
|
|
517
|
-
static createFromTimeline_(context, info, initSegmentReference) {
|
|
518
|
-
const MpdUtils = shaka.dash.MpdUtils;
|
|
519
|
-
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
520
|
-
|
|
521
|
-
const periodStart = context.periodInfo.start;
|
|
522
|
-
const periodDuration = context.periodInfo.duration;
|
|
523
|
-
|
|
524
|
-
const timestampOffset = periodStart - info.scaledPresentationTimeOffset;
|
|
525
|
-
const appendWindowStart = periodStart;
|
|
526
|
-
const appendWindowEnd = periodDuration ?
|
|
527
|
-
periodStart + periodDuration : Infinity;
|
|
528
|
-
|
|
529
|
-
/** @type {!Array.<!shaka.media.SegmentReference>} */
|
|
530
|
-
const references = [];
|
|
531
|
-
for (let i = 0; i < info.timeline.length; i++) {
|
|
532
|
-
const {start, unscaledStart, end} = info.timeline[i];
|
|
533
|
-
|
|
534
|
-
// Note: i = k - 1, where k indicates the k'th segment listed in the MPD.
|
|
535
|
-
// (See section 5.3.9.5.3 of the DASH spec.)
|
|
536
|
-
const segmentReplacement = i + info.startNumber;
|
|
537
|
-
|
|
538
|
-
// Consider the presentation time offset in segment uri computation
|
|
539
|
-
const timeReplacement = unscaledStart +
|
|
540
|
-
info.unscaledPresentationTimeOffset;
|
|
541
|
-
const repId = context.representation.id;
|
|
542
|
-
const bandwidth = context.bandwidth || null;
|
|
543
|
-
const mediaTemplate = info.mediaTemplate;
|
|
544
|
-
const baseUris = context.representation.baseUris;
|
|
545
|
-
|
|
546
|
-
// This callback must not capture any non-local
|
|
547
|
-
// variables, such as info, context, etc. Make
|
|
548
|
-
// sure any values you reference here have
|
|
549
|
-
// been assigned to local variables within the
|
|
550
|
-
// loop, or else we will end up with a leak.
|
|
551
|
-
const createUris =
|
|
552
|
-
() => {
|
|
553
|
-
goog.asserts.assert(
|
|
554
|
-
mediaTemplate,
|
|
555
|
-
'There should be a media template with a timeline');
|
|
556
|
-
const mediaUri = MpdUtils.fillUriTemplate(
|
|
557
|
-
mediaTemplate, repId,
|
|
558
|
-
segmentReplacement, bandwidth || null, timeReplacement);
|
|
559
|
-
return ManifestParserUtils
|
|
560
|
-
.resolveUris(baseUris, [mediaUri])
|
|
561
|
-
.map((g) => {
|
|
562
|
-
return g.toString();
|
|
563
|
-
});
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
references.push(new shaka.media.SegmentReference(
|
|
567
|
-
periodStart + start,
|
|
568
|
-
periodStart + end,
|
|
569
|
-
createUris,
|
|
570
|
-
/* startByte= */ 0,
|
|
571
|
-
/* endByte= */ null,
|
|
572
|
-
initSegmentReference,
|
|
573
|
-
timestampOffset,
|
|
574
|
-
appendWindowStart,
|
|
575
|
-
appendWindowEnd));
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return references;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
522
|
/**
|
|
582
523
|
* Creates an init segment reference from a context object.
|
|
583
524
|
*
|
|
584
525
|
* @param {shaka.dash.DashParser.Context} context
|
|
526
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
585
527
|
* @return {shaka.media.InitSegmentReference}
|
|
586
528
|
* @private
|
|
587
529
|
*/
|
|
588
|
-
static createInitSegment_(context) {
|
|
530
|
+
static createInitSegment_(context, aes128Key) {
|
|
589
531
|
const MpdUtils = shaka.dash.MpdUtils;
|
|
590
532
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
591
533
|
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
@@ -608,7 +550,14 @@ shaka.dash.SegmentTemplate = class {
|
|
|
608
550
|
return resolvedUris;
|
|
609
551
|
};
|
|
610
552
|
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
611
|
-
return new shaka.media.InitSegmentReference(
|
|
553
|
+
return new shaka.media.InitSegmentReference(
|
|
554
|
+
getUris,
|
|
555
|
+
/* startByte= */ 0,
|
|
556
|
+
/* endByte= */ null,
|
|
557
|
+
qualityInfo,
|
|
558
|
+
/* timescale= */ null,
|
|
559
|
+
/* segmentData= */ null,
|
|
560
|
+
aes128Key);
|
|
612
561
|
}
|
|
613
562
|
};
|
|
614
563
|
|
|
@@ -635,10 +584,11 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
635
584
|
* @param {number} periodEnd
|
|
636
585
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
637
586
|
* @param {boolean} shouldFit
|
|
638
|
-
*
|
|
587
|
+
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
639
588
|
*/
|
|
640
589
|
constructor(templateInfo, representationId, bandwidth, baseUris,
|
|
641
|
-
periodStart, periodEnd, initSegmentReference, shouldFit
|
|
590
|
+
periodStart, periodEnd, initSegmentReference, shouldFit,
|
|
591
|
+
aes128Key) {
|
|
642
592
|
super([]);
|
|
643
593
|
|
|
644
594
|
/** @private {?shaka.dash.SegmentTemplate.SegmentTemplateInfo} */
|
|
@@ -655,6 +605,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
655
605
|
this.periodEnd_ = periodEnd;
|
|
656
606
|
/** @private {shaka.media.InitSegmentReference} */
|
|
657
607
|
this.initSegmentReference_ = initSegmentReference;
|
|
608
|
+
/** @private {shaka.extern.aes128Key|undefined} */
|
|
609
|
+
this.aes128Key_ = aes128Key;
|
|
658
610
|
|
|
659
611
|
|
|
660
612
|
if (shouldFit) {
|
|
@@ -894,7 +846,13 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
894
846
|
this.initSegmentReference_,
|
|
895
847
|
timestampOffset,
|
|
896
848
|
this.periodStart_,
|
|
897
|
-
this.periodEnd_
|
|
849
|
+
this.periodEnd_,
|
|
850
|
+
/* partialReferences= */ [],
|
|
851
|
+
/* tilesLayout= */ '',
|
|
852
|
+
/* tileDuration= */ null,
|
|
853
|
+
/* syncTime= */ null,
|
|
854
|
+
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
855
|
+
this.aes128Key_);
|
|
898
856
|
this.references[correctedPosition] = ref;
|
|
899
857
|
}
|
|
900
858
|
|
package/lib/dependencies/all.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.dependencies');
|
|
8
8
|
|
|
9
|
+
goog.require('shaka.Deprecate');
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @export
|
|
11
13
|
*/
|
|
@@ -22,6 +24,12 @@ shaka.dependencies = class {
|
|
|
22
24
|
if (!shaka.dependencies.Allowed[key]) {
|
|
23
25
|
throw new Error(`${key} is not supported`);
|
|
24
26
|
}
|
|
27
|
+
if (key == shaka.dependencies.Allowed.muxjs) {
|
|
28
|
+
shaka.Deprecate.deprecateFeature(5,
|
|
29
|
+
'mux.js',
|
|
30
|
+
'mux.js is no longer used in Shaka Player.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
25
33
|
shaka.dependencies.dependencies_.set(key, () => dep);
|
|
26
34
|
}
|
|
27
35
|
|
|
@@ -36,12 +44,6 @@ shaka.dependencies = class {
|
|
|
36
44
|
return shaka.dependencies.dependencies_.has(key);
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
/** @return {?muxjs} */
|
|
40
|
-
static muxjs() {
|
|
41
|
-
return /** @type {?muxjs} */ (shaka.dependencies.dependencies_.get(
|
|
42
|
-
shaka.dependencies.Allowed.muxjs)());
|
|
43
|
-
}
|
|
44
|
-
|
|
45
47
|
/** @return {?ISOBoxer} */
|
|
46
48
|
static isoBoxer() {
|
|
47
49
|
return /** @type {?ISOBoxer} */ (shaka.dependencies.dependencies_.get(
|
|
@@ -65,6 +67,5 @@ shaka.dependencies.Allowed = {
|
|
|
65
67
|
* @private {!Map.<shaka.dependencies.Allowed, function():?>}
|
|
66
68
|
*/
|
|
67
69
|
shaka.dependencies.dependencies_ = new Map([
|
|
68
|
-
[shaka.dependencies.Allowed.muxjs, () => window.muxjs],
|
|
69
70
|
[shaka.dependencies.Allowed.ISOBoxer, () => window.ISOBoxer],
|
|
70
71
|
]);
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -9,6 +9,7 @@ goog.provide('shaka.hls.HlsParser');
|
|
|
9
9
|
|
|
10
10
|
goog.require('goog.Uri');
|
|
11
11
|
goog.require('goog.asserts');
|
|
12
|
+
goog.require('shaka.abr.Ewma');
|
|
12
13
|
goog.require('shaka.hls.ManifestTextParser');
|
|
13
14
|
goog.require('shaka.hls.Playlist');
|
|
14
15
|
goog.require('shaka.hls.PlaylistType');
|
|
@@ -215,6 +216,13 @@ shaka.hls.HlsParser = class {
|
|
|
215
216
|
|
|
216
217
|
/** @private {boolean} */
|
|
217
218
|
this.lowLatencyByterangeOptimization_ = false;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* An ewma that tracks how long updates take.
|
|
222
|
+
* This is to mitigate issues caused by slow parsing on embedded devices.
|
|
223
|
+
* @private {!shaka.abr.Ewma}
|
|
224
|
+
*/
|
|
225
|
+
this.averageUpdateDuration_ = new shaka.abr.Ewma(5);
|
|
218
226
|
}
|
|
219
227
|
|
|
220
228
|
|
|
@@ -787,7 +795,7 @@ shaka.hls.HlsParser = class {
|
|
|
787
795
|
// enough info here to determine the presentation type and duration.
|
|
788
796
|
if (playlist.type == shaka.hls.PlaylistType.MEDIA) {
|
|
789
797
|
if (this.isLive_()) {
|
|
790
|
-
this.changePresentationTimelineToLive_();
|
|
798
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
791
799
|
const delay = this.getUpdatePlaylistDelay_();
|
|
792
800
|
this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay);
|
|
793
801
|
}
|
|
@@ -856,7 +864,7 @@ shaka.hls.HlsParser = class {
|
|
|
856
864
|
|
|
857
865
|
let segmentUris = [firstSegment.absoluteUri];
|
|
858
866
|
const initSegmentRef = this.getInitSegmentReference_(
|
|
859
|
-
playlist
|
|
867
|
+
playlist, firstSegment.tags, new Map());
|
|
860
868
|
if (initSegmentRef) {
|
|
861
869
|
segmentUris = initSegmentRef.getUris();
|
|
862
870
|
}
|
|
@@ -932,7 +940,11 @@ shaka.hls.HlsParser = class {
|
|
|
932
940
|
hasVideo = true;
|
|
933
941
|
break;
|
|
934
942
|
case 'hvc':
|
|
935
|
-
|
|
943
|
+
if (videoInfo.codec) {
|
|
944
|
+
codecs.push(videoInfo.codec);
|
|
945
|
+
} else {
|
|
946
|
+
codecs.push('hvc1.1.6.L93.90');
|
|
947
|
+
}
|
|
936
948
|
hasVideo = true;
|
|
937
949
|
break;
|
|
938
950
|
}
|
|
@@ -1781,7 +1793,13 @@ shaka.hls.HlsParser = class {
|
|
|
1781
1793
|
goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
|
|
1782
1794
|
'Should only be called on media tags!');
|
|
1783
1795
|
const languageValue = tag.getAttributeValue('LANGUAGE');
|
|
1784
|
-
|
|
1796
|
+
let language = this.getLanguage_(languageValue);
|
|
1797
|
+
if (!languageValue) {
|
|
1798
|
+
const nameValue = tag.getAttributeValue('NAME');
|
|
1799
|
+
if (nameValue) {
|
|
1800
|
+
language = nameValue;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1785
1803
|
|
|
1786
1804
|
// The GROUP-ID value is a quoted-string that specifies the group to which
|
|
1787
1805
|
// the Rendition belongs.
|
|
@@ -1790,7 +1808,9 @@ shaka.hls.HlsParser = class {
|
|
|
1790
1808
|
// The value of INSTREAM-ID is a quoted-string that specifies a Rendition
|
|
1791
1809
|
// within the segments in the Media Playlist. This attribute is REQUIRED
|
|
1792
1810
|
// if the TYPE attribute is CLOSED-CAPTIONS.
|
|
1793
|
-
|
|
1811
|
+
// We need replace SERVICE string by our internal svc string.
|
|
1812
|
+
const instreamId = tag.getRequiredAttrValue('INSTREAM-ID')
|
|
1813
|
+
.replace('SERVICE', 'svc');
|
|
1794
1814
|
if (!this.groupIdToClosedCaptionsMap_.get(groupId)) {
|
|
1795
1815
|
this.groupIdToClosedCaptionsMap_.set(groupId, new Map());
|
|
1796
1816
|
}
|
|
@@ -2054,7 +2074,7 @@ shaka.hls.HlsParser = class {
|
|
|
2054
2074
|
if (this.isLive_() && !wasLive) {
|
|
2055
2075
|
// Now that we know that the presentation is live, convert the timeline
|
|
2056
2076
|
// to live.
|
|
2057
|
-
this.changePresentationTimelineToLive_();
|
|
2077
|
+
this.changePresentationTimelineToLive_(playlist);
|
|
2058
2078
|
}
|
|
2059
2079
|
|
|
2060
2080
|
// Copy values from the real stream info to our initial one.
|
|
@@ -2485,6 +2505,7 @@ shaka.hls.HlsParser = class {
|
|
|
2485
2505
|
return {
|
|
2486
2506
|
id: this.globalId_++,
|
|
2487
2507
|
originalId: name,
|
|
2508
|
+
groupId: null,
|
|
2488
2509
|
createSegmentIndex: () => Promise.resolve(),
|
|
2489
2510
|
segmentIndex: null,
|
|
2490
2511
|
mimeType,
|
|
@@ -2587,7 +2608,7 @@ shaka.hls.HlsParser = class {
|
|
|
2587
2608
|
/**
|
|
2588
2609
|
* @param {!shaka.hls.Tag} drmTag
|
|
2589
2610
|
* @param {!shaka.hls.Playlist} playlist
|
|
2590
|
-
* @return {!shaka.extern.
|
|
2611
|
+
* @return {!shaka.extern.aes128Key}
|
|
2591
2612
|
* @private
|
|
2592
2613
|
*/
|
|
2593
2614
|
parseAES128DrmTag_(drmTag, playlist) {
|
|
@@ -2621,7 +2642,7 @@ shaka.hls.HlsParser = class {
|
|
|
2621
2642
|
throw new shaka.util.Error(
|
|
2622
2643
|
shaka.util.Error.Severity.CRITICAL,
|
|
2623
2644
|
shaka.util.Error.Category.MANIFEST,
|
|
2624
|
-
shaka.util.Error.Code.
|
|
2645
|
+
shaka.util.Error.Code.AES_128_INVALID_IV_LENGTH);
|
|
2625
2646
|
}
|
|
2626
2647
|
}
|
|
2627
2648
|
|
|
@@ -2644,7 +2665,7 @@ shaka.hls.HlsParser = class {
|
|
|
2644
2665
|
throw new shaka.util.Error(
|
|
2645
2666
|
shaka.util.Error.Severity.CRITICAL,
|
|
2646
2667
|
shaka.util.Error.Category.MANIFEST,
|
|
2647
|
-
shaka.util.Error.Code.
|
|
2668
|
+
shaka.util.Error.Code.AES_128_INVALID_KEY_LENGTH);
|
|
2648
2669
|
}
|
|
2649
2670
|
|
|
2650
2671
|
const algorithm = {
|
|
@@ -2770,9 +2791,10 @@ shaka.hls.HlsParser = class {
|
|
|
2770
2791
|
|
|
2771
2792
|
|
|
2772
2793
|
/**
|
|
2794
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2773
2795
|
* @private
|
|
2774
2796
|
*/
|
|
2775
|
-
changePresentationTimelineToLive_() {
|
|
2797
|
+
changePresentationTimelineToLive_(playlist) {
|
|
2776
2798
|
// The live edge will be calculated from segments, so we don't need to
|
|
2777
2799
|
// set a presentation start time. We will assert later that this is
|
|
2778
2800
|
// working as expected.
|
|
@@ -2795,8 +2817,12 @@ shaka.hls.HlsParser = class {
|
|
|
2795
2817
|
} else if (this.presentationDelay_) {
|
|
2796
2818
|
presentationDelay = this.presentationDelay_;
|
|
2797
2819
|
} else {
|
|
2798
|
-
const
|
|
2799
|
-
|
|
2820
|
+
const playlistSegments = playlist.segments.length;
|
|
2821
|
+
let delaySegments = this.config_.hls.liveSegmentsDelay;
|
|
2822
|
+
if (delaySegments > (playlistSegments - 2)) {
|
|
2823
|
+
delaySegments = Math.max(1, playlistSegments - 2);
|
|
2824
|
+
}
|
|
2825
|
+
presentationDelay = this.maxTargetDuration_ * delaySegments;
|
|
2800
2826
|
}
|
|
2801
2827
|
|
|
2802
2828
|
this.presentationTimeline_.setPresentationStartTime(0);
|
|
@@ -2806,13 +2832,13 @@ shaka.hls.HlsParser = class {
|
|
|
2806
2832
|
|
|
2807
2833
|
/**
|
|
2808
2834
|
* Get the InitSegmentReference for a segment if it has a EXT-X-MAP tag.
|
|
2809
|
-
* @param {
|
|
2835
|
+
* @param {!shaka.hls.Playlist} playlist
|
|
2810
2836
|
* @param {!Array.<!shaka.hls.Tag>} tags Segment tags
|
|
2811
2837
|
* @param {!Map.<string, string>} variables
|
|
2812
2838
|
* @return {shaka.media.InitSegmentReference}
|
|
2813
2839
|
* @private
|
|
2814
2840
|
*/
|
|
2815
|
-
getInitSegmentReference_(
|
|
2841
|
+
getInitSegmentReference_(playlist, tags, variables) {
|
|
2816
2842
|
/** @type {?shaka.hls.Tag} */
|
|
2817
2843
|
const mapTag = shaka.hls.Utils.getFirstTagWithName(tags, 'EXT-X-MAP');
|
|
2818
2844
|
|
|
@@ -2823,7 +2849,7 @@ shaka.hls.HlsParser = class {
|
|
|
2823
2849
|
const verbatimInitSegmentUri = mapTag.getRequiredAttrValue('URI');
|
|
2824
2850
|
const absoluteInitSegmentUri = this.variableSubstitution_(
|
|
2825
2851
|
shaka.hls.Utils.constructAbsoluteUri(
|
|
2826
|
-
|
|
2852
|
+
playlist.absoluteUri, verbatimInitSegmentUri),
|
|
2827
2853
|
variables);
|
|
2828
2854
|
|
|
2829
2855
|
const mapTagKey = [
|
|
@@ -2831,8 +2857,18 @@ shaka.hls.HlsParser = class {
|
|
|
2831
2857
|
mapTag.getAttributeValue('BYTERANGE', ''),
|
|
2832
2858
|
].join('-');
|
|
2833
2859
|
if (!this.mapTagToInitSegmentRefMap_.has(mapTagKey)) {
|
|
2860
|
+
/** @type {shaka.extern.aes128Key|undefined} */
|
|
2861
|
+
let aes128Key = undefined;
|
|
2862
|
+
for (const tag of tags) {
|
|
2863
|
+
if (tag.name == 'EXT-X-KEY') {
|
|
2864
|
+
if (tag.getRequiredAttrValue('METHOD') == 'AES-128' &&
|
|
2865
|
+
tag.id < mapTag.id) {
|
|
2866
|
+
aes128Key = this.parseAES128DrmTag_(tag, playlist);
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2834
2870
|
const initSegmentRef = this.createInitSegmentReference_(
|
|
2835
|
-
absoluteInitSegmentUri, mapTag);
|
|
2871
|
+
absoluteInitSegmentUri, mapTag, aes128Key);
|
|
2836
2872
|
this.mapTagToInitSegmentRefMap_.set(mapTagKey, initSegmentRef);
|
|
2837
2873
|
}
|
|
2838
2874
|
return this.mapTagToInitSegmentRefMap_.get(mapTagKey);
|
|
@@ -2843,10 +2879,11 @@ shaka.hls.HlsParser = class {
|
|
|
2843
2879
|
* playlist.
|
|
2844
2880
|
* @param {string} absoluteInitSegmentUri
|
|
2845
2881
|
* @param {!shaka.hls.Tag} mapTag EXT-X-MAP
|
|
2882
|
+
* @param {shaka.extern.aes128Key=} aes128Key
|
|
2846
2883
|
* @return {!shaka.media.InitSegmentReference}
|
|
2847
2884
|
* @private
|
|
2848
2885
|
*/
|
|
2849
|
-
createInitSegmentReference_(absoluteInitSegmentUri, mapTag) {
|
|
2886
|
+
createInitSegmentReference_(absoluteInitSegmentUri, mapTag, aes128Key) {
|
|
2850
2887
|
let startByte = 0;
|
|
2851
2888
|
let endByte = null;
|
|
2852
2889
|
const byterange = mapTag.getAttributeValue('BYTERANGE');
|
|
@@ -2857,12 +2894,26 @@ shaka.hls.HlsParser = class {
|
|
|
2857
2894
|
const byteLength = Number(blocks[0]);
|
|
2858
2895
|
startByte = Number(blocks[1]);
|
|
2859
2896
|
endByte = startByte + byteLength - 1;
|
|
2897
|
+
|
|
2898
|
+
if (aes128Key) {
|
|
2899
|
+
// MAP segment encrypted with method 'AES-128', when served with
|
|
2900
|
+
// HTTP Range, has the unencrypted size specified in the range.
|
|
2901
|
+
// See: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
|
2902
|
+
const length = (endByte + 1) - startByte;
|
|
2903
|
+
if (length % 16) {
|
|
2904
|
+
endByte += (16 - (length % 16));
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2860
2907
|
}
|
|
2861
2908
|
|
|
2862
2909
|
const initSegmentRef = new shaka.media.InitSegmentReference(
|
|
2863
2910
|
() => [absoluteInitSegmentUri],
|
|
2864
2911
|
startByte,
|
|
2865
|
-
endByte
|
|
2912
|
+
endByte,
|
|
2913
|
+
/* mediaQuality= */ null,
|
|
2914
|
+
/* timescale= */ null,
|
|
2915
|
+
/* segmentData= */ null,
|
|
2916
|
+
aes128Key);
|
|
2866
2917
|
return initSegmentRef;
|
|
2867
2918
|
}
|
|
2868
2919
|
|
|
@@ -2877,15 +2928,13 @@ shaka.hls.HlsParser = class {
|
|
|
2877
2928
|
* @param {string} absoluteMediaPlaylistUri
|
|
2878
2929
|
* @param {string} type
|
|
2879
2930
|
* @param {string} mimeType
|
|
2880
|
-
* @param {
|
|
2881
|
-
* @param {shaka.extern.HlsAes128Key=} hlsAes128Key
|
|
2931
|
+
* @param {shaka.extern.aes128Key=} aes128Key
|
|
2882
2932
|
* @return {shaka.media.SegmentReference}
|
|
2883
2933
|
* @private
|
|
2884
2934
|
*/
|
|
2885
2935
|
createSegmentReference_(
|
|
2886
2936
|
initSegmentReference, previousReference, hlsSegment, startTime,
|
|
2887
|
-
variables, absoluteMediaPlaylistUri, type, mimeType,
|
|
2888
|
-
hlsAes128Key) {
|
|
2937
|
+
variables, absoluteMediaPlaylistUri, type, mimeType, aes128Key) {
|
|
2889
2938
|
const tags = hlsSegment.tags;
|
|
2890
2939
|
const extinfTag =
|
|
2891
2940
|
shaka.hls.Utils.getFirstTagWithName(tags, 'EXTINF');
|
|
@@ -3022,7 +3071,7 @@ shaka.hls.HlsParser = class {
|
|
|
3022
3071
|
pStartByte,
|
|
3023
3072
|
pEndByte,
|
|
3024
3073
|
initSegmentReference,
|
|
3025
|
-
/* timestampOffset= */ 0,
|
|
3074
|
+
/* timestampOffset= */ 0,
|
|
3026
3075
|
/* appendWindowStart= */ 0,
|
|
3027
3076
|
/* appendWindowEnd= */ Infinity,
|
|
3028
3077
|
/* partialReferences= */ [],
|
|
@@ -3030,7 +3079,7 @@ shaka.hls.HlsParser = class {
|
|
|
3030
3079
|
/* tileDuration= */ null,
|
|
3031
3080
|
partialSyncTime,
|
|
3032
3081
|
partialStatus,
|
|
3033
|
-
|
|
3082
|
+
aes128Key);
|
|
3034
3083
|
if (item.name == 'EXT-X-PRELOAD-HINT') {
|
|
3035
3084
|
partial.markAsPreload();
|
|
3036
3085
|
isPreloadSegment = true;
|
|
@@ -3067,8 +3116,11 @@ shaka.hls.HlsParser = class {
|
|
|
3067
3116
|
return null;
|
|
3068
3117
|
}
|
|
3069
3118
|
endTime = startTime + duration;
|
|
3070
|
-
} else {
|
|
3119
|
+
} else if (partialSegmentRefs.length) {
|
|
3071
3120
|
endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
|
|
3121
|
+
} else {
|
|
3122
|
+
// Skip segments without duration and without partialsegments
|
|
3123
|
+
return null;
|
|
3072
3124
|
}
|
|
3073
3125
|
|
|
3074
3126
|
if (segmentWithByteRangeOptimization) {
|
|
@@ -3131,7 +3183,7 @@ shaka.hls.HlsParser = class {
|
|
|
3131
3183
|
startByte,
|
|
3132
3184
|
endByte,
|
|
3133
3185
|
initSegmentReference,
|
|
3134
|
-
timestampOffset
|
|
3186
|
+
/* timestampOffset= */ 0,
|
|
3135
3187
|
/* appendWindowStart= */ 0,
|
|
3136
3188
|
/* appendWindowEnd= */ Infinity,
|
|
3137
3189
|
partialSegmentRefs,
|
|
@@ -3139,7 +3191,7 @@ shaka.hls.HlsParser = class {
|
|
|
3139
3191
|
tileDuration,
|
|
3140
3192
|
syncTime,
|
|
3141
3193
|
status,
|
|
3142
|
-
|
|
3194
|
+
aes128Key,
|
|
3143
3195
|
);
|
|
3144
3196
|
|
|
3145
3197
|
if (segmentWithByteRangeOptimization) {
|
|
@@ -3206,8 +3258,8 @@ shaka.hls.HlsParser = class {
|
|
|
3206
3258
|
/** @type {shaka.media.InitSegmentReference} */
|
|
3207
3259
|
let initSegmentRef;
|
|
3208
3260
|
|
|
3209
|
-
/** @type {shaka.extern.
|
|
3210
|
-
let
|
|
3261
|
+
/** @type {shaka.extern.aes128Key|undefined} */
|
|
3262
|
+
let aes128Key = undefined;
|
|
3211
3263
|
|
|
3212
3264
|
let discontinuitySequence = shaka.hls.Utils.getFirstTagWithNameAsNumber(
|
|
3213
3265
|
playlist.tags, 'EXT-X-DISCONTINUITY-SEQUENCE', 0);
|
|
@@ -3230,7 +3282,6 @@ shaka.hls.HlsParser = class {
|
|
|
3230
3282
|
const references = [];
|
|
3231
3283
|
|
|
3232
3284
|
let previousReference = null;
|
|
3233
|
-
let lastDiscontinuityStartTime = firstStartTime;
|
|
3234
3285
|
|
|
3235
3286
|
/** @type {!Array.<{bitrate: number, duration: number}>} */
|
|
3236
3287
|
const bitrates = [];
|
|
@@ -3245,23 +3296,22 @@ shaka.hls.HlsParser = class {
|
|
|
3245
3296
|
item.tags, 'EXT-X-DISCONTINUITY');
|
|
3246
3297
|
if (discontinuityTag) {
|
|
3247
3298
|
discontinuitySequence++;
|
|
3248
|
-
lastDiscontinuityStartTime = startTime;
|
|
3249
3299
|
}
|
|
3250
3300
|
|
|
3251
3301
|
// Apply new AES-128 tags as you see them, keeping a running total.
|
|
3252
3302
|
for (const drmTag of item.tags) {
|
|
3253
3303
|
if (drmTag.name == 'EXT-X-KEY') {
|
|
3254
3304
|
if (drmTag.getRequiredAttrValue('METHOD') == 'AES-128') {
|
|
3255
|
-
|
|
3305
|
+
aes128Key = this.parseAES128DrmTag_(drmTag, playlist);
|
|
3256
3306
|
} else {
|
|
3257
|
-
|
|
3307
|
+
aes128Key = undefined;
|
|
3258
3308
|
}
|
|
3259
3309
|
}
|
|
3260
3310
|
}
|
|
3261
3311
|
|
|
3262
3312
|
mediaSequenceToStartTime.set(position, startTime);
|
|
3263
3313
|
|
|
3264
|
-
initSegmentRef = this.getInitSegmentReference_(playlist
|
|
3314
|
+
initSegmentRef = this.getInitSegmentReference_(playlist,
|
|
3265
3315
|
item.tags, variables);
|
|
3266
3316
|
|
|
3267
3317
|
// If the stream is low latency and the user has not configured the
|
|
@@ -3285,8 +3335,7 @@ shaka.hls.HlsParser = class {
|
|
|
3285
3335
|
playlist.absoluteUri,
|
|
3286
3336
|
type,
|
|
3287
3337
|
mimeType,
|
|
3288
|
-
|
|
3289
|
-
hlsAes128Key);
|
|
3338
|
+
aes128Key);
|
|
3290
3339
|
|
|
3291
3340
|
if (reference) {
|
|
3292
3341
|
const bitrate = shaka.hls.Utils.getFirstTagWithNameAsNumber(
|
|
@@ -3654,12 +3703,20 @@ shaka.hls.HlsParser = class {
|
|
|
3654
3703
|
}
|
|
3655
3704
|
|
|
3656
3705
|
try {
|
|
3706
|
+
const startTime = Date.now();
|
|
3657
3707
|
await this.update();
|
|
3658
3708
|
|
|
3709
|
+
// Keep track of how long the longest manifest update took.
|
|
3710
|
+
const endTime = Date.now();
|
|
3711
|
+
|
|
3659
3712
|
// This may have converted to VOD, in which case we stop updating.
|
|
3660
3713
|
if (this.isLive_()) {
|
|
3714
|
+
const updateDuration = (endTime - startTime) / 1000.0;
|
|
3715
|
+
this.averageUpdateDuration_.sample(1, updateDuration);
|
|
3661
3716
|
const delay = this.getUpdatePlaylistDelay_();
|
|
3662
|
-
|
|
3717
|
+
const finalDelay = Math.max(0,
|
|
3718
|
+
delay - this.averageUpdateDuration_.getEstimate());
|
|
3719
|
+
this.updatePlaylistTimer_.tickAfter(/* seconds= */ finalDelay);
|
|
3663
3720
|
}
|
|
3664
3721
|
} catch (error) {
|
|
3665
3722
|
// Detect a call to stop() during this.update()
|
|
@@ -3682,6 +3739,13 @@ shaka.hls.HlsParser = class {
|
|
|
3682
3739
|
// Try again very soon.
|
|
3683
3740
|
this.updatePlaylistTimer_.tickAfter(/* seconds= */ 0.1);
|
|
3684
3741
|
}
|
|
3742
|
+
|
|
3743
|
+
// Detect a call to stop()
|
|
3744
|
+
if (!this.playerInterface_) {
|
|
3745
|
+
return;
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
this.playerInterface_.onManifestUpdated();
|
|
3685
3749
|
}
|
|
3686
3750
|
|
|
3687
3751
|
|