shaka-player 4.12.4 → 4.12.6

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 (55) hide show
  1. package/dist/deps.js +2 -2
  2. package/dist/locales.js +35 -35
  3. package/dist/shaka-player.compiled.d.ts +11 -3
  4. package/dist/shaka-player.compiled.debug.d.ts +11 -3
  5. package/dist/shaka-player.compiled.debug.externs.js +8 -5
  6. package/dist/shaka-player.compiled.debug.js +340 -331
  7. package/dist/shaka-player.compiled.debug.map +3 -3
  8. package/dist/shaka-player.compiled.externs.js +8 -5
  9. package/dist/shaka-player.compiled.js +1383 -1378
  10. package/dist/shaka-player.compiled.map +4 -4
  11. package/dist/shaka-player.ui.d.ts +11 -3
  12. package/dist/shaka-player.ui.debug.d.ts +11 -3
  13. package/dist/shaka-player.ui.debug.externs.js +8 -5
  14. package/dist/shaka-player.ui.debug.js +357 -348
  15. package/dist/shaka-player.ui.debug.map +3 -3
  16. package/dist/shaka-player.ui.externs.js +8 -5
  17. package/dist/shaka-player.ui.js +1605 -1599
  18. package/dist/shaka-player.ui.map +3 -3
  19. package/externs/shaka/codecs.js +21 -0
  20. package/externs/shaka/offline.js +4 -0
  21. package/lib/cast/cast_utils.js +1 -0
  22. package/lib/dash/dash_parser.js +3 -0
  23. package/lib/hls/hls_parser.js +26 -5
  24. package/lib/media/drm_engine.js +70 -29
  25. package/lib/media/manifest_filterer.js +2 -1
  26. package/lib/media/media_source_engine.js +138 -129
  27. package/lib/media/segment_utils.js +50 -44
  28. package/lib/media/streaming_engine.js +9 -1
  29. package/lib/offline/download_info.js +5 -0
  30. package/lib/offline/download_manager.js +54 -0
  31. package/lib/offline/manifest_converter.js +1 -0
  32. package/lib/offline/storage.js +12 -3
  33. package/lib/player.js +52 -29
  34. package/lib/polyfill/media_capabilities.js +1 -1
  35. package/lib/text/simple_text_displayer.js +9 -1
  36. package/lib/text/ui_text_displayer.js +2 -14
  37. package/lib/transmuxer/aac_transmuxer.js +11 -3
  38. package/lib/transmuxer/ac3_transmuxer.js +11 -3
  39. package/lib/transmuxer/ec3_transmuxer.js +11 -3
  40. package/lib/transmuxer/h264.js +143 -70
  41. package/lib/transmuxer/mp3_transmuxer.js +11 -3
  42. package/lib/transmuxer/ts_transmuxer.js +68 -28
  43. package/lib/util/drm_utils.js +20 -0
  44. package/lib/util/mime_utils.js +3 -0
  45. package/lib/util/object_utils.js +83 -0
  46. package/lib/util/platform.js +48 -40
  47. package/lib/util/stream_utils.js +37 -113
  48. package/lib/util/ts_parser.js +111 -85
  49. package/package.json +1 -1
  50. package/ui/ad_counter.js +5 -0
  51. package/ui/controls.js +4 -2
  52. package/ui/fast_forward_button.js +7 -0
  53. package/ui/play_button.js +1 -1
  54. package/ui/playback_rate_selection.js +1 -1
  55. package/ui/rewind_button.js +7 -0
@@ -27,6 +27,27 @@
27
27
  shaka.extern.MPEG_PES;
28
28
 
29
29
 
