shaka-player 4.4.2 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +67 -25
  3. package/README.md +16 -10
  4. package/demo/asset_card.js +18 -21
  5. package/demo/cast_receiver/index.html +0 -1
  6. package/demo/close_button.js +0 -3
  7. package/demo/common/asset.js +27 -5
  8. package/demo/common/assets.js +150 -52
  9. package/demo/config.js +192 -253
  10. package/demo/custom.js +39 -98
  11. package/demo/front.js +7 -10
  12. package/demo/index.html +19 -22
  13. package/demo/input.js +6 -11
  14. package/demo/input_container.js +8 -9
  15. package/demo/main.js +52 -124
  16. package/demo/search.js +23 -35
  17. package/demo/service_worker.js +0 -3
  18. package/demo/tooltip.js +3 -5
  19. package/demo/visualizer.js +3 -5
  20. package/demo/visualizer_button.js +1 -20
  21. package/dist/demo.compiled.debug.js +187 -211
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +187 -211
  24. package/dist/demo.compiled.map +4 -4
  25. package/dist/deps.js +27 -24
  26. package/dist/locales.js +31 -31
  27. package/dist/receiver.compiled.debug.js +42 -61
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +42 -61
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +728 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +728 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +475 -51
  34. package/dist/shaka-player.compiled.debug.js +576 -480
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +475 -51
  37. package/dist/shaka-player.compiled.js +1117 -1056
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +783 -410
  40. package/dist/shaka-player.ui.debug.d.ts +783 -410
  41. package/dist/shaka-player.ui.debug.externs.js +496 -51
  42. package/dist/shaka-player.ui.debug.js +647 -542
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +496 -51
  45. package/dist/shaka-player.ui.js +1260 -1194
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/lcevc-integration.md +14 -14
  48. package/docs/tutorials/faq.md +27 -55
  49. package/docs/tutorials/index.json +2 -1
  50. package/docs/tutorials/lcevc.md +118 -0
  51. package/docs/tutorials/offline.md +1 -1
  52. package/docs/tutorials/ui-customization.md +4 -0
  53. package/externs/css_style_declaration.js +19 -0
  54. package/externs/lcevc.js +37 -13
  55. package/externs/media_remote.js +68 -0
  56. package/externs/mediatailor.js +193 -0
  57. package/externs/pictureinpicture.js +11 -0
  58. package/externs/shaka/ads.js +27 -0
  59. package/externs/shaka/manifest.js +10 -5
  60. package/externs/shaka/manifest_parser.js +7 -1
  61. package/externs/shaka/offline.js +4 -0
  62. package/externs/shaka/player.js +12 -1
  63. package/karma.conf.js +7 -3
  64. package/lib/abr/simple_abr_manager.js +43 -3
  65. package/lib/ads/ad_manager.js +104 -50
  66. package/lib/ads/media_tailor_ad.js +297 -0
  67. package/lib/ads/media_tailor_ad_manager.js +828 -0
  68. package/lib/cea/ts_cea_parser.js +15 -2
  69. package/lib/config/codec_switching_strategy.js +24 -0
  70. package/lib/dash/content_protection.js +120 -2
  71. package/lib/dash/dash_parser.js +79 -13
  72. package/lib/dash/mpd_utils.js +10 -6
  73. package/lib/dash/segment_base.js +13 -5
  74. package/lib/dash/segment_list.js +13 -5
  75. package/lib/dash/segment_template.js +43 -85
  76. package/lib/dependencies/all.js +8 -7
  77. package/lib/hls/hls_parser.js +101 -37
  78. package/lib/lcevc/lcevc_dec.js +220 -0
  79. package/lib/media/adaptation_set.js +22 -11
  80. package/lib/media/adaptation_set_criteria.js +25 -7
  81. package/lib/media/media_source_engine.js +215 -27
  82. package/lib/media/segment_index.js +5 -5
  83. package/lib/media/segment_reference.js +10 -5
  84. package/lib/media/streaming_engine.js +44 -39
  85. package/lib/mss/mss_parser.js +1 -0
  86. package/lib/net/networking_engine.js +1 -0
  87. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  88. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  89. package/lib/offline/manifest_converter.js +1 -0
  90. package/lib/offline/storage.js +3 -0
  91. package/lib/player.js +142 -72
  92. package/lib/routing/payload.js +5 -1
  93. package/lib/text/cue.js +62 -47
  94. package/lib/text/ttml_text_parser.js +17 -0
  95. package/lib/text/ui_text_displayer.js +4 -0
  96. package/lib/text/vtt_text_parser.js +35 -22
  97. package/lib/transmuxer/h265.js +862 -0
  98. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  99. package/lib/transmuxer/ts_transmuxer.js +160 -15
  100. package/lib/util/cmcd_manager.js +6 -1
  101. package/lib/util/error.js +28 -9
  102. package/lib/util/exp_golomb.js +30 -2
  103. package/lib/util/fake_event.js +3 -0
  104. package/lib/util/manifest_parser_utils.js +10 -4
  105. package/lib/util/mp4_generator.js +4 -4
  106. package/lib/util/periods.js +2 -0
  107. package/lib/util/platform.js +54 -0
  108. package/lib/util/player_configuration.js +8 -0
  109. package/lib/util/state_history.js +6 -2
  110. package/lib/util/stream_utils.js +133 -217
  111. package/lib/util/ts_parser.js +229 -43
  112. package/maintained-branches.md +3 -2
  113. package/package.json +4 -6
  114. package/roadmap.md +15 -5
  115. package/shaka-player.uncompiled.js +2 -1
  116. package/support.html +0 -1
  117. package/test/cast/cast_receiver_integration.js +47 -0
  118. package/test/codec_switching/codec_switching_integration.js +181 -0
  119. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  120. package/test/dash/dash_parser_integration.js +73 -0
  121. package/test/dash/dash_parser_live_unit.js +2 -0
  122. package/test/dash/dash_parser_manifest_unit.js +47 -0
  123. package/test/dash/dash_parser_segment_base_unit.js +7 -0
  124. package/test/dash/dash_parser_segment_list_unit.js +23 -17
  125. package/test/dash/dash_parser_segment_template_unit.js +49 -0
  126. package/test/demo/demo_unit.js +0 -16
  127. package/test/hls/hls_live_unit.js +35 -0
  128. package/test/hls/hls_parser_unit.js +8 -61
  129. package/test/media/adaptation_set_criteria_unit.js +118 -0
  130. package/test/media/adaptation_set_unit.js +1 -0
  131. package/test/media/media_source_engine_unit.js +165 -1
  132. package/test/media/segment_index_unit.js +4 -4
  133. package/test/media/segment_prefetch_unit.js +1 -1
  134. package/test/media/streaming_engine_unit.js +17 -17
  135. package/test/mss/mss_parser_unit.js +2 -0
  136. package/test/offline/manifest_convert_unit.js +5 -0
  137. package/test/offline/storage_integration.js +1 -4
  138. package/test/player_unit.js +102 -131
  139. package/test/routing/walker_unit.js +1 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  143. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  144. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  145. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  146. package/test/test/assets/dash-aes-128/license +1 -0
  147. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  148. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  149. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  150. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  151. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  153. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  154. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  155. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  166. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  167. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  175. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  176. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  177. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  178. package/test/test/util/dash_parser_util.js +20 -7
  179. package/test/test/util/fake_ad_manager.js +20 -0
  180. package/test/test/util/fake_media_source_engine.js +8 -2
  181. package/test/test/util/manifest_generator.js +7 -3
  182. package/test/test/util/mss_parser_util.js +4 -0
  183. package/test/test/util/offline_utils.js +1 -0
  184. package/test/test/util/streaming_engine_util.js +7 -4
  185. package/test/text/ttml_text_parser_unit.js +52 -0
  186. package/test/text/vtt_text_parser_unit.js +105 -48
  187. package/test/transmuxer/transmuxer_integration.js +121 -4
  188. package/test/ui/ui_unit.js +3 -10
  189. package/test/util/stream_utils_unit.js +208 -74
  190. package/test/util/ts_parser_unit.js +1 -1
  191. package/ui/controls.js +125 -0
  192. package/ui/externs/ui.js +8 -1
  193. package/ui/pip_button.js +22 -120
  194. package/ui/remote_button.js +201 -0
  195. package/ui/ui.js +5 -2
  196. package/demo/common/message_ids.js +0 -309
  197. package/demo/locales/en.json +0 -287
  198. package/demo/locales/source.json +0 -1142
  199. package/externs/mux.js +0 -69
  200. package/lib/lcevc/lcevc_dil.js +0 -152
  201. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  202. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -36,8 +36,8 @@ describe('Transmuxer Player', () => {
36
36
  // We must enable this, once it is resolved:
37
37
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313
38
38
  const chromeVersion = shaka.util.Platform.chromeVersion();
39
- if (shaka.util.Platform.isEdge() &&
40
- chromeVersion && chromeVersion <= 116) {
39
+ if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() &&
40
+ chromeVersion && chromeVersion <= 118) {
41
41
  return false;
42
42
  }
43
43
  return true;
@@ -57,8 +57,8 @@ describe('Transmuxer Player', () => {
57
57
  // We must enable this, once it is resolved:
58
58
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313
59
59
  const chromeVersion = shaka.util.Platform.chromeVersion();
60
- if (shaka.util.Platform.isEdge() &&
61
- chromeVersion && chromeVersion <= 116) {
60
+ if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() &&
61
+ chromeVersion && chromeVersion <= 118) {
62
62
  return false;
63
63
  }
64
64
  return true;
@@ -273,6 +273,33 @@ describe('Transmuxer Player', () => {
273
273
 
274
274
  await player.unload();
275
275
  });
276
+
277
+ it('H.265 in TS', async () => {
278
+ const chromeVersion = shaka.util.Platform.chromeVersion();
279
+ if (shaka.util.Platform.isWindows() &&
280
+ chromeVersion && chromeVersion === 117) {
281
+ // It appears that Chrome 117 beta in Windows is incorrectly reporting
282
+ // H.265 in MediaCapabilities
283
+ pending('Codec H.265 is not supported by the platform.');
284
+ }
285
+ const mimeType = 'video/mp4; codecs="hvc1.2.4.L123.B0"';
286
+ if (!MediaSource.isTypeSupported(mimeType)) {
287
+ pending('Codec H.265 is not supported by the platform.');
288
+ }
289
+ await player.load('/base/test/test/assets/hls-ts-h265/hevc.m3u8');
290
+ await video.play();
291
+ expect(player.isLive()).toBe(false);
292
+
293
+ // Wait for the video to start playback. If it takes longer than 10
294
+ // seconds, fail the test.
295
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
296
+
297
+ // Play for 15 seconds, but stop early if the video ends. If it takes
298
+ // longer than 45 seconds, fail the test.
299
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 15, 45);
300
+
301
+ await player.unload();
302
+ });
276
303
  });
277
304
 
278
305
  describe('for muxed content', () => {
@@ -292,5 +319,95 @@ describe('Transmuxer Player', () => {
292
319
 
293
320
  await player.unload();
294
321
  });
322
+
323
+ it('H.265+AAC in TS', async () => {
324
+ const chromeVersion = shaka.util.Platform.chromeVersion();
325
+ if (shaka.util.Platform.isWindows() &&
326
+ chromeVersion && chromeVersion === 117) {
327
+ // It appears that Chrome 117 beta in Windows is incorrectly reporting
328
+ // H.265 in MediaCapabilities
329
+ pending('Codec H.265 is not supported by the platform.');
330
+ }
331
+ if (!MediaSource.isTypeSupported('video/mp4; codecs="hvc1.1.6.L93.90"')) {
332
+ pending('Codec H.265 is not supported by the platform.');
333
+ }
334
+ // eslint-disable-next-line max-len
335
+ await player.load('/base/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8');
336
+ await video.play();
337
+ expect(player.isLive()).toBe(false);
338
+
339
+ // Wait for the video to start playback. If it takes longer than 10
340
+ // seconds, fail the test.
341
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
342
+
343
+ // Play for 15 seconds, but stop early if the video ends. If it takes
344
+ // longer than 45 seconds, fail the test.
345
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 15, 45);
346
+
347
+ await player.unload();
348
+ });
349
+
350
+ it('H.264+MP3 in TS', async () => {
351
+ if (!MediaSource.isTypeSupported('audio/mp4; codecs="mp3"')) {
352
+ pending('Codec MP3 in MP4 is not supported by the platform.');
353
+ }
354
+
355
+ // eslint-disable-next-line max-len
356
+ await player.load('/base/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8');
357
+ await video.play();
358
+ expect(player.isLive()).toBe(false);
359
+
360
+ // Wait for the video to start playback. If it takes longer than 10
361
+ // seconds, fail the test.
362
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
363
+
364
+ // Play for 15 seconds, but stop early if the video ends. If it takes
365
+ // longer than 45 seconds, fail the test.
366
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 15, 45);
367
+
368
+ await player.unload();
369
+ });
370
+
371
+ it('H.264+AC3 in TS', async () => {
372
+ if (!isAc3Supported()) {
373
+ pending('Codec AC-3 is not supported by the platform.');
374
+ }
375
+
376
+ // eslint-disable-next-line max-len
377
+ await player.load('/base/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8');
378
+ await video.play();
379
+ expect(player.isLive()).toBe(false);
380
+
381
+ // Wait for the video to start playback. If it takes longer than 10
382
+ // seconds, fail the test.
383
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
384
+
385
+ // Play for 15 seconds, but stop early if the video ends. If it takes
386
+ // longer than 45 seconds, fail the test.
387
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 15, 45);
388
+
389
+ await player.unload();
390
+ });
391
+
392
+ it('H.264+EC3 in TS', async () => {
393
+ if (!isEc3Supported()) {
394
+ pending('Codec EC-3 is not supported by the platform.');
395
+ }
396
+
397
+ // eslint-disable-next-line max-len
398
+ await player.load('/base/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8');
399
+ await video.play();
400
+ expect(player.isLive()).toBe(false);
401
+
402
+ // Wait for the video to start playback. If it takes longer than 10
403
+ // seconds, fail the test.
404
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
405
+
406
+ // Play for 15 seconds, but stop early if the video ends. If it takes
407
+ // longer than 45 seconds, fail the test.
408
+ await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 15, 45);
409
+
410
+ await player.unload();
411
+ });
295
412
  });
