shaka-player 4.7.13 → 4.8.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 (114) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +1 -0
  3. package/LICENSE +54 -0
  4. package/README.md +22 -1
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +34 -23
  8. package/dist/locales.js +44 -34
  9. package/dist/shaka-player.compiled.d.ts +194 -44
  10. package/dist/shaka-player.compiled.debug.d.ts +194 -44
  11. package/dist/shaka-player.compiled.debug.externs.js +474 -337
  12. package/dist/shaka-player.compiled.debug.js +949 -832
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +474 -337
  15. package/dist/shaka-player.compiled.js +1237 -1171
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +257 -47
  18. package/dist/shaka-player.ui.debug.d.ts +257 -47
  19. package/dist/shaka-player.ui.debug.externs.js +591 -376
  20. package/dist/shaka-player.ui.debug.js +1165 -965
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +591 -376
  23. package/dist/shaka-player.ui.js +1521 -1404
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/externs/device_sensor_event.js +18 -0
  26. package/externs/hisense.js +16 -0
  27. package/externs/playstation.js +31 -0
  28. package/externs/shaka/abr_manager.js +3 -1
  29. package/externs/shaka/ads.js +5 -0
  30. package/externs/shaka/codecs.js +13 -0
  31. package/externs/shaka/manifest.js +58 -6
  32. package/externs/shaka/net.js +13 -1
  33. package/externs/shaka/player.js +184 -13
  34. package/externs/shaka/text.js +19 -0
  35. package/externs/tizen.js +41 -0
  36. package/externs/webos.js +19 -0
  37. package/externs/xbox.js +43 -0
  38. package/lib/abr/simple_abr_manager.js +9 -1
  39. package/lib/ads/ad_manager.js +19 -2
  40. package/lib/ads/client_side_ad_manager.js +5 -3
  41. package/lib/ads/media_tailor_ad_manager.js +9 -0
  42. package/lib/cast/cast_receiver.js +0 -14
  43. package/lib/cast/cast_utils.js +1 -0
  44. package/lib/cea/mp4_cea_parser.js +6 -1
  45. package/lib/dash/content_protection.js +97 -53
  46. package/lib/dash/dash_parser.js +230 -176
  47. package/lib/dash/mpd_utils.js +72 -65
  48. package/lib/dash/segment_base.js +27 -21
  49. package/lib/dash/segment_list.js +18 -16
  50. package/lib/dash/segment_template.js +26 -21
  51. package/lib/hls/hls_parser.js +358 -164
  52. package/lib/media/buffering_observer.js +25 -1
  53. package/lib/media/drm_engine.js +91 -71
  54. package/lib/media/manifest_filterer.js +220 -0
  55. package/lib/media/media_source_engine.js +34 -5
  56. package/lib/media/preload_manager.js +827 -0
  57. package/lib/media/presentation_timeline.js +11 -0
  58. package/lib/media/segment_index.js +40 -30
  59. package/lib/media/segment_prefetch.js +140 -43
  60. package/lib/media/segment_reference.js +31 -8
  61. package/lib/media/segment_utils.js +208 -25
  62. package/lib/media/streaming_engine.js +319 -63
  63. package/lib/mss/content_protection.js +31 -25
  64. package/lib/mss/mss_parser.js +74 -55
  65. package/lib/net/networking_engine.js +49 -4
  66. package/lib/offline/storage.js +3 -3
  67. package/lib/player.js +882 -673
  68. package/lib/polyfill/media_capabilities.js +16 -1
  69. package/lib/text/simple_text_displayer.js +9 -0
  70. package/lib/text/stub_text_displayer.js +7 -0
  71. package/lib/text/text_engine.js +16 -3
  72. package/lib/text/ttml_text_parser.js +116 -114
  73. package/lib/text/ui_text_displayer.js +28 -11
  74. package/lib/text/vtt_text_parser.js +54 -115
  75. package/lib/transmuxer/opus.js +91 -0
  76. package/lib/transmuxer/ts_transmuxer.js +115 -0
  77. package/lib/util/cmcd_manager.js +152 -3
  78. package/lib/util/dom_utils.js +11 -0
  79. package/lib/util/error.js +5 -0
  80. package/lib/util/fake_event.js +2 -0
  81. package/lib/util/manifest_parser_utils.js +97 -3
  82. package/lib/util/mp4_box_parsers.js +346 -17
  83. package/lib/util/mp4_generator.js +23 -0
  84. package/lib/util/periods.js +19 -0
  85. package/lib/util/platform.js +161 -9
  86. package/lib/util/player_configuration.js +61 -3
  87. package/lib/util/stats.js +16 -0
  88. package/lib/util/stream_utils.js +16 -6
  89. package/lib/util/string_utils.js +36 -0
  90. package/lib/util/tXml.js +814 -0
  91. package/lib/util/ts_parser.js +50 -0
  92. package/lib/util/xml_utils.js +10 -338
  93. package/package.json +2 -2
  94. package/shaka-player.uncompiled.js +8 -0
  95. package/ui/controls.js +187 -5
  96. package/ui/enums.js +2 -0
  97. package/ui/externs/ui.js +30 -3
  98. package/ui/gl_matrix/matrix_4x4.js +568 -0
  99. package/ui/gl_matrix/matrix_quaternion.js +45 -0
  100. package/ui/less/containers.less +11 -0
  101. package/ui/locales/en-GB.json +2 -0
  102. package/ui/locales/en.json +2 -0
  103. package/ui/locales/es-419.json +2 -0
  104. package/ui/locales/es.json +2 -0
  105. package/ui/locales/source.json +8 -0
  106. package/ui/recenter_vr.js +126 -0
  107. package/ui/resolution_selection.js +25 -5
  108. package/ui/statistics_button.js +12 -0
  109. package/ui/text_selection.js +1 -1
  110. package/ui/toggle_stereoscopic.js +127 -0
  111. package/ui/ui.js +74 -38
  112. package/ui/vr_manager.js +557 -0
  113. package/ui/vr_utils.js +232 -0
  114. package/ui/vr_webgl.js +697 -0