30
+ /**
31
+ * @typedef {{
32
+ * data: !Uint8Array,
33
+ * frame: boolean,
34
+ * isKeyframe: boolean,
35
+ * pts: ?number,
36
+ * dts: ?number,
37
+ * nalus: !Array.<!shaka.extern.VideoNalu>
38
+ * }}
39
+ *
40
+ * @summary VideoSample.
41
+ * @property {!Uint8Array} data
42
+ * @property {boolean} frame
43
+ * @property {boolean} isKeyframe
44
+ * @property {?number} pts
45
+ * @property {?number} dts
46
+ * @property {!Array.<!shaka.extern.VideoNalu>} nalus
47
+ */
48
+ shaka.extern.VideoSample;
49
+
50
+
30
51
  /**
31
52
  * @typedef {{
32
53
  * data: !Uint8Array,
@@ -141,6 +141,7 @@ shaka.extern.ManifestDB;
141
141
  * spatialAudio: boolean,
142
142
  * closedCaptions: Map.<string, string>,
143
143
  * tilesLayout: (string|undefined),
144
+ * mssPrivateData: (shaka.extern.MssPrivateData|undefined),
144
145
  * external: boolean,
145
146
  * fastSwitching: boolean,
146
147
  * isAudioMuxedInVideo: boolean
@@ -214,6 +215,9 @@ shaka.extern.ManifestDB;
214
215
  * The value is a grid-item-dimension consisting of two positive decimal
215
216
  * integers in the format: column-x-row ('4x3'). It describes the arrangement
216
217
  * of Images in a Grid. The minimum valid LAYOUT is '1x1'.
218
+ * @property {(shaka.extern.MssPrivateData|undefined)} mssPrivateData
219
+ * <i>Microsoft Smooth Streaming only.</i> <br>
220
+ * Private MSS data that is necessary to be able to do transmuxing.
217
221
  * @property {boolean} external
218
222
  * Indicate if the stream was added externally.
219
223
  * Eg: external text tracks.
@@ -329,6 +329,7 @@ shaka.cast.CastUtils.PlayerGetterMethods = {
329
329
  'getLoadMode': 10,
330
330
  'getManifestType': 10,
331
331
  'isFullyLoaded': 1,
332
+ 'isEnded': 1,
332
333
  };
333
334
 
334
335
 
@@ -1505,6 +1505,9 @@ shaka.dash.DashParser = class {
1505
1505
  let shouldDeleteIndex = true;
1506
1506
  for (const contextId of this.indexStreamMap_[pId]) {
1507
1507
  const stream = this.streamMap_[contextId];
1508
+ if (!stream) {
1509
+ continue;
1510
+ }
1508
1511
  if (stream.segmentIndex && !stream.segmentIndex.isEmpty()) {
1509
1512
  shouldDeleteIndex = false;
1510
1513
  continue;
@@ -1136,8 +1136,8 @@ shaka.hls.HlsParser = class {
1136
1136
 
1137
1137
  if (shaka.util.TsParser.probe(
1138
1138
  shaka.util.BufferUtils.toUint8(data))) {
1139
- const basicInfo =
1140
- shaka.media.SegmentUtils.getBasicInfoFromTs(data);
1139
+ const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromTs(
1140
+ data, this.config_.disableAudio, this.config_.disableVideo);
1141
1141
  if (basicInfo) {
1142
1142
  return basicInfo;
1143
1143
  }
@@ -2763,12 +2763,23 @@ shaka.hls.HlsParser = class {
2763
2763
  }
2764
2764
  }
2765
2765
  this.notifySegmentsForStreams_(streamInfos.map((s) => s.stream));
2766
- const liveWithNoProgramaDateTime =
2766
+
2767
+ const activeStreamInfos = Array.from(this.uriToStreamInfosMap_.values())
2768
+ .filter((s) => s.stream.segmentIndex);
2769
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
2770
+ const hasAudio =
2771
+ activeStreamInfos.some((s) => s.stream.type == ContentType.AUDIO);
2772
+ const hasVideo =
2773
+ activeStreamInfos.some((s) => s.stream.type == ContentType.VIDEO);
2774
+
2775
+ const liveWithNoProgramDateTime =
2767
2776
  this.isLive_() && !this.usesProgramDateTime_;
2777
+ const vodWithOnlyAudioOrVideo = !this.isLive_() &&
2778
+ this.usesProgramDateTime_ && !(hasAudio && hasVideo);
2768
2779
  if (this.config_.hls.ignoreManifestProgramDateTime ||
2769
- liveWithNoProgramaDateTime) {
2780
+ liveWithNoProgramDateTime || vodWithOnlyAudioOrVideo) {
2770
2781
  this.syncStreamsWithSequenceNumber_(
2771
- streamInfos, liveWithNoProgramaDateTime);
2782
+ streamInfos, liveWithNoProgramDateTime);
2772
2783
  } else {
2773
2784
  this.syncStreamsWithProgramDateTime_(streamInfos);
2774
2785
  if (this.config_.hls.ignoreManifestProgramDateTimeForTypes.length > 0) {
@@ -2906,6 +2917,16 @@ shaka.hls.HlsParser = class {
2906
2917
 
2907
2918
  if (!mimeType) {
2908
2919
  mimeType = await this.guessMimeType_(type, codecs, segments);
2920
+
2921
+ // Some manifests don't say what text codec they use, this is a problem
2922
+ // if the cmft extension is used because we identify the mimeType as
2923
+ // application/mp4. In this case if we don't detect initialization
2924
+ // segments, we assume that the mimeType is text/vtt.
2925
+ if (type == shaka.util.ManifestParserUtils.ContentType.TEXT &&
2926
+ !codecs && mimeType == 'application/mp4' &&
2927
+ segments[0] && !segments[0].initSegmentReference) {
2928
+ mimeType = 'text/vtt';
2929
+ }
2909
2930
  }
2910
2931
 
2911
2932
  const {drmInfos, keyIds, encrypted, aesEncrypted} =
@@ -928,14 +928,16 @@ shaka.media.DrmEngine = class {
928
928
  'Got MediaKeySystemAccess with configuration',
929
929
  realConfig);
930
930
 
931
+ const keySystem =
932
+ this.config_.keySystemsMapping[mediaKeySystemAccess.keySystem] ||
933
+ mediaKeySystemAccess.keySystem;
934
+
931
935
  if (variants.length) {
932
936
  this.currentDrmInfo_ = this.createDrmInfoByInfos_(
933
- mediaKeySystemAccess.keySystem,
934
- drmInfosByKeySystem.get(mediaKeySystemAccess.keySystem));
937
+ keySystem, drmInfosByKeySystem.get(keySystem));
935
938
  } else {
936
939
  this.currentDrmInfo_ = shaka.media.DrmEngine.createDrmInfoByConfigs_(
937
- mediaKeySystemAccess.keySystem,
938
- configsByKeySystem.get(mediaKeySystemAccess.keySystem));
940
+ keySystem, configsByKeySystem.get(keySystem));
939
941
  }
940
942
  if (!this.currentDrmInfo_.licenseServerUri) {
941
943
  throw new shaka.util.Error(
@@ -1050,8 +1052,12 @@ shaka.media.DrmEngine = class {
1050
1052
  if (!decodingInfo.supported || !decodingInfo.keySystemAccess) {
1051
1053
  continue;
1052
1054
  }
1053
- const drmInfos =
1054
- drmInfosByKeySystem.get(decodingInfo.keySystemAccess.keySystem);
1055
+ const originalKeySystem = decodingInfo.keySystemAccess.keySystem;
1056
+ let drmInfos = drmInfosByKeySystem.get(originalKeySystem);
1057
+ if (!drmInfos && this.config_.keySystemsMapping[originalKeySystem]) {
1058
+ drmInfos = drmInfosByKeySystem.get(
1059
+ this.config_.keySystemsMapping[originalKeySystem]);
1060
+ }
1055
1061
  for (const info of drmInfos) {
1056
1062
  if (!!info.licenseServerUri == shouldHaveLicenseServer) {
1057
1063
  return decodingInfo.keySystemAccess;
@@ -1450,6 +1456,11 @@ shaka.media.DrmEngine = class {
1450
1456
  }
1451
1457
  // NOTE: allowCrossSiteCredentials can be set in a request filter.
1452
1458
 
1459
+ if (shaka.util.DrmUtils.isClearKeySystem(
1460
+ this.currentDrmInfo_.keySystem)) {
1461
+ this.fixClearKeyRequest_(request, this.currentDrmInfo_);
1462
+ }
1463
+
1453
1464
  if (shaka.util.DrmUtils.isPlayReadyKeySystem(
1454
1465
  this.currentDrmInfo_.keySystem)) {
1455
1466
  this.unpackPlayReadyRequest_(request);
@@ -1603,6 +1614,31 @@ shaka.media.DrmEngine = class {
1603
1614
  /** @type{string} */(shaka.util.TXml.getTextContents(challenge)));