296
413
  });
@@ -616,19 +616,10 @@ describe('UI', () => {
616
616
  player.configure('abr.enabled', false);
617
617
 
618
618
  const tracks = player.getVariantTracks();
619
- const en2 =
620
- tracks.find((t) => t.language == 'en' && t.channelsCount == 2);
621
619
  const en1 =
622
620
  tracks.find((t) => t.language == 'en' && t.channelsCount == 1);
623
621
  const es = tracks.find((t) => t.language == 'es');
624
622
 
625
- // There are 3 variants with English 2-channel, but one is a duplicate
626
- // and shouldn't appear in the list.
627
- goog.asserts.assert(en2, 'Unable to find tracks');
628
- player.selectVariantTrack(en2, true);
629
- await updateResolutionMenu();
630
- expect(getResolutions()).toEqual(['240p', '480p']);
631
-
632
623
  // There is 1 variant with English 1-channel.
633
624
  goog.asserts.assert(en1, 'Unable to find tracks');
634
625
  player.selectVariantTrack(en1, true);
@@ -646,7 +637,9 @@ describe('UI', () => {
646
637
  const manifest =
647
638
  shaka.test.ManifestGenerator.generate((manifest) => {
648
639
  manifest.addVariant(0, (variant) => {
649
- variant.addAudio(0);
640
+ variant.addAudio(0, (stream) => {
641
+ stream.roles = ['main'];
642
+ });
650
643
  variant.bandwidth = 100000;
651
644
  });
652
645
  manifest.addVariant(1, (variant) => {
@@ -636,7 +636,8 @@ describe('StreamUtils', () => {
636
636
 
637
637
  const noVariant = null;
638
638
  await shaka.util.StreamUtils.filterManifest(
639
- fakeDrmEngine, noVariant, manifest);
639
+ fakeDrmEngine, noVariant, manifest,
640
+ shaka.config.CodecSwitchingStrategy.RELOAD);
640
641
 
641
642
  // Covers a regression in which we would remove streams with codecs.
642
643
  // The last two streams should be removed because their full MIME types
@@ -673,7 +674,8 @@ describe('StreamUtils', () => {
673
674
 
674
675
  const noVariant = null;
675
676
  await shaka.util.StreamUtils.filterManifest(
676
- fakeDrmEngine, noVariant, manifest);
677
+ fakeDrmEngine, noVariant, manifest,
678
+ shaka.config.CodecSwitchingStrategy.RELOAD);
677
679
 
678
680
  // Covers a regression in which we would remove streams with codecs.
679
681
  // The first 4 streams should be there because they are always supported.
@@ -691,6 +693,38 @@ describe('StreamUtils', () => {
691
693
  jasmine.objectContaining({id: 5}));
692
694
  });
693
695
 
696
+ it('does not filter manifest when codec switching is enabled', async () => {
697
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
698
+ manifest.addVariant(1, (variant) => {
699
+ variant.addAudio(10, (stream) => {
700
+ stream.codecs = 'mp4a.69';
701
+ });
702
+ variant.addVideo(11, (stream) => {
703
+ stream.codecs = 'avc1';
704
+ });
705
+ });
706
+ });
707
+
708
+ const originalFilterManifestByCurrentVariant =
709
+ shaka.util.StreamUtils.filterManifestByCurrentVariant;
710
+
711
+ try {
712
+ const filterManifestByCurrentVariantSpy =
713
+ jasmine.createSpy('filterManifestByCurrentVariant');
714
+ shaka.util.StreamUtils.filterManifestByCurrentVariant =
715
+ shaka.test.Util.spyFunc(filterManifestByCurrentVariantSpy);
716
+
717
+ await shaka.util.StreamUtils.filterManifest(
718
+ fakeDrmEngine, /* currentVariant= */ null, manifest,
719
+ shaka.config.CodecSwitchingStrategy.RELOAD);
720
+
721
+ expect(filterManifestByCurrentVariantSpy).not.toHaveBeenCalled();
722
+ } finally {
723
+ shaka.util.StreamUtils.filterManifestByCurrentVariant =
724
+ originalFilterManifestByCurrentVariant;
725
+ }
726
+ });
727
+
694
728
  it('filters transport streams', async () => {
695
729
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
696
730
  manifest.addVariant(0, (variant) => {
@@ -705,7 +739,8 @@ describe('StreamUtils', () => {
705
739
  });
706
740
 
707
741
  await shaka.util.StreamUtils.filterManifest(
708
- fakeDrmEngine, /* currentVariant= */ null, manifest);
742
+ fakeDrmEngine, /* currentVariant= */ null, manifest,
743
+ shaka.config.CodecSwitchingStrategy.RELOAD);
709
744
 
710
745
  // Covers a regression in which we would remove streams with codecs.
711
746
  // The last two streams should be removed because their full MIME types
@@ -732,7 +767,8 @@ describe('StreamUtils', () => {
732
767
  });
733
768
 
734
769
  await shaka.util.StreamUtils.filterManifest(
735
- fakeDrmEngine, /* currentVariant= */ null, manifest);
770
+ fakeDrmEngine, /* currentVariant= */ null, manifest,
771
+ shaka.config.CodecSwitchingStrategy.RELOAD);
736
772
  expect(manifest.variants.length).toBe(1);
737
773
  });
738
774
 
@@ -749,7 +785,8 @@ describe('StreamUtils', () => {
749
785
  });
750
786
 
751
787
  await shaka.util.StreamUtils.filterManifest(
752
- fakeDrmEngine, /* currentVariant= */ null, manifest);
788
+ fakeDrmEngine, /* currentVariant= */ null, manifest,
789
+ shaka.config.CodecSwitchingStrategy.RELOAD);
753
790
 
754
791
  expect(manifest.variants.length).toBe(1);
755
792
  });
@@ -813,148 +850,245 @@ describe('StreamUtils', () => {
813
850
  });
814
851
 
815
852
  await shaka.util.StreamUtils.filterManifest(
816
- fakeDrmEngine, /* currentVariant= */ null, manifest);
853
+ fakeDrmEngine, /* currentVariant= */ null, manifest,
854
+ shaka.config.CodecSwitchingStrategy.RELOAD);
817
855
 
818
856
  expect(manifest.variants.length).toBe(1);
819
857
  });
820
858
  });