@@ -6,6 +6,7 @@
6
6
 
7
7
  goog.provide('shaka.util.Platform');
8
8
 
9
+ goog.require('shaka.log');
9
10
  goog.require('shaka.util.Timer');
10
11
 
11
12
 
@@ -149,10 +150,9 @@ shaka.util.Platform = class {
149
150
  * @return {boolean}
150
151
  */
151
152
  static isWebOS3() {
152
- // See: http://webostv.developer.lge.com/discover/specifications/web-engine/
153
- return shaka.util.Platform.userAgentContains_('Web0S') &&
154
- shaka.util.Platform.userAgentContains_(
155
- 'Chrome/38.0.2125.122 Safari/537.36');
153
+ // See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
154
+ return shaka.util.Platform.isWebOS() &&
155
+ shaka.util.Platform.chromeVersion() === 38;
156
156
  }
157
157
 
158
158
  /**
@@ -161,18 +161,20 @@ shaka.util.Platform = class {
161
161
  * @return {boolean}
162
162
  */
163
163
  static isWebOS4() {
164
- // See: http://webostv.developer.lge.com/discover/specifications/web-engine/
165
- return !!navigator.userAgent.match(/webOS\/4/i);
164
+ // See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
165
+ return shaka.util.Platform.isWebOS() &&
166
+ shaka.util.Platform.chromeVersion() === 53;
166
167
  }
167
168
 
168
169
  /**
169
- * Check if the current platform is a WebOS 4.
170
+ * Check if the current platform is a WebOS 5.
170
171
  *
171
172
  * @return {boolean}
172
173
  */
173
174
  static isWebOS5() {
174
- // See: http://webostv.developer.lge.com/discover/specifications/web-engine/
175
- return !!navigator.userAgent.match(/webOS\/5/i);
175
+ // See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
176
+ return shaka.util.Platform.isWebOS() &&
177
+ shaka.util.Platform.chromeVersion() === 68;
176
178
  }
177
179
 
178
180
  /**
@@ -440,6 +442,25 @@ shaka.util.Platform = class {
440
442
  return shaka.util.Platform.userAgentContains_('Android');
441
443
  }
442
444
 
445
+ /**
446
+ * Return true if the platform is controlled by a remote control.
447
+ *
448
+ * @return {boolean}
449
+ */
450
+ static isSmartTV() {
451
+ const Platform = shaka.util.Platform;
452
+ if (Platform.isTizen() || Platform.isWebOS() ||
453
+ Platform.isXboxOne() || Platform.isPS4() ||
454
+ Platform.isPS5() || Platform.isAmazonFireTV() ||
455
+ Platform.isEOS() || Platform.isAPL() ||
456
+ Platform.isVirginMedia() || Platform.isOrange() ||
457
+ Platform.isWPE() || Platform.isChromecast() ||
458
+ Platform.isHisense()) {
459
+ return true;
460
+ }
461
+ return false;
462
+ }
463
+
443
464
  /**
444
465
  * Check if the user agent contains a key. This is the best way we know of
445
466
  * right now to detect platforms. If there is a better way, please send a
@@ -554,6 +575,137 @@ shaka.util.Platform = class {
554
575
 
555
576
  return false;
556
577
  }
578
+
579
+ /**
580
+ * Detect the maximum resolution that the platform's hardware can handle.
581
+ *
582
+ * @return {!Promise.<{width: number, height: number}>}
583
+ */
584
+ static async detectMaxHardwareResolution() {
585
+ const Platform = shaka.util.Platform;
586
+ const maxResolution = {
587
+ width: Infinity,
588
+ height: Infinity,
589
+ };
590
+
591
+ if (Platform.isChromecast()) {
592
+ // In our tests, the original Chromecast seems to have trouble decoding
593
+ // above 1080p. It would be a waste to select a higher res anyway, given
594
+ // that the device only outputs 1080p to begin with.
595
+ // Chromecast has an extension to query the device/display's resolution.
596
+ if (window.cast && cast.__platform__ &&
597
+ cast.__platform__.canDisplayType && cast.__platform__.canDisplayType(
598
+ 'video/mp4; codecs="avc1.640028"; width=3840; height=2160')) {
599
+ // The device and display can both do 4k. Assume a 4k limit.
600
+ maxResolution.width = 3840;
601
+ maxResolution.height = 2160;
602
+ } else {
603
+ // Chromecast has always been able to do 1080p. Assume a 1080p limit.
604
+ maxResolution.width = 1920;
605
+ maxResolution.height = 1080;
606
+ }
607
+ } else if (Platform.isTizen()) {
608
+ maxResolution.width = 1920;
609
+ maxResolution.height = 1080;
610
+ try {
611
+ if (webapis.systeminfo && webapis.systeminfo.getMaxVideoResolution) {
612
+ const maxVideoResolution =
613
+ webapis.systeminfo.getMaxVideoResolution();
614
+ maxResolution.width = maxVideoResolution.width;
615
+ maxResolution.height = maxVideoResolution.height;
616
+ } else {
617
+ if (webapis.productinfo.is8KPanelSupported &&
618
+ webapis.productinfo.is8KPanelSupported()) {
619
+ maxResolution.width = 7680;
620
+ maxResolution.height = 4320;
621
+ } else if (webapis.productinfo.isUdPanelSupported &&
622
+ webapis.productinfo.isUdPanelSupported()) {
623
+ maxResolution.width = 3840;
624
+ maxResolution.height = 2160;
625
+ }
626
+ }
627
+ } catch (e) {
628
+ shaka.log.alwaysWarn('Tizen: Error detecting screen size, default ' +
629
+ 'screen size 1920x1080.');
630
+ }
631
+ } else if (Platform.isXboxOne()) {
632
+ const protectionCapabilities =
633
+ new Windows.Media.Protection.ProtectionCapabilities();
634
+ const protectionResult =
635
+ Windows.Media.Protection.ProtectionCapabilityResult;
636
+ // isTypeSupported may return "maybe", which means the operation is not
637
+ // completed. This means we need to retry
638
+ // https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilityresult?view=winrt-22621
639
+ let result = null;
640
+ try {
641
+ const type =
642
+ 'video/mp4;codecs="hvc1,mp4a";features="decode-res-x=3840,' +
643
+ 'decode-res-y=2160,decode-bitrate=20000,decode-fps=30,' +
644
+ 'decode-bpc=10,display-res-x=3840,display-res-y=2160,' +
645
+ 'display-bpc=8"';
646
+ const keySystem = 'com.microsoft.playready.recommendation';
647
+ do {
648
+ result = protectionCapabilities.isTypeSupported(type, keySystem);
649
+ } while (result === protectionResult.maybe);
650
+ } catch (e) {
651
+ result = protectionResult.notSupported;
652
+ }
653
+ if (result === protectionResult.probably) {
654
+ maxResolution.width = 3840;
655
+ maxResolution.height = 2160;
656
+ } else {
657
+ maxResolution.width = 1920;
658
+ maxResolution.height = 1080;
659
+ }
660
+ } else if (Platform.isWebOS()) {
661
+ try {
662
+ const deviceInfo =
663
+ /** @type {{screenWidth: number, screenHeight: number}} */(
664
+ JSON.parse(window.PalmSystem.deviceInfo));
665
+ // WebOS has always been able to do 1080p. Assume a 1080p limit.
666
+ maxResolution.width = Math.max(1920, deviceInfo.screenWidth);
667
+ maxResolution.height = Math.max(1080, deviceInfo.screenHeight);
668
+ } catch (e) {
669
+ shaka.log.alwaysWarn('WebOS: Error detecting screen size, default ' +
670
+ 'screen size 1920x1080.');
671
+ maxResolution.width = 1920;
672
+ maxResolution.height = 1080;
673
+ }
674
+ } else if (Platform.isHisense()) {
675
+ // eslint-disable-next-line new-cap
676
+ if (window.Hisense_Get4KSupportState &&
677
+ // eslint-disable-next-line new-cap
678
+ window.Hisense_Get4KSupportState()) {
679
+ maxResolution.width = 3840;
680
+ maxResolution.height = 2160;
681
+ } else {
682
+ maxResolution.width = 1920;
683
+ maxResolution.height = 1080;
684
+ }
685
+ } else if (Platform.isPS4() || Platform.isPS5()) {
686
+ let supports4K = false;
687
+ try {
688
+ const result = await window.msdk.device.getDisplayInfo();
689
+ supports4K = result.resolution === '4K';
690
+ } catch (e) {
691
+ try {
692
+ const result = await window.msdk.device.getDisplayInfoImmediate();
693
+ supports4K = result.resolution === '4K';
694
+ } catch (e) {
695
+ shaka.log.alwaysWarn(
696
+ 'PlayStation: Failed to get the display info:', e);
697
+ }
698
+ }
699
+ if (supports4K) {
700
+ maxResolution.width = 3840;
701
+ maxResolution.height = 2160;
702
+ } else {
703
+ maxResolution.width = 1920;
704
+ maxResolution.height = 1080;
705
+ }
706
+ }
707
+ return maxResolution;
708
+ }
557
709
  };
