shaka-player 4.4.3 → 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 (198) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +64 -45
  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 +22 -5
  8. package/demo/common/assets.js +132 -49
  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 +51 -123
  16. package/demo/search.js +22 -34
  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 +152 -178
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +152 -178
  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 +22 -43
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +22 -43
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +507 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +507 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +205 -51
  34. package/dist/shaka-player.compiled.debug.js +541 -450
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +205 -51
  37. package/dist/shaka-player.compiled.js +1120 -1066
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +562 -410
  40. package/dist/shaka-player.ui.debug.d.ts +562 -410
  41. package/dist/shaka-player.ui.debug.externs.js +226 -51
  42. package/dist/shaka-player.ui.debug.js +606 -506
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +226 -51
  45. package/dist/shaka-player.ui.js +1266 -1207
  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/ui-customization.md +4 -0
  52. package/externs/css_style_declaration.js +19 -0
  53. package/externs/lcevc.js +37 -13
  54. package/externs/media_remote.js +68 -0
  55. package/externs/mediatailor.js +193 -0
  56. package/externs/pictureinpicture.js +11 -0
  57. package/externs/shaka/ads.js +27 -0
  58. package/externs/shaka/manifest.js +10 -5
  59. package/externs/shaka/manifest_parser.js +7 -1
  60. package/externs/shaka/offline.js +4 -0
  61. package/externs/shaka/player.js +12 -1
  62. package/karma.conf.js +7 -3
  63. package/lib/abr/simple_abr_manager.js +43 -3
  64. package/lib/ads/ad_manager.js +104 -50
  65. package/lib/ads/media_tailor_ad.js +297 -0
  66. package/lib/ads/media_tailor_ad_manager.js +828 -0
  67. package/lib/cea/ts_cea_parser.js +15 -2
  68. package/lib/config/codec_switching_strategy.js +24 -0
  69. package/lib/dash/content_protection.js +120 -2
  70. package/lib/dash/dash_parser.js +75 -12
  71. package/lib/dash/mpd_utils.js +10 -6
  72. package/lib/dash/segment_base.js +13 -5
  73. package/lib/dash/segment_list.js +13 -5
  74. package/lib/dash/segment_template.js +43 -85
  75. package/lib/dependencies/all.js +8 -7
  76. package/lib/hls/hls_parser.js +44 -16
  77. package/lib/lcevc/lcevc_dec.js +220 -0
  78. package/lib/media/adaptation_set.js +22 -11
  79. package/lib/media/adaptation_set_criteria.js +25 -7
  80. package/lib/media/media_source_engine.js +215 -27
  81. package/lib/media/segment_index.js +1 -1
  82. package/lib/media/segment_reference.js +7 -7
  83. package/lib/media/streaming_engine.js +33 -18
  84. package/lib/mss/mss_parser.js +1 -0
  85. package/lib/net/networking_engine.js +1 -0
  86. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  87. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  88. package/lib/offline/manifest_converter.js +1 -0
  89. package/lib/offline/storage.js +3 -0
  90. package/lib/player.js +142 -72
  91. package/lib/routing/payload.js +5 -1
  92. package/lib/text/cue.js +15 -0
  93. package/lib/text/ttml_text_parser.js +17 -0
  94. package/lib/text/ui_text_displayer.js +4 -0
  95. package/lib/text/vtt_text_parser.js +33 -20
  96. package/lib/transmuxer/h265.js +862 -0
  97. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  98. package/lib/transmuxer/ts_transmuxer.js +160 -15
  99. package/lib/util/error.js +28 -9
  100. package/lib/util/exp_golomb.js +30 -2
  101. package/lib/util/fake_event.js +3 -0
  102. package/lib/util/mp4_generator.js +4 -4
  103. package/lib/util/periods.js +2 -0
  104. package/lib/util/platform.js +40 -0
  105. package/lib/util/player_configuration.js +8 -0
  106. package/lib/util/state_history.js +6 -2
  107. package/lib/util/stream_utils.js +133 -217
  108. package/lib/util/ts_parser.js +226 -40
  109. package/maintained-branches.md +3 -2
  110. package/package.json +4 -6
  111. package/roadmap.md +15 -5
  112. package/shaka-player.uncompiled.js +2 -1
  113. package/support.html +0 -1
  114. package/test/cast/cast_receiver_integration.js +47 -0
  115. package/test/codec_switching/codec_switching_integration.js +181 -0
  116. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  117. package/test/dash/dash_parser_integration.js +73 -0
  118. package/test/dash/dash_parser_live_unit.js +2 -0
  119. package/test/dash/dash_parser_manifest_unit.js +42 -0
  120. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  121. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  122. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  123. package/test/demo/demo_unit.js +0 -16
  124. package/test/hls/hls_live_unit.js +2 -0
  125. package/test/hls/hls_parser_unit.js +8 -6
  126. package/test/media/adaptation_set_criteria_unit.js +118 -0
  127. package/test/media/adaptation_set_unit.js +1 -0
  128. package/test/media/media_source_engine_unit.js +165 -1
  129. package/test/media/segment_index_unit.js +4 -4
  130. package/test/media/segment_prefetch_unit.js +1 -1
  131. package/test/media/streaming_engine_unit.js +17 -17
  132. package/test/mss/mss_parser_unit.js +2 -0
  133. package/test/offline/manifest_convert_unit.js +5 -0
  134. package/test/offline/storage_integration.js +1 -4
  135. package/test/player_unit.js +102 -131
  136. package/test/routing/walker_unit.js +1 -0
  137. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  138. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  139. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  143. package/test/test/assets/dash-aes-128/license +1 -0
  144. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  145. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  146. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  147. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  148. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  149. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  150. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  151. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  153. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  154. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  155. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  166. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  167. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  175. package/test/test/util/dash_parser_util.js +4 -0
  176. package/test/test/util/fake_ad_manager.js +20 -0
  177. package/test/test/util/fake_media_source_engine.js +8 -2
  178. package/test/test/util/manifest_generator.js +7 -3
  179. package/test/test/util/mss_parser_util.js +4 -0
  180. package/test/test/util/offline_utils.js +1 -0
  181. package/test/test/util/streaming_engine_util.js +7 -4
  182. package/test/text/ttml_text_parser_unit.js +52 -0
  183. package/test/text/vtt_text_parser_unit.js +103 -31
  184. package/test/transmuxer/transmuxer_integration.js +117 -0
  185. package/test/ui/ui_unit.js +3 -10
  186. package/test/util/stream_utils_unit.js +208 -74
  187. package/ui/controls.js +125 -0
  188. package/ui/externs/ui.js +8 -1
  189. package/ui/pip_button.js +22 -120
  190. package/ui/remote_button.js +201 -0
  191. package/ui/ui.js +5 -2
  192. package/demo/common/message_ids.js +0 -309
  193. package/demo/locales/en.json +0 -288
  194. package/demo/locales/source.json +0 -1146
  195. package/externs/mux.js +0 -69
  196. package/lib/lcevc/lcevc_dil.js +0 -152
  197. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  198. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -0,0 +1,14 @@
