shaka-player 4.2.3 → 4.3.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 (147) hide show
  1. package/.github/workflows/sync-labels.yaml +1 -1
  2. package/.github/workflows/update-issues.yaml +1 -1
  3. package/AUTHORS +5 -0
  4. package/CHANGELOG.md +85 -39
  5. package/CONTRIBUTORS +5 -0
  6. package/README.md +14 -0
  7. package/demo/common/assets.js +58 -0
  8. package/demo/common/message_ids.js +22 -1
  9. package/demo/config.js +89 -5
  10. package/demo/demo.less +7 -1
  11. package/demo/index.html +8 -1
  12. package/demo/locales/en.json +21 -1
  13. package/demo/locales/source.json +82 -2
  14. package/demo/main.js +57 -1
  15. package/demo/search.js +2 -0
  16. package/demo/visualizer.js +337 -0
  17. package/demo/visualizer_button.js +103 -0
  18. package/dist/controls.css +1 -1
  19. package/dist/controls.css.map +1 -1
  20. package/dist/demo.compiled.debug.js +83 -58
  21. package/dist/demo.compiled.debug.map +4 -4
  22. package/dist/demo.compiled.js +83 -58
  23. package/dist/demo.compiled.map +4 -4
  24. package/dist/demo.css +1 -1
  25. package/dist/demo.css.map +1 -1
  26. package/dist/deps.js +18 -11
  27. package/dist/locales.js +32 -32
  28. package/dist/receiver.compiled.debug.js +23 -19
  29. package/dist/receiver.compiled.debug.map +3 -3
  30. package/dist/receiver.compiled.js +23 -19
  31. package/dist/receiver.compiled.map +3 -3
  32. package/dist/shaka-player.compiled.d.ts +178 -27
  33. package/dist/shaka-player.compiled.debug.d.ts +178 -27
  34. package/dist/shaka-player.compiled.debug.externs.js +163 -32
  35. package/dist/shaka-player.compiled.debug.js +488 -422
  36. package/dist/shaka-player.compiled.debug.map +4 -4
  37. package/dist/shaka-player.compiled.externs.js +163 -32
  38. package/dist/shaka-player.compiled.js +895 -857
  39. package/dist/shaka-player.compiled.map +4 -4
  40. package/dist/shaka-player.ui.d.ts +178 -27
  41. package/dist/shaka-player.ui.debug.d.ts +178 -27
  42. package/dist/shaka-player.ui.debug.externs.js +163 -32
  43. package/dist/shaka-player.ui.debug.js +519 -450
  44. package/dist/shaka-player.ui.debug.map +4 -4
  45. package/dist/shaka-player.ui.externs.js +163 -32
  46. package/dist/shaka-player.ui.js +1053 -1015
  47. package/dist/shaka-player.ui.map +4 -4
  48. package/docs/design/lcevc-architecture.png +0 -0
  49. package/docs/design/lcevc-demo.png +0 -0
  50. package/docs/design/lcevc-integration.md +72 -0
  51. package/docs/tutorials/fairplay.md +7 -0
  52. package/docs/tutorials/faq.md +1 -1
  53. package/docs/tutorials/ui.md +7 -7
  54. package/docs/tutorials/upgrade.md +6 -0
  55. package/externs/ima.js +13 -1
  56. package/externs/lcevc.js +81 -0
  57. package/externs/mux.js +4 -42
  58. package/externs/shaka/ads.js +11 -1
  59. package/externs/shaka/manifest_parser.js +5 -1
  60. package/externs/shaka/player.js +178 -15
  61. package/lib/abr/simple_abr_manager.js +7 -0
  62. package/lib/ads/ad_manager.js +0 -8
  63. package/lib/ads/client_side_ad.js +15 -0
  64. package/lib/ads/client_side_ad_manager.js +21 -8
  65. package/lib/ads/server_side_ad.js +15 -0
  66. package/lib/ads/server_side_ad_manager.js +3 -3
  67. package/lib/cast/cast_proxy.js +2 -1
  68. package/lib/cast/cast_receiver.js +19 -5
  69. package/lib/cast/cast_sender.js +2 -1
  70. package/lib/cast/cast_utils.js +18 -6
  71. package/lib/cea/dummy_cea_parser.js +28 -0
  72. package/lib/cea/i_cea_parser.js +14 -2
  73. package/lib/cea/mp4_cea_parser.js +87 -5
  74. package/lib/config/auto_show_text.js +33 -0
  75. package/lib/dash/dash_parser.js +1 -1
  76. package/lib/hls/hls_parser.js +799 -376
  77. package/lib/lcevc/lcevc_dil.js +152 -0
  78. package/lib/media/closed_caption_parser.js +9 -6
  79. package/lib/media/drm_engine.js +14 -6
  80. package/lib/media/media_source_engine.js +112 -26
  81. package/lib/media/playhead.js +23 -1
  82. package/lib/media/presentation_timeline.js +26 -11
  83. package/lib/media/segment_reference.js +49 -1
  84. package/lib/media/streaming_engine.js +145 -24
  85. package/lib/media/transmuxer.js +79 -18
  86. package/lib/offline/storage.js +1 -0
  87. package/lib/player.js +477 -85
  88. package/lib/polyfill/patchedmediakeys_apple.js +55 -1
  89. package/lib/text/ui_text_displayer.js +5 -5
  90. package/lib/text/vtt_text_parser.js +35 -1
  91. package/lib/util/dom_utils.js +0 -1
  92. package/lib/util/error.js +17 -0
  93. package/lib/util/fake_event.js +2 -0
  94. package/lib/util/id3_utils.js +300 -0
  95. package/lib/util/manifest_parser_utils.js +4 -0
  96. package/lib/util/mime_utils.js +3 -6
  97. package/lib/util/mp4_box_parsers.js +15 -5
  98. package/lib/util/platform.js +9 -1
  99. package/lib/util/player_configuration.js +23 -1
  100. package/lib/util/ts_parser.js +499 -0
  101. package/maintained-branches.md +2 -2
  102. package/package.json +4 -1
  103. package/roadmap.md +27 -7
  104. package/test/ads/ad_manager_unit.js +180 -29
  105. package/test/cast/cast_receiver_integration.js +97 -16
  106. package/test/cast/cast_receiver_unit.js +17 -12
  107. package/test/cast/cast_utils_unit.js +4 -1
  108. package/test/dash/dash_parser_content_protection_unit.js +1 -0
  109. package/test/dash/dash_parser_live_unit.js +1 -0
  110. package/test/dash/dash_parser_manifest_unit.js +93 -1
  111. package/test/dash/dash_parser_segment_base_unit.js +1 -0
  112. package/test/dash/dash_parser_segment_list_unit.js +1 -0
  113. package/test/dash/dash_parser_segment_template_unit.js +1 -0
  114. package/test/demo/demo_unit.js +2 -1
  115. package/test/hls/hls_live_unit.js +253 -19
  116. package/test/hls/hls_parser_unit.js +500 -12
  117. package/test/media/closed_caption_parser_unit.js +2 -1
  118. package/test/media/drm_engine_integration.js +3 -1
  119. package/test/media/media_source_engine_integration.js +102 -6
  120. package/test/media/media_source_engine_unit.js +10 -5
  121. package/test/media/playhead_unit.js +41 -0
  122. package/test/media/streaming_engine_integration.js +17 -1
  123. package/test/media/streaming_engine_unit.js +180 -24
  124. package/test/media/transmuxer_integration.js +21 -10
  125. package/test/player_integration.js +224 -82
  126. package/test/player_unit.js +92 -2
  127. package/test/polyfill/patchedmediakeys_apple_unit.js +124 -0
  128. package/test/test/assets/id3-metadata.aac +0 -0
  129. package/test/test/assets/id3-metadata.ts +0 -0
  130. package/test/test/assets/thumbnails-sprites.vtt +10 -0
  131. package/test/test/assets/thumbnails.vtt +10 -0
  132. package/test/test/util/dash_parser_util.js +2 -0
  133. package/test/test/util/fake_ad.js +21 -0
  134. package/test/test/util/fake_media_source_engine.js +7 -0
  135. package/test/test/util/id3_generator.js +100 -0
  136. package/test/test/util/manifest_generator.js +3 -6
  137. package/test/test/util/simple_fakes.js +7 -0
  138. package/test/test/util/stream_generator.js +38 -0
  139. package/test/test/util/test_scheme.js +43 -14
  140. package/test/text/vtt_text_parser_unit.js +11 -0
  141. package/test/ui/text_displayer_layout_unit.js +14 -0
  142. package/test/util/id3_utils_unit.js +116 -0
  143. package/test/util/ts_parser_unit.js +77 -0
  144. package/ui/controls.js +4 -1
  145. package/ui/less/containers.less +7 -0
  146. package/ui/settings_menu.js +11 -2
  147. package/ui/ui.js +43 -4