1604
1615
  }
1605
1616
 
1617
+ /**
1618
+ * Some old ClearKey CDMs don't include the type in the body request.
1619
+ *
1620
+ * @param {shaka.extern.Request} request
1621
+ * @param {shaka.extern.DrmInfo} drmInfo
1622
+ * @private
1623
+ */
1624
+ fixClearKeyRequest_(request, drmInfo) {
1625
+ try {
1626
+ const body = shaka.util.StringUtils.fromBytesAutoDetect(request.body);
1627
+ if (body) {
1628
+ const licenseBody =
1629
+ /** @type {shaka.media.DrmEngine.ClearKeyLicenceRequestFormat} */ (
1630
+ JSON.parse(body));
1631
+ if (!licenseBody.type) {
1632
+ licenseBody.type = drmInfo.sessionType;
1633
+ request.body =
1634
+ shaka.util.StringUtils.toUTF8(JSON.stringify(licenseBody));
1635
+ }
1636
+ }
1637
+ } catch (e) {
1638
+ shaka.log.info('Error unpacking ClearKey license', e);
1639
+ }
1640
+ }
1641
+
1606
1642
  /**
1607
1643
  * @param {!Event} event
1608
1644
  * @private
@@ -2001,18 +2037,10 @@ shaka.media.DrmEngine = class {
2001
2037
  * @private
2002
2038
  */
