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.
Files changed (202) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +67 -25
  3. package/README.md +16 -10
  4. package/demo/asset_card.js +18 -21
  5. package/demo/cast_receiver/index.html +0 -1
  6. package/demo/close_button.js +0 -3
  7. package/demo/common/asset.js +27 -5
  8. package/demo/common/assets.js +150 -52
  9. package/demo/config.js +192 -253
  10. package/demo/custom.js +39 -98
  11. package/demo/front.js +7 -10
  12. package/demo/index.html +19 -22
  13. package/demo/input.js +6 -11
  14. package/demo/input_container.js +8 -9
  15. package/demo/main.js +52 -124
  16. package/demo/search.js +23 -35
  17. package/demo/service_worker.js +0 -3
  18. package/demo/tooltip.js +3 -5
  19. package/demo/visualizer.js +3 -5
  20. package/demo/visualizer_button.js +1 -20
  21. package/dist/demo.compiled.debug.js +187 -211
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +187 -211
  24. package/dist/demo.compiled.map +4 -4
  25. package/dist/deps.js +27 -24
  26. package/dist/locales.js +31 -31
  27. package/dist/receiver.compiled.debug.js +42 -61
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +42 -61
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +728 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +728 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +475 -51
  34. package/dist/shaka-player.compiled.debug.js +576 -480
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +475 -51
  37. package/dist/shaka-player.compiled.js +1117 -1056
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +783 -410
  40. package/dist/shaka-player.ui.debug.d.ts +783 -410
  41. package/dist/shaka-player.ui.debug.externs.js +496 -51
  42. package/dist/shaka-player.ui.debug.js +647 -542
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +496 -51
  45. package/dist/shaka-player.ui.js +1260 -1194
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/lcevc-integration.md +14 -14
  48. package/docs/tutorials/faq.md +27 -55
  49. package/docs/tutorials/index.json +2 -1
  50. package/docs/tutorials/lcevc.md +118 -0
  51. package/docs/tutorials/offline.md +1 -1
  52. package/docs/tutorials/ui-customization.md +4 -0
  53. package/externs/css_style_declaration.js +19 -0
  54. package/externs/lcevc.js +37 -13
  55. package/externs/media_remote.js +68 -0
  56. package/externs/mediatailor.js +193 -0
  57. package/externs/pictureinpicture.js +11 -0
  58. package/externs/shaka/ads.js +27 -0
  59. package/externs/shaka/manifest.js +10 -5
  60. package/externs/shaka/manifest_parser.js +7 -1
  61. package/externs/shaka/offline.js +4 -0
  62. package/externs/shaka/player.js +12 -1
  63. package/karma.conf.js +7 -3
  64. package/lib/abr/simple_abr_manager.js +43 -3
  65. package/lib/ads/ad_manager.js +104 -50
  66. package/lib/ads/media_tailor_ad.js +297 -0
  67. package/lib/ads/media_tailor_ad_manager.js +828 -0
  68. package/lib/cea/ts_cea_parser.js +15 -2
  69. package/lib/config/codec_switching_strategy.js +24 -0
  70. package/lib/dash/content_protection.js +120 -2
  71. package/lib/dash/dash_parser.js +79 -13
  72. package/lib/dash/mpd_utils.js +10 -6
  73. package/lib/dash/segment_base.js +13 -5
  74. package/lib/dash/segment_list.js +13 -5
  75. package/lib/dash/segment_template.js +43 -85
  76. package/lib/dependencies/all.js +8 -7
  77. package/lib/hls/hls_parser.js +101 -37
  78. package/lib/lcevc/lcevc_dec.js +220 -0
  79. package/lib/media/adaptation_set.js +22 -11
  80. package/lib/media/adaptation_set_criteria.js +25 -7
  81. package/lib/media/media_source_engine.js +215 -27
  82. package/lib/media/segment_index.js +5 -5
  83. package/lib/media/segment_reference.js +10 -5
  84. package/lib/media/streaming_engine.js +44 -39
  85. package/lib/mss/mss_parser.js +1 -0
  86. package/lib/net/networking_engine.js +1 -0
  87. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  88. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  89. package/lib/offline/manifest_converter.js +1 -0
  90. package/lib/offline/storage.js +3 -0
  91. package/lib/player.js +142 -72
  92. package/lib/routing/payload.js +5 -1
  93. package/lib/text/cue.js +62 -47
  94. package/lib/text/ttml_text_parser.js +17 -0
  95. package/lib/text/ui_text_displayer.js +4 -0
  96. package/lib/text/vtt_text_parser.js +35 -22
  97. package/lib/transmuxer/h265.js +862 -0
  98. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  99. package/lib/transmuxer/ts_transmuxer.js +160 -15
  100. package/lib/util/cmcd_manager.js +6 -1
  101. package/lib/util/error.js +28 -9
  102. package/lib/util/exp_golomb.js +30 -2
  103. package/lib/util/fake_event.js +3 -0
  104. package/lib/util/manifest_parser_utils.js +10 -4
  105. package/lib/util/mp4_generator.js +4 -4
  106. package/lib/util/periods.js +2 -0
  107. package/lib/util/platform.js +54 -0
  108. package/lib/util/player_configuration.js +8 -0
  109. package/lib/util/state_history.js +6 -2
  110. package/lib/util/stream_utils.js +133 -217
  111. package/lib/util/ts_parser.js +229 -43
  112. package/maintained-branches.md +3 -2
  113. package/package.json +4 -6
  114. package/roadmap.md +15 -5
  115. package/shaka-player.uncompiled.js +2 -1
  116. package/support.html +0 -1
  117. package/test/cast/cast_receiver_integration.js +47 -0
  118. package/test/codec_switching/codec_switching_integration.js +181 -0
  119. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  120. package/test/dash/dash_parser_integration.js +73 -0
  121. package/test/dash/dash_parser_live_unit.js +2 -0
  122. package/test/dash/dash_parser_manifest_unit.js +47 -0
  123. package/test/dash/dash_parser_segment_base_unit.js +7 -0
  124. package/test/dash/dash_parser_segment_list_unit.js +23 -17
  125. package/test/dash/dash_parser_segment_template_unit.js +49 -0
  126. package/test/demo/demo_unit.js +0 -16
  127. package/test/hls/hls_live_unit.js +35 -0
  128. package/test/hls/hls_parser_unit.js +8 -61
  129. package/test/media/adaptation_set_criteria_unit.js +118 -0
  130. package/test/media/adaptation_set_unit.js +1 -0
  131. package/test/media/media_source_engine_unit.js +165 -1
  132. package/test/media/segment_index_unit.js +4 -4
  133. package/test/media/segment_prefetch_unit.js +1 -1
  134. package/test/media/streaming_engine_unit.js +17 -17
  135. package/test/mss/mss_parser_unit.js +2 -0
  136. package/test/offline/manifest_convert_unit.js +5 -0
  137. package/test/offline/storage_integration.js +1 -4
  138. package/test/player_unit.js +102 -131
  139. package/test/routing/walker_unit.js +1 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  143. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  144. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  145. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  146. package/test/test/assets/dash-aes-128/license +1 -0
  147. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  148. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  149. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  150. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  151. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  153. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  154. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  155. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  166. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  167. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  175. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  176. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  177. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  178. package/test/test/util/dash_parser_util.js +20 -7
  179. package/test/test/util/fake_ad_manager.js +20 -0
  180. package/test/test/util/fake_media_source_engine.js +8 -2
  181. package/test/test/util/manifest_generator.js +7 -3
  182. package/test/test/util/mss_parser_util.js +4 -0
  183. package/test/test/util/offline_utils.js +1 -0
  184. package/test/test/util/streaming_engine_util.js +7 -4
  185. package/test/text/ttml_text_parser_unit.js +52 -0
  186. package/test/text/vtt_text_parser_unit.js +105 -48
  187. package/test/transmuxer/transmuxer_integration.js +121 -4
  188. package/test/ui/ui_unit.js +3 -10
  189. package/test/util/stream_utils_unit.js +208 -74
  190. package/test/util/ts_parser_unit.js +1 -1
  191. package/ui/controls.js +125 -0
  192. package/ui/externs/ui.js +8 -1
  193. package/ui/pip_button.js +22 -120
  194. package/ui/remote_button.js +201 -0
  195. package/ui/ui.js +5 -2
  196. package/demo/common/message_ids.js +0 -309
  197. package/demo/locales/en.json +0 -287
  198. package/demo/locales/source.json +0 -1142
  199. package/externs/mux.js +0 -69
  200. package/lib/lcevc/lcevc_dil.js +0 -152
  201. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  202. 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 = SegmentTemplate.createInitSegment_(context);
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(getUris, 0, null, qualityInfo);
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
 