558
710
 
559
711
  /** @private {shaka.util.Timer} */
@@ -94,6 +94,13 @@ shaka.util.PlayerConfiguration = class {
94
94
  ignoreDuplicateInitData: !shaka.util.Platform.isTizen2(),
95
95
  };
96
96
 
97
+ // The Xbox One and PS4 only support the Playready DRM, so they should
98
+ // prefer that key system by default to improve startup performance.
99
+ if (shaka.util.Platform.isXboxOne() ||
100
+ shaka.util.Platform.isPS4()) {
101
+ drm.preferredKeySystems.push('com.microsoft.playready');
102
+ }
103
+
97
104
  let codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD;
98
105
  let multiTypeVariantsAllowed = false;
99
106
  if (shaka.util.Platform.supportsSmoothCodecSwitching()) {
@@ -133,17 +140,22 @@ shaka.util.PlayerConfiguration = class {
133
140
  'com.microsoft.playready',
134
141
  'urn:uuid:79f0049a-4098-8642-ab92-e65be0885f95':
135
142
  'com.microsoft.playready',
136
- 'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb':
137
- 'com.adobe.primetime',
138
143
  },
139
144
  manifestPreprocessor: (element) => {
140
145
  return shaka.util.ConfigUtils.referenceParametersAndReturn(
141
146
  [element],
142
147
  element);
143
148
  },
149
+ manifestPreprocessorTXml: (element) => {
150
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
151
+ [element],
152
+ element);
153
+ },
144
154
  sequenceMode: false,