1
+ #EXTM3U
2
+ #EXT-X-VERSION:3
3
+ #EXT-X-TARGETDURATION:6
4
+ #EXT-X-PLAYLIST-TYPE:VOD
5
+ #EXT-X-INDEPENDENT-SEGMENTS
6
+ #EXTINF:6.000,
7
+ ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts
8
+ #EXTINF:6.000,
9
+ ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts
10
+ #EXTINF:6.000,
11
+ ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts
12
+ #EXTINF:6.000,
13
+ ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts
14
+ #EXT-X-ENDLIST
@@ -0,0 +1,23 @@
1
+ #EXTM3U
2
+ #EXT-X-TARGETDURATION:6
3
+ #EXT-X-ALLOW-CACHE:YES
4
+ #EXT-X-PLAYLIST-TYPE:VOD
5
+ #EXT-X-VERSION:3
6
+ #EXT-X-MEDIA-SEQUENCE:1
7
+ #EXTINF:2.436,
8
+ seg-1-v1-a1.ts
9
+ #EXTINF:3.337,
10
+ seg-2-v1-a1.ts
11
+ #EXTINF:3.337,
12
+ seg-3-v1-a1.ts
13
+ #EXTINF:5.005,
14
+ seg-4-v1-a1.ts
15
+ #EXTINF:5.005,
16
+ seg-5-v1-a1.ts
17
+ #EXTINF:5.005,
18
+ seg-6-v1-a1.ts
19
+ #EXTINF:5.606,
20
+ seg-7-v1-a1.ts
21
+ #EXTINF:5.005,
22
+ seg-8-v1-a1.ts
23
+ #EXT-X-ENDLIST
@@ -45,6 +45,8 @@ shaka.test.Dash = class {
45
45
  enableLowLatencyMode: () => {},
46
46
  updateDuration: () => {},
47
47
  newDrmInfo: (stream) => {},
48
+ onManifestUpdated: () => {},
49
+ getBandwidthEstimate: () => 1e6,
48
50
  };
