shaka-player 4.5.0 → 4.6.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 (214) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/AUTHORS +2 -0
  3. package/CHANGELOG.md +98 -0
  4. package/CODE_OF_CONDUCT.md +1 -1
  5. package/CONTRIBUTORS +2 -0
  6. package/README.md +38 -32
  7. package/demo/common/asset.js +11 -17
  8. package/demo/common/assets.js +117 -11
  9. package/demo/config.js +28 -1
  10. package/demo/custom.js +52 -38
  11. package/demo/main.js +11 -3
  12. package/demo/search.js +7 -0
  13. package/dist/controls.css +1 -1
  14. package/dist/controls.css.map +1 -1
  15. package/dist/demo.compiled.debug.js +133 -124
  16. package/dist/demo.compiled.debug.map +3 -3
  17. package/dist/demo.compiled.js +133 -124
  18. package/dist/demo.compiled.map +3 -3
  19. package/dist/deps.js +20 -18
  20. package/dist/locales.js +35 -31
  21. package/dist/receiver.compiled.debug.js +58 -50
  22. package/dist/receiver.compiled.debug.map +3 -3
  23. package/dist/receiver.compiled.js +58 -50
  24. package/dist/receiver.compiled.map +3 -3
  25. package/dist/shaka-player.compiled.d.ts +440 -390
  26. package/dist/shaka-player.compiled.debug.d.ts +440 -390
  27. package/dist/shaka-player.compiled.debug.externs.js +162 -77
  28. package/dist/shaka-player.compiled.debug.js +786 -736
  29. package/dist/shaka-player.compiled.debug.map +4 -4
  30. package/dist/shaka-player.compiled.externs.js +162 -77
  31. package/dist/shaka-player.compiled.js +1154 -1121
  32. package/dist/shaka-player.compiled.map +4 -4
  33. package/dist/shaka-player.ui.d.ts +491 -437
  34. package/dist/shaka-player.ui.debug.d.ts +491 -437
  35. package/dist/shaka-player.ui.debug.externs.js +167 -77
  36. package/dist/shaka-player.ui.debug.js +877 -811
  37. package/dist/shaka-player.ui.debug.map +4 -4
  38. package/dist/shaka-player.ui.externs.js +167 -77
  39. package/dist/shaka-player.ui.js +1362 -1318
  40. package/dist/shaka-player.ui.map +4 -4
  41. package/docs/tutorials/ad_monetization.md +54 -0
  42. package/docs/tutorials/basic-usage.md +2 -1
  43. package/docs/tutorials/errors.md +2 -1
  44. package/docs/tutorials/offline.md +10 -8
  45. package/docs/tutorials/plugins.md +5 -0
  46. package/docs/tutorials/ui-customization.md +13 -0
  47. package/docs/tutorials/ui.md +2 -1
  48. package/docs/tutorials/upgrade.md +3 -0
  49. package/externs/managedmediasource.js +24 -0
  50. package/externs/shaka/abr_manager.js +6 -2
  51. package/externs/shaka/cea.js +7 -0
  52. package/externs/shaka/codecs.js +5 -3
  53. package/externs/shaka/manifest.js +21 -5
  54. package/externs/shaka/manifest_parser.js +17 -0
  55. package/externs/shaka/net.js +2 -2
  56. package/externs/shaka/offline.js +9 -2
  57. package/externs/shaka/player.js +53 -7
  58. package/externs/shaka/text.js +3 -1
  59. package/externs/shaka/transmuxer.js +1 -1
  60. package/lib/abr/simple_abr_manager.js +25 -8
  61. package/lib/ads/media_tailor_ad_manager.js +14 -3
  62. package/lib/cast/cast_receiver.js +1 -1
  63. package/lib/cea/cea_decoder.js +28 -0
  64. package/lib/cea/dummy_caption_decoder.js +5 -0
  65. package/lib/dash/dash_parser.js +249 -83
  66. package/lib/dash/mpd_utils.js +52 -31
  67. package/lib/dash/segment_base.js +4 -5
  68. package/lib/dash/segment_list.js +5 -4
  69. package/lib/dash/segment_template.js +83 -26
  70. package/lib/hls/hls_classes.js +28 -43
  71. package/lib/hls/hls_parser.js +761 -649
  72. package/lib/hls/hls_utils.js +64 -5
  73. package/lib/hls/manifest_text_parser.js +7 -11
  74. package/lib/media/adaptation_set.js +20 -13
  75. package/lib/media/adaptation_set_criteria.js +70 -18
  76. package/lib/media/closed_caption_parser.js +13 -0
  77. package/lib/media/content_workarounds.js +6 -0
  78. package/lib/media/drm_engine.js +8 -13
  79. package/lib/media/manifest_parser.js +8 -113
  80. package/lib/media/media_source_capabilities.js +10 -3
  81. package/lib/media/media_source_engine.js +75 -21
  82. package/lib/media/play_rate_controller.js +8 -38
  83. package/lib/media/presentation_timeline.js +7 -1
  84. package/lib/media/quality_observer.js +1 -1
  85. package/lib/media/segment_index.js +5 -5
  86. package/lib/media/segment_prefetch.js +92 -24
  87. package/lib/media/segment_reference.js +67 -1
  88. package/lib/media/segment_utils.js +343 -0
  89. package/lib/media/stall_detector.js +0 -3
  90. package/lib/media/streaming_engine.js +41 -21
  91. package/lib/mss/mss_parser.js +18 -2
  92. package/lib/net/networking_engine.js +66 -12
  93. package/lib/net/networking_utils.js +95 -0
  94. package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
  95. package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
  96. package/lib/offline/manifest_converter.js +2 -0
  97. package/lib/offline/offline_manifest_parser.js +10 -0
  98. package/lib/offline/storage.js +11 -7
  99. package/lib/player.js +993 -1502
  100. package/lib/polyfill/mediasource.js +22 -1
  101. package/lib/text/mp4_ttml_parser.js +2 -2
  102. package/lib/text/srt_text_parser.js +2 -2
  103. package/lib/text/stub_text_displayer.js +51 -0
  104. package/lib/text/text_engine.js +3 -2
  105. package/lib/text/ttml_text_parser.js +28 -5
  106. package/lib/text/ui_text_displayer.js +4 -0
  107. package/lib/text/vtt_text_parser.js +7 -2
  108. package/lib/transmuxer/aac_transmuxer.js +1 -1
  109. package/lib/transmuxer/ac3_transmuxer.js +1 -1
  110. package/lib/transmuxer/ec3_transmuxer.js +1 -1
  111. package/lib/transmuxer/h264.js +5 -4
  112. package/lib/transmuxer/h265.js +5 -4
  113. package/lib/transmuxer/mp3_transmuxer.js +1 -1
  114. package/lib/transmuxer/mpeg_ts_transmuxer.js +1 -1
  115. package/lib/transmuxer/mss_transmuxer.js +1 -1
  116. package/lib/transmuxer/ts_transmuxer.js +33 -13
  117. package/lib/util/buffer_utils.js +26 -4
  118. package/lib/util/content_steering_manager.js +358 -0
  119. package/lib/util/error.js +2 -6
  120. package/lib/util/fairplay_utils.js +1 -1
  121. package/lib/util/fake_event.js +5 -1
  122. package/lib/util/id3_utils.js +50 -1
  123. package/lib/util/manifest_parser_utils.js +12 -8
  124. package/lib/util/mp4_generator.js +2 -4
  125. package/lib/util/mutex.js +59 -0
  126. package/lib/util/object_utils.js +1 -1
  127. package/lib/util/periods.js +154 -179
  128. package/lib/util/platform.js +4 -3
  129. package/lib/util/player_configuration.js +35 -6
  130. package/lib/util/stream_utils.js +105 -98
  131. package/lib/util/ts_parser.js +124 -73
  132. package/lib/util/uint8array_utils.js +5 -1
  133. package/lib/util/xml_utils.js +5 -0
  134. package/maintained-branches.md +2 -2
  135. package/package.json +1 -1
  136. package/roadmap.md +15 -5
  137. package/shaka-player.uncompiled.js +0 -1
  138. package/test/abr/simple_abr_manager_unit.js +33 -33
  139. package/test/ads/ad_manager_unit.js +3 -2
  140. package/test/cast/cast_receiver_integration.js +3 -4
  141. package/test/cast/cast_utils_unit.js +2 -0
  142. package/test/cea/cea_decoder_unit.js +7 -0
  143. package/test/codec_switching/codec_switching_integration.js +2 -1
  144. package/test/dash/dash_parser_integration.js +2 -1
  145. package/test/dash/dash_parser_live_unit.js +0 -19
  146. package/test/dash/dash_parser_manifest_unit.js +494 -2
  147. package/test/dash/mpd_utils_unit.js +61 -30
  148. package/test/hls/hls_live_unit.js +12 -3
  149. package/test/hls/hls_parser_unit.js +377 -27
  150. package/test/hls/manifest_text_parser_unit.js +32 -99
  151. package/test/media/adaptation_set_criteria_unit.js +172 -21
  152. package/test/media/adaptation_set_unit.js +1 -0
  153. package/test/media/content_workarounds_unit.js +1 -1
  154. package/test/media/drm_engine_unit.js +3 -3
  155. package/test/media/media_source_engine_unit.js +1 -1
  156. package/test/media/play_rate_controller_unit.js +0 -48
  157. package/test/media/segment_index_unit.js +2 -1
  158. package/test/mss/mss_player_integration.js +3 -2
  159. package/test/net/networking_engine_unit.js +3 -3
  160. package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
  161. package/test/offline/manifest_convert_unit.js +9 -0
  162. package/test/offline/offline_integration.js +2 -1
  163. package/test/offline/storage_integration.js +21 -9
  164. package/test/player_external.js +4 -2
  165. package/test/player_integration.js +15 -4
  166. package/test/player_load_graph_integration.js +47 -151
  167. package/test/player_src_equals_external.js +1 -0
  168. package/test/player_src_equals_integration.js +71 -4
  169. package/test/player_unit.js +80 -27
  170. package/test/test/util/fake_media_source_engine.js +5 -0
  171. package/test/test/util/fake_networking_engine.js +9 -1
  172. package/test/test/util/fake_segment_prefetch.js +3 -0
  173. package/test/test/util/manifest_generator.js +4 -0
  174. package/test/test/util/manifest_parser_util.js +14 -2
  175. package/test/test/util/offline_utils.js +1 -0
  176. package/test/test/util/simple_fakes.js +2 -2
  177. package/test/test/util/streaming_engine_util.js +3 -0
  178. package/test/test/util/test_scheme.js +6 -0
  179. package/test/test/util/ui_utils.js +4 -3
  180. package/test/text/mp4_ttml_parser_unit.js +4 -4
  181. package/test/text/srt_text_parser_unit.js +1 -1
  182. package/test/text/text_displayer_layout_unit.js +1 -1
  183. package/test/text/text_engine_unit.js +6 -0
  184. package/test/text/ttml_text_parser_unit.js +33 -2
  185. package/test/transmuxer/transmuxer_engine_integration.js +9 -0
  186. package/test/transmuxer/transmuxer_integration.js +33 -3
  187. package/test/ui/ad_ui_unit.js +2 -2
  188. package/test/ui/ui_customization_unit.js +17 -16
  189. package/test/ui/ui_integration.js +30 -20
  190. package/test/ui/ui_unit.js +25 -19
  191. package/test/util/buffer_utils_unit.js +1 -1
  192. package/test/util/content_steering_manager_unit.js +427 -0
  193. package/test/util/id3_utils_unit.js +52 -0
  194. package/test/util/stream_utils_unit.js +17 -113
  195. package/test/util/ts_parser_unit.js +3 -3
  196. package/third_party/closure-uri/uri.js +13 -1
  197. package/ui/audio_language_selection.js +9 -2
  198. package/ui/externs/ui.js +17 -2
  199. package/ui/language_utils.js +43 -8
  200. package/ui/less/range_elements.less +33 -0
  201. package/ui/locales/en.json +1 -0
  202. package/ui/locales/es-419.json +1 -0
  203. package/ui/locales/es.json +1 -0
  204. package/ui/locales/source.json +4 -0
  205. package/ui/localization.js +10 -0
  206. package/ui/remote_button.js +3 -1
  207. package/ui/resolution_selection.js +47 -10
  208. package/ui/seek_bar.js +296 -3
  209. package/ui/text_selection.js +2 -1
  210. package/ui/ui.js +6 -2
  211. package/lib/routing/node.js +0 -23
  212. package/lib/routing/payload.js +0 -47
  213. package/lib/routing/walker.js +0 -587
  214. package/test/routing/walker_unit.js +0 -505