821
859
 
822
860
  describe('chooseCodecsAndFilterManifest', () => {
823
- const avc1Codecs = 'avc1.640028';
824
- const vp09Codecs = 'vp09.00.40.08.00.02.02.02.00';
825
-
826
- const addVariant1080Avc1 = (manifest) => {
861
+ const addVariant720Avc1 = (manifest) => {
827
862
  manifest.addVariant(0, (variant) => {
828
863
  variant.bandwidth = 5058558;
829
864
  variant.addAudio(1, (stream) => {
830
865
  stream.bandwidth = 129998;
831
- stream.codecs = 'opus';
866
+ stream.mime('audio/mp4', 'mp4a.40.2');
832
867
  });
833
868
  variant.addVideo(2, (stream) => {
834
869
  stream.bandwidth = 4928560;
835
- stream.codecs = avc1Codecs;
836
- stream.size(1920, 1080);
870
+ stream.size(1280, 720);
871
+ stream.mime('video/mp4', 'avc1.640028');
837
872
  });
838
873
  });
839
874
  };
840
875
 
841
- const addVariant1080Vp9 = (manifest) => {
876
+ const addVariant720Vp9 = (manifest) => {
842
877
  manifest.addVariant(3, (variant) => {
843
878
  variant.bandwidth = 4911000;
844
879
  variant.addAudio(4, (stream) => {
845
880
  stream.bandwidth = 129998;
846
- stream.codecs = 'vorbis';
881
+ stream.mime('audio/webm', 'vorbis');
847
882
  });
848
883
  variant.addVideo(5, (stream) => {
849
884
  stream.bandwidth = 4781002;
850
- stream.codecs = vp09Codecs;
851
- stream.size(1920, 1080);
885
+ stream.size(1280, 720);
886
+ stream.mime('video/webm', 'vp9');
852
887
  });
853
888
  });
854
889
  };
855
890
 
856
- const addVariant2160Vp9 = (manifest) => {
891
+ const addVariant1080Vp9 = (manifest) => {
857
892
  manifest.addVariant(6, (variant) => {
858
893
  variant.bandwidth = 10850316;
859
- variant.addAudio(7, (stream) => {
894
+ variant.addAudio(1, (stream) => {
860
895
  stream.bandwidth = 129998;
861
- stream.codecs = 'opus';
896
+ stream.mime('audio/mp4', 'mp4a.40.2');
862
897
  });
863
898
  variant.addVideo(8, (stream) => {
864
899
  stream.bandwidth = 10784324;
865
- stream.codecs = vp09Codecs;
866
- stream.size(3840, 2160);
900
+ stream.size(1920, 1080);
901
+ stream.mime('video/webm', 'vp9');
867
902
  });
868
903
  });
869
904
  };
870
905
 
906
+ it('should filter variants by the best available bandwidth' +
907
+ ' for video resolution', () => {
908
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
909
+ manifest.addVariant(0, (variant) => {
910
+ variant.bandwidth = 4058558;
911
+ variant.addVideo(1, (stream) => {
912
+ stream.bandwidth = 300000;
913
+ stream.size(10, 10);
914
+ });
915
+ });
916
+ manifest.addVariant(2, (variant) => {
917
+ variant.bandwidth = 4781002;
918
+ variant.addVideo(3, (stream) => {
919
+ stream.bandwidth = 400000;
920
+ stream.size(10, 10);
921
+ });
922
+ });
923
+ manifest.addVariant(4, (variant) => {
924
+ variant.addVideo(5, (stream) => {
925
+ stream.bandwidth = 500000;
926
+ stream.size(20, 20);
927
+ });
928
+ });
929
+ manifest.addVariant(6, (variant) => {
930
+ variant.addVideo(7, (stream) => {
931
+ stream.bandwidth = 600000;
932
+ stream.size(20, 20);
933
+ });
934
+ });
935
+ });
936
+
937
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
938
+ /* preferredVideoCodecs= */[],
939
+ /* preferredAudioCodecs= */[],
940
+ /* preferredAudioChannelCount= */2,
941
+ /* preferredDecodingAttributes= */[]);
942
+
943
+ expect(manifest.variants.length).toBe(2);
944
+ expect(manifest.variants.every((v) => [300000, 500000].includes(
945
+ v.video.bandwidth))).toBeTruthy();
946
+ });
947
+
948
+ it('should filter variants by the best available bandwidth' +
949
+ ' for audio language', () => {
950
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
951
+ manifest.addVariant(0, (variant) => {
952
+ variant.bandwidth = 4058558;
953
+ variant.addAudio(1, (stream) => {
954
+ stream.bandwidth = 100000;
955
+ stream.language = 'en';
956
+ });
957
+ });
958
+ manifest.addVariant(2, (variant) => {
959
+ variant.bandwidth = 4781002;
960
+ variant.addAudio(3, (stream) => {
961
+ stream.bandwidth = 200000;
962
+ stream.language = 'en';
963
+ });
964
+ });
965
+ manifest.addVariant(4, (variant) => {
966
+ variant.addAudio(5, (stream) => {
967
+ stream.bandwidth = 100000;
968
+ stream.language = 'es';
969
+ });
970
+ });
971
+ manifest.addVariant(6, (variant) => {
972
+ variant.addAudio(7, (stream) => {
973
+ stream.bandwidth = 500000;
974
+ stream.language = 'es';
975
+ });
976
+ });
977
+ });
978
+
979
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
980
+ /* preferredVideoCodecs= */[],
981
+ /* preferredAudioCodecs= */[],
982
+ /* preferredAudioChannelCount= */2,
983
+ /* preferredDecodingAttributes= */[]);
984
+
985
+ expect(manifest.variants.length).toBe(2);
986
+ expect(manifest.variants.every((v) => v.audio.bandwidth == 100000))
987
+ .toBeTruthy();
988
+ });
989
+
990
+ it('should allow multiple codecs for codec switching', () => {
991
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
992
+ pending('Codec VP9 is not supported by the platform.');
993
+ }
994
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vorbis"')) {
995
+ pending('Codec vorbis is not supported by the platform.');
996
+ }
997
+ // This test is flaky in some Tizen devices, due to codec restrictions.
998
+ if (shaka.util.Platform.isTizen()) {
999
+ pending('Skip flaky test in Tizen');
1000
+ }
1001
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1002
+ addVariant720Avc1(manifest);
1003
+ addVariant720Vp9(manifest);
1004
+ addVariant1080Vp9(manifest);
1005
+ });
1006
+
1007
+ manifest.variants[0].video.bandwidth = 1;
1008
+
1009
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
1010
+ /* preferredVideoCodecs= */[],
1011
+ /* preferredAudioCodecs= */[],
1012
+ /* preferredAudioChannelCount= */2,
1013
+ /* preferredDecodingAttributes= */[]);
1014
+
1015
+ expect(manifest.variants.length).toBe(2);
1016
+ expect(manifest.variants[0].video.codecs)
1017
+ .not.toBe(manifest.variants[1].video.codecs);
1018
+ });
1019
+
871
1020
  it('chooses preferred audio and video codecs', () => {
1021
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
1022
+ pending('Codec VP9 is not supported by the platform.');
1023
+ }
1024
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vorbis"')) {
1025
+ pending('Codec vorbis is not supported by the platform.');
1026
+ }
872
1027
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
873
- addVariant1080Avc1(manifest);
1028
+ addVariant720Avc1(manifest);
1029
+ addVariant720Vp9(manifest);
874
1030
  addVariant1080Vp9(manifest);