@@ -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
  ]);
@@ -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.absoluteUri, firstSegment.tags, new Map());
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
- codecs.push('hvc1.1.6.L93.90');
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
- const language = this.getLanguage_(languageValue);
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
- const instreamId = tag.getRequiredAttrValue('INSTREAM-ID');
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.HlsAes128Key}
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.HLS_AES_128_INVALID_IV_LENGTH);
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.HLS_AES_128_INVALID_KEY_LENGTH);
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 numberOfSegments = this.config_.hls.liveSegmentsDelay;
2799
- presentationDelay = this.maxTargetDuration_ * numberOfSegments;
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 {string} playlistUri The absolute uri of the media playlist.
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_(playlistUri, tags, variables) {
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
- playlistUri, verbatimInitSegmentUri),
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 {number} timestampOffset
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, timestampOffset,
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, // This value is ignored in sequence mode.
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
- hlsAes128Key);
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, // This value is ignored in sequence mode.
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
- hlsAes128Key,
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.HlsAes128Key|undefined} */
3210
- let hlsAes128Key = undefined;
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
- hlsAes128Key = this.parseAES128DrmTag_(drmTag, playlist);
3305
+ aes128Key = this.parseAES128DrmTag_(drmTag, playlist);
3256
3306
  } else {
3257
- hlsAes128Key = undefined;
3307
+ aes128Key = undefined;
3258
3308
  }
3259
3309
  }
3260
3310
  }
3261
3311
 
3262
3312
  mediaSequenceToStartTime.set(position, startTime);
3263
3313
 
3264
- initSegmentRef = this.getInitSegmentReference_(playlist.absoluteUri,
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
- lastDiscontinuityStartTime,
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
- this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay);
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