2003
2039
  async closeSession_(session) {
2004
- const DrmEngine = shaka.media.DrmEngine;
2005
-
2006
- const timeout = new Promise((resolve, reject) => {
2007
- const timer = new shaka.util.Timer(reject);
2008
- timer.tickAfter(DrmEngine.CLOSE_TIMEOUT_);
2009
- });
2010
-
2011
2040
  try {
2012
- await Promise.race([
2013
- Promise.all([session.close(), session.closed]),
2014
- timeout,
2015
- ]);
2041
+ await shaka.util.Functional.promiseWithTimeout(
2042
+ shaka.media.DrmEngine.CLOSE_TIMEOUT_,
2043
+ Promise.all([session.close(), session.closed]));
2016
2044
  } catch (e) {
2017
2045
  shaka.log.warning('Timeout waiting for session close');
2018
2046
  }
@@ -2452,26 +2480,24 @@ shaka.media.DrmEngine = class {
2452
2480
  // The order of preference for drmInfo:
2453
2481
  // 1. Clear Key config, used for debugging, should override everything else.
2454
2482
  // (The application can still specify a clearkey license server.)
2455
- // 2. Application-configured servers, if any are present, should override
2456
- // anything from the manifest. Nuance: if key system A is in the
2457
- // manifest and key system B is in the player config, only B will be
2458
- // used, not A.
2483
+ // 2. Application-configured servers, if present, override
2484
+ // anything from the manifest.
2459
2485
  // 3. Manifest-provided license servers are only used if nothing else is
2460
2486
  // specified.
2461
2487
  // This is important because it allows the application a clear way to
2462
- // indicate which DRM systems should be used on platforms with multiple DRM
2463
- // systems.
2464
- // The only way to get license servers from the manifest is not to specify
2465
- // any in your player config.
2488
+ // indicate which DRM systems should be ignored on platforms with multiple
2489
+ // DRM systems.
2490
+ // Alternatively, use config.preferredKeySystems to specify the preferred
2491
+ // key system.
2466
2492
 
2467
2493
  if (originalKeySystem == 'org.w3.clearkey' && drmInfo.licenseServerUri) {
2468
2494
  // Preference 1: Clear Key with pre-configured keys will have a data URI
2469
2495
  // assigned as its license server. Don't change anything.
2470
2496
  return;
2471
- } else if (servers.size) {
2472
- // Preference 2: If anything is configured at the application level,
2473
- // override whatever was in the manifest.
2474
- const server = servers.get(originalKeySystem) || '';
2497
+ } else if (servers.size && servers.get(originalKeySystem)) {
2498
+ // Preference 2: If a license server for this keySystem is configured at
2499
+ // the application level, override whatever was in the manifest.
2500
+ const server = servers.get(originalKeySystem);
2475
2501
 
2476
2502
  drmInfo.licenseServerUri = server;
2477
2503
  } else {
@@ -2632,6 +2658,21 @@ shaka.media.DrmEngine.SessionMetaData;
2632
2658
  */
2633
2659
  shaka.media.DrmEngine.PlayerInterface;
2634
2660
 
2661
+ /**
2662
+ * @typedef {{
2663
+ * kids: !Array.<string>,
2664
+ * type: string
2665
+ * }}
2666
+ *
2667
+ * @property {!Array.<string>} kids
2668
+ * An array of key IDs. Each element of the array is the base64url encoding of
2669
+ * the octet sequence containing the key ID value.
2670
+ * @property {string} type
2671
+ * The requested MediaKeySessionType.
2672
+ * @see https://www.w3.org/TR/encrypted-media/#clear-key-request-format
2673
+ */
2674
+ shaka.media.DrmEngine.ClearKeyLicenceRequestFormat;
2675
+
2635
2676
  /**
2636
2677
  * The amount of time, in seconds, we wait to consider a session closed.
2637
2678
  * This allows us to work around Chrome bug https://crbug.com/1108158.
@@ -50,7 +50,8 @@ shaka.media.ManifestFilterer = class {
50
50
  async filterManifest(manifest) {
51
51
  goog.asserts.assert(manifest, 'Manifest should exist!');
52
52
  await shaka.util.StreamUtils.filterManifest(this.drmEngine_, manifest,
53
- this.config_.drm.preferredKeySystems);
53
+ this.config_.drm.preferredKeySystems,
54
+ this.config_.drm.keySystemsMapping);
54
55
  if (!this.config_.streaming.dontChooseCodecs) {
55
56
  shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
56
57
  manifest,