@@ -48,7 +48,7 @@ describe('Player', () => {
48
48
  /** @type {!shaka.test.FakeVideo} */
49
49
  let video;
50
50
 
51
- beforeEach(() => {
51
+ beforeEach(async () => {
52
52
  // By default, errors are a failure.
53
53
  logErrorSpy = jasmine.createSpy('shaka.log.error');
54
54
  logErrorSpy.calls.reset();
@@ -124,6 +124,7 @@ describe('Player', () => {
124
124
  open: jasmine.createSpy('open').and.returnValue(Promise.resolve()),
125
125
  destroy:
126
126
  jasmine.createSpy('destroy').and.returnValue(Promise.resolve()),
127
+ setTextDisplayer: jasmine.createSpy('setTextDisplayer'),
127
128
  setUseEmbeddedText: jasmine.createSpy('setUseEmbeddedText'),
128
129
  getUseEmbeddedText: jasmine.createSpy('getUseEmbeddedText'),
129
130
  setSegmentRelativeVttTiming:
@@ -151,7 +152,8 @@ describe('Player', () => {
151
152
  }
152
153
 
153
154
  video = new shaka.test.FakeVideo(20);
154
- player = new shaka.Player(video, dependencyInjector);
155
+ player = new shaka.Player(null, dependencyInjector);
156
+ await player.attach(video);
155
157
  player.configure({
156
158
  // Ensures we don't get a warning about missing preference.
157
159
  preferredAudioLanguage: 'en',
@@ -170,6 +172,7 @@ describe('Player', () => {
170
172
  try {
171
173
  await player.destroy();
172
174
  } finally {
175
+ player.releaseAllMutexes();
173
176
  shaka.log.error = originalLogError;
174
177
  shaka.log.alwaysError = originalLogError;
175
178
  shaka.log.warning = originalLogWarn;
@@ -234,31 +237,6 @@ describe('Player', () => {
234
237
  expect(mediaSourceEngine.destroy).toHaveBeenCalled();
235
238
  expect(drmEngine.destroy).toHaveBeenCalled();
236
239
  });
237
-
238
- // TODO(vaage): Re-enable once the parser is integrated into the load graph
239
- // better.
240
- xit('destroys parser first when interrupting load', async () => {
241
- const p = shaka.test.Util.shortDelay();
242
- /** @type {!shaka.test.FakeManifestParser} */
243
- const parser = new shaka.test.FakeManifestParser(manifest);
244
- parser.start.and.returnValue(p);
245
- parser.stop.and.callFake(() => {
246
- expect(abrManager.stop).not.toHaveBeenCalled();
247
- expect(abrManager.release).not.toHaveBeenCalled();
248
- expect(networkingEngine.destroy).not.toHaveBeenCalled();
249
- });
250
- shaka.media.ManifestParser.registerParserByMime(
251
- fakeMimeType, () => parser);
252
-
253
- const load = player.load(fakeManifestUri, 0, fakeMimeType);
254
- await shaka.test.Util.shortDelay();
255
- await player.destroy();
256
- expect(abrManager.stop).toHaveBeenCalled();
257
- expect(abrManager.release).toHaveBeenCalled();
258
- expect(networkingEngine.destroy).toHaveBeenCalled();
259
- expect(parser.stop).toHaveBeenCalled();
260
- await expectAsync(load).toBeRejected();
261
- });
262
240
  });
263
241
 
264
242
  describe('load/unload', () => {
@@ -1503,6 +1481,7 @@ describe('Player', () => {
1503
1481
  frameRate: 1000000 / 42000,
1504
1482
  pixelAspectRatio: '59:54',
1505
1483
  hdr: null,
1484
+ videoLayout: null,
1506
1485
  mimeType: 'video/mp4',
1507
1486
  audioMimeType: 'audio/mp4',
1508
1487
  videoMimeType: 'video/mp4',
@@ -1541,6 +1520,7 @@ describe('Player', () => {
1541
1520
  frameRate: 24,
1542
1521
  pixelAspectRatio: '59:54',
1543
1522
  hdr: null,
1523
+ videoLayout: null,
1544
1524
  mimeType: 'video/mp4',
1545
1525
  audioMimeType: 'audio/mp4',
1546
1526
  videoMimeType: 'video/mp4',
@@ -1579,6 +1559,7 @@ describe('Player', () => {
1579
1559
  frameRate: 1000000 / 42000,
1580
1560
  pixelAspectRatio: '59:54',
1581
1561
  hdr: null,
1562
+ videoLayout: null,
1582
1563
  mimeType: 'video/mp4',
1583
1564
  audioMimeType: 'audio/mp4',
1584
1565
  videoMimeType: 'video/mp4',
@@ -1617,6 +1598,7 @@ describe('Player', () => {
1617
1598
  frameRate: 24,
1618
1599
  pixelAspectRatio: '59:54',
1619
1600
  hdr: null,
1601
+ videoLayout: null,
1620
1602
  mimeType: 'video/mp4',
1621
1603
  audioMimeType: 'audio/mp4',
1622
1604
  videoMimeType: 'video/mp4',
@@ -1655,6 +1637,7 @@ describe('Player', () => {
1655
1637
  frameRate: 1000000 / 42000,
1656
1638
  pixelAspectRatio: '59:54',
1657
1639
  hdr: null,
1640
+ videoLayout: null,
1658
1641
  mimeType: 'video/mp4',
1659
1642
  audioMimeType: 'audio/mp4',
1660
1643
  videoMimeType: 'video/mp4',
@@ -1693,6 +1676,7 @@ describe('Player', () => {
1693
1676
  frameRate: 24,
1694
1677
  pixelAspectRatio: '59:54',
1695
1678
  hdr: null,
1679
+ videoLayout: null,
1696
1680
  mimeType: 'video/mp4',
1697
1681
  audioMimeType: 'audio/mp4',
1698
1682
  videoMimeType: 'video/mp4',
@@ -1731,6 +1715,7 @@ describe('Player', () => {
1731
1715
  frameRate: 1000000 / 42000,
1732
1716
  pixelAspectRatio: '59:54',
1733
1717
  hdr: null,
1718
+ videoLayout: null,
1734
1719
  mimeType: 'video/mp4',
1735
1720
  audioMimeType: 'audio/mp4',
1736
1721
  videoMimeType: 'video/mp4',
@@ -1769,6 +1754,7 @@ describe('Player', () => {
1769
1754
  frameRate: 24,
1770
1755
  pixelAspectRatio: '59:54',
1771
1756
  hdr: null,
1757
+ videoLayout: null,
1772
1758
  mimeType: 'video/mp4',
1773
1759
  audioMimeType: 'audio/mp4',
1774
1760
  videoMimeType: 'video/mp4',
@@ -1826,6 +1812,7 @@ describe('Player', () => {
1826
1812
  frameRate: null,
1827
1813
  pixelAspectRatio: null,
1828
1814
  hdr: null,
1815
+ videoLayout: null,
1829
1816
  videoId: null,
1830
1817
  audioId: null,
1831
1818
  originalAudioId: null,
@@ -1864,6 +1851,7 @@ describe('Player', () => {
1864
1851
  frameRate: null,
1865
1852
  pixelAspectRatio: null,
1866
1853
  hdr: null,
1854
+ videoLayout: null,
1867
1855
  videoId: null,
1868
1856
  audioId: null,
1869
1857
  originalAudioId: null,
@@ -1902,6 +1890,7 @@ describe('Player', () => {
1902
1890
  frameRate: null,
1903
1891
  pixelAspectRatio: null,
1904
1892
  hdr: null,
1893
+ videoLayout: null,
1905
1894
  videoId: null,
1906
1895
  audioId: null,
1907
1896
  originalAudioId: null,
@@ -1943,6 +1932,7 @@ describe('Player', () => {
1943
1932
  frameRate: null,
1944
1933
  pixelAspectRatio: null,
1945
1934
  hdr: null,
1935
+ videoLayout: null,
1946
1936
  videoId: null,
1947
1937
  audioId: null,
1948
1938
  originalAudioId: null,
@@ -4179,6 +4169,69 @@ describe('Player', () => {
4179
4169
  expect(thumbnail8.duration).toBe(10);
4180
4170
  });
4181
4171
  });
4172
+
4173
+ describe('getAllThumbnails', () => {
4174
+ it('returns all thumbnails', async () => {
4175
+ const uris = () => ['thumbnail'];
4176
+ const ref = new shaka.media.SegmentReference(
4177
+ 0, 60, uris, 0, null, null, 0, 0, Infinity, [],
4178
+ );
4179
+ const index = new shaka.media.SegmentIndex([ref]);
4180
+
4181
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
4182
+ manifest.addVariant(0, (variant) => {
4183
+ variant.addVideo(1);
4184
+ });
4185
+ manifest.addImageStream(5, (stream) => {
4186
+ stream.originalId = 'thumbnail';
4187
+ stream.width = 200;
4188
+ stream.height = 150;
4189
+ stream.mimeType = 'image/jpeg';
4190
+ stream.tilesLayout = '2x3';
4191
+ stream.segmentIndex = index;
4192
+ });
4193
+ });
4194
+
4195
+ await player.load(fakeManifestUri, 0, fakeMimeType);
4196
+
4197
+ expect(player.getImageTracks()[0].width).toBe(100);
4198
+ expect(player.getImageTracks()[0].height).toBe(50);
4199
+ const thumbnails = await player.getAllThumbnails(5);
4200
+ expect(thumbnails.length).toBe(6);
4201
+ expect(thumbnails[0]).toEqual(jasmine.objectContaining({
4202
+ imageHeight: 150,
4203
+ imageWidth: 200,
4204
+ positionX: 0,
4205
+ positionY: 0,
4206
+ width: 100,
4207
+ height: 50,
4208
+ }));
4209
+ expect(thumbnails[1]).toEqual(jasmine.objectContaining({
4210
+ imageHeight: 150,
4211
+ imageWidth: 200,
4212
+ positionX: 100,
4213
+ positionY: 0,
4214
+ width: 100,
4215
+ height: 50,
4216
+ }));
4217
+ expect(thumbnails[2]).toEqual(jasmine.objectContaining({
4218
+ imageHeight: 150,
4219
+ imageWidth: 200,
4220
+ positionX: 0,
4221
+ positionY: 50,
4222
+ width: 100,
4223
+ height: 50,
4224
+ }));
4225
+ expect(thumbnails[5]).toEqual(jasmine.objectContaining({
4226
+ imageHeight: 150,
4227
+ imageWidth: 200,
4228
+ positionX: 100,
4229
+ positionY: 100,
4230
+ width: 100,
4231
+ height: 50,
4232
+ }));
4233
+ });
4234
+ });
4182
4235
  });
4183
4236
 
4184
4237
  describe('config streaming.startAtSegmentBoundary', () => {
@@ -147,6 +147,11 @@ shaka.test.FakeMediaSourceEngine = class {
147
147
  return Promise.resolve();
148
148
  }
149
149
 
150
+ /** @override */
151
+ isStreamingAllowed() {
152
+ return true;
153
+ }
154
+
150
155
  /**
151
156
  * @param {string} type
152
157
  * @return {?number}
@@ -49,6 +49,9 @@ shaka.test.FakeNetworkingEngine = class {
49
49
  /** @type {!jasmine.Spy} */
50
50
  this.setForceHTTPS = jasmine.createSpy('setForceHTTPS').and.stub();
51
51
 
52
+ /** @private {number} */
53
+ this.maxUris_ = 1;
54
+
52
55
  // The prototype has already been applied; create spies for the
53
56
  // methods but still call it by default.
54
57
  spyOn(this, 'destroy').and.callThrough();
@@ -67,7 +70,7 @@ shaka.test.FakeNetworkingEngine = class {
67
70
  */
68
71
  requestImpl_(type, request) {
69
72
  expect(request).toBeTruthy();
70
- expect(request.uris.length).toBe(1);
73
+ expect(request.uris.length).toBeLessThanOrEqual(this.maxUris_);
71
74
 
72
75
  const requestedUri = request.uris[0];
73
76
 
@@ -288,6 +291,11 @@ shaka.test.FakeNetworkingEngine = class {
288
291
  return this;
289
292
  }
290
293
 
294
+ setMaxUris(maxUris) {
295
+ this.maxUris_ = maxUris;
296
+ return this;
297
+ }
298
+
291
299
  /**
292
300
  * Expects that a request for the given segment has occurred.
293
301
  *
@@ -78,4 +78,7 @@ shaka.test.FakeSegmentPrefetch = class {
78
78
  }
79
79
  return null;
80
80
  }
81
+
82
+ /** @override */
83
+ prefetchInitSegment(reference) {}
81
84
  };
@@ -556,11 +556,15 @@ shaka.test.ManifestGenerator.Stream = class {
556
556
  /** @type {(string|undefined)} */
557
557
  this.hdr = undefined;
558
558
  /** @type {(string|undefined)} */
559
+ this.videoLayout = undefined;
560
+ /** @type {(string|undefined)} */
559
561
  this.tilesLayout = undefined;
560
562
  /** @type {?shaka.media.ManifestParser.AccessibilityPurpose} */
561
563
  this.accessibilityPurpose;
562
564
  /** @type {boolean} */
563
565
  this.external = false;
566
+ /** @type {boolean} */
567
+ this.fastSwitching = false;
564
568
  }
565
569
 
566
570
  /** @type {shaka.extern.Stream} */
@@ -42,7 +42,7 @@ shaka.test.ManifestParser = class {
42
42
  /**
43
43
  * Creates a segment reference using a relative URI.
44
44
  *
45
- * @param {string} uri A relative URI to http://example.com
45
+ * @param {string|Array.<string>} uri A relative URI to http://example.com
46
46
  * @param {number} start
47
47
  * @param {number} end
48
48
  * @param {string=} baseUri
@@ -57,7 +57,19 @@ shaka.test.ManifestParser = class {
57
57
  static makeReference(uri, start, end, baseUri = '',
58
58
  startByte = 0, endByte = null, timestampOffset = 0,
59
59
  partialReferences = [], tilesLayout = '', syncTime = null) {
60
- const getUris = () => uri.length ? [baseUri + uri] : [];
60
+ const getUris = () => {
61
+ const uris = [];
62
+ if (uri instanceof Array) {
63
+ for (const url of uri) {
64
+ if (url.length) {
65
+ uris.push(baseUri + url);
66
+ }
67
+ }
68
+ } else if (uri.length) {
69
+ uris.push(baseUri + uri);
70
+ }
71
+ return uris;
72
+ };
61
73
 
62
74
  // If a test wants to verify these, they can be set explicitly after
63
75
  // makeReference is called.
@@ -59,6 +59,7 @@ shaka.test.OfflineUtils = class {
59
59
  spatialAudio: false,
60
60
  closedCaptions: null,
61
61
  external: false,
62
+ fastSwitching: false,
62
63
  };
63
64
  }
64
65
 
@@ -529,7 +529,7 @@ shaka.test.FakeTransmuxer = class {
529
529
  jasmine.createSpy('transmux').and.returnValue(Promise.resolve(output));
530
530
 
531
531
  /** @type {!jasmine.Spy} */
532
- this.getOrginalMimeType =
533
- jasmine.createSpy('getOrginalMimeType').and.returnValue('mimeType');
532
+ this.getOriginalMimeType =
533
+ jasmine.createSpy('getOriginalMimeType').and.returnValue('mimeType');
534
534
  }
535
535
  };
@@ -417,6 +417,7 @@ shaka.test.StreamingEngineUtil = class {
417
417
  spatialAudio: false,
418
418
  accessibilityPurpose: null,
419
419
  external: false,
420
+ fastSwitching: false,
420
421
  };
421
422
  }
422
423
 
@@ -459,6 +460,7 @@ shaka.test.StreamingEngineUtil = class {
459
460
  spatialAudio: false,
460
461
  accessibilityPurpose: null,
461
462
  external: false,
463
+ fastSwitching: false,
462
464
  };
463
465
  }
464
466
 
@@ -498,6 +500,7 @@ shaka.test.StreamingEngineUtil = class {
498
500
  spatialAudio: false,
499
501
  accessibilityPurpose: null,
500
502
  external: false,
503
+ fastSwitching: false,
501
504
  };
502
505
  }
503
506
  };
@@ -763,6 +763,12 @@ shaka.test.TestScheme.ManifestParser = class {
763
763
 
764
764
  /** @override */
765
765
  onExpirationUpdated() {}
766
+
767
+ /** @override */
768
+ onInitialVariantChosen() {}
769
+
770
+ /** @override */
771
+ banLocation() {}
766
772
  };
767
773
 
768
774
 
@@ -9,10 +9,11 @@ shaka.test.UiUtils = class {
9
9
  * @param {!HTMLElement} videoContainer
10
10
  * @param {!HTMLMediaElement} video
11
11
  * @param {!Object=} config
12
- * @return {!shaka.ui.Overlay}
12
+ * @return {!Promise.<!shaka.ui.Overlay>}
13
13
  */
14
- static createUIThroughAPI(videoContainer, video, config) {
15
- const player = new shaka.Player(video);
14
+ static async createUIThroughAPI(videoContainer, video, config) {
15
+ const player = new shaka.Player();
16
+ await player.attach(video);
16
17
  // Create UI
17
18
  config = config || {};
18
19
  const ui = new shaka.ui.Overlay(player, videoContainer, video);
@@ -43,7 +43,7 @@ describe('Mp4TtmlParser', () => {
43
43
  parser.parseInit(ttmlInitSegment);
44
44
  const time =
45
45
  {periodStart: 0, segmentStart: 0, segmentEnd: 60, vttOffset: 0};
46
- const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time);
46
+ const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time, null);
47
47
  // Bodies.
48
48
  expect(ret.length).toBe(2);
49
49
  // Divs.
@@ -63,10 +63,10 @@ describe('Mp4TtmlParser', () => {
63
63
  const parser = new shaka.text.Mp4TtmlParser();
64
64
  parser.parseInit(ttmlInitSegment);
65
65
 
66
- const ret1 = parser.parseMedia(ttmlSegment, time1);
66
+ const ret1 = parser.parseMedia(ttmlSegment, time1, null);
67
67
  expect(ret1.length).toBeGreaterThan(0);
68
68
 
69
- const ret2 = parser.parseMedia(ttmlSegment, time2);
69
+ const ret2 = parser.parseMedia(ttmlSegment, time2, null);
70
70
  expect(ret2.length).toBeGreaterThan(0);
71
71
 
72
72
  expect(ret2[0].startTime).toBe(ret1[0].startTime + 7);
@@ -164,7 +164,7 @@ describe('Mp4TtmlParser', () => {
164
164
  parser.parseInit(ttmlInitSegment);
165
165
  const time =
166
166
  {periodStart: 0, segmentStart: 0, segmentEnd: 60, vttOffset: 0};
167
- const result = parser.parseMedia(ttmlSegment, time);
167
+ const result = parser.parseMedia(ttmlSegment, time, null);
168
168
  shaka.test.TtmlUtils.verifyHelper(
169
169
  cues, result, {startTime: 23, endTime: 53.5});
170
170
  });
@@ -149,7 +149,7 @@ describe('SrtTextParser', () => {
149
149
  const data = BufferUtils.toUint8(StringUtils.toUTF8(text));
150
150
 
151
151
  const parser = new shaka.text.SrtTextParser();
152
- const result = parser.parseMedia(data, time);
152
+ const result = parser.parseMedia(data, time, null);
153
153
 
154
154
  const expected = cues.map((cue) => {
155
155
  if (cue.nestedCues) {
@@ -37,7 +37,7 @@ filterDescribe('Cue layout', shaka.test.TextLayoutTests.supported, () => {
37
37
  // Set up UI controls. The video element is in a paused state by
38
38
  // default, so the controls should be shown. The video is not in the
39
39
  // DOM and is purely temporary.
40
- const player = new shaka.Player(null);
40
+ const player = new shaka.Player();
41
41
  ui = new shaka.ui.Overlay(
42
42
  player, /** @type {!HTMLElement} */(helper.videoContainer),
43
43
  shaka.test.UiUtils.createVideoElement());
@@ -105,6 +105,7 @@ describe('TextEngine', () => {
105
105
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
106
106
  dummyData,
107
107
  {periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
108
+ undefined,
108
109
  ]);
109
110
 
110
111
  expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
@@ -120,6 +121,7 @@ describe('TextEngine', () => {
120
121
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
121
122
  dummyData,
122
123
  {periodStart: 0, segmentStart: 3, segmentEnd: 5, vttOffset: 0},
124
+ undefined,
123
125
  ]);
124
126
 
125
127
  expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
@@ -272,6 +274,7 @@ describe('TextEngine', () => {
272
274
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
273
275
  dummyData,
274
276
  {periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
277
+ undefined,
275
278
  ]);
276
279
  expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
277
280
  [
@@ -286,6 +289,7 @@ describe('TextEngine', () => {
286
289
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
287
290
  dummyData,
288
291
  {periodStart: 4, segmentStart: 4, segmentEnd: 7, vttOffset: 4},
292
+ undefined,
289
293
  ]);
290
294
  expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
291
295
  [
@@ -316,6 +320,7 @@ describe('TextEngine', () => {
316
320
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
317
321
  dummyData,
318
322
  {periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
323
+ undefined,
319
324
  ]);
320
325
 
321
326
  textEngine.setTimestampOffset(8);
@@ -325,6 +330,7 @@ describe('TextEngine', () => {
325
330
  expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
326
331
  dummyData,
327
332
  {periodStart: 8, segmentStart: 4, segmentEnd: 7, vttOffset: 4},
333
+ undefined,
328
334
  ]);
329
335
  });
330
336
  });
@@ -1263,6 +1263,35 @@ describe('TtmlTextParser', () => {
1263
1263
  });
1264
1264
  });
1265
1265
 
1266
+ it('supports smpte:backgroundImage attribute with url', () => {
1267
+ verifyHelper(
1268
+ [
1269
+ {
1270
+ startTime: 62.05,
1271
+ endTime: 3723.2,
1272
+ payload: '',
1273
+ },
1274
+ ],
1275
+ '<tt ' +
1276
+ 'xmlns:ttm="http://www.w3.org/ns/ttml#metadata" ' +
1277
+ 'xmlns:smpte="http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt">' +
1278
+ '<metadata>' +
1279
+ '<smpte:image imageType="PNG" encoding="Base64" xml:id="img_0">' +
1280
+ 'base64EncodedImage</smpte:image>' +
1281
+ '</metadata>' +
1282
+ '<body><div smpte:backgroundImage="img_0.png">' +
1283
+ '<p begin="01:02.05" end="01:02:03.200"></p>' +
1284
+ '</div></body></tt>',
1285
+ {periodStart: 0, segmentStart: 60, segmentEnd: 3730, vttOffset: 0},
1286
+ {startTime: 62.05, endTime: 3723.2},
1287
+ {
1288
+ startTime: 62.05,
1289
+ endTime: 3723.2,
1290
+ backgroundImage: 'foo://bar/img_0.png',
1291
+ isContainer: false,
1292
+ });
1293
+ });
1294
+
1266
1295
  it('supports smpte:backgroundImage attribute in div element', () => {
1267
1296
  verifyHelper(
1268
1297
  [],
@@ -2112,7 +2141,8 @@ describe('TtmlTextParser', () => {
2112
2141
  function verifyHelper(cues, text, time, bodyProperties, divProperties) {
2113
2142
  const data =
2114
2143
  shaka.util.BufferUtils.toUint8(shaka.util.StringUtils.toUTF8(text));
2115
- const result = new shaka.text.TtmlTextParser().parseMedia(data, time);
2144
+ const result = new shaka.text.TtmlTextParser()
2145
+ .parseMedia(data, time, 'foo://bar');
2116
2146
  shaka.test.TtmlUtils.verifyHelper(
2117
2147
  cues, result, bodyProperties, divProperties);
2118
2148
  }
@@ -2139,7 +2169,8 @@ describe('TtmlTextParser', () => {
2139
2169
  expect(() => {
2140
2170
  new shaka.text.TtmlTextParser().parseMedia(
2141
2171
  shaka.util.BufferUtils.toUint8(data),
2142
- {periodStart: 0, segmentStart: 0, segmentEnd: 10, vttOffset: 0});
2172
+ {periodStart: 0, segmentStart: 0, segmentEnd: 10, vttOffset: 0},
2173
+ 'foo://bar');
2143
2174
  }).toThrow(error);
2144
2175
  }
2145
2176
  });
@@ -56,5 +56,14 @@ describe('TransmuxerEngine', () => {
56
56
  ContentType.VIDEO, 'video/MP2T; codecs="avc1.420001"'))
57
57
  .toBe('video/mp4; codecs="avc1.420001"');
58
58
  });
59
+
60
+ it('converts legacy avc1 codec strings', () => {
61
+ expect(convertCodecs(
62
+ ContentType.VIDEO, 'video/mp2t; codecs="avc1.100.42"'))
63
+ .toBe('video/mp4; codecs="avc1.64002a"');
64
+ expect(convertCodecs(
65
+ ContentType.VIDEO, 'video/mp2t; codecs="avc1.66.1"'))
66
+ .toBe('video/mp4; codecs="avc1.420001"');
67
+ });
59
68
  });
60
69
  });
@@ -4,7 +4,36 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- describe('Transmuxer Player', () => {
7
+ /**
8
+ * For unknown reasons, these tests fail in the test labs for Edge on Windows,
9
+ * in ways that do not seem to be unrelated to transmuxers.
10
+ * Practical testing has not found any sign that playback is actually broken in
11
+ * Edge, so these tests are disabled on Edge for the time being.
12
+ * TODO(#5834): Remove this filter once the tests are fixed.
13
+ * @return {boolean}
14
+ */
15
+ function checkNoBrokenEdge() {
16
+ const chromeVersion = shaka.util.Platform.chromeVersion();
17
+ if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() &&
18
+ chromeVersion && chromeVersion <= 118) {
19
+ // When the tests fail, it's due to the manifest parser failing to find a
20
+ // factory. Attempt to find a factory first, to avoid filtering the tests
21
+ // when running in a non-broken Edge environment.
22
+ const uri = 'fakeuri.m3u8';
23
+ const mimeType = 'application/x-mpegurl';
24
+ /* eslint-disable no-restricted-syntax */
25
+ try {
26
+ shaka.media.ManifestParser.getFactory(uri, mimeType);
27
+ return true;
28
+ } catch (error) {
29
+ return false;
30
+ }
31
+ /* eslint-enable no-restricted-syntax */
32
+ }
33
+ return true;
34
+ }
35
+
36
+ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => {
8
37
  const Util = shaka.test.Util;
9
38
 
10
39
  /** @type {!jasmine.Spy} */
@@ -73,7 +102,8 @@ describe('Transmuxer Player', () => {
73
102
 
74
103
  beforeEach(async () => {
75
104
  await shaka.test.TestScheme.createManifests(compiledShaka, '_compiled');
76
- player = new compiledShaka.Player(video);
105
+ player = new compiledShaka.Player();
106
+ await player.attach(video);
77
107
 
78
108
  player.configure('mediaSource.forceTransmux', true);
79
109
  player.configure('streaming.useNativeHlsOnSafari', false);
@@ -161,7 +191,7 @@ describe('Transmuxer Player', () => {
161
191
  pending('Codec EC-3 is not supported by the platform.');
162
192
  }
163
193
 
164
- await player.load('/base/test/test/assets/hls-raw-ac3/prog_index.m3u8');
194
+ await player.load('/base/test/test/assets/hls-raw-ec3/prog_index.m3u8');
165
195
  await video.play();
166
196
  expect(player.isLive()).toBe(false);
167
197
 
@@ -25,14 +25,14 @@ describe('Ad UI', () => {
25
25
  shaka.Player.setAdManagerFactory(() => new shaka.test.FakeAdManager());
26
26
  });
27
27
 
28
- beforeEach(() => {
28
+ beforeEach(async () => {
29
29
  container =
30
30
  /** @type {!HTMLElement} */ (document.createElement('div'));
31
31
  document.body.appendChild(container);
32
32
 
33
33
  video = shaka.test.UiUtils.createVideoElement();
34
34
  container.appendChild(video);
35
- UiUtils.createUIThroughAPI(container, video);
35
+ await UiUtils.createUIThroughAPI(container, video);
36
36
  adManager = video['ui'].getControls().getPlayer().getAdManager();
37
37
  });
38
38