875
- addVariant2160Vp9(manifest);
876
1031
  });
877
1032
  const variants =
878
1033
  shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
879
- /* preferredVideoCodecs= */['vp09'],
880
- /* preferredAudioCodecs= */['opus']);
1034
+ /* preferredVideoCodecs= */['vp9'],
1035
+ /* preferredAudioCodecs= */['mp4a']);
881
1036
 
882
1037
  expect(variants.length).toBe(1);
883
- expect(variants[0].video.codecs).toBe(vp09Codecs);
884
- expect(variants[0].audio.codecs).toBe('opus');
1038
+ expect(variants[0].video.codecs).toBe('vp9');
1039
+ expect(variants[0].audio.codecs).toBe('mp4a.40.2');
885
1040
  });
886
1041
 
887
1042
  it('chooses preferred video codecs', () => {
1043
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
1044
+ pending('Codec VP9 is not supported by the platform.');
1045
+ }
1046
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vorbis"')) {
1047
+ pending('Codec vorbis is not supported by the platform.');
1048
+ }
888
1049
  // If no preferred audio codecs is specified or can be found, choose the
889
1050
  // variants with preferred video codecs.
890
1051
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
891
- addVariant1080Avc1(manifest);
1052
+ addVariant720Avc1(manifest);
1053
+ addVariant720Vp9(manifest);
892
1054
  addVariant1080Vp9(manifest);