@@ -24,6 +24,7 @@ goog.require('shaka.util.Destroyer');
24
24
  goog.require('shaka.util.Error');
25
25
  goog.require('shaka.util.FakeEvent');
26
26
  goog.require('shaka.util.IDestroyable');
27
+ goog.require('shaka.util.Id3Utils');
27
28
  goog.require('shaka.util.ManifestParserUtils');
28
29
  goog.require('shaka.util.MimeUtils');
29
30
  goog.require('shaka.util.Mp4Parser');
@@ -77,6 +78,9 @@ shaka.media.StreamingEngine = class {
77
78
  /** @private {?shaka.extern.Stream} */
78
79
  this.currentTextStream_ = null;
79
80
 
81
+ /** @private {boolean} */
82
+ this.parsedPrftEventRaised_ = false;
83
+
80
84
  /**
81
85
  * Maps a content type, e.g., 'audio', 'video', or 'text', to a MediaState.
82
86
  *
@@ -780,9 +784,9 @@ shaka.media.StreamingEngine = class {
780
784
 
781
785
  // Init MediaSourceEngine.
782
786
  const mediaSourceEngine = this.playerInterface_.mediaSourceEngine;
783
- const forceTransmuxTS = this.config_.forceTransmuxTS;
787
+ const forceTransmux = this.config_.forceTransmux;
784
788
 
785
- await mediaSourceEngine.init(streamsByType, forceTransmuxTS,
789
+ await mediaSourceEngine.init(streamsByType, forceTransmux,
786
790
  this.manifest_.sequenceMode);
787
791
  this.destroyer_.ensureNotDestroyed();
788
792
 
@@ -1370,7 +1374,8 @@ shaka.media.StreamingEngine = class {
1370
1374
  JSON.stringify(buffered));
1371
1375
 
1372
1376
  if (!mediaState.waitingToClearBuffer) {
1373
- this.playerInterface_.onSegmentAppended();
1377
+ this.playerInterface_.onSegmentAppended(
1378
+ reference.startTime, reference.endTime, mediaState.type);
1374
1379
  }
1375
1380
 
1376
1381
  // Update right away.
@@ -1403,16 +1408,6 @@ shaka.media.StreamingEngine = class {
1403
1408
  this.mediaStates_.delete(ContentType.TEXT);
1404
1409
  } else if (error.code == shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR) {
1405
1410
  this.handleQuotaExceeded_(mediaState, error);
1406
- } else if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
1407
- error.data && error.data[1] == 404) {
1408
- // The segment could not be found, does not exist, or is not available.
1409
- // In any case just try again.
1410
- // The current segment is not available. Schedule another update to
1411
- // fetch the segment again.
1412
- shaka.log.v2(logPrefix, 'segment not available.');
1413
- mediaState.performingUpdate = false;
1414
- mediaState.updateTimer = null;
1415
- this.scheduleUpdate_(mediaState, 1);
1416
1411
  } else {
1417
1412
  shaka.log.error(logPrefix, 'failed fetch and append: code=' +
1418
1413
  error.code);
@@ -1455,9 +1450,10 @@ shaka.media.StreamingEngine = class {
1455
1450
 
1456
1451
  /**
1457
1452
  * Clear per-stream error states and retry any failed streams.
1453
+ * @param {number} delaySeconds
1458
1454
  * @return {boolean} False if unable to retry.
1459
1455
  */
1460
- retry() {
1456
+ retry(delaySeconds) {
1461
1457
  if (this.destroyer_.destroyed()) {
1462
1458
  shaka.log.error('Unable to retry after StreamingEngine is destroyed!');
1463
1459
  return false;
@@ -1474,7 +1470,7 @@ shaka.media.StreamingEngine = class {
1474
1470
  if (mediaState.hasError) {
1475
1471
  shaka.log.info(logPrefix, 'Retrying after failure...');
1476
1472
  mediaState.hasError = false;
1477
- this.scheduleUpdate_(mediaState, 0.1);
1473
+ this.scheduleUpdate_(mediaState, delaySeconds);
1478
1474
  }
1479
1475
  }
1480
1476
 
@@ -1635,6 +1631,17 @@ shaka.media.StreamingEngine = class {
1635
1631
  try {
1636
1632
  const initSegment = await fetchInit;
1637
1633
  this.destroyer_.ensureNotDestroyed();
1634
+
1635
+ const parser = new shaka.util.Mp4Parser();
1636
+ const Mp4Parser = shaka.util.Mp4Parser;
1637
+ parser.box('moov', Mp4Parser.children)
1638
+ .box('trak', Mp4Parser.children)
1639
+ .box('mdia', Mp4Parser.children)
1640
+ .fullBox('mdhd', (box) => {
1641
+ this.parseMDHD_(reference, box);
1642
+ })
1643
+ .parse(initSegment);
1644
+
1638
1645
  shaka.log.v1(logPrefix, 'appending init segment');
1639
1646
  const hasClosedCaptions = mediaState.stream.closedCaptions &&
1640
1647
  mediaState.stream.closedCaptions.size > 0;
@@ -1674,15 +1681,36 @@ shaka.media.StreamingEngine = class {
1674
1681
 
1675
1682
  const hasClosedCaptions = stream.closedCaptions &&
1676
1683
  stream.closedCaptions.size > 0;
1677
- if ((stream.emsgSchemeIdUris != null &&
1678
- stream.emsgSchemeIdUris.length > 0) ||
1679
- this.config_.dispatchAllEmsgBoxes) {
1680
- new shaka.util.Mp4Parser()
1684
+
1685
+ let parser;
1686
+ const hasEmsg = ((stream.emsgSchemeIdUris != null &&
1687
+ stream.emsgSchemeIdUris.length > 0) ||
1688
+ this.config_.dispatchAllEmsgBoxes);
1689
+ const shouldParsePrftBox =
1690
+ (this.config_.parsePrftBox && !this.parsedPrftEventRaised_);
1691
+
1692
+ if (hasEmsg || shouldParsePrftBox) {
1693
+ parser = new shaka.util.Mp4Parser();
1694
+ }
1695
+
1696
+ if (hasEmsg) {
1697
+ parser
1681
1698
  .fullBox(
1682
1699
  'emsg',
1683
1700
  (box) => this.parseEMSG_(
1684
- reference, stream.emsgSchemeIdUris, box))
1685
- .parse(segment);
1701
+ reference, stream.emsgSchemeIdUris, box));
1702
+ }
1703
+
1704
+ if (shouldParsePrftBox) {
1705
+ parser
1706
+ .fullBox(
1707
+ 'prft',
1708
+ (box) => this.parsePrft_(
1709
+ reference, box));
1710
+ }
1711
+
1712
+ if (hasEmsg || shouldParsePrftBox) {
1713
+ parser.parse(segment);
1686
1714
  }
1687
1715
 
1688
1716
  await this.evict_(mediaState, presentationTime);
@@ -1778,6 +1806,21 @@ shaka.media.StreamingEngine = class {
1778
1806
  // A special scheme in DASH used to signal manifest updates.
1779
1807
  if (schemeId == 'urn:mpeg:dash:event:2012') {
1780
1808
  this.playerInterface_.onManifestUpdate();
1809
+ } else if (schemeId == 'https://aomedia.org/emsg/ID3') {
1810
+ // See https://aomediacodec.github.io/id3-emsg/
1811
+ const frames = shaka.util.Id3Utils.getID3Frames(messageData);
1812
+ if (frames.length && reference) {
1813
+ /** @private {shaka.extern.ID3Metadata} */
1814
+ const metadata = {
1815
+ cueTime: reference.startTime,
1816
+ data: messageData,
1817
+ frames: frames,
1818
+ dts: reference.startTime,
1819
+ pts: reference.startTime,
1820
+ };
1821
+ this.playerInterface_.onMetadata(
1822
+ [metadata], /* offset= */ 0, reference.endTime);
1823
+ }
1781
1824
  } else {
1782
1825
  /** @type {shaka.extern.EmsgInfo} */
1783
1826
  const emsg = {
@@ -1801,6 +1844,77 @@ shaka.media.StreamingEngine = class {
1801
1844
  }
1802
1845
  }
1803
1846
 
1847
+ /**
1848
+ * Parse MDHD box.
1849
+ * @param {!shaka.media.SegmentReference} reference
1850
+ * @param {!shaka.extern.ParsedBox} box
1851
+ * @private
1852
+ */
1853
+ parseMDHD_(reference, box) {
1854
+ const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
1855
+ box.reader || 0, box.version || 0);
1856
+ reference.initSegmentReference.timescale = parsedMDHDBox.timescale;
1857
+ }
1858
+
1859
+ /**
1860
+ * Parse PRFT box.
1861
+ * @param {!shaka.media.SegmentReference} reference
1862
+ * @param {!shaka.extern.ParsedBox} box
1863
+ * @private
1864
+ */
1865
+ parsePrft_(reference, box) {
1866
+ if (this.parsedPrftEventRaised_ ||
1867
+ !reference.initSegmentReference.timescale) {
1868
+ return;
1869
+ }
1870
+ box.reader.readUint32(); // Ignore referenceTrackId
1871
+ const ntpTimestampSec = box.reader.readUint32();
1872
+ const ntpTimestampFrac = box.reader.readUint32();
1873
+ const ntpTimestamp = ntpTimestampSec * 1000 +
1874
+ ntpTimestampFrac / 2**32 * 1000;
1875
+
1876
+ let mediaTime;
1877
+ if (box.version === 0) {
1878
+ mediaTime = box.reader.readUint32();
1879
+ } else {
1880
+ try {
1881
+ mediaTime = box.reader.readUint64();
1882
+ } catch (e) {
1883
+ shaka.log.warning('parsePrft_: parsing mediatime resulted in a '+
1884
+ 'MEDIA.JS_INTEGER_OVERFLOW exception');
1885
+ this.parsedPrftEventRaised_ = true;
1886
+ return;
1887
+ }
1888
+ }
1889
+
1890
+ const timescale = reference.initSegmentReference.timescale;
1891
+ const wallClockTime = this.convertNtp(ntpTimestamp);
1892
+ const programStartDate = new Date(wallClockTime -
1893
+ (mediaTime / timescale) * 1000);
1894
+ const prftInfo = {
1895
+ wallClockTime,
1896
+ programStartDate,
1897
+ };
1898
+
1899
+ const eventName = shaka.util.FakeEvent.EventName.Prft;
1900
+ const data = (new Map()).set('detail', prftInfo);
1901
+ const event = new shaka.util.FakeEvent(
1902
+ eventName, data);
1903
+ this.playerInterface_.onEvent(event);
1904
+ this.parsedPrftEventRaised_ = true;
1905
+ }
1906
+
1907
+
1908
+ /**
1909
+ * Convert Ntp ntpTimeStamp to UTC Time
1910
+ *
1911
+ * @param {number} ntpTimeStamp
1912
+ * @return {number} utcTime
1913
+ */
1914
+ convertNtp(ntpTimeStamp) {
1915
+ const start = new Date(Date.UTC(1900, 0, 1, 0, 0, 0));
1916
+ return new Date(start.getTime() + ntpTimeStamp).getTime();
1917
+ }
1804
1918
 
1805
1919
  /**
1806
1920
  * Evicts media to meet the max buffer behind limit.
@@ -2080,10 +2194,12 @@ shaka.media.StreamingEngine = class {
2080
2194
  * onError: function(!shaka.util.Error),
2081
2195
  * onEvent: function(!Event),
2082
2196
  * onManifestUpdate: function(),
2083
- * onSegmentAppended: function(),
2197
+ * onSegmentAppended: function(number, number,
2198
+ * !shaka.util.ManifestParserUtils.ContentType),
2084
2199
  * onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference),
2085
2200
  * beforeAppendSegment: function(
2086
- * shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise
2201
+ * shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise,
2202
+ * onMetadata: !function(!Array.<shaka.extern.ID3Metadata>, number, ?number)
2087
2203
  * }}
2088
2204
  *
2089
2205
  * @property {function():number} getPresentationTime
@@ -2106,14 +2222,19 @@ shaka.media.StreamingEngine = class {
2106
2222
  * Called when an event occurs that should be sent to the app.
2107
2223
  * @property {function()} onManifestUpdate
2108
2224
  * Called when an embedded 'emsg' box should trigger a manifest update.
2109
- * @property {function()} onSegmentAppended
2225
+ * @property {function(number, number,
2226
+ * !shaka.util.ManifestParserUtils.ContentType)} onSegmentAppended
2110
2227
  * Called after a segment is successfully appended to a MediaSource.
2228
+ * The parameters are the start and end time.
2111
2229
  * @property
2112
2230
  * {function(!number, !shaka.media.InitSegmentReference)} onInitSegmentAppended
2113
2231
  * Called when an init segment is appended to a MediaSource.
2114
2232
  * @property {!function(shaka.util.ManifestParserUtils.ContentType,
2115
2233
  * !BufferSource):Promise} beforeAppendSegment
2116
2234
  * A function called just before appending to the source buffer.
2235
+ * @property
2236
+ * {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)} onMetadata
2237
+ * Called when an ID3 is found in a EMSG.
2117
2238
  */
2118
2239
  shaka.media.StreamingEngine.PlayerInterface;
2119
2240
 
@@ -18,13 +18,18 @@ goog.require('shaka.dependencies');
18
18
 
19
19
  /**
20
20
  * Transmuxer provides all operations for transmuxing from Transport
21
- * Stream to MP4.
21
+ * Stream or AAC to MP4.
22
22
  *
23
23
  * @implements {shaka.util.IDestroyable}
24
24
  */
25
25
  shaka.media.Transmuxer = class {
26
- /** */
27
- constructor() {
26
+ /**
27
+ * @param {string} mimeType
28
+ */
29
+ constructor(mimeType) {
30
+ /** @private {string} */
31
+ this.originalMimeType_ = mimeType;
32
+
28
33
  /** @private {?muxjs} */
29
34
  this.muxjs_ = shaka.dependencies.muxjs();
30
35
 
@@ -42,9 +47,6 @@ shaka.media.Transmuxer = class {
42
47
  /** @private {!Array.<muxjs.mp4.ClosedCaption>} */
43
48
  this.captions_ = [];
44
49
 
45
- /** @private {!Array.<muxjs.mp4.Metadata>} */
46
- this.metadata_ = [];
47
-
48
50
  /** @private {boolean} */
49
51
  this.isTransmuxing_ = false;
50
52
 
@@ -64,7 +66,8 @@ shaka.media.Transmuxer = class {
64
66
 
65
67
 
66
68
  /**
67
- * Check if the content type is Transport Stream, and if muxjs is loaded.
69
+ * Check if the content type is Transport Stream or AAC, and if muxjs is
70
+ * loaded.
68
71
  * @param {string} mimeType
69
72
  * @param {string=} contentType
70
73
  * @return {boolean}
@@ -72,41 +75,88 @@ shaka.media.Transmuxer = class {
72
75
  static isSupported(mimeType, contentType) {
73
76
  const Transmuxer = shaka.media.Transmuxer;
74
77
 
75
- if (!shaka.dependencies.muxjs() || !Transmuxer.isTsContainer(mimeType)) {
78
+ const isTs = Transmuxer.isTsContainer_(mimeType);
79
+ const isAac = Transmuxer.isAacContainer_(mimeType);
80
+
81
+ if (!shaka.dependencies.muxjs() || (!isTs && !isAac)) {
76
82
  return false;
77
83
  }
78
84
 
85
+ if (isAac) {
86
+ return MediaSource.isTypeSupported(Transmuxer.convertAacCodecs_());
87
+ }
88
+
79
89
  if (contentType) {
80
90
  return MediaSource.isTypeSupported(
81
- Transmuxer.convertTsCodecs(contentType, mimeType));
91
+ Transmuxer.convertTsCodecs_(contentType, mimeType));
82
92
  }
83
93
 
84
94
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
85
95
 
86
- const audioMime = Transmuxer.convertTsCodecs(ContentType.AUDIO, mimeType);
87
- const videoMime = Transmuxer.convertTsCodecs(ContentType.VIDEO, mimeType);
96
+ const audioMime = Transmuxer.convertTsCodecs_(ContentType.AUDIO, mimeType);
97
+ const videoMime = Transmuxer.convertTsCodecs_(ContentType.VIDEO, mimeType);
88
98
  return MediaSource.isTypeSupported(audioMime) ||
89
99
  MediaSource.isTypeSupported(videoMime);
90
100
  }
91
101
 
92
102
 
103
+ /**
104
+ * Check if the mimetype is 'audio/aac'.
105
+ * @param {string} mimeType
106
+ * @return {boolean}
107
+ * @private
108
+ */
109
+ static isAacContainer_(mimeType) {
110
+ return mimeType.toLowerCase().split(';')[0] == 'audio/aac';
111
+ }
112
+
113
+
93
114
  /**
94
115
  * Check if the mimetype contains 'mp2t'.
95
116
  * @param {string} mimeType
96
117
  * @return {boolean}
118
+ * @private
97
119
  */
98
- static isTsContainer(mimeType) {
120
+ static isTsContainer_(mimeType) {
99
121
  return mimeType.toLowerCase().split(';')[0].split('/')[1] == 'mp2t';
100
122
  }
101
123
 
102
124
 
125
+ /**
126
+ * For any stream, convert its codecs to MP4 codecs.
127
+ * @param {string} contentType
128
+ * @param {string} mimeType
129
+ * @return {string}
130
+ */
131
+ static convertCodecs(contentType, mimeType) {
132
+ const Transmuxer = shaka.media.Transmuxer;
133
+ if (Transmuxer.isAacContainer_(mimeType)) {
134
+ return Transmuxer.convertAacCodecs_();
135
+ } else if (Transmuxer.isTsContainer_(mimeType)) {
136
+ return Transmuxer.convertTsCodecs_(contentType, mimeType);
137
+ }
138
+ return mimeType;
139
+ }
140
+
141
+
142
+ /**
143
+ * For aac stream, convert its codecs to MP4 codecs.
144
+ * @return {string}
145
+ * @private
146
+ */
147
+ static convertAacCodecs_() {
148
+ return 'audio/mp4; codecs="mp4a.40.2"';
149
+ }
150
+
151
+
103
152
  /**
104
153
  * For transport stream, convert its codecs to MP4 codecs.
105
154
  * @param {string} contentType
106
155
  * @param {string} tsMimeType
107
156
  * @return {string}
157
+ * @private
108
158
  */
109
- static convertTsCodecs(contentType, tsMimeType) {
159
+ static convertTsCodecs_(contentType, tsMimeType) {
110
160
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
111
161
  let mp4MimeType = tsMimeType.replace(/mp2t/i, 'mp4');
112
162
  if (contentType == ContentType.AUDIO) {
@@ -148,12 +198,20 @@ shaka.media.Transmuxer = class {
148
198
  }
149
199
 
150
200
 
201
+ /**
202
+ * Returns the original mimetype of the transmuxer.
203
+ * @return {string}
204
+ */
205
+ getOrginalMimeType() {
206
+ return this.originalMimeType_;
207
+ }
208
+
209
+
151
210
  /**
152
211
  * Transmux from Transport stream to MP4, using the mux.js library.
153
212
  * @param {BufferSource} data
154
213
  * @return {!Promise.<{data: !Uint8Array,
155
- * captions: !Array.<!muxjs.mp4.ClosedCaption>,
156
- * metadata: !Array.<!Object>}>}
214
+ * captions: !Array.<!muxjs.mp4.ClosedCaption>}>}
157
215
  */
158
216
  transmux(data) {
159
217
  goog.asserts.assert(!this.isTransmuxing_,
@@ -162,7 +220,6 @@ shaka.media.Transmuxer = class {
162
220
  this.transmuxPromise_ = new shaka.util.PublicPromise();
163
221
  this.transmuxedData_ = [];
164
222
  this.captions_ = [];
165
- this.metadata_ = [];
166
223
 
167
224
  const dataArray = shaka.util.BufferUtils.toUint8(data);
168
225
  this.muxTransmuxer_.push(dataArray);
@@ -182,6 +239,12 @@ shaka.media.Transmuxer = class {
182
239
  return this.transmuxPromise_;
183
240
  }
184
241
 
242
+ /**
243
+ * Reset captions from Transport stream to MP4, using the mux.js library.
244
+ */
245
+ resetCaptions() {
246
+ this.muxTransmuxer_.resetCaptions();
247
+ }
185
248
 
186
249
  /**
187
250
  * Handles the 'data' event of the transmuxer.
@@ -194,7 +257,6 @@ shaka.media.Transmuxer = class {
194
257
  */
195
258
  onTransmuxed_(segment) {
196
259
  this.captions_ = segment.captions;
197
- this.metadata_ = segment.metadata;
198
260
  this.transmuxedData_.push(
199
261
  shaka.util.Uint8ArrayUtils.concat(segment.initSegment, segment.data));
200
262
  }
@@ -209,7 +271,6 @@ shaka.media.Transmuxer = class {
209
271
  const output = {
210
272
  data: shaka.util.Uint8ArrayUtils.concat(...this.transmuxedData_),
211
273
  captions: this.captions_,
212
- metadata: this.metadata_,
213
274
  };
214
275
 
215
276
  this.transmuxPromise_.resolve(output);
@@ -1170,6 +1170,7 @@ shaka.offline.Storage = class {
1170
1170
  isAutoLowLatencyMode: () => false,
1171
1171
  enableLowLatencyMode: () => {},
1172
1172
  updateDuration: () => {},
1173
+ newDrmInfo: (stream) => {},
1173
1174
  };
1174
1175
 
1175
1176
  parser.configure(config.manifest);