shaka-player 4.4.3 → 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 (307) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/workflows/release-please.yaml +2 -27
  3. package/AUTHORS +2 -0
  4. package/CHANGELOG.md +156 -39
  5. package/CODE_OF_CONDUCT.md +1 -1
  6. package/CONTRIBUTORS +2 -0
  7. package/README.md +54 -42
  8. package/demo/asset_card.js +18 -21
  9. package/demo/cast_receiver/index.html +0 -1
  10. package/demo/close_button.js +0 -3
  11. package/demo/common/asset.js +33 -22
  12. package/demo/common/assets.js +249 -60
  13. package/demo/config.js +219 -253
  14. package/demo/custom.js +88 -133
  15. package/demo/front.js +7 -10
  16. package/demo/index.html +19 -22
  17. package/demo/input.js +6 -11
  18. package/demo/input_container.js +8 -9
  19. package/demo/main.js +62 -126
  20. package/demo/search.js +29 -34
  21. package/demo/service_worker.js +0 -3
  22. package/demo/tooltip.js +3 -5
  23. package/demo/visualizer.js +3 -5
  24. package/demo/visualizer_button.js +1 -20
  25. package/dist/controls.css +1 -1
  26. package/dist/controls.css.map +1 -1
  27. package/dist/demo.compiled.debug.js +211 -228
  28. package/dist/demo.compiled.debug.map +4 -4
  29. package/dist/demo.compiled.js +211 -228
  30. package/dist/demo.compiled.map +4 -4
  31. package/dist/deps.js +42 -37
  32. package/dist/locales.js +34 -30
  33. package/dist/receiver.compiled.debug.js +64 -77
  34. package/dist/receiver.compiled.debug.map +4 -4
  35. package/dist/receiver.compiled.js +64 -77
  36. package/dist/receiver.compiled.map +4 -4
  37. package/dist/shaka-player.compiled.d.ts +343 -151
  38. package/dist/shaka-player.compiled.debug.d.ts +343 -151
  39. package/dist/shaka-player.compiled.debug.externs.js +356 -117
  40. package/dist/shaka-player.compiled.debug.js +952 -811
  41. package/dist/shaka-player.compiled.debug.map +4 -4
  42. package/dist/shaka-player.compiled.externs.js +356 -117
  43. package/dist/shaka-player.compiled.js +1165 -1078
  44. package/dist/shaka-player.compiled.map +4 -4
  45. package/dist/shaka-player.ui.d.ts +359 -153
  46. package/dist/shaka-player.ui.debug.d.ts +359 -153
  47. package/dist/shaka-player.ui.debug.externs.js +382 -117
  48. package/dist/shaka-player.ui.debug.js +1084 -918
  49. package/dist/shaka-player.ui.debug.map +4 -4
  50. package/dist/shaka-player.ui.externs.js +382 -117
  51. package/dist/shaka-player.ui.js +1377 -1274
  52. package/dist/shaka-player.ui.map +4 -4
  53. package/docs/design/lcevc-integration.md +14 -14
  54. package/docs/tutorials/ad_monetization.md +54 -0
  55. package/docs/tutorials/basic-usage.md +2 -1
  56. package/docs/tutorials/errors.md +2 -1
  57. package/docs/tutorials/faq.md +27 -55
  58. package/docs/tutorials/index.json +2 -1
  59. package/docs/tutorials/lcevc.md +118 -0
  60. package/docs/tutorials/offline.md +10 -8
  61. package/docs/tutorials/plugins.md +5 -0
  62. package/docs/tutorials/ui-customization.md +17 -0
  63. package/docs/tutorials/ui.md +2 -1
  64. package/docs/tutorials/upgrade.md +3 -0
  65. package/externs/css_style_declaration.js +19 -0
  66. package/externs/lcevc.js +37 -13
  67. package/externs/managedmediasource.js +24 -0
  68. package/externs/media_remote.js +68 -0
  69. package/externs/mediatailor.js +193 -0
  70. package/externs/pictureinpicture.js +11 -0
  71. package/externs/shaka/abr_manager.js +6 -2
  72. package/externs/shaka/ads.js +27 -0
  73. package/externs/shaka/cea.js +7 -0
  74. package/externs/shaka/codecs.js +5 -3
  75. package/externs/shaka/manifest.js +31 -10
  76. package/externs/shaka/manifest_parser.js +24 -1
  77. package/externs/shaka/net.js +2 -2
  78. package/externs/shaka/offline.js +13 -2
  79. package/externs/shaka/player.js +65 -8
  80. package/externs/shaka/text.js +3 -1
  81. package/externs/shaka/transmuxer.js +1 -1
  82. package/karma.conf.js +7 -3
  83. package/lib/abr/simple_abr_manager.js +66 -9
  84. package/lib/ads/ad_manager.js +104 -50
  85. package/lib/ads/media_tailor_ad.js +297 -0
  86. package/lib/ads/media_tailor_ad_manager.js +839 -0
  87. package/lib/cast/cast_receiver.js +1 -1
  88. package/lib/cea/cea_decoder.js +28 -0
  89. package/lib/cea/dummy_caption_decoder.js +5 -0
  90. package/lib/cea/ts_cea_parser.js +15 -2
  91. package/lib/config/codec_switching_strategy.js +24 -0
  92. package/lib/dash/content_protection.js +120 -2
  93. package/lib/dash/dash_parser.js +322 -93
  94. package/lib/dash/mpd_utils.js +62 -37
  95. package/lib/dash/segment_base.js +17 -10
  96. package/lib/dash/segment_list.js +18 -9
  97. package/lib/dash/segment_template.js +122 -107
  98. package/lib/dependencies/all.js +8 -7
  99. package/lib/hls/hls_classes.js +28 -43
  100. package/lib/hls/hls_parser.js +798 -658
  101. package/lib/hls/hls_utils.js +64 -5
  102. package/lib/hls/manifest_text_parser.js +7 -11
  103. package/lib/lcevc/lcevc_dec.js +220 -0
  104. package/lib/media/adaptation_set.js +32 -14
  105. package/lib/media/adaptation_set_criteria.js +86 -16
  106. package/lib/media/closed_caption_parser.js +13 -0
  107. package/lib/media/content_workarounds.js +6 -0
  108. package/lib/media/drm_engine.js +8 -13
  109. package/lib/media/manifest_parser.js +8 -113
  110. package/lib/media/media_source_capabilities.js +10 -3
  111. package/lib/media/media_source_engine.js +286 -44
  112. package/lib/media/play_rate_controller.js +8 -38
  113. package/lib/media/presentation_timeline.js +7 -1
  114. package/lib/media/quality_observer.js +1 -1
  115. package/lib/media/segment_index.js +6 -6
  116. package/lib/media/segment_prefetch.js +92 -24
  117. package/lib/media/segment_reference.js +73 -7
  118. package/lib/media/segment_utils.js +343 -0
  119. package/lib/media/stall_detector.js +0 -3
  120. package/lib/media/streaming_engine.js +73 -38
  121. package/lib/mss/mss_parser.js +19 -2
  122. package/lib/net/networking_engine.js +67 -12
  123. package/lib/net/networking_utils.js +95 -0
  124. package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
  125. package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
  126. package/lib/offline/manifest_converter.js +3 -0
  127. package/lib/offline/offline_manifest_parser.js +10 -0
  128. package/lib/offline/storage.js +14 -7
  129. package/lib/player.js +1098 -1537
  130. package/lib/polyfill/mediasource.js +22 -1
  131. package/lib/text/cue.js +15 -0
  132. package/lib/text/mp4_ttml_parser.js +2 -2
  133. package/lib/text/srt_text_parser.js +2 -2
  134. package/lib/text/stub_text_displayer.js +51 -0
  135. package/lib/text/text_engine.js +3 -2
  136. package/lib/text/ttml_text_parser.js +45 -5
  137. package/lib/text/ui_text_displayer.js +8 -0
  138. package/lib/text/vtt_text_parser.js +40 -22
  139. package/lib/transmuxer/aac_transmuxer.js +1 -1
  140. package/lib/transmuxer/ac3_transmuxer.js +1 -1
  141. package/lib/transmuxer/ec3_transmuxer.js +1 -1
  142. package/lib/transmuxer/h264.js +5 -4
  143. package/lib/transmuxer/h265.js +863 -0
  144. package/lib/transmuxer/mp3_transmuxer.js +1 -1
  145. package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
  146. package/lib/transmuxer/mss_transmuxer.js +1 -1
  147. package/lib/transmuxer/ts_transmuxer.js +187 -22
  148. package/lib/util/buffer_utils.js +26 -4
  149. package/lib/util/content_steering_manager.js +358 -0
  150. package/lib/util/error.js +30 -15
  151. package/lib/util/exp_golomb.js +30 -2
  152. package/lib/util/fairplay_utils.js +1 -1
  153. package/lib/util/fake_event.js +8 -1
  154. package/lib/util/id3_utils.js +50 -1
  155. package/lib/util/manifest_parser_utils.js +12 -8
  156. package/lib/util/mp4_generator.js +6 -8
  157. package/lib/util/mutex.js +59 -0
  158. package/lib/util/object_utils.js +1 -1
  159. package/lib/util/periods.js +156 -179
  160. package/lib/util/platform.js +44 -3
  161. package/lib/util/player_configuration.js +43 -6
  162. package/lib/util/state_history.js +6 -2
  163. package/lib/util/stream_utils.js +206 -283
  164. package/lib/util/ts_parser.js +335 -98
  165. package/lib/util/uint8array_utils.js +5 -1
  166. package/lib/util/xml_utils.js +5 -0
  167. package/maintained-branches.md +3 -2
  168. package/package.json +4 -6
  169. package/roadmap.md +25 -5
  170. package/shaka-player.uncompiled.js +2 -2
  171. package/support.html +0 -1
  172. package/test/abr/simple_abr_manager_unit.js +33 -33
  173. package/test/ads/ad_manager_unit.js +3 -2
  174. package/test/cast/cast_receiver_integration.js +50 -4
  175. package/test/cast/cast_utils_unit.js +2 -0
  176. package/test/cea/cea_decoder_unit.js +7 -0
  177. package/test/codec_switching/codec_switching_integration.js +182 -0
  178. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  179. package/test/dash/dash_parser_integration.js +74 -0
  180. package/test/dash/dash_parser_live_unit.js +2 -19
  181. package/test/dash/dash_parser_manifest_unit.js +536 -2
  182. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  183. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  184. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  185. package/test/dash/mpd_utils_unit.js +61 -30
  186. package/test/demo/demo_unit.js +0 -16
  187. package/test/hls/hls_live_unit.js +14 -3
  188. package/test/hls/hls_parser_unit.js +385 -33
  189. package/test/hls/manifest_text_parser_unit.js +32 -99
  190. package/test/media/adaptation_set_criteria_unit.js +284 -15
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/content_workarounds_unit.js +1 -1
  193. package/test/media/drm_engine_unit.js +3 -3
  194. package/test/media/media_source_engine_unit.js +166 -2
  195. package/test/media/play_rate_controller_unit.js +0 -48
  196. package/test/media/segment_index_unit.js +5 -4
  197. package/test/media/segment_prefetch_unit.js +1 -1
  198. package/test/media/streaming_engine_unit.js +17 -17
  199. package/test/mss/mss_parser_unit.js +2 -0
  200. package/test/mss/mss_player_integration.js +3 -2
  201. package/test/net/networking_engine_unit.js +3 -3
  202. package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
  203. package/test/offline/manifest_convert_unit.js +14 -0
  204. package/test/offline/offline_integration.js +2 -1
  205. package/test/offline/storage_integration.js +22 -13
  206. package/test/player_external.js +4 -2
  207. package/test/player_integration.js +15 -4
  208. package/test/player_load_graph_integration.js +47 -151
  209. package/test/player_src_equals_external.js +1 -0
  210. package/test/player_src_equals_integration.js +71 -4
  211. package/test/player_unit.js +182 -158
  212. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  213. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  214. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  215. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  216. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  217. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  218. package/test/test/assets/dash-aes-128/license +1 -0
  219. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  220. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  221. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  222. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  223. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  224. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  225. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  226. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  227. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  228. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  229. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  230. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  231. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  232. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  233. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  234. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  235. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  236. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  237. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  238. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  239. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  240. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  241. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  242. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  243. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  244. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  245. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  246. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  247. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  248. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  249. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  250. package/test/test/util/dash_parser_util.js +4 -0
  251. package/test/test/util/fake_ad_manager.js +20 -0
  252. package/test/test/util/fake_media_source_engine.js +13 -2
  253. package/test/test/util/fake_networking_engine.js +9 -1
  254. package/test/test/util/fake_segment_prefetch.js +3 -0
  255. package/test/test/util/manifest_generator.js +11 -3
  256. package/test/test/util/manifest_parser_util.js +14 -2
  257. package/test/test/util/mss_parser_util.js +4 -0
  258. package/test/test/util/offline_utils.js +2 -0
  259. package/test/test/util/simple_fakes.js +2 -2
  260. package/test/test/util/streaming_engine_util.js +10 -4
  261. package/test/test/util/test_scheme.js +6 -0
  262. package/test/test/util/ui_utils.js +4 -3
  263. package/test/text/mp4_ttml_parser_unit.js +4 -4
  264. package/test/text/srt_text_parser_unit.js +1 -1
  265. package/test/text/text_displayer_layout_unit.js +1 -1
  266. package/test/text/text_engine_unit.js +6 -0
  267. package/test/text/ttml_text_parser_unit.js +85 -2
  268. package/test/text/vtt_text_parser_unit.js +103 -31
  269. package/test/transmuxer/transmuxer_engine_integration.js +9 -0
  270. package/test/transmuxer/transmuxer_integration.js +150 -3
  271. package/test/ui/ad_ui_unit.js +2 -2
  272. package/test/ui/ui_customization_unit.js +17 -16
  273. package/test/ui/ui_integration.js +30 -20
  274. package/test/ui/ui_unit.js +28 -29
  275. package/test/util/buffer_utils_unit.js +1 -1
  276. package/test/util/content_steering_manager_unit.js +427 -0
  277. package/test/util/id3_utils_unit.js +52 -0
  278. package/test/util/stream_utils_unit.js +207 -169
  279. package/test/util/ts_parser_unit.js +3 -3
  280. package/third_party/closure-uri/uri.js +13 -1
  281. package/ui/audio_language_selection.js +9 -2
  282. package/ui/controls.js +125 -0
  283. package/ui/externs/ui.js +24 -2
  284. package/ui/language_utils.js +43 -8
  285. package/ui/less/range_elements.less +33 -0
  286. package/ui/locales/en.json +1 -0
  287. package/ui/locales/es-419.json +1 -0
  288. package/ui/locales/es.json +1 -0
  289. package/ui/locales/source.json +4 -0
  290. package/ui/localization.js +10 -0
  291. package/ui/pip_button.js +22 -120
  292. package/ui/remote_button.js +203 -0
  293. package/ui/resolution_selection.js +47 -10
  294. package/ui/seek_bar.js +296 -3
  295. package/ui/text_selection.js +2 -1
  296. package/ui/ui.js +11 -4
  297. package/demo/common/message_ids.js +0 -309
  298. package/demo/locales/en.json +0 -288
  299. package/demo/locales/source.json +0 -1146
  300. package/externs/mux.js +0 -69
  301. package/lib/lcevc/lcevc_dil.js +0 -152
  302. package/lib/routing/node.js +0 -23
  303. package/lib/routing/payload.js +0 -43
  304. package/lib/routing/walker.js +0 -587
  305. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  306. package/test/routing/walker_unit.js +0 -504
  307. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -40,7 +40,18 @@ shaka.polyfill.MediaSource = class {
40
40
  } else if (safariVersion) {
41
41
  // NOTE: shaka.Player.isBrowserSupported() has its own restrictions on
42
42
  // Safari version.
43
- if (safariVersion <= 12) {
43
+ if (safariVersion <= 10) {
44
+ // Safari 8 does not implement appendWindowEnd.
45
+ // Safari 9 & 10 do not correctly implement abort() on SourceBuffer.
46
+ // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=160316
47
+ // Blacklist these very outdated versions.
48
+ // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
49
+ // Safari 10 fires spurious 'updateend' events after endOfStream().
50
+ // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165336
51
+
52
+ shaka.log.info('Blacklisting MSE on Safari <= 10.');
53
+ shaka.polyfill.MediaSource.blacklist_();
54
+ } else if (safariVersion <= 12) {
44
55
  shaka.log.info('Patching Safari 11 & 12 MSE bugs.');
45
56
  // Safari 11 & 12 do not correctly implement abort() on SourceBuffer.
46
57
  // Calling abort() before appending a segment causes that segment to be
@@ -89,6 +100,16 @@ shaka.polyfill.MediaSource = class {
89
100
  }
90
101
  }
91
102
 
103
+ /**
104
+ * Blacklist the current browser by making
105
+ * MediaSourceEngine.isBrowserSupported fail later.
106
+ *
107
+ * @private
108
+ */
109
+ static blacklist_() {
110
+ window['MediaSource'] = null;
111
+ }
112
+
92
113
  /**
93
114
  * Stub out abort(). On some buggy MSE implementations, calling abort()
94
115
  * causes various problems.
package/lib/text/cue.js CHANGED
@@ -222,6 +222,13 @@ shaka.text.Cue = class {
222
222
  */
223
223
  this.opacity = 1;
224
224
 
225
+ /**
226
+ * Text combine upright as a CSS text-combine-upright value.
227
+ * @type {string}
228
+ * @export
229
+ */
230
+ this.textCombineUpright = '';
231
+
225
232
  /**
226
233
  * Text decoration. A combination of underline, overline
227
234
  * and line through. Empty array means no decoration.
@@ -292,6 +299,14 @@ shaka.text.Cue = class {
292
299
  */
293
300
  this.lineBreak = false;
294
301
 
302
+ /**
303
+ * Used to indicate the type of ruby tag that should be used when rendering
304
+ * the cue. Valid values: ruby, rp, rt.
305
+ * @type {?string}
306
+ * @export
307
+ */
308
+ this.rubyTag = null;
309
+
295
310
  /**
296
311
  * The number of horizontal and vertical cells into which the Root Container
297
312
  * Region area is divided.
@@ -75,7 +75,7 @@ shaka.text.Mp4TtmlParser = class {
75
75
  * @override
76
76
  * @export
77
77
  */
78
- parseMedia(data, time) {
78
+ parseMedia(data, time, uri) {
79
79
  const Mp4Parser = shaka.util.Mp4Parser;
80
80
 
81
81
  let sawMDAT = false;
@@ -86,7 +86,7 @@ shaka.text.Mp4TtmlParser = class {
86
86
  sawMDAT = true;
87
87
  // Join this to any previous payload, in case the mp4 has multiple
88
88
  // mdats.
89
- payload = payload.concat(this.parser_.parseMedia(data, time));
89
+ payload = payload.concat(this.parser_.parseMedia(data, time, uri));
90
90
  }));
91
91
  parser.parse(data, /* partialOkay= */ false);
92
92
 
@@ -55,7 +55,7 @@ shaka.text.SrtTextParser = class {
55
55
  * @override
56
56
  * @export
57
57
  */
58
- parseMedia(data, time) {
58
+ parseMedia(data, time, uri) {
59
59
  const SrtTextParser = shaka.text.SrtTextParser;
60
60
  const BufferUtils = shaka.util.BufferUtils;
61
61
  const StringUtils = shaka.util.StringUtils;
@@ -67,7 +67,7 @@ shaka.text.SrtTextParser = class {
67
67
 
68
68
  const newData = BufferUtils.toUint8(StringUtils.toUTF8(vvtText));
69
69
 
70
- return this.parser_.parseMedia(newData, time);
70
+ return this.parser_.parseMedia(newData, time, uri);
71
71
  }
72
72
 
73
73
  /**
@@ -0,0 +1,51 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.text.StubTextDisplayer');
8
+
9
+ /**
10
+ * A stub text displayer plugin that does nothing
11
+ *
12
+ * @implements {shaka.extern.TextDisplayer}
13
+ * @export
14
+ */
15
+ shaka.text.StubTextDisplayer = class {
16
+ /**
17
+ * @override
18
+ * @export
19
+ */
20
+ remove(start, end) {
21
+ }
22
+
23
+ /**
24
+ * @override
25
+ * @export
26
+ */
27
+ append(cues) {
28
+ }
29
+
30
+ /**
31
+ * @override
32
+ * @export
33
+ */
34
+ destroy() {
35
+ }
36
+
37
+ /**
38
+ * @override
39
+ * @export
40
+ */
41
+ isTextVisible() {
42
+ return false;
43
+ }
44
+
45
+ /**
46
+ * @override
47
+ * @export
48
+ */
49
+ setTextVisibility(on) {
50
+ }
51
+ };
@@ -166,9 +166,10 @@ shaka.text.TextEngine = class {
166
166
  * @param {BufferSource} buffer
167
167
  * @param {?number} startTime relative to the start of the presentation
168
168
  * @param {?number} endTime relative to the start of the presentation
169
+ * @param {?string=} uri
169
170
  * @return {!Promise}
170
171
  */
171
- async appendBuffer(buffer, startTime, endTime) {
172
+ async appendBuffer(buffer, startTime, endTime, uri) {
172
173
  goog.asserts.assert(
173
174
  this.parser_, 'The parser should already be initialized');
174
175
 
@@ -198,7 +199,7 @@ shaka.text.TextEngine = class {
198
199
 
199
200
  // Parse the buffer and add the new cues.
200
201
  const allCues = this.parser_.parseMedia(
201
- shaka.util.BufferUtils.toUint8(buffer), time);
202
+ shaka.util.BufferUtils.toUint8(buffer), time, uri);
202
203
  const cuesToAppend = allCues.filter((cue) => {
203
204
  return cue.startTime >= this.appendWindowStart_ &&
204
205
  cue.startTime < this.appendWindowEnd_;
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.text.TtmlTextParser');
8
8
 
9
9
  goog.require('goog.asserts');
10
+ goog.require('goog.Uri');
10
11
  goog.require('shaka.log');
11
12
  goog.require('shaka.text.Cue');
12
13
  goog.require('shaka.text.CueRegion');
@@ -50,7 +51,7 @@ shaka.text.TtmlTextParser = class {
50
51
  * @override
51
52
  * @export
52
53
  */
53
- parseMedia(data, time) {
54
+ parseMedia(data, time, uri) {
54
55
  const TtmlTextParser = shaka.text.TtmlTextParser;
55
56
  const XmlUtils = shaka.util.XmlUtils;
56
57
  const ttpNs = TtmlTextParser.parameterNs_;
@@ -147,7 +148,7 @@ shaka.text.TtmlTextParser = class {
147
148
  body, time, rateInfo, metadataElements, styles,
148
149
  regionElements, cueRegions, whitespaceTrim,
149
150
  cellResolutionInfo, /* parentCueElement= */ null,
150
- /* isContent= */ false);
151
+ /* isContent= */ false, uri);
151
152
  if (cue) {
152
153
  // According to the TTML spec, backgrounds default to transparent.
153
154
  // So default the background of the top-level element to transparent.
@@ -175,12 +176,14 @@ shaka.text.TtmlTextParser = class {
175
176
  * @param {?{columns: number, rows: number}} cellResolution
176
177
  * @param {?Element} parentCueElement
177
178
  * @param {boolean} isContent
179
+ * @param {?(string|undefined)} uri
178
180
  * @return {shaka.text.Cue}
179
181
  * @private
180
182
  */
181
183
  static parseCue_(
182
184
  cueNode, timeContext, rateInfo, metadataElements, styles, regionElements,
183
- cueRegions, whitespaceTrim, cellResolution, parentCueElement, isContent) {
185
+ cueRegions, whitespaceTrim, cellResolution, parentCueElement, isContent,
186
+ uri) {
184
187
  /** @type {Element} */
185
188
  let cueElement;
186
189
  /** @type {Element} */
@@ -222,7 +225,21 @@ shaka.text.TtmlTextParser = class {
222
225
  }
223
226
  }
224
227
 
225
- if (cueNode.nodeName == 'p' || imageElement) {
228
+ let imageUri = null;
229
+ const backgroundImage = shaka.util.XmlUtils.getAttributeNSList(
230
+ cueElement,
231
+ shaka.text.TtmlTextParser.smpteNsList_,
232
+ 'backgroundImage');
233
+ if (uri && backgroundImage && !backgroundImage.startsWith('#')) {
234
+ const baseUri = new goog.Uri(uri);
235
+ const relativeUri = new goog.Uri(backgroundImage);
236
+ const newUri = baseUri.resolve(relativeUri).toString();
237
+ if (newUri) {
238
+ imageUri = newUri;
239
+ }
240
+ }
241
+
242
+ if (cueNode.nodeName == 'p' || imageElement || imageUri) {
226
243
  isContent = true;
227
244
  }
228
245
 
@@ -255,6 +272,7 @@ shaka.text.TtmlTextParser = class {
255
272
  cellResolution,
256
273
  cueElement,
257
274
  isContent,
275
+ uri,
258
276
  );
259
277
 
260
278
  // This node may or may not generate a nested cue.
@@ -388,6 +406,7 @@ shaka.text.TtmlTextParser = class {
388
406
  cueElement,
389
407
  regionElementForStyle,
390
408
  imageElement,
409
+ imageUri,
391
410
  styles,
392
411
  /** isNested= */ parentIsContent, // "nested in a <div>" doesn't count.
393
412
  /** isLeaf= */ (nestedCues.length == 0));
@@ -490,13 +509,15 @@ shaka.text.TtmlTextParser = class {
490
509
  * @param {!Element} cueElement
491
510
  * @param {Element} region
492
511
  * @param {Element} imageElement
512
+ * @param {?string} imageUri
493
513
  * @param {!Array.<!Element>} styles
494
514
  * @param {boolean} isNested
495
515
  * @param {boolean} isLeaf
496
516
  * @private
497
517
  */
498
518
  static addStyle_(
499
- cue, cueElement, region, imageElement, styles, isNested, isLeaf) {
519
+ cue, cueElement, region, imageElement, imageUri, styles,
520
+ isNested, isLeaf) {
500
521
  const TtmlTextParser = shaka.text.TtmlTextParser;
501
522
  const Cue = shaka.text.Cue;
502
523
 
@@ -664,6 +685,8 @@ shaka.text.TtmlTextParser = class {
664
685
  backgroundImageData) {
665
686
  cue.backgroundImage = 'data:image/png;base64,' + backgroundImageData;
666
687
  }
688
+ } else if (imageUri) {
689
+ cue.backgroundImage = imageUri;
667
690
  }
668
691
 
669
692
  const textOutline = TtmlTextParser.getStyleAttribute_(
@@ -724,6 +747,23 @@ shaka.text.TtmlTextParser = class {
724
747
  if (textDecorationElement) {
725
748
  TtmlTextParser.addTextDecoration_(cue, textDecorationElement);
726
749
  }
750
+
751
+ const textCombine = TtmlTextParser.getStyleAttribute_(
752
+ cueElement, region, styles, 'textCombine', shouldInheritRegionStyles);
753
+ if (textCombine) {
754
+ cue.textCombineUpright = textCombine;
755
+ }
756
+
757
+ const ruby = TtmlTextParser.getStyleAttribute_(
758
+ cueElement, region, styles, 'ruby', shouldInheritRegionStyles);
759
+ switch (ruby) {
760
+ case 'container':
761
+ cue.rubyTag = 'ruby';
762
+ break;
763
+ case 'text':
764
+ cue.rubyTag = 'rt';
765
+ break;
766
+ }
727
767
  }
728
768
 
729
769
  /**
@@ -452,6 +452,9 @@ shaka.text.UITextDisplayer = class {
452
452
  if (cue.lineBreak) {
453
453
  type = 'br';
454
454
  }
455
+ if (cue.rubyTag) {
456
+ type = cue.rubyTag;
457
+ }
455
458
 
456
459
  const needWrapper = !isNested && cue.nestedCues.length > 0;
457
460
 
@@ -561,6 +564,7 @@ shaka.text.UITextDisplayer = class {
561
564
  style.paddingRight =
562
565
  shaka.text.UITextDisplayer.convertLengthValue_(
563
566
  cue.linePadding, cue, this.videoContainer_);
567
+ style.textCombineUpright = cue.textCombineUpright;
564
568
  style.textShadow = cue.textShadow;
565
569
 
566
570
  if (cue.backgroundImage) {
@@ -600,6 +604,10 @@ shaka.text.UITextDisplayer = class {
600
604
  // Only do this for the text itself.
601
605
  elem.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
602
606
  }
607
+ const fontFamily = inherit((c) => c.fontFamily);
608
+ if (fontFamily) {
609
+ elem.style.fontFamily = fontFamily;
610
+ }
603
611
  }
604
612
  if (text) {
605
613
  elem.textContent = text;
@@ -333,6 +333,10 @@ shaka.text.VttTextParser = class {
333
333
  validStyle = true;
334
334
  cue.opacity = parseFloat(value);
335
335
  break;
336
+ case 'text-combine-upright':
337
+ validStyle = true;
338
+ cue.textCombineUpright = value;
339
+ break;
336
340
  case 'text-shadow':
337
341
  validStyle = true;
338
342
  cue.textShadow = value;
@@ -417,8 +421,6 @@ shaka.text.VttTextParser = class {
417
421
  cue = new shaka.text.Cue(start, end, '');
418
422
  }
419
423
 
420
- VttTextParser.parseCueStyles(payload, cue, styles);
421
-
422
424
  // Parse optional settings.
423
425
  parser.skipWhitespace();
424
426
  let word = parser.readWord();
@@ -432,6 +434,8 @@ shaka.text.VttTextParser = class {
432
434
  word = parser.readWord();
433
435
  }
434
436
 
437
+ VttTextParser.parseCueStyles(payload, cue, styles);
438
+
435
439
  if (id != null) {
436
440
  cue.id = id;
437
441
  }
@@ -456,8 +460,6 @@ shaka.text.VttTextParser = class {
456
460
  const xmlPayload = '<span>' + payload + '</span>';
457
461
  const element = shaka.util.XmlUtils.parseXmlString(xmlPayload, 'span');
458
462
  if (element) {
459
- /** @type {!Array.<!shaka.text.Cue>} */
460
- const cues = [];
461
463
  const childNodes = element.childNodes;
462
464
  if (childNodes.length == 1) {
463
465
  const childNode = childNodes[0];
@@ -468,10 +470,8 @@ shaka.text.VttTextParser = class {
468
470
  }
469
471
  }
470
472
  for (const childNode of childNodes) {
471
- VttTextParser.generateCueFromElement_(
472
- childNode, rootCue, cues, styles);
473
+ VttTextParser.generateCueFromElement_(childNode, rootCue, styles);
473
474
  }
474
- rootCue.nestedCues = cues;
475
475
  } else {
476
476
  shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
477
477
  rootCue.payload = VttTextParser.htmlUnescape_(payload);
@@ -688,6 +688,8 @@ shaka.text.VttTextParser = class {
688
688
  cue.fontWeight = refCue.fontWeight;
689
689
  cue.fontStyle = refCue.fontStyle;
690
690
  cue.opacity = refCue.opacity;
691
+ cue.rubyTag = refCue.rubyTag;
692
+ cue.textCombineUpright = refCue.textCombineUpright;
691
693
  cue.textShadow = refCue.textShadow;
692
694
  cue.wrapLine = refCue.wrapLine;
693
695
  }
@@ -695,13 +697,21 @@ shaka.text.VttTextParser = class {
695
697
  /**
696
698
  * @param {!Node} element
697
699
  * @param {!shaka.text.Cue} rootCue
698
- * @param {Array.<!shaka.text.Cue>} cues
699
700
  * @param {!Map.<string, shaka.text.Cue>} styles
700
701
  * @private
701
702
  */
702
- static generateCueFromElement_(element, rootCue, cues, styles) {
703
+ static generateCueFromElement_(element, rootCue, styles) {
703
704
  const VttTextParser = shaka.text.VttTextParser;
704
705
  const nestedCue = rootCue.clone();
706
+ // We don't want propagate some properties.
707
+ nestedCue.nestedCues = [];
708
+ nestedCue.payload = '';
709
+ nestedCue.rubyTag = '';
710
+ // We don't want propagate some position settings
711
+ nestedCue.line = null;
712
+ nestedCue.region = new shaka.text.CueRegion();
713
+ nestedCue.position = null;
714
+ nestedCue.size = 0;
705
715
  if (element.nodeType === Node.ELEMENT_NODE && element.nodeName) {
706
716
  const bold = shaka.text.Cue.fontWeight.BOLD;
707
717
  const italic = shaka.text.Cue.fontStyle.ITALIC;
@@ -724,10 +734,10 @@ shaka.text.VttTextParser = class {
724
734
  }
725
735
  switch (tag) {
726
736
  case 'br': {
727
- const lineBreakCue = rootCue.clone();
728
- lineBreakCue.lineBreak = true;
729
- cues.push(lineBreakCue);
730
- break;
737
+ const lineBreakCue = shaka.text.Cue.lineBreak(
738
+ nestedCue.startTime, nestedCue.endTime);
739
+ rootCue.nestedCues.push(lineBreakCue);
740
+ return;
731
741
  }
732
742
  case 'b':
733
743
  nestedCue.fontWeight = bold;
@@ -758,34 +768,42 @@ shaka.text.VttTextParser = class {
758
768
  }
759
769
  break;
760
770
  }
771
+ case 'ruby':
772
+ case 'rp':
773
+ case 'rt':
774
+ nestedCue.rubyTag = tag;
775
+ break;
761
776
  default:
762
777
  break;
763
778
  }
764
779
  }
765
780
  }
766
- const isTextNode = shaka.util.XmlUtils.isText(element);
767
- if (isTextNode) {
781
+
782
+ const isTextNode = (item) => shaka.util.XmlUtils.isText(item);
783
+ const childNodes = element.childNodes;
784
+ if (isTextNode(element) ||
785
+ (childNodes.length == 1 && isTextNode(childNodes[0]))) {
768
786
  // Trailing line breaks may lost when convert cue to HTML tag
769
787
  // Need to insert line break cue to preserve line breaks
770
788
  const textArr = element.textContent.split('\n');
771
789
  let isFirst = true;
772
790
  for (const text of textArr) {
773
791
  if (!isFirst) {
774
- const lineBreakCue = rootCue.clone();
775
- lineBreakCue.lineBreak = true;
776
- cues.push(lineBreakCue);
792
+ const lineBreakCue = shaka.text.Cue.lineBreak(
793
+ nestedCue.startTime, nestedCue.endTime);
794
+ rootCue.nestedCues.push(lineBreakCue);
777
795
  }
778
796
  if (text.length > 0) {
779
797
  const textCue = nestedCue.clone();
780
798
  textCue.payload = VttTextParser.htmlUnescape_(text);
781
- cues.push(textCue);
799
+ rootCue.nestedCues.push(textCue);
782
800
  }
783
801
  isFirst = false;
784
802
  }
785
803
  } else {
786
- for (const childNode of element.childNodes) {
787
- VttTextParser.generateCueFromElement_(
788
- childNode, nestedCue, cues, styles);
804
+ rootCue.nestedCues.push(nestedCue);
805
+ for (const childNode of childNodes) {
806
+ VttTextParser.generateCueFromElement_(childNode, nestedCue, styles);
789
807
  }
790
808
  }
791
809
  }
@@ -95,7 +95,7 @@ shaka.transmuxer.AacTransmuxer = class {
95
95
  * @override
96
96
  * @export
97
97
  */
98
- getOrginalMimeType() {
98
+ getOriginalMimeType() {
99
99
  return this.originalMimeType_;
100
100
  }
101
101
 
@@ -93,7 +93,7 @@ shaka.transmuxer.Ac3Transmuxer = class {
93
93
  * @override
94
94
  * @export
95
95
  */
96
- getOrginalMimeType() {
96
+ getOriginalMimeType() {
97
97
  return this.originalMimeType_;
98
98
  }
99
99
 
@@ -93,7 +93,7 @@ shaka.transmuxer.Ec3Transmuxer = class {
93
93
  * @override
94
94
  * @export
95
95
  */
96
- getOrginalMimeType() {
96
+ getOriginalMimeType() {
97
97
  return this.originalMimeType_;
98
98
  }
99
99
 
@@ -175,7 +175,7 @@ shaka.transmuxer.H264 = class {
175
175
  static parseFrame(nalus) {
176
176
  const H264 = shaka.transmuxer.H264;
177
177
  let isKeyframe = false;
178
- let data = new Uint8Array([]);
178
+ const nalusData = [];
179
179
  const spsNalu = nalus.find((nalu) => {
180
180
  return nalu.type == H264.NALU_TYPE_SPS_;
181
181
  });
@@ -240,13 +240,14 @@ shaka.transmuxer.H264 = class {
240
240
  naluLength[1] = (size >> 16) & 0xff;
241
241
  naluLength[2] = (size >> 8) & 0xff;
242
242
  naluLength[3] = size & 0xff;
243
- data = shaka.util.Uint8ArrayUtils.concat(
244
- data, naluLength, nalu.fullData);
243
+ nalusData.push(shaka.util.Uint8ArrayUtils.concat(
244
+ naluLength, nalu.fullData));
245
245
  }
246
246
  }
247
- if (!data.byteLength) {
247
+ if (!nalusData.length) {
248
248
  return null;
249
249
  }
250
+ const data = shaka.util.Uint8ArrayUtils.concat(...nalusData);
250
251
  return {
251
252
  data,
252
253
  isKeyframe,