893
- addVariant2160Vp9(manifest);
894
1055
  });
895
1056
  const variants =
896
1057
  shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
897
- /* preferredVideoCodecs= */['vp09'],
1058
+ /* preferredVideoCodecs= */['vp9'],
898
1059
  /* preferredAudioCodecs= */[]);
899
1060
 
900
1061
  expect(variants.length).toBe(2);
901
- expect(variants[0].video.codecs).toBe(vp09Codecs);
1062
+ expect(variants[0].video.codecs).toBe('vp9');
902
1063
  expect(variants[0].audio.codecs).toBe('vorbis');
903
- expect(variants[1].video.codecs).toBe(vp09Codecs);
904
- expect(variants[1].audio.codecs).toBe('opus');
1064
+ expect(variants[1].video.codecs).toBe('vp9');
1065
+ expect(variants[1].audio.codecs).toBe('mp4a.40.2');
905
1066
  });
906
1067
 
907
1068
  it('chooses preferred audio codecs', () => {
1069
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vp9"')) {
1070
+ pending('Codec VP9 is not supported by the platform.');
1071
+ }
1072
+ if (!MediaSource.isTypeSupported('video/webm; codecs="vorbis"')) {
1073
+ pending('Codec vorbis is not supported by the platform.');
1074
+ }
908
1075
  // If no preferred video codecs is specified or can be found, choose the
909
1076
  // variants with preferred audio codecs.
910
1077
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
911
- addVariant1080Avc1(manifest);
1078
+ addVariant720Avc1(manifest);
1079
+ addVariant720Vp9(manifest);
912
1080
  addVariant1080Vp9(manifest);
913
- addVariant2160Vp9(manifest);
914
1081
  });