49
51
  try {
50
52
  const manifest = await dashParser.start('dummy://foo', playerInterface);
@@ -85,6 +87,8 @@ shaka.test.Dash = class {
85
87
  enableLowLatencyMode: () => {},
86
88
  updateDuration: () => {},
87
89
  newDrmInfo: (stream) => {},
90
+ onManifestUpdated: () => {},
91
+ getBandwidthEstimate: () => 1e6,
88
92
  };
89
93
 
90
94
  try {
@@ -39,6 +39,14 @@ shaka.test.FakeAdManager = class extends shaka.util.FakeEventTarget {
39
39
  /** @override */
40
40
  updateClientSideAdsRenderingSettings(adsRenderingSettings) {}
41
41
 
42
+ /** @override */
43
+ initMediaTailor(networkingEngine, video) {}
44
+
45
+ /** @override */
46
+ requestMediaTailorStream(url, adsParams, backupUrl) {
47
+ return Promise.resolve('fake:url');
48
+ }
49
+
42
50
  /** @override */
43
51
  initServerSide(adContainer, video) {}
44
52
 
@@ -57,11 +65,23 @@ shaka.test.FakeAdManager = class extends shaka.util.FakeEventTarget {
57
65
  return [];
58
66
  }
59
67
 
68
+ /**
69
+ * @override
70
+ */
71
+ getCuePoints() {
72
+ return [];
73
+ }
74
+
60
75
  /** @override */
61
76
  getStats() {
62
77
  return this.stats_;
63
78
  }
64
79
 
80
+ /**
81
+ * @override
82
+ */
83
+ onManifestUpdated(isLive) {}
84
+
65
85
  /**
66
86
  * @override
67
87
  */
@@ -134,8 +134,8 @@ shaka.test.FakeMediaSourceEngine = class {
134
134
  jasmine.createSpy('setSegmentRelativeVttTiming').and.stub();
135
135
 
136
136
  /** @type {!jasmine.Spy} */
137
- this.updateLcevcDil =
138
- jasmine.createSpy('updateLcevcDil').and.stub();
137
+ this.updateLcevcDec =
138
+ jasmine.createSpy('updateLcevcDec').and.stub();
139
139
 
140
140
  /** @type {!jasmine.Spy} */
141
141
  this.resync=
@@ -341,6 +341,12 @@ shaka.test.FakeMediaSourceEngine = class {
341
341
  return Promise.resolve();
342
342
  }
343
343
 
344
+
345
+ /** @override */
346
+ isResetMediaSourceNecessary() {
347
+ return false;
348
+ }
349
+
344
350
  /**
345
351
  * @param {string} type
346
352
  * @return {!Promise}
@@ -459,9 +459,11 @@ shaka.test.ManifestGenerator.Stream = class {
459
459
  * @param {string=} label
460
460
  */
461
461
  constructor(manifest, isPartial, id, type, lang, label) {
462
- goog.asserts.assert(
463
- !manifest || !manifest.isIdUsed_(id),
464
- 'Streams should have unique ids!');
462
+ // variants can be made up of different combinations of video
463
+ // and audio streams
464
+ // goog.asserts.assert(
465
+ // !manifest || !manifest.isIdUsed_(id),
466
+ // 'Streams should have unique ids!');
465
467
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
466
468
 
467
469
  /** @const {shaka.test.ManifestGenerator.Manifest} */
@@ -499,6 +501,8 @@ shaka.test.ManifestGenerator.Stream = class {
499
501
 
500
502
  /** @type {?string} */
501
503
  this.originalId = null;
504
+ /** @type {?string} */
505
+ this.groupId = null;
502
506
  /** @type {shaka.extern.CreateSegmentIndexFunction} */
503
507
  this.createSegmentIndex = shaka.test.Util.spyFunc(create);
504
508
  /** @type {shaka.media.SegmentIndex} */
@@ -45,6 +45,8 @@ shaka.test.Mss = class {
45
45
  enableLowLatencyMode: () => {},
46
46
  updateDuration: () => {},
47
47
  newDrmInfo: (stream) => {},
48
+ onManifestUpdated: () => {},
49
+ getBandwidthEstimate: () => 1e6,
48
50
  };
49
51
  const manifest = await mssParser.start('dummy://foo', playerInterface);
50
52
  const stream = manifest.variants[0].audio;
@@ -81,6 +83,8 @@ shaka.test.Mss = class {
81
83
  enableLowLatencyMode: () => {},
82
84
  updateDuration: () => {},
83
85
  newDrmInfo: (stream) => {},
86
+ onManifestUpdated: () => {},
87
+ getBandwidthEstimate: () => 1e6,
84
88
  };
85
89
  const p = mssParser.start('dummy://foo', playerInterface);
86
90
  await expectAsync(p).toBeRejectedWith(
@@ -33,6 +33,7 @@ shaka.test.OfflineUtils = class {
33
33
  return {
34
34
  id,
35
35
  originalId: id.toString(),
36
+ groupId: null,
36
37
  primary: false,
37
38
  presentationTimeOffset: 0,
38
39
  type,
@@ -149,13 +149,13 @@ shaka.test.StreamingEngineUtil = class {
149
149
  * ranges for each type of init segment.
150
150
  * @param {!Object.<string,number>=} timestampOffsets The timestamp offset
151
151
  * for each type of segment
152
- * @param {shaka.extern.HlsAes128Key=} hlsAes128Key The AES-128 key to provide
152
+ * @param {shaka.extern.aes128Key=} aes128Key The AES-128 key to provide
153
153
  * to streams, if desired.
154
154
  * @return {shaka.extern.Manifest}
155
155
  */
156
156
  static createManifest(
157
157
  presentationTimeline, periodStartTimes, presentationDuration,
158
- segmentDurations, initSegmentRanges, timestampOffsets, hlsAes128Key) {
158
+ segmentDurations, initSegmentRanges, timestampOffsets, aes128Key) {
159
159
  const Util = shaka.test.Util;
160
160
 
161
161
  /**
@@ -268,9 +268,9 @@ shaka.test.StreamingEngineUtil = class {
268
268
  appendWindowStart,
269
269
  appendWindowEnd);
270
270
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
271
- if (hlsAes128Key &&
271
+ if (aes128Key &&
272
272
  (type == ContentType.AUDIO || type == ContentType.VIDEO)) {
273
- ref.hlsAes128Key = hlsAes128Key;
273
+ ref.aes128Key = aes128Key;
274
274
  }
275
275
  return ref;
276
276
  };
@@ -394,6 +394,7 @@ shaka.test.StreamingEngineUtil = class {
394
394
  return {
395
395
  id: id,
396
396
  originalId: id.toString(),
397
+ groupId: null,
397
398
  createSegmentIndex: Util.spyFunc(jasmine.createSpy('createSegmentIndex')),
398
399
  segmentIndex: null,
399
400
  mimeType: 'audio/mp4',
@@ -433,6 +434,7 @@ shaka.test.StreamingEngineUtil = class {
433
434
  return {
434
435
  id: id,
435
436
  originalId: id.toString(),
437
+ groupId: null,
436
438
  createSegmentIndex: Util.spyFunc(jasmine.createSpy('createSegmentIndex')),
437
439
  segmentIndex: null,
438
440
  mimeType: mimeType,
@@ -473,6 +475,7 @@ shaka.test.StreamingEngineUtil = class {
473
475
  return {
474
476
  id: id,
475
477
  originalId: id.toString(),
478
+ groupId: null,
476
479
  createSegmentIndex: Util.spyFunc(jasmine.createSpy('createSegmentIndex')),
477
480
  segmentIndex: null,
478
481
  mimeType: 'text/vtt',
@@ -1147,6 +1147,31 @@ describe('TtmlTextParser', () => {
1147
1147
  {startTime: 62.05, endTime: 3723.2});
1148
1148
  });
1149
1149
 
1150
+ it('supports textCombine setting', () => {
1151
+ verifyHelper(
1152
+ [
1153
+ {
1154
+ startTime: 62.05,
1155
+ endTime: 3723.2,
1156
+ payload: 'Test',
1157
+ textCombineUpright: 'all',
1158
+ writingMode: Cue.writingMode.VERTICAL_LEFT_TO_RIGHT,
1159
+ },
1160
+ ],
1161
+ '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling">' +
1162
+ '<layout>' +
1163
+ '<region xml:id="subtitleArea" ' +
1164
+ 'tts:writingMode="tb" ' +
1165
+ 'tts:textCombine="all"/>' +
1166
+ '</layout>' +
1167
+ '<body region="subtitleArea"><div>' +
1168
+ '<p begin="01:02.05" end="01:02:03.200">Test</p>' +
1169
+ '</div></body></tt>',
1170
+ {periodStart: 0, segmentStart: 60, segmentEnd: 3730, vttOffset: 0},
1171
+ {startTime: 62.05, endTime: 3723.2, region: {id: 'subtitleArea'}},
1172
+ {startTime: 62.05, endTime: 3723.2});
1173
+ });
1174
+
1150
1175
  it('disregards empty divs and ps', () => {
1151
1176
  verifyHelper(
1152
1177
  [
@@ -1286,6 +1311,33 @@ describe('TtmlTextParser', () => {
1286
1311
  {startTime: 62.05, endTime: 3723.2});
1287
1312
  });
1288
1313
 
1314
+ it('supports tts:ruby', () => {
1315
+ verifyHelper(
1316
+ [{
1317
+ startTime: 62.05,
1318
+ endTime: 3723.2,
1319
+ payload: '',
1320
+ nestedCues: [{
1321
+ startTime: 62.05,
1322
+ endTime: 3723.2,
1323
+ payload: 'Line1',
1324
+ }, {
1325
+ startTime: 62.05,
1326
+ endTime: 3723.2,
1327
+ payload: 'Line2',
1328
+ rubyTag: 'rt',
1329
+ }],
1330
+ rubyTag: 'ruby',
1331
+ }],
1332
+ // With anonymous spans
1333
+ '<tt xmlns:tts="http://www.w3.org/ns/ttml#styling"><body><div>' +
1334
+ '<p begin="01:02.05" end="01:02:03.200" tts:ruby="container">' +
1335
+ '<span tts:ruby="base">Line1</span><span tts:ruby="text">Line2' +
1336
+ '</span></p></div></body></tt>',
1337
+ {periodStart: 0, segmentStart: 60, segmentEnd: 3730, vttOffset: 0},
1338
+ {startTime: 62.05, endTime: 3723.2});
1339
+ });
1340
+
1289
1341
  it('inserts line breaks for <br> tags', () => {
1290
1342
  verifyHelper(
1291
1343
  [{
@@ -646,6 +646,7 @@ describe('VttTextParser', () => {
646
646
  payload: 'Test',
647
647
  color: 'cyan',
648
648
  fontSize: '10px',
649
+ textCombineUpright: 'all',
649
650
  textShadow: textShadow,
650
651
  },
651
652
  {
@@ -654,6 +655,7 @@ describe('VttTextParser', () => {
654
655
  payload: 'Test2',
655
656
  color: 'cyan',
656
657
  fontSize: '10px',
658
+ textCombineUpright: 'all',
657
659
  textShadow: textShadow,
658
660
  },
659
661
  ],
@@ -663,6 +665,7 @@ describe('VttTextParser', () => {
663
665
  'color: cyan;\n'+
664
666
  'font-size: 10px;\n'+
665
667
  `text-shadow: ${textShadow};\n`+
668
+ 'text-combine-upright: all;\n'+
666
669
  '}\n\n' +
667
670
  '00:00:20.000 --> 00:00:40.000\n' +
668
671
  'Test\n\n' +
@@ -761,16 +764,21 @@ describe('VttTextParser', () => {
761
764
  {
762
765
  startTime: 50,
763
766
  endTime: 60,
764
- payload: 'Test',
765
- fontWeight: Cue.fontWeight.BOLD,
766
- fontStyle: Cue.fontStyle.NORMAL,
767
- },
768
- {
769
- startTime: 50,
770
- endTime: 60,
771
- payload: '5',
767
+ payload: '',
772
768
  fontWeight: Cue.fontWeight.BOLD,
773
- fontStyle: Cue.fontStyle.ITALIC,
769
+ nestedCues: [
770
+ {
771
+ startTime: 50,
772
+ endTime: 60,
773
+ payload: 'Test',
774
+ },
775
+ {
776
+ startTime: 50,
777
+ endTime: 60,
778
+ payload: '5',
779
+ fontStyle: Cue.fontStyle.ITALIC,
780
+ },
781
+ ],
774
782
  },
775
783
  ],
776
784
  },
@@ -801,16 +809,21 @@ describe('VttTextParser', () => {
801
809
  {
802
810
  startTime: 80,
803
811
  endTime: 90,
804
- payload: 'Test ',
805
- fontWeight: Cue.fontWeight.BOLD,
806
- fontStyle: Cue.fontStyle.NORMAL,
807
- },
808
- {
809
- startTime: 80,
810
- endTime: 90,
811
- payload: '7',
812
+ payload: '',
812
813
  fontWeight: Cue.fontWeight.BOLD,
813
- fontStyle: Cue.fontStyle.ITALIC,
814
+ nestedCues: [
815
+ {
816
+ startTime: 80,
817
+ endTime: 90,
818
+ payload: 'Test ',
819
+ },
820
+ {
821
+ startTime: 80,
822
+ endTime: 90,
823
+ payload: '7',
824
+ fontStyle: Cue.fontStyle.ITALIC,
825
+ },
826
+ ],
814
827
  },
815
828
  ],
816
829
  },
@@ -903,6 +916,48 @@ describe('VttTextParser', () => {
903
916
  {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
904
917
  });
905
918
 
919
+ it('supports ruby html tags', () => {
920
+ verifyHelper(
921
+ [
922
+ {
923
+ startTime: 20,
924
+ endTime: 40,
925
+ payload: '',
926
+ nestedCues: [
927
+ {
928
+ startTime: 20,
929
+ endTime: 40,
930
+ payload: '',
931
+ rubyTag: 'ruby',
932
+ nestedCues: [
933
+ {
934
+ startTime: 20,
935
+ endTime: 40,
936
+ payload: 'Test',
937
+ },
938
+ {
939
+ startTime: 20,
940
+ endTime: 40,
941
+ payload: '2',
942
+ rubyTag: 'rt',
943
+ },
944
+ {
945
+ startTime: 20,
946
+ endTime: 40,
947
+ payload: '3',
948
+ rubyTag: 'rp',
949
+ },
950
+ ],
951
+ },
952
+ ],
953
+ },
954
+ ],
955
+ 'WEBVTT\n\n' +
956
+ '00:00:20.000 --> 00:00:40.000\n' +
957
+ '<ruby>Test<rt>2</rt><rp>3</rp></ruby>',
958
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
959
+ });
960
+
906
961
  it('supports only two digits in the timestamp', () => {
907
962
  verifyHelper(
908
963
  [
@@ -998,14 +1053,22 @@ describe('VttTextParser', () => {
998
1053
  {
999
1054
  startTime: 70,
1000
1055
  endTime: 80,
1001
- payload: 'Test5.1',
1056
+ payload: '',
1002
1057
  color: 'red',
1003
- },
1004
- {
1005
- startTime: 70,
1006
- endTime: 80,
1007
- payload: 'Test5.2',
1008
- color: 'lime',
1058
+ nestedCues: [
1059
+ {
1060
+ startTime: 70,
1061
+ endTime: 80,
1062
+ payload: 'Test5.1',
1063
+ color: 'red',
1064
+ },
1065
+ {
1066
+ startTime: 70,
1067
+ endTime: 80,
1068
+ payload: 'Test5.2',
1069
+ color: 'lime',
1070
+ },
1071
+ ],
1009
1072
  },
1010
1073
  ],
1011
1074
  },
@@ -1185,9 +1248,17 @@ describe('VttTextParser', () => {
1185
1248
  {
1186
1249
  startTime: 10,
1187
1250
  endTime: 20,
1188
- payload: '2',
1251
+ payload: '',
1189
1252
  color: 'magenta',
1190
- fontStyle: Cue.fontStyle.ITALIC,
1253
+ nestedCues: [
1254
+ {
1255
+ startTime: 10,
1256
+ endTime: 20,
1257
+ payload: '2',
1258
+ color: 'magenta',
1259
+ fontStyle: Cue.fontStyle.ITALIC,
1260
+ },
1261
+ ],
1191
1262
  },
1192
1263
  ],
1193
1264
  },
@@ -1255,13 +1326,14 @@ describe('VttTextParser', () => {
1255
1326
  parser.setSequenceMode(sequenceMode);
1256
1327
  const result = parser.parseMedia(data, time);
1257
1328
 
1258
- const expected = cues.map((cue) => {
1329
+ const checkCue = (cue) => {
1259
1330
  if (cue.nestedCues) {
1260
- cue.nestedCues = cue.nestedCues.map(
1261
- (nestedCue) => jasmine.objectContaining(nestedCue));
1331
+ cue.nestedCues = cue.nestedCues.map((nestedCue) => checkCue(nestedCue));
1262
1332
  }
1263
1333
  return jasmine.objectContaining(cue);
1264
- });
1334
+ };
1335
+
1336
+ const expected = cues.map(checkCue);
1265
1337
  expect(result).toEqual(expected);
1266
1338
  }
1267
1339
 
@@ -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) => {