145
155
  enableAudioGroups: false,
146
156
  multiTypeVariantsAllowed,
157
+ useStreamOnceInPeriodFlattening: false,
158
+ updatePeriod: -1,
147
159
  },
148
160
  hls: {
149
161
  ignoreTextStreamFailures: false,
@@ -151,6 +163,7 @@ shaka.util.PlayerConfiguration = class {
151
163
  defaultAudioCodec: 'mp4a.40.2',
152
164
  defaultVideoCodec: 'avc1.42E01E',
153
165
  ignoreManifestProgramDateTime: false,
166
+ ignoreManifestProgramDateTimeForTypes: [],
154
167
  mediaPlaylistFullMimeType:
155
168
  'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"',
156
169
  useSafariBehaviorForLive: true,
@@ -166,6 +179,11 @@ shaka.util.PlayerConfiguration = class {
166
179
  [element],
167
180
  element);
168
181
  },
182
+ manifestPreprocessorTXml: (element) => {
183
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
184
+ [element],
185
+ element);
186
+ },
169
187
  sequenceMode: false,
170
188
  keySystemsBySystemId: {
171
189
  '9a04f079-9840-4286-ab92-e65be0885f95':
@@ -192,6 +210,7 @@ shaka.util.PlayerConfiguration = class {
192
210
  rebufferingGoal: 2,
193
211
  bufferingGoal: 10,
194
212
  bufferBehind: 30,
213
+ evictionGoal: 1,
195
214
  ignoreTextStreamFailures: false,
196
215
  alwaysStreamText: false,
197
216
  startAtSegmentBoundary: false,
@@ -205,6 +224,7 @@ shaka.util.PlayerConfiguration = class {
205
224
  stallThreshold: 1 /* seconds */,
206
225
  stallSkip: 0.1 /* seconds */,
207
226
  useNativeHlsOnSafari: true,
227
+ useNativeHlsForFairPlay: true,
208
228
  // If we are within 2 seconds of the start of a live segment, fetch the
209
229
  // previous one. This allows for segment drift, but won't download an
210
230
  // extra segment if we aren't close to the start.
@@ -223,13 +243,23 @@ shaka.util.PlayerConfiguration = class {
223
243
  // When low latency streaming is enabled, segmentPrefetchLimit will
224
244
  // default to 2 if not specified.
225
245
  segmentPrefetchLimit: 0,
246
+ prefetchAudioLanguages: [],
247
+ disableAudioPrefetch: false,
248
+ disableTextPrefetch: false,
249
+ disableVideoPrefetch: false,
226
250
  liveSync: false,
227
251
  liveSyncMaxLatency: 1,
228
252
  liveSyncPlaybackRate: 1.1,
229
253
  liveSyncMinLatency: 0,
230
254
  liveSyncMinPlaybackRate: 1,
255
+ liveSyncPanicMode: false,
256
+ liveSyncPanicThreshold: 60,
231
257
  allowMediaSourceRecoveries: true,
232
258
  minTimeBetweenRecoveries: 5,
259
+ vodDynamicPlaybackRate: false,
260
+ vodDynamicPlaybackRateLowBufferRate: 0.95,
261
+ vodDynamicPlaybackRateBufferRatio: 0.5,
262
+ infiniteLiveStreamDuration: false,
233
263
  };
234
264
 
235
265
  // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines
@@ -316,7 +346,9 @@ shaka.util.PlayerConfiguration = class {
316
346
  enabled: false,
317
347
  sessionId: '',
318
348
  contentId: '',
349
+ rtpSafetyFactor: 5,
319
350
  useHeaders: false,
351
+ includeKeys: [],
320
352
  };
321
353
 
322
354
  const cmsd = {
@@ -334,13 +366,38 @@ shaka.util.PlayerConfiguration = class {
334
366
 
335
367
  const mediaSource = {
336
368
  codecSwitchingStrategy: codecSwitchingStrategy,
337
- sourceBufferExtraFeatures: '',
369
+ addExtraFeaturesToSourceBuffer: (mimeType) => {
370
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
371
+ [mimeType],
372
+ '');
373
+ },
338
374
  forceTransmux: false,
339
375
  insertFakeEncryptionInInit: true,
376
+ modifyCueCallback: (cue, uri) => {
377
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
378
+ [cue, uri],
379
+ undefined);
380
+ },
340
381
  };
341
382
 
383
+ let skipPlayDetection = false;
384
+ if (shaka.util.Platform.isWebOS() ||
385
+ shaka.util.Platform.isTizen() ||
386
+ shaka.util.Platform.isChromecast() ||
387
+ shaka.util.Platform.isHisense() ||
388
+ shaka.util.Platform.isPS5() ||
389
+ shaka.util.Platform.isPS4() ||
390
+ shaka.util.Platform.isXboxOne()) {
391
+ skipPlayDetection = true;
392
+ }
393
+
342
394
  const ads = {
343
395
  customPlayheadTracker: false,
396
+ skipPlayDetection,
397
+ };
398
+
399
+ const textDisplayer = {
400
+ captionsUpdatePeriod: 0.25,
344
401
  };
345
402
 
346
403
  const AutoShowText = shaka.config.AutoShowText;
@@ -383,6 +440,7 @@ shaka.util.PlayerConfiguration = class {
383
440
  },
384
441
  playRangeStart: 0,
385
442
  playRangeEnd: Infinity,
443
+ textDisplayer: textDisplayer,
386
444
  textDisplayFactory: () => null,
387
445
  cmcd: cmcd,
388
446
  cmsd: cmsd,
package/lib/util/stats.js CHANGED
@@ -62,6 +62,9 @@ shaka.util.Stats = class {
62
62
  /** @private {number} */
63
63
  this.bandwidthEstimate_ = NaN;
64
64
 
65
+ /** @private {number} */
66
+ this.bytesDownloaded_ = NaN;
67
+
65
68
  /** @private {!shaka.util.StateHistory} */
66
69
  this.stateHistory_ = new shaka.util.StateHistory();
67
70
 
@@ -203,6 +206,17 @@ shaka.util.Stats = class {
203
206
  this.bandwidthEstimate_ = bandwidth;
204
207
  }
205
208
 
209
+ /**
210
+ * @param {number} bytesDownloaded
211
+ */
212
+ addBytesDownloaded(bytesDownloaded) {
213
+ if (isNaN(this.bytesDownloaded_)) {
214
+ this.bytesDownloaded_ = bytesDownloaded;
215
+ } else {
216
+ this.bytesDownloaded_ += bytesDownloaded;
217
+ }
218
+ }
219
+
206
220
  /**
207
221
  * @return {!shaka.util.StateHistory}
208
222
  */
@@ -244,6 +258,7 @@ shaka.util.Stats = class {
244
258
  licenseTime: this.licenseTimeSeconds_,
245
259
  liveLatency: this.liveLatencySeconds_,
246
260
  maxSegmentDuration: this.maxSegmentDurationSeconds_,
261
+ bytesDownloaded: this.bytesDownloaded_,
247
262
  stateHistory: this.stateHistory_.getCopy(),
248
263
  switchHistory: this.switchHistory_.getCopy(),
249
264
  };
@@ -276,6 +291,7 @@ shaka.util.Stats = class {
276
291
  licenseTime: NaN,
277
292
  liveLatency: NaN,
278
293
  maxSegmentDuration: NaN,
294
+ bytesDownloaded: NaN,
279
295
  switchHistory: [],
280
296
  stateHistory: [],
281
297
  };
@@ -263,13 +263,20 @@ shaka.util.StreamUtils = class {
263
263
  // |video.width| and |video.height| can be undefined, which breaks
264
264
  // the math, so make sure they are there first.
265
265
  if (video && video.width && video.height) {
266
- if (!inRange(video.width,
266
+ let videoWidth = video.width;
267
+ let videoHeight = video.height;
268
+ if (videoHeight > videoWidth) {
269
+ // Vertical video.
270
+ [videoWidth, videoHeight] = [videoHeight, videoWidth];
271
+ }
272
+
273
+ if (!inRange(videoWidth,
267
274
  restrictions.minWidth,
268
275
  Math.min(restrictions.maxWidth, maxHwRes.width))) {
269
276
  return false;
270
277
  }
271
278
 
272
- if (!inRange(video.height,
279
+ if (!inRange(videoHeight,
273
280
  restrictions.minHeight,
274
281
  Math.min(restrictions.maxHeight, maxHwRes.height))) {
275
282
  return false;
@@ -330,10 +337,12 @@ shaka.util.StreamUtils = class {
330
337
  *
331
338
  * @param {shaka.media.DrmEngine} drmEngine
332
339
  * @param {shaka.extern.Manifest} manifest
340
+ * @param {!Array<string>=} preferredKeySystems
333
341
  */
334
- static async filterManifest(drmEngine, manifest) {
342
+ static async filterManifest(drmEngine, manifest, preferredKeySystems = []) {
335
343
  await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
336
- drmEngine, manifest, manifest.offlineSessionIds.length > 0);
344
+ drmEngine, manifest, manifest.offlineSessionIds.length > 0,
345
+ preferredKeySystems);
337
346
  shaka.util.StreamUtils.filterTextStreams_(manifest);
338
347
  await shaka.util.StreamUtils.filterImageStreams_(manifest);
339
348
  }
@@ -346,15 +355,16 @@ shaka.util.StreamUtils = class {
346
355
  * @param {shaka.media.DrmEngine} drmEngine
347
356
  * @param {shaka.extern.Manifest} manifest
348
357
  * @param {boolean} usePersistentLicenses
358
+ * @param {!Array<string>} preferredKeySystems
349
359
  */
350
360
  static async filterManifestByMediaCapabilities(
351
- drmEngine, manifest, usePersistentLicenses) {
361
+ drmEngine, manifest, usePersistentLicenses, preferredKeySystems) {
352
362
  goog.asserts.assert(navigator.mediaCapabilities,
353
363
  'MediaCapabilities should be valid.');
354
364
 
355
365
  await shaka.util.StreamUtils.getDecodingInfosForVariants(
356
366
  manifest.variants, usePersistentLicenses, /* srcEquals= */ false,
357
- /** preferredKeySystems= */ []);
367
+ preferredKeySystems);
358
368
 
359
369
  let keySystem = null;
360
370
  if (drmEngine) {
@@ -276,6 +276,42 @@ shaka.util.StringUtils = class {
276
276
  static resetFromCharCode() {
277
277
  shaka.util.StringUtils.fromCharCodeImpl_.reset();
278
278
  }
279
+
280
+ /**
281
+ * This method converts the HTML entities &amp;, &lt;, &gt;, &quot;, &#39;,
282
+ * &nbsp;, &lrm; and &rlm; in string to their corresponding characters.
283
+ *
284
+ * @param {!string} input
285
+ * @return {string}
286
+ */
287
+ static htmlUnescape(input) {
288
+ // Used to map HTML entities to characters.
289
+ const htmlUnescapes = {
290
+ '&amp;': '&',
291
+ '&lt;': '<',
292
+ '&gt;': '>',
293
+ '&quot;': '"',
294
+ '&#39;': '\'',
295
+ '&apos;': '\'',
296
+ '&nbsp;': '\u{a0}',
297
+ '&lrm;': '\u{200e}',
298
+ '&rlm;': '\u{200f}',
299
+ };
300
+
301
+ // Used to match HTML entities and HTML characters.
302
+ const reEscapedHtml = /&(?:amp|lt|gt|quot|apos|#(0+)?39|nbsp|lrm|rlm);/g;
303
+ const reHasEscapedHtml = RegExp(reEscapedHtml.source);
304
+ // This check is an optimization, since replace always makes a copy
305
+ if (input && reHasEscapedHtml.test(input)) {
306
+ return input.replace(reEscapedHtml, (entity) => {
307
+ // The only thing that might not match the dictionary above is the
308
+ // single quote, which can be matched by many strings in the regex, but
309
+ // only has a single entry in the dictionary.
310
+ return htmlUnescapes[entity] || '\'';
311
+ });
312
+ }
313
+ return input || '';
314
+ }
279
315
  };
280
316
 
281
317