915
1082
  const variants =
916
1083
  shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
917
1084
  /* preferredVideoCodecs= */['foo'],
918
- /* preferredAudioCodecs= */['opus']);
1085
+ /* preferredAudioCodecs= */['mp4a.40.2']);
919
1086
 
920
1087
  expect(variants.length).toBe(2);
921
- expect(variants[0].video.codecs).toBe(avc1Codecs);
922
- expect(variants[0].audio.codecs).toBe('opus');
923
- expect(variants[1].video.codecs).toBe(vp09Codecs);
924
- expect(variants[1].audio.codecs).toBe('opus');
925
- });
926
-
927
- it('chooses variants with different sizes (density) by codecs', () => {
928
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
929
- addVariant1080Avc1(manifest);
930
- addVariant1080Vp9(manifest);
931
- addVariant2160Vp9(manifest);
932
- });
933
-
934
- shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
935
- /* preferredVideoCodecs= */[],
936
- /* preferredAudioCodecs= */[],
937
- /* preferredAudioChannelCount= */2,
938
- /* preferredDecodingAttributes= */[]);
939
-
940
- expect(manifest.variants.length).toBe(1);
941
- expect(manifest.variants[0].video.codecs).toBe(vp09Codecs);
942
- });
943
-
944
- it('chooses variants with same sizes (density) by codecs', () => {
945
- manifest = shaka.test.ManifestGenerator.generate((manifest) => {
946
- addVariant1080Avc1(manifest);
947
- addVariant1080Vp9(manifest);
948
- });
949
-
950
- shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
951
- /* preferredVideoCodecs= */[],
952
- /* preferredAudioCodecs= */[],
953
- /* preferredAudioChannelCount= */2,
954
- /* preferredDecodingAttributes= */[]);
955
-
956
- expect(manifest.variants.length).toBe(1);
957
- expect(manifest.variants[0].video.codecs).toBe(vp09Codecs);
1088
+ expect(variants[0].video.codecs).toBe('avc1.640028');
1089
+ expect(variants[0].audio.codecs).toBe('mp4a.40.2');
1090
+ expect(variants[1].video.codecs).toBe('vp9');
1091
+ expect(variants[1].audio.codecs).toBe('mp4a.40.2');
958
1092
  });
959
1093
 
960
1094
  it('chooses variants by decoding attributes', async () => {
@@ -72,6 +72,6 @@ describe('TsParser', () => {
72
72
  const codecs = new shaka.util.TsParser().parse(tsSegment)
73
73
  .getCodecs();
74
74
  expect(codecs.audio).toBe('aac');
75
- expect(codecs.video).toBe('');
75
+ expect(codecs.video).toBe(null);
76
76
  });
77
77
  });