shaka-player 4.3.9 → 4.4.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 (321) hide show
  1. package/.github/workflows/build-and-test.yaml +11 -18
  2. package/.github/workflows/compute-incremental-coverage.py +3 -0
  3. package/.github/workflows/release-please.yaml +7 -0
  4. package/.github/workflows/selenium-lab-tests.yaml +45 -10
  5. package/AUTHORS +9 -0
  6. package/CHANGELOG.md +295 -190
  7. package/CONTRIBUTORS +8 -0
  8. package/LICENSE +32 -0
  9. package/README.md +63 -10
  10. package/demo/autoTemplate.txt +40 -5
  11. package/demo/close_button.js +11 -0
  12. package/demo/common/asset.js +13 -1
  13. package/demo/common/assets.js +112 -28
  14. package/demo/common/message_ids.js +25 -1
  15. package/demo/config.js +69 -10
  16. package/demo/customWarning.txt +2 -2
  17. package/demo/index.html +3 -1
  18. package/demo/locales/en.json +26 -2
  19. package/demo/locales/source.json +105 -9
  20. package/demo/main.js +57 -9
  21. package/demo/search.js +3 -1
  22. package/demo/service_worker.js +3 -0
  23. package/dist/controls.css +1 -1
  24. package/dist/controls.css.map +1 -1
  25. package/dist/demo.compiled.debug.js +132 -118
  26. package/dist/demo.compiled.debug.map +3 -3
  27. package/dist/demo.compiled.js +132 -118
  28. package/dist/demo.compiled.map +3 -3
  29. package/dist/deps.js +46 -28
  30. package/dist/locales.js +31 -31
  31. package/dist/receiver.compiled.debug.js +60 -52
  32. package/dist/receiver.compiled.debug.map +3 -3
  33. package/dist/receiver.compiled.js +60 -52
  34. package/dist/receiver.compiled.map +3 -3
  35. package/dist/shaka-player.compiled.d.ts +676 -391
  36. package/dist/shaka-player.compiled.debug.d.ts +676 -391
  37. package/dist/shaka-player.compiled.debug.externs.js +1188 -616
  38. package/dist/shaka-player.compiled.debug.js +1046 -700
  39. package/dist/shaka-player.compiled.debug.map +4 -4
  40. package/dist/shaka-player.compiled.externs.js +1188 -616
  41. package/dist/shaka-player.compiled.js +1094 -933
  42. package/dist/shaka-player.compiled.map +4 -4
  43. package/dist/shaka-player.ui.d.ts +677 -392
  44. package/dist/shaka-player.ui.debug.d.ts +677 -392
  45. package/dist/shaka-player.ui.debug.externs.js +1023 -451
  46. package/dist/shaka-player.ui.debug.js +1101 -738
  47. package/dist/shaka-player.ui.debug.map +4 -4
  48. package/dist/shaka-player.ui.externs.js +1023 -451
  49. package/dist/shaka-player.ui.js +1244 -1071
  50. package/dist/shaka-player.ui.map +4 -4
  51. package/docs/tutorials/ad_monetization.md +15 -1
  52. package/docs/tutorials/application-level-redirects.md +1 -1
  53. package/docs/tutorials/config.md +9 -5
  54. package/docs/tutorials/drm-config.md +61 -0
  55. package/docs/tutorials/fairplay.md +19 -4
  56. package/docs/tutorials/license-server-auth.md +4 -4
  57. package/docs/tutorials/license-wrapping.md +2 -2
  58. package/docs/tutorials/ui-customization.md +7 -3
  59. package/docs/tutorials/ui.md +7 -7
  60. package/docs/tutorials/upgrade.md +3 -0
  61. package/externs/ima.js +123 -2
  62. package/externs/isoboxer.js +217 -0
  63. package/externs/mediakeys.js +18 -0
  64. package/externs/mux.js +1 -105
  65. package/externs/pictureinpicture.js +48 -0
  66. package/externs/shaka/ads.js +61 -1
  67. package/externs/shaka/cea.js +110 -0
  68. package/externs/shaka/codecs.js +32 -0
  69. package/externs/shaka/manifest.js +101 -1
  70. package/externs/shaka/manifest_parser.js +0 -10
  71. package/externs/shaka/net.js +36 -7
  72. package/externs/shaka/offline.js +8 -1
  73. package/externs/shaka/player.js +220 -21
  74. package/externs/shaka/text.js +1 -382
  75. package/externs/shaka/transmuxer.js +59 -0
  76. package/karma.conf.js +15 -0
  77. package/lib/abr/simple_abr_manager.js +6 -3
  78. package/lib/ads/ad_manager.js +60 -2
  79. package/lib/ads/client_side_ad.js +86 -0
  80. package/lib/ads/client_side_ad_manager.js +93 -5
  81. package/lib/ads/server_side_ad.js +86 -0
  82. package/lib/ads/server_side_ad_manager.js +13 -0
  83. package/lib/cast/cast_utils.js +1 -0
  84. package/lib/cea/cea608_data_channel.js +24 -14
  85. package/lib/cea/cea608_memory.js +5 -2
  86. package/lib/cea/cea708_service.js +8 -9
  87. package/lib/cea/cea708_window.js +1 -2
  88. package/lib/cea/cea_decoder.js +23 -6
  89. package/lib/cea/cea_utils.js +25 -2
  90. package/lib/cea/dummy_caption_decoder.js +21 -0
  91. package/lib/cea/dummy_cea_parser.js +1 -3
  92. package/lib/cea/mp4_cea_parser.js +15 -10
  93. package/lib/cea/ts_cea_parser.js +69 -0
  94. package/lib/dash/content_protection.js +32 -2
  95. package/lib/dash/dash_parser.js +93 -31
  96. package/lib/dash/mpd_utils.js +6 -25
  97. package/lib/dash/segment_base.js +12 -14
  98. package/lib/dash/segment_list.js +10 -6
  99. package/lib/dash/segment_template.js +349 -32
  100. package/lib/dependencies/all.js +8 -0
  101. package/lib/hls/hls_classes.js +33 -8
  102. package/lib/hls/hls_parser.js +805 -191
  103. package/lib/hls/manifest_text_parser.js +4 -14
  104. package/lib/media/adaptation_set_criteria.js +43 -3
  105. package/lib/media/closed_caption_parser.js +74 -12
  106. package/lib/media/drm_engine.js +189 -49
  107. package/lib/media/gap_jumping_controller.js +1 -1
  108. package/lib/media/manifest_parser.js +34 -0
  109. package/lib/media/media_source_capabilities.js +10 -0
  110. package/lib/media/media_source_engine.js +475 -231
  111. package/lib/media/playhead.js +1 -1
  112. package/lib/media/presentation_timeline.js +62 -0
  113. package/lib/media/segment_index.js +50 -14
  114. package/lib/media/segment_prefetch.js +277 -0
  115. package/lib/media/segment_reference.js +70 -4
  116. package/lib/media/streaming_engine.js +258 -81
  117. package/lib/media/video_wrapper.js +15 -7
  118. package/lib/mss/content_protection.js +353 -0
  119. package/lib/mss/mss_parser.js +1081 -0
  120. package/lib/net/networking_engine.js +60 -10
  121. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  122. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  123. package/lib/offline/manifest_converter.js +6 -0
  124. package/lib/offline/storage.js +2 -4
  125. package/lib/player.js +309 -105
  126. package/lib/polyfill/media_capabilities.js +43 -3
  127. package/lib/polyfill/patchedmediakeys_apple.js +5 -0
  128. package/lib/polyfill/patchedmediakeys_nop.js +5 -0
  129. package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
  130. package/lib/text/cue.js +208 -130
  131. package/lib/text/lrc_text_parser.js +2 -2
  132. package/lib/text/mp4_vtt_parser.js +2 -2
  133. package/lib/text/sbv_text_parser.js +1 -1
  134. package/lib/text/simple_text_displayer.js +2 -1
  135. package/lib/text/srt_text_parser.js +9 -1
  136. package/lib/text/ssa_text_parser.js +2 -2
  137. package/lib/text/text_engine.js +3 -21
  138. package/lib/text/text_utils.js +71 -20
  139. package/lib/text/ui_text_displayer.js +14 -14
  140. package/lib/text/vtt_text_parser.js +22 -14
  141. package/lib/transmuxer/aac_transmuxer.js +224 -0
  142. package/lib/transmuxer/ac3.js +142 -0
  143. package/lib/transmuxer/ac3_transmuxer.js +212 -0
  144. package/lib/transmuxer/adts.js +232 -0
  145. package/lib/transmuxer/ec3.js +103 -0
  146. package/lib/transmuxer/ec3_transmuxer.js +212 -0
  147. package/lib/transmuxer/h264.js +324 -0
  148. package/lib/transmuxer/mp3_transmuxer.js +204 -0
  149. package/lib/transmuxer/mpeg_audio.js +196 -0
  150. package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
  151. package/lib/transmuxer/mss_transmuxer.js +389 -0
  152. package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
  153. package/lib/transmuxer/transmuxer_engine.js +161 -0
  154. package/lib/transmuxer/ts_transmuxer.js +738 -0
  155. package/lib/util/cmcd_manager.js +131 -71
  156. package/lib/util/error.js +62 -26
  157. package/lib/util/exp_golomb.js +220 -0
  158. package/lib/util/fairplay_utils.js +64 -13
  159. package/lib/util/id3_utils.js +56 -3
  160. package/lib/util/language_utils.js +11 -8
  161. package/lib/util/manifest_parser_utils.js +3 -0
  162. package/lib/util/mime_utils.js +44 -7
  163. package/lib/util/mp4_box_parsers.js +233 -5
  164. package/lib/util/mp4_generator.js +1381 -0
  165. package/lib/util/periods.js +40 -34
  166. package/lib/util/platform.js +25 -3
  167. package/lib/util/player_configuration.js +38 -1
  168. package/lib/util/stream_utils.js +138 -27
  169. package/lib/util/text_parser.js +1 -1
  170. package/lib/util/ts_parser.js +470 -47
  171. package/lib/util/xml_utils.js +16 -3
  172. package/maintained-branches.md +2 -2
  173. package/package.json +4 -2
  174. package/roadmap.md +21 -6
  175. package/shaka-player.uncompiled.js +18 -0
  176. package/test/abr/simple_abr_manager_unit.js +32 -4
  177. package/test/ads/ad_manager_unit.js +18 -2
  178. package/test/cast/cast_utils_unit.js +7 -2
  179. package/test/cea/cea608_memory_unit.js +24 -0
  180. package/test/cea/cea_decoder_unit.js +33 -0
  181. package/test/dash/dash_parser_content_protection_unit.js +93 -3
  182. package/test/dash/dash_parser_live_unit.js +56 -13
  183. package/test/dash/dash_parser_manifest_unit.js +70 -2
  184. package/test/dash/dash_parser_segment_base_unit.js +14 -9
  185. package/test/dash/dash_parser_segment_template_unit.js +286 -6
  186. package/test/demo/demo_unit.js +5 -1
  187. package/test/hls/hls_live_unit.js +188 -28
  188. package/test/hls/hls_parser_unit.js +250 -109
  189. package/test/hls/manifest_text_parser_unit.js +18 -13
  190. package/test/media/adaptation_set_criteria_unit.js +46 -14
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/drm_engine_integration.js +11 -8
  193. package/test/media/drm_engine_unit.js +220 -7
  194. package/test/media/media_source_engine_integration.js +122 -38
  195. package/test/media/media_source_engine_unit.js +133 -153
  196. package/test/media/playhead_unit.js +3 -0
  197. package/test/media/presentation_timeline_unit.js +51 -0
  198. package/test/media/segment_index_unit.js +52 -0
  199. package/test/media/segment_prefetch_unit.js +243 -0
  200. package/test/media/streaming_engine_integration.js +9 -3
  201. package/test/media/streaming_engine_unit.js +440 -59
  202. package/test/mss/mss_parser_content_protection_unit.js +49 -0
  203. package/test/mss/mss_parser_unit.js +472 -0
  204. package/test/mss/mss_player_integration.js +123 -0
  205. package/test/offline/manifest_convert_unit.js +9 -0
  206. package/test/offline/storage_integration.js +6 -1
  207. package/test/player_integration.js +4 -1
  208. package/test/player_unit.js +386 -133
  209. package/test/polyfill/media_capabilities_unit.js +18 -0
  210. package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
  211. package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
  212. package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
  213. package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
  214. package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
  215. package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
  216. package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
  217. package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
  218. package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
  219. package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
  220. package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
  221. package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
  222. package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
  223. package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
  224. package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
  225. package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
  226. package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
  227. package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
  228. package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
  229. package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
  230. package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
  231. package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
  232. package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
  233. package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
  234. package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
  235. package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
  236. package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
  237. package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
  238. package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
  239. package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
  240. package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
  241. package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
  242. package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
  243. package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
  244. package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
  245. package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
  246. package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
  247. package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
  248. package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
  249. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
  250. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
  251. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
  252. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
  253. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
  254. package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
  255. package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
  256. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
  257. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
  258. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
  259. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
  260. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
  261. package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
  262. package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
  263. package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
  264. package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
  265. package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
  266. package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
  267. package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
  268. package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
  269. package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
  270. package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
  271. package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
  272. package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
  273. package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
  274. package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
  275. package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
  276. package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
  277. package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
  278. package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
  279. package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
  280. package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
  281. package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
  282. package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
  283. package/test/test/boot.js +7 -2
  284. package/test/test/util/fake_ad.js +99 -0
  285. package/test/test/util/fake_ad_manager.js +7 -1
  286. package/test/test/util/fake_networking_engine.js +41 -14
  287. package/test/test/util/fake_segment_prefetch.js +81 -0
  288. package/test/test/util/manifest_generator.js +19 -5
  289. package/test/test/util/mss_parser_util.js +115 -0
  290. package/test/test/util/offline_utils.js +1 -0
  291. package/test/test/util/simple_fakes.js +12 -3
  292. package/test/test/util/streaming_engine_util.js +14 -4
  293. package/test/test/util/ttml_utils.js +2 -2
  294. package/test/test/util/ui_utils.js +5 -1
  295. package/test/text/cue_integration.js +1 -1
  296. package/test/text/srt_text_parser_unit.js +78 -0
  297. package/test/text/text_engine_unit.js +17 -8
  298. package/test/text/ui_text_displayer_unit.js +4 -4
  299. package/test/text/vtt_text_parser_unit.js +59 -40
  300. package/test/text/web_vtt_generator_unit.js +9 -3
  301. package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
  302. package/test/transmuxer/transmuxer_engine_integration.js +60 -0
  303. package/test/transmuxer/transmuxer_integration.js +296 -0
  304. package/test/util/cmcd_manager_unit.js +162 -13
  305. package/test/util/language_utils_unit.js +9 -2
  306. package/test/util/mp4_box_parsers_unit.js +39 -4
  307. package/test/util/periods_unit.js +34 -26
  308. package/test/util/stream_utils_unit.js +60 -107
  309. package/ui/controls.js +19 -1
  310. package/ui/controls.less +1 -0
  311. package/ui/externs/ui.js +13 -3
  312. package/ui/language_utils.js +15 -0
  313. package/ui/less/thumbnails.less +26 -0
  314. package/ui/locales/oc.json +42 -0
  315. package/ui/pip_button.js +83 -2
  316. package/ui/range_element.js +15 -0
  317. package/ui/resolution_selection.js +9 -2
  318. package/ui/seek_bar.js +230 -1
  319. package/ui/ui.js +5 -0
  320. package/lib/cea/i_caption_decoder.js +0 -51
  321. package/lib/cea/i_cea_parser.js +0 -68
@@ -0,0 +1,1381 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.util.Mp4Generator');
8
+
9
+ goog.require('goog.asserts');
10
+ goog.require('shaka.util.ManifestParserUtils');
11
+ goog.require('shaka.util.Uint8ArrayUtils');
12
+
13
+
14
+ shaka.util.Mp4Generator = class {
15
+ /**
16
+ * @param {!Array.<shaka.util.Mp4Generator.StreamInfo>} streamInfos
17
+ */
18
+ constructor(streamInfos) {
19
+ shaka.util.Mp4Generator.initStaticProperties_();
20
+
21
+ /** @private {!Array.<shaka.util.Mp4Generator.StreamInfo>} */
22
+ this.streamInfos_ = streamInfos;
23
+ }
24
+
25
+ /**
26
+ * Generate a Init Segment (MP4).
27
+ *
28
+ * @return {!Uint8Array}
29
+ */
30
+ initSegment() {
31
+ const Mp4Generator = shaka.util.Mp4Generator;
32
+ const movie = this.moov_();
33
+ const length = Mp4Generator.FTYP_.byteLength + movie.byteLength;
34
+ const result = new Uint8Array(length);
35
+ result.set(Mp4Generator.FTYP_);
36
+ result.set(movie, Mp4Generator.FTYP_.byteLength);
37
+ return result;
38
+ }
39
+
40
+ /**
41
+ * Generate a MOOV box
42
+ *
43
+ * @return {!Uint8Array}
44
+ * @private
45
+ */
46
+ moov_() {
47
+ goog.asserts.assert(this.streamInfos_.length > 0,
48
+ 'StreamInfos must have elements');
49
+ const Mp4Generator = shaka.util.Mp4Generator;
50
+ let traks = new Uint8Array([]);
51
+ for (const streamInfo of this.streamInfos_) {
52
+ traks = shaka.util.Uint8ArrayUtils.concat(traks, this.trak_(streamInfo));
53
+ }
54
+ const firstStreamInfo = this.streamInfos_[0];
55
+ return Mp4Generator.box('moov',
56
+ this.mvhd_(firstStreamInfo),
57
+ traks,
58
+ this.mvex_(firstStreamInfo),
59
+ this.pssh_(firstStreamInfo));
60
+ }
61
+
62
+ /**
63
+ * Generate a MVHD box
64
+ *
65
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
66
+ * @return {!Uint8Array}
67
+ * @private
68
+ */
69
+ mvhd_(streamInfo) {
70
+ const Mp4Generator = shaka.util.Mp4Generator;
71
+ const duration = streamInfo.duration * streamInfo.timescale;
72
+ const upperWordDuration =
73
+ Math.floor(duration / (Mp4Generator.UINT32_MAX_ + 1));
74
+ const lowerWordDuration =
75
+ Math.floor(duration % (Mp4Generator.UINT32_MAX_ + 1));
76
+ const bytes = new Uint8Array([
77
+ 0x01, // version 1
78
+ 0x00, 0x00, 0x00, // flags
79
+ 0x00, 0x00, 0x00, 0x00,
80
+ 0x00, 0x00, 0x00, 0x02, // creation_time
81
+ 0x00, 0x00, 0x00, 0x00,
82
+ 0x00, 0x00, 0x00, 0x03, // modification_time
83
+ ...this.breakNumberIntoBytes_(streamInfo.timescale, 4), // timescale
84
+ ...this.breakNumberIntoBytes_(upperWordDuration, 4),
85
+ ...this.breakNumberIntoBytes_(lowerWordDuration, 4), // duration
86
+ 0x00, 0x01, 0x00, 0x00, // 1.0 rate
87
+ 0x01, 0x00, // 1.0 volume
88
+ 0x00, 0x00, // reserved
89
+ 0x00, 0x00, 0x00, 0x00, // reserved
90
+ 0x00, 0x00, 0x00, 0x00, // reserved
91
+ 0x00, 0x01, 0x00, 0x00,
92
+ 0x00, 0x00, 0x00, 0x00,
93
+ 0x00, 0x00, 0x00, 0x00,
94
+ 0x00, 0x00, 0x00, 0x00,
95
+ 0x00, 0x01, 0x00, 0x00,
96
+ 0x00, 0x00, 0x00, 0x00,
97
+ 0x00, 0x00, 0x00, 0x00,
98
+ 0x00, 0x00, 0x00, 0x00,
99
+ 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
100
+ 0x00, 0x00, 0x00, 0x00,
101
+ 0x00, 0x00, 0x00, 0x00,
102
+ 0x00, 0x00, 0x00, 0x00,
103
+ 0x00, 0x00, 0x00, 0x00,
104
+ 0x00, 0x00, 0x00, 0x00,
105
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
106
+ 0xff, 0xff, 0xff, 0xff, // next_track_ID
107
+ ]);
108
+ return Mp4Generator.box('mvhd', bytes);
109
+ }
110
+
111
+ /**
112
+ * Generate a TRAK box
113
+ *
114
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
115
+ * @return {!Uint8Array}
116
+ * @private
117
+ */
118
+ trak_(streamInfo) {
119
+ const Mp4Generator = shaka.util.Mp4Generator;
120
+ return Mp4Generator.box('trak',
121
+ this.tkhd_(streamInfo), this.mdia_(streamInfo));
122
+ }
123
+
124
+ /**
125
+ * Generate a TKHD box
126
+ *
127
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
128
+ * @return {!Uint8Array}
129
+ * @private
130
+ */
131
+ tkhd_(streamInfo) {
132
+ const Mp4Generator = shaka.util.Mp4Generator;
133
+ const id = streamInfo.id + 1;
134
+ const width = streamInfo.stream.width || 0;
135
+ const height = streamInfo.stream.height || 0;
136
+ const duration = streamInfo.duration * streamInfo.timescale;
137
+ const upperWordDuration =
138
+ Math.floor(duration / (Mp4Generator.UINT32_MAX_ + 1));
139
+ const lowerWordDuration =
140
+ Math.floor(duration % (Mp4Generator.UINT32_MAX_ + 1));
141
+ const bytes = new Uint8Array([
142
+ 0x01, // version 1
143
+ 0x00, 0x00, 0x07, // flags
144
+ 0x00, 0x00, 0x00, 0x00,
145
+ 0x00, 0x00, 0x00, 0x02, // creation_time
146
+ 0x00, 0x00, 0x00, 0x00,
147
+ 0x00, 0x00, 0x00, 0x03, // modification_time
148
+ ...this.breakNumberIntoBytes_(id, 4), // track_ID
149
+ 0x00, 0x00, 0x00, 0x00, // reserved
150
+ ...this.breakNumberIntoBytes_(upperWordDuration, 4),
151
+ ...this.breakNumberIntoBytes_(lowerWordDuration, 4), // duration
152
+ 0x00, 0x00, 0x00, 0x00,
153
+ 0x00, 0x00, 0x00, 0x00, // reserved
154
+ 0x00, 0x00, // layer
155
+ 0x00, 0x00, // alternate_group
156
+ 0x00, 0x00, // non-audio track volume
157
+ 0x00, 0x00, // reserved
158
+ 0x00, 0x01, 0x00, 0x00,
159
+ 0x00, 0x00, 0x00, 0x00,
160
+ 0x00, 0x00, 0x00, 0x00,
161
+ 0x00, 0x00, 0x00, 0x00,
162
+ 0x00, 0x01, 0x00, 0x00,
163
+ 0x00, 0x00, 0x00, 0x00,
164
+ 0x00, 0x00, 0x00, 0x00,
165
+ 0x00, 0x00, 0x00, 0x00,
166
+ 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
167
+ ...this.breakNumberIntoBytes_(width, 2),
168
+ 0x00, 0x00, // width
169
+ ...this.breakNumberIntoBytes_(height, 2),
170
+ 0x00, 0x00, // height
171
+ ]);
172
+ return Mp4Generator.box('tkhd', bytes);
173
+ }
174
+
175
+ /**
176
+ * Generate a MDIA box
177
+ *
178
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
179
+ * @return {!Uint8Array}
180
+ * @private
181
+ */
182
+ mdia_(streamInfo) {
183
+ const Mp4Generator = shaka.util.Mp4Generator;
184
+ return Mp4Generator.box('mdia', this.mdhd_(streamInfo),
185
+ this.hdlr_(streamInfo), this.minf_(streamInfo));
186
+ }
187
+
188
+ /**
189
+ * Generate a MDHD box
190
+ *
191
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
192
+ * @return {!Uint8Array}
193
+ * @private
194
+ */
195
+ mdhd_(streamInfo) {
196
+ const Mp4Generator = shaka.util.Mp4Generator;
197
+ const duration = streamInfo.duration * streamInfo.timescale;
198
+ const upperWordDuration =
199
+ Math.floor(duration / (Mp4Generator.UINT32_MAX_ + 1));
200
+ const lowerWordDuration =
201
+ Math.floor(duration % (Mp4Generator.UINT32_MAX_ + 1));
202
+ const language = streamInfo.stream.language;
203
+ const languageNumber = ((language.charCodeAt(0) - 0x60) << 10) |
204
+ ((language.charCodeAt(1) - 0x60) << 5) |
205
+ ((language.charCodeAt(2) - 0x60));
206
+ const bytes = new Uint8Array([
207
+ 0x01, // version 1
208
+ 0x00, 0x00, 0x00, // flags
209
+ 0x00, 0x00, 0x00, 0x00,
210
+ 0x00, 0x00, 0x00, 0x02, // creation_time
211
+ 0x00, 0x00, 0x00, 0x00,
212
+ 0x00, 0x00, 0x00, 0x03, // modification_time
213
+ ...this.breakNumberIntoBytes_(streamInfo.timescale, 4), // timescale
214
+ ...this.breakNumberIntoBytes_(upperWordDuration, 4),
215
+ ...this.breakNumberIntoBytes_(lowerWordDuration, 4), // duration
216
+ ...this.breakNumberIntoBytes_(languageNumber, 2), // language
217
+ 0x00, 0x00,
218
+ ]);
219
+ return Mp4Generator.box('mdhd', bytes);
220
+ }
221
+
222
+ /**
223
+ * Generate a HDLR box
224
+ *
225
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
226
+ * @return {!Uint8Array}
227
+ * @private
228
+ */
229
+ hdlr_(streamInfo) {
230
+ const Mp4Generator = shaka.util.Mp4Generator;
231
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
232
+ let bytes = new Uint8Array([]);
233
+ switch (streamInfo.type) {
234
+ case ContentType.VIDEO:
235
+ bytes = Mp4Generator.HDLR_TYPES_.video;
236
+ break;
237
+ case ContentType.AUDIO:
238
+ bytes = Mp4Generator.HDLR_TYPES_.audio;
239
+ break;
240
+ }
241
+ return Mp4Generator.box('hdlr', bytes);
242
+ }
243
+
244
+ /**
245
+ * Generate a MINF box
246
+ *
247
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
248
+ * @return {!Uint8Array}
249
+ * @private
250
+ */
251
+ minf_(streamInfo) {
252
+ const Mp4Generator = shaka.util.Mp4Generator;
253
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
254
+ switch (streamInfo.type) {
255
+ case ContentType.VIDEO:
256
+ return Mp4Generator.box(
257
+ 'minf', Mp4Generator.box('vmhd', Mp4Generator.VMHD_),
258
+ Mp4Generator.DINF_, this.stbl_(streamInfo));
259
+ case ContentType.AUDIO:
260
+ return Mp4Generator.box(
261
+ 'minf', Mp4Generator.box('smhd', Mp4Generator.SMHD_),
262
+ Mp4Generator.DINF_, this.stbl_(streamInfo));
263
+ }
264
+ return new Uint8Array([]);
265
+ }
266
+
267
+ /**
268
+ * Generate a STBL box
269
+ *
270
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
271
+ * @return {!Uint8Array}
272
+ * @private
273
+ */
274
+ stbl_(streamInfo) {
275
+ const Mp4Generator = shaka.util.Mp4Generator;
276
+ return Mp4Generator.box(
277
+ 'stbl',
278
+ this.stsd_(streamInfo),
279
+ Mp4Generator.box('stts', Mp4Generator.STTS_),
280
+ Mp4Generator.box('stsc', Mp4Generator.STSC_),
281
+ Mp4Generator.box('stsz', Mp4Generator.STSZ_),
282
+ Mp4Generator.box('stco', Mp4Generator.STCO_));
283
+ }
284
+
285
+ /**
286
+ * Generate a STSD box
287
+ *
288
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
289
+ * @return {!Uint8Array}
290
+ * @private
291
+ */
292
+ stsd_(streamInfo) {
293
+ const Mp4Generator = shaka.util.Mp4Generator;
294
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
295
+ let bytes = new Uint8Array([]);
296
+ switch (streamInfo.type) {
297
+ case ContentType.VIDEO:
298
+ if (streamInfo.stream.codecs.includes('avc1.') ||
299
+ streamInfo.stream.codecs.includes('avc3.')) {
300
+ bytes = this.avc1_(streamInfo);
301
+ } else if (streamInfo.stream.codecs.includes('hev1.') ||
302
+ streamInfo.stream.codecs.includes('hvc1.')) {
303
+ bytes = this.hvc1_(streamInfo);
304
+ }
305
+ break;
306
+ case ContentType.AUDIO:
307
+ if (streamInfo.stream.mimeType === 'audio/mpeg' ||
308
+ streamInfo.stream.codecs.includes('mp3') ||
309
+ streamInfo.stream.codecs.includes('mp4a.40.34')) {
310
+ bytes = this.mp3_(streamInfo);
311
+ } else if (streamInfo.stream.mimeType === 'audio/ac3' ||
312
+ streamInfo.stream.codecs.includes('ac-3')) {
313
+ bytes = this.ac3_(streamInfo);
314
+ } else if (streamInfo.stream.mimeType === 'audio/ec3' ||
315
+ streamInfo.stream.codecs.includes('ec-3')) {
316
+ bytes = this.ec3_(streamInfo);
317
+ } else {
318
+ bytes = this.mp4a_(streamInfo);
319
+ }
320
+ break;
321
+ }
322
+ return Mp4Generator.box('stsd', Mp4Generator.STSD_, bytes);
323
+ }
324
+
325
+ /**
326
+ * Generate a AVC1 box
327
+ *
328
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
329
+ * @return {!Uint8Array}
330
+ * @private
331
+ */
332
+ avc1_(streamInfo) {
333
+ const Mp4Generator = shaka.util.Mp4Generator;
334
+
335
+ const width = streamInfo.stream.width || 0;
336
+ const height = streamInfo.stream.height || 0;
337
+
338
+ let avcCBox;
339
+ if (streamInfo.videoConfig.byteLength > 0) {
340
+ avcCBox = Mp4Generator.box('avcC', streamInfo.videoConfig);
341
+ } else {
342
+ avcCBox = Mp4Generator.box('avcC', this.avcC_(streamInfo));
343
+ }
344
+
345
+ const avc1Bytes = new Uint8Array([
346
+ 0x00, 0x00, 0x00,
347
+ 0x00, 0x00, 0x00, // reserved
348
+ 0x00, 0x01, // data_reference_index
349
+ 0x00, 0x00, // pre_defined
350
+ 0x00, 0x00, // reserved
351
+ 0x00, 0x00, 0x00, 0x00,
352
+ 0x00, 0x00, 0x00, 0x00,
353
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
354
+ ...this.breakNumberIntoBytes_(width, 2), // width
355
+ ...this.breakNumberIntoBytes_(height, 2), // height
356
+ 0x00, 0x48, 0x00, 0x00, // horizresolution
357
+ 0x00, 0x48, 0x00, 0x00, // vertresolution
358
+ 0x00, 0x00, 0x00, 0x00, // reserved
359
+ 0x00, 0x01, // frame_count
360
+ 0x13,
361
+ 0x76, 0x69, 0x64, 0x65,
362
+ 0x6f, 0x6a, 0x73, 0x2d,
363
+ 0x63, 0x6f, 0x6e, 0x74,
364
+ 0x72, 0x69, 0x62, 0x2d,
365
+ 0x68, 0x6c, 0x73, 0x00,
366
+ 0x00, 0x00, 0x00, 0x00,
367
+ 0x00, 0x00, 0x00, 0x00,
368
+ 0x00, 0x00, 0x00, // compressorname
369
+ 0x00, 0x18, // depth = 24
370
+ 0x11, 0x11, // pre_defined = -1
371
+ ]);
372
+
373
+ let boxName = 'avc1';
374
+ let sinfBox = new Uint8Array([]);
375
+ if (streamInfo.encrypted) {
376
+ sinfBox = this.sinf_(streamInfo);
377
+ boxName = 'encv';
378
+ }
379
+ return Mp4Generator.box(boxName, avc1Bytes, avcCBox, sinfBox);
380
+ }
381
+
382
+ /**
383
+ * Generate a AVCC box
384
+ *
385
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
386
+ * @return {!Uint8Array}
387
+ * @private
388
+ */
389
+ avcC_(streamInfo) {
390
+ const NALUTYPE_SPS = 7;
391
+ const NALUTYPE_PPS = 8;
392
+
393
+ // length = 7 by default (0 SPS and 0 PPS)
394
+ let avcCLength = 7;
395
+
396
+ // First get all SPS and PPS from nalus
397
+ const sps = [];
398
+ const pps = [];
399
+ let AVCProfileIndication = 0;
400
+ let AVCLevelIndication = 0;
401
+ let profileCompatibility = 0;
402
+ for (let i = 0; i < streamInfo.videoNalus.length; i++) {
403
+ const naluBytes = this.hexStringToBuffer_(streamInfo.videoNalus[i]);
404
+ const naluType = naluBytes[0] & 0x1F;
405
+ switch (naluType) {
406
+ case NALUTYPE_SPS:
407
+ sps.push(naluBytes);
408
+ // 2 = sequenceParameterSetLength field length
409
+ avcCLength += naluBytes.length + 2;
410
+ break;
411
+ case NALUTYPE_PPS:
412
+ pps.push(naluBytes);
413
+ // 2 = pictureParameterSetLength field length
414
+ avcCLength += naluBytes.length + 2;
415
+ break;
416
+ default:
417
+ break;
418
+ }
419
+ }
420
+ // Get profile and level from SPS
421
+ if (sps.length > 0) {
422
+ AVCProfileIndication = sps[0][1];
423
+ profileCompatibility = sps[0][2];
424
+ AVCLevelIndication = sps[0][3];
425
+ }
426
+
427
+ // Generate avcC buffer
428
+ const avcCBytes = new Uint8Array(avcCLength);
429
+ let i = 0;
430
+ // configurationVersion = 1
431
+ avcCBytes[i++] = 1;
432
+ avcCBytes[i++] = AVCProfileIndication;
433
+ avcCBytes[i++] = profileCompatibility;
434
+ avcCBytes[i++] = AVCLevelIndication;
435
+ // '11111' + lengthSizeMinusOne = 3
436
+ avcCBytes[i++] = 0xFF;
437
+ // '111' + numOfSequenceParameterSets
438
+ avcCBytes[i++] = 0xE0 | sps.length;
439
+ for (let n = 0; n < sps.length; n++) {
440
+ avcCBytes[i++] = (sps[n].length & 0xFF00) >> 8;
441
+ avcCBytes[i++] = (sps[n].length & 0x00FF);
442
+ avcCBytes.set(sps[n], i);
443
+ i += sps[n].length;
444
+ }
445
+ // numOfPictureParameterSets
446
+ avcCBytes[i++] = pps.length;
447
+ for (let n = 0; n < pps.length; n++) {
448
+ avcCBytes[i++] = (pps[n].length & 0xFF00) >> 8;
449
+ avcCBytes[i++] = (pps[n].length & 0x00FF);
450
+ avcCBytes.set(pps[n], i);
451
+ i += pps[n].length;
452
+ }
453
+ return avcCBytes;
454
+ }
455
+
456
+ /**
457
+ * Generate a HVC1 box
458
+ *
459
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
460
+ * @return {!Uint8Array}
461
+ * @private
462
+ */
463
+ hvc1_(streamInfo) {
464
+ const Mp4Generator = shaka.util.Mp4Generator;
465
+
466
+ const width = streamInfo.stream.width || 0;
467
+ const height = streamInfo.stream.height || 0;
468
+
469
+ let hvcCBox = new Uint8Array([]);
470
+ if (streamInfo.videoConfig.byteLength > 0) {
471
+ hvcCBox = Mp4Generator.box('hvcC', streamInfo.videoConfig);
472
+ }
473
+
474
+ const hvc1Bytes = new Uint8Array([
475
+ 0x00, 0x00, 0x00,
476
+ 0x00, 0x00, 0x00, // reserved
477
+ 0x00, 0x01, // data_reference_index
478
+ 0x00, 0x00, // pre_defined
479
+ 0x00, 0x00, // reserved
480
+ 0x00, 0x00, 0x00, 0x00,
481
+ 0x00, 0x00, 0x00, 0x00,
482
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
483
+ ...this.breakNumberIntoBytes_(width, 2), // width
484
+ ...this.breakNumberIntoBytes_(height, 2), // height
485
+ 0x00, 0x48, 0x00, 0x00, // horizresolution
486
+ 0x00, 0x48, 0x00, 0x00, // vertresolution
487
+ 0x00, 0x00, 0x00, 0x00, // reserved
488
+ 0x00, 0x01, // frame_count
489
+ 0x13,
490
+ 0x76, 0x69, 0x64, 0x65,
491
+ 0x6f, 0x6a, 0x73, 0x2d,
492
+ 0x63, 0x6f, 0x6e, 0x74,
493
+ 0x72, 0x69, 0x62, 0x2d,
494
+ 0x68, 0x6c, 0x73, 0x00,
495
+ 0x00, 0x00, 0x00, 0x00,
496
+ 0x00, 0x00, 0x00, 0x00,
497
+ 0x00, 0x00, 0x00, // compressorname
498
+ 0x00, 0x18, // depth = 24
499
+ 0x11, 0x11, // pre_defined = -1
500
+ ]);
501
+
502
+ let boxName = 'hvc1';
503
+ let sinfBox = new Uint8Array([]);
504
+ if (streamInfo.encrypted) {
505
+ sinfBox = this.sinf_(streamInfo);
506
+ boxName = 'encv';
507
+ }
508
+ return Mp4Generator.box(boxName, hvc1Bytes, hvcCBox, sinfBox);
509
+ }
510
+
511
+ /**
512
+ * Generate STSD bytes
513
+ *
514
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
515
+ * @return {!Uint8Array}
516
+ * @private
517
+ */
518
+ audioStsd_(streamInfo) {
519
+ const channelsCount = streamInfo.stream.channelsCount || 2;
520
+ const audioSamplingRate = streamInfo.stream.audioSamplingRate || 44100;
521
+ const bytes = new Uint8Array([
522
+ 0x00, 0x00, 0x00, // reserved
523
+ 0x00, 0x00, 0x00, // reserved
524
+ 0x00, 0x01, // data_reference_index
525
+ 0x00, 0x00, 0x00, 0x00,
526
+ 0x00, 0x00, 0x00, 0x00, // reserved
527
+ 0x00,
528
+ channelsCount, // channelcount
529
+ 0x00, 0x10, // sampleSize:16bits
530
+ 0x00, 0x00, 0x00, 0x00, // reserved2
531
+ ...this.breakNumberIntoBytes_(audioSamplingRate, 2), // Sample Rate
532
+ 0x00, 0x00,
533
+ ]);
534
+ return bytes;
535
+ }
536
+
537
+ /**
538
+ * Generate a .MP3 box
539
+ *
540
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
541
+ * @return {!Uint8Array}
542
+ * @private
543
+ */
544
+ mp3_(streamInfo) {
545
+ const Mp4Generator = shaka.util.Mp4Generator;
546
+ return Mp4Generator.box('.mp3', this.audioStsd_(streamInfo));
547
+ }
548
+
549
+ /**
550
+ * Generate a AC-3 box
551
+ *
552
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
553
+ * @return {!Uint8Array}
554
+ * @private
555
+ */
556
+ ac3_(streamInfo) {
557
+ const Mp4Generator = shaka.util.Mp4Generator;
558
+ const dac3Box = Mp4Generator.box('dac3', streamInfo.audioConfig);
559
+
560
+ let boxName = 'ac-3';
561
+ let sinfBox = new Uint8Array([]);
562
+ if (streamInfo.encrypted) {
563
+ sinfBox = this.sinf_(streamInfo);
564
+ boxName = 'enca';
565
+ }
566
+ return Mp4Generator.box(boxName,
567
+ this.audioStsd_(streamInfo), dac3Box, sinfBox);
568
+ }
569
+
570
+ /**
571
+ * Generate a EC-3 box
572
+ *
573
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
574
+ * @return {!Uint8Array}
575
+ * @private
576
+ */
577
+ ec3_(streamInfo) {
578
+ const Mp4Generator = shaka.util.Mp4Generator;
579
+ const dec3Box = Mp4Generator.box('dec3', streamInfo.audioConfig);
580
+
581
+ let boxName = 'ec-3';
582
+ let sinfBox = new Uint8Array([]);
583
+ if (streamInfo.encrypted) {
584
+ sinfBox = this.sinf_(streamInfo);
585
+ boxName = 'enca';
586
+ }
587
+ return Mp4Generator.box(boxName,
588
+ this.audioStsd_(streamInfo), dec3Box, sinfBox);
589
+ }
590
+
591
+ /**
592
+ * Generate a MP4A box
593
+ *
594
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
595
+ * @return {!Uint8Array}
596
+ * @private
597
+ */
598
+ mp4a_(streamInfo) {
599
+ const Mp4Generator = shaka.util.Mp4Generator;
600
+ let esdsBox;
601
+ if (streamInfo.audioConfig.byteLength > 0) {
602
+ esdsBox = Mp4Generator.box('esds', streamInfo.audioConfig);
603
+ } else {
604
+ esdsBox = Mp4Generator.box('esds', this.esds_(streamInfo));
605
+ }
606
+
607
+ let boxName = 'mp4a';
608
+ let sinfBox = new Uint8Array([]);
609
+ if (streamInfo.encrypted) {
610
+ sinfBox = this.sinf_(streamInfo);
611
+ boxName = 'enca';
612
+ }
613
+ return Mp4Generator.box(boxName,
614
+ this.audioStsd_(streamInfo), esdsBox, sinfBox);
615
+ }
616
+
617
+ /**
618
+ * Generate a ESDS box
619
+ *
620
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
621
+ * @return {!Uint8Array}
622
+ * @private
623
+ */
624
+ esds_(streamInfo) {
625
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
626
+
627
+ const id = streamInfo.id + 1;
628
+ const bandwidth = streamInfo.stream.bandwidth || 0;
629
+ const channelsCount = streamInfo.stream.channelsCount || 2;
630
+ const audioSamplingRate = streamInfo.stream.audioSamplingRate || 44100;
631
+
632
+ const audioCodec = shaka.util.ManifestParserUtils.guessCodecs(
633
+ ContentType.AUDIO, streamInfo.stream.codecs.split(','));
634
+
635
+ const samplingFrequencyIndex = {
636
+ 96000: 0x0,
637
+ 88200: 0x1,
638
+ 64000: 0x2,
639
+ 48000: 0x3,
640
+ 44100: 0x4,
641
+ 32000: 0x5,
642
+ 24000: 0x6,
643
+ 22050: 0x7,
644
+ 16000: 0x8,
645
+ 12000: 0x9,
646
+ 11025: 0xA,
647
+ 8000: 0xB,
648
+ 7350: 0xC,
649
+ };
650
+
651
+ let indexFreq = samplingFrequencyIndex[audioSamplingRate];
652
+ // In HE AAC Sampling frequence equals to SamplingRate * 2
653
+ if (audioCodec === 'mp4a.40.5' || audioCodec === 'mp4a.40.29') {
654
+ indexFreq = samplingFrequencyIndex[audioSamplingRate * 2];
655
+ }
656
+
657
+ const audioObjectType = parseInt(audioCodec.split('.').pop(), 10);
658
+
659
+ return new Uint8Array([
660
+ 0x00, // version
661
+ 0x00, 0x00, 0x00, // flags
662
+
663
+ // ES_Descriptor
664
+ 0x03, // tag, ES_DescrTag
665
+ 0x19, // length
666
+ ...this.breakNumberIntoBytes_(id, 2), // ES_ID
667
+ 0x00, // streamDependenceFlag, URL_flag, reserved, streamPriority
668
+
669
+ // DecoderConfigDescriptor
670
+ 0x04, // tag, DecoderConfigDescrTag
671
+ 0x11, // length
672
+ 0x40, // object type
673
+ 0x15, // streamType
674
+ 0x00, 0x06, 0x00, // bufferSizeDB
675
+ ...this.breakNumberIntoBytes_(bandwidth, 4), // maxBitrate
676
+ ...this.breakNumberIntoBytes_(bandwidth, 4), // avgBitrate
677
+ // DecoderSpecificInfo
678
+ 0x05, // tag, DecoderSpecificInfoTag
679
+ 0x02, // length
680
+ // ISO/IEC 14496-3, AudioSpecificConfig
681
+ // for samplingFrequencyIndex see
682
+ // ISO/IEC 13818-7:2006, 8.1.3.2.2, Table 35
683
+ (audioObjectType << 3) | (indexFreq >>> 1),
684
+ (indexFreq << 7) | (channelsCount << 3),
685
+ 0x06, 0x01, 0x02, // GASpecificConfig
686
+ ]);
687
+ }
688
+
689
+ /**
690
+ * Generate a MVEX box
691
+ *
692
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
693
+ * @return {!Uint8Array}
694
+ * @private
695
+ */
696
+ mvex_(streamInfo) {
697
+ const Mp4Generator = shaka.util.Mp4Generator;
698
+ return Mp4Generator.box('mvex', this.trex_(streamInfo));
699
+ }
700
+
701
+ /**
702
+ * Generate a TREX box
703
+ *
704
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
705
+ * @return {!Uint8Array}
706
+ * @private
707
+ */
708
+ trex_(streamInfo) {
709
+ const Mp4Generator = shaka.util.Mp4Generator;
710
+ const id = streamInfo.id + 1;
711
+ const bytes = new Uint8Array([
712
+ 0x00, // version 0
713
+ 0x00, 0x00, 0x00, // flags
714
+ ...this.breakNumberIntoBytes_(id, 4), // track_ID
715
+ 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
716
+ 0x00, 0x00, 0x00, 0x00, // default_sample_duration
717
+ 0x00, 0x00, 0x00, 0x00, // default_sample_size
718
+ 0x00, 0x01, 0x00, 0x01, // default_sample_flags
719
+ ]);
720
+ return Mp4Generator.box('trex', bytes);
721
+ }
722
+
723
+ /**
724
+ * Generate a PSSH box
725
+ *
726
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
727
+ * @return {!Uint8Array}
728
+ * @private
729
+ */
730
+ pssh_(streamInfo) {
731
+ let boxes = new Uint8Array([]);
732
+ if (!streamInfo.encrypted) {
733
+ return boxes;
734
+ }
735
+
736
+ for (const drmInfo of streamInfo.stream.drmInfos) {
737
+ if (!drmInfo.initData) {
738
+ continue;
739
+ }
740
+ for (const initData of drmInfo.initData) {
741
+ boxes = shaka.util.Uint8ArrayUtils.concat(boxes, initData.initData);
742
+ }
743
+ }
744
+ return boxes;
745
+ }
746
+
747
+ /**
748
+ * Generate a SINF box
749
+ *
750
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
751
+ * @return {!Uint8Array}
752
+ * @private
753
+ */
754
+ sinf_(streamInfo) {
755
+ const Mp4Generator = shaka.util.Mp4Generator;
756
+ return Mp4Generator.box('sinf',
757
+ this.frma_(streamInfo), this.schm_(), this.schi_(streamInfo));
758
+ }
759
+
760
+ /**
761
+ * Generate a FRMA box
762
+ *
763
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
764
+ * @return {!Uint8Array}
765
+ * @private
766
+ */
767
+ frma_(streamInfo) {
768
+ const codec = streamInfo.stream.codecs.substring(
769
+ 0, streamInfo.stream.codecs.indexOf('.'));
770
+ const Mp4Generator = shaka.util.Mp4Generator;
771
+ const codecNumber = this.stringToCharCode_(codec);
772
+ const bytes = new Uint8Array([
773
+ ...this.breakNumberIntoBytes_(codecNumber, 4),
774
+ ]);
775
+ return Mp4Generator.box('frma', bytes);
776
+ }
777
+
778
+ /**
779
+ * Generate a SCHM box
780
+ *
781
+ * @return {!Uint8Array}
782
+ * @private
783
+ */
784
+ schm_() {
785
+ const Mp4Generator = shaka.util.Mp4Generator;
786
+ const bytes = new Uint8Array([
787
+ 0x00, // version 0
788
+ 0x00, 0x00, 0x00, // flags
789
+ 0x63, 0x65, 0x6e, 0x63, // Scheme: cenc
790
+ 0x00, 0x01, 0x00, 0x00, // Scheme version: 1.0
791
+ ]);
792
+ return Mp4Generator.box('schm', bytes);
793
+ }
794
+
795
+ /**
796
+ * Generate a SCHI box
797
+ *
798
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
799
+ * @return {!Uint8Array}
800
+ * @private
801
+ */
802
+ schi_(streamInfo) {
803
+ const Mp4Generator = shaka.util.Mp4Generator;
804
+ return Mp4Generator.box('schi', this.tenc_(streamInfo));
805
+ }
806
+
807
+ /**
808
+ * Generate a TENC box
809
+ *
810
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
811
+ * @return {!Uint8Array}
812
+ * @private
813
+ */
814
+ tenc_(streamInfo) {
815
+ // Default key ID: all zeros (dummy)
816
+ let defaultKeyId = new Uint8Array([
817
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819
+ ]);
820
+ for (const drmInfo of streamInfo.stream.drmInfos) {
821
+ if (drmInfo && drmInfo.keyIds && drmInfo.keyIds.size) {
822
+ for (const keyId of drmInfo.keyIds) {
823
+ defaultKeyId = this.hexStringToBuffer_(keyId);
824
+ }
825
+ }
826
+ }
827
+
828
+ const Mp4Generator = shaka.util.Mp4Generator;
829
+ const bytes = new Uint8Array([
830
+ 0x00, // version 0
831
+ 0x00, 0x00, 0x00, // flags
832
+ 0x00, 0x00, // Reserved fields
833
+ 0x01, // Default protected: true
834
+ 0x08, // Default per-sample IV size: 8
835
+ ]);
836
+ goog.asserts.assert(defaultKeyId, 'Default KID should be non-null');
837
+ return Mp4Generator.box('tenc', bytes, defaultKeyId);
838
+ }
839
+
840
+ /**
841
+ * Generate a Segment Data (MP4).
842
+ *
843
+ * @return {!Uint8Array}
844
+ */
845
+ segmentData() {
846
+ let result = new Uint8Array([]);
847
+ for (const streamInfo of this.streamInfos_) {
848
+ result = shaka.util.Uint8ArrayUtils.concat(result,
849
+ this.moof_(streamInfo), this.mdat_(streamInfo));
850
+ }
851
+ return result;
852
+ }
853
+
854
+ /**
855
+ * Generate a MOOF box
856
+ *
857
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
858
+ * @return {!Uint8Array}
859
+ * @private
860
+ */
861
+ moof_(streamInfo) {
862
+ const Mp4Generator = shaka.util.Mp4Generator;
863
+ return Mp4Generator.box('moof',
864
+ this.mfhd_(streamInfo), this.traf_(streamInfo));
865
+ }
866
+
867
+ /**
868
+ * Generate a MOOF box
869
+ *
870
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
871
+ * @return {!Uint8Array}
872
+ * @private
873
+ */
874
+ mfhd_(streamInfo) {
875
+ const Mp4Generator = shaka.util.Mp4Generator;
876
+ const sequenceNumber =
877
+ streamInfo.data ? streamInfo.data.sequenceNumber : 0;
878
+ const bytes = new Uint8Array([
879
+ 0x00, // version 0
880
+ 0x00, 0x00, 0x00, // flags
881
+ ...this.breakNumberIntoBytes_(sequenceNumber, 4),
882
+ ]);
883
+ return Mp4Generator.box('mfhd', bytes);
884
+ }
885
+
886
+ /**
887
+ * Generate a TRAF box
888
+ *
889
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
890
+ * @return {!Uint8Array}
891
+ * @private
892
+ */
893
+ traf_(streamInfo) {
894
+ const Mp4Generator = shaka.util.Mp4Generator;
895
+ const sampleDependencyTable = this.sdtp_(streamInfo);
896
+ const offset = sampleDependencyTable.length +
897
+ 32 + // tfhd
898
+ 20 + // tfdt
899
+ 8 + // traf header
900
+ 16 + // mfhd
901
+ 8 + // moof header
902
+ 8; // mdat header;
903
+ return Mp4Generator.box('traf',
904
+ this.tfhd_(streamInfo),
905
+ this.tfdt_(streamInfo),
906
+ this.trun_(streamInfo, offset),
907
+ sampleDependencyTable);
908
+ }
909
+
910
+ /**
911
+ * Generate a SDTP box
912
+ *
913
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
914
+ * @return {!Uint8Array}
915
+ * @private
916
+ */
917
+ sdtp_(streamInfo) {
918
+ const Mp4Generator = shaka.util.Mp4Generator;
919
+ const samples = streamInfo.data ? streamInfo.data.samples : [];
920
+ const bytes = new Uint8Array(4 + samples.length);
921
+ // leave the full box header (4 bytes) all zero
922
+ // write the sample table
923
+ for (let i = 0; i < samples.length; i++) {
924
+ const flags = samples[i].flags;
925
+ bytes[i + 4] = (flags.dependsOn << 4) |
926
+ (flags.isDependedOn << 2) |
927
+ flags.hasRedundancy;
928
+ }
929
+ return Mp4Generator.box('sdtp', bytes);
930
+ }
931
+
932
+ /**
933
+ * Generate a TFHD box
934
+ *
935
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
936
+ * @return {!Uint8Array}
937
+ * @private
938
+ */
939
+ tfhd_(streamInfo) {
940
+ const Mp4Generator = shaka.util.Mp4Generator;
941
+ const id = streamInfo.id + 1;
942
+ const bytes = new Uint8Array([
943
+ 0x00, // version 0
944
+ 0x00, 0x00, 0x3a, // flags
945
+ ...this.breakNumberIntoBytes_(id, 4), // track_ID
946
+ 0x00, 0x00, 0x00, 0x01, // sample_description_index
947
+ 0x00, 0x00, 0x00, 0x00, // default_sample_duration
948
+ 0x00, 0x00, 0x00, 0x00, // default_sample_size
949
+ 0x00, 0x00, 0x00, 0x00, // default_sample_flags
950
+ ]);
951
+ return Mp4Generator.box('tfhd', bytes);
952
+ }
953
+
954
+ /**
955
+ * Generate a TFDT box
956
+ *
957
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
958
+ * @return {!Uint8Array}
959
+ * @private
960
+ */
961
+ tfdt_(streamInfo) {
962
+ const Mp4Generator = shaka.util.Mp4Generator;
963
+ const baseMediaDecodeTime =
964
+ streamInfo.data ? streamInfo.data.baseMediaDecodeTime : 0;
965
+ const upperWordBaseMediaDecodeTime =
966
+ Math.floor(baseMediaDecodeTime / (Mp4Generator.UINT32_MAX_ + 1));
967
+ const lowerWordBaseMediaDecodeTime =
968
+ Math.floor(baseMediaDecodeTime % (Mp4Generator.UINT32_MAX_ + 1));
969
+ const bytes = new Uint8Array([
970
+ 0x01, // version 1
971
+ 0x00, 0x00, 0x00, // flags
972
+ ...this.breakNumberIntoBytes_(upperWordBaseMediaDecodeTime, 4),
973
+ ...this.breakNumberIntoBytes_(lowerWordBaseMediaDecodeTime, 4),
974
+ ]);
975
+ return Mp4Generator.box('tfdt', bytes);
976
+ }
977
+
978
+ /**
979
+ * Generate a TRUN box
980
+ *
981
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
982
+ * @param {number} offset
983
+ * @return {!Uint8Array}
984
+ * @private
985
+ */
986
+ trun_(streamInfo, offset) {
987
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
988
+ const Mp4Generator = shaka.util.Mp4Generator;
989
+
990
+ const samples = streamInfo.data ? streamInfo.data.samples : [];
991
+ const samplesLength = samples.length;
992
+ const byteslen = 12 + 16 * samplesLength;
993
+ const bytes = new Uint8Array(byteslen);
994
+ offset += 8 + byteslen;
995
+ const isVideo = streamInfo.type === ContentType.VIDEO;
996
+ bytes.set(
997
+ [
998
+ // version 1 for video with signed-int sample_composition_time_offset
999
+ isVideo ? 0x01 : 0x00,
1000
+ 0x00, 0x0f, 0x01, // flags
1001
+ ...this.breakNumberIntoBytes_(samplesLength, 4), // sample_count
1002
+ ...this.breakNumberIntoBytes_(offset, 4), // data_offset
1003
+ ],
1004
+ 0,
1005
+ );
1006
+ for (let i = 0; i < samplesLength; i++) {
1007
+ const sample = samples[i];
1008
+ const duration = this.breakNumberIntoBytes_(sample.duration, 4);
1009
+ const size = this.breakNumberIntoBytes_(sample.size, 4);
1010
+ const flags = sample.flags;
1011
+ const cts = this.breakNumberIntoBytes_(sample.cts, 4);
1012
+ bytes.set(
1013
+ [
1014
+ ...duration, // sample_duration
1015
+ ...size, // sample_size
1016
+ (flags.isLeading << 2) | flags.dependsOn,
1017
+ (flags.isDependedOn << 6) | (flags.hasRedundancy << 4) |
1018
+ flags.isNonSync,
1019
+ flags.degradPrio & (0xf0 << 8),
1020
+ flags.degradPrio & 0x0f, // sample_flags
1021
+ ...cts, // sample_composition_time_offset
1022
+ ],
1023
+ 12 + 16 * i,
1024
+ );
1025
+ }
1026
+ return Mp4Generator.box('trun', bytes);
1027
+ }
1028
+
1029
+ /**
1030
+ * Generate a MDAT box
1031
+ *
1032
+ * @return {!Uint8Array}
1033
+ * @private
1034
+ */
1035
+ mdat_(streamInfo) {
1036
+ const Mp4Generator = shaka.util.Mp4Generator;
1037
+ const samples = streamInfo.data ? streamInfo.data.samples : [];
1038
+ let bytes = new Uint8Array([]);
1039
+ for (const sample of samples) {
1040
+ bytes = shaka.util.Uint8ArrayUtils.concat(bytes, sample.data);
1041
+ }
1042
+ return Mp4Generator.box('mdat', bytes);
1043
+ }
1044
+
1045
+
1046
+ /**
1047
+ * @param {number} number
1048
+ * @param {number} numBytes
1049
+ * @return {!Array.<number>}
1050
+ * @private
1051
+ */
1052
+ breakNumberIntoBytes_(number, numBytes) {
1053
+ const bytes = [];
1054
+ for (let byte = numBytes - 1; byte >= 0; byte--) {
1055
+ bytes.push((number >> (8 * byte)) & 0xff);
1056
+ }
1057
+ return bytes;
1058
+ }
1059
+
1060
+ /**
1061
+ * Convert a hex string to buffer.
1062
+ *
1063
+ * @param {string} str
1064
+ * @return {Uint8Array}
1065
+ * @private
1066
+ */
1067
+ hexStringToBuffer_(str) {
1068
+ const buf = new Uint8Array(str.length / 2);
1069
+ for (let i = 0; i < str.length / 2; i += 1) {
1070
+ buf[i] = parseInt(String(str[i * 2] + str[i * 2 + 1]), 16);
1071
+ }
1072
+ return buf;
1073
+ }
1074
+
1075
+ /**
1076
+ * Convert a string to char code.
1077
+ *
1078
+ * @param {string} str
1079
+ * @return {number}
1080
+ * @private
1081
+ */
1082
+ stringToCharCode_(str) {
1083
+ let code = 0;
1084
+ for (let i = 0; i < str.length; i += 1) {
1085
+ code |= str.charCodeAt(i) << ((str.length - i - 1) * 8);
1086
+ }
1087
+ return code;
1088
+ }
1089
+
1090
+ /**
1091
+ * @private
1092
+ */
1093
+ static initStaticProperties_() {
1094
+ const Mp4Generator = shaka.util.Mp4Generator;
1095
+ if (Mp4Generator.initializated_) {
1096
+ return;
1097
+ }
1098
+
1099
+ Mp4Generator.initializated_ = true;
1100
+
1101
+ const majorBrand = new Uint8Array([105, 115, 111, 109]); // isom
1102
+ const avc1Brand = new Uint8Array([97, 118, 99, 49]); // avc1
1103
+ const minorVersion = new Uint8Array([0, 0, 0, 1]);
1104
+
1105
+ Mp4Generator.FTYP_ = Mp4Generator.box(
1106
+ 'ftyp', majorBrand, minorVersion, majorBrand, avc1Brand);
1107
+ const drefBox = Mp4Generator.box('dref', Mp4Generator.DREF_);
1108
+ Mp4Generator.DINF_ = Mp4Generator.box('dinf', drefBox);
1109
+ }
1110
+
1111
+ /**
1112
+ * Generate a box
1113
+ *
1114
+ * @param {string} boxName
1115
+ * @param {...!Uint8Array} payload
1116
+ * @return {!Uint8Array}
1117
+ */
1118
+ static box(boxName, ...payload) {
1119
+ let type = shaka.util.Mp4Generator.BOX_TYPES_[boxName];
1120
+ if (!type) {
1121
+ type = [
1122
+ boxName.charCodeAt(0),
1123
+ boxName.charCodeAt(1),
1124
+ boxName.charCodeAt(2),
1125
+ boxName.charCodeAt(3),
1126
+ ];
1127
+ shaka.util.Mp4Generator.BOX_TYPES_[boxName] = type;
1128
+ }
1129
+ // make the header for the box
1130
+ let size = 8;
1131
+ // calculate the total size we need to allocate
1132
+ for (let i = payload.length - 1; i >= 0; i--) {
1133
+ size += payload[i].byteLength;
1134
+ }
1135
+ const result = new Uint8Array(size);
1136
+ result[0] = (size >> 24) & 0xff;
1137
+ result[1] = (size >> 16) & 0xff;
1138
+ result[2] = (size >> 8) & 0xff;
1139
+ result[3] = size & 0xff;
1140
+ result.set(type, 4);
1141
+
1142
+ // copy the payload into the result
1143
+ for (let i = 0, pointer = 8; i < payload.length; i++) {
1144
+ // copy payload[i] array @ offset pointer
1145
+ result.set(payload[i], pointer);
1146
+ pointer += payload[i].byteLength;
1147
+ }
1148
+ return result;
1149
+ }
1150
+ };
1151
+
1152
+ /**
1153
+ * @private {boolean}
1154
+ */
1155
+ shaka.util.Mp4Generator.initializated_ = false;
1156
+
1157
+
1158
+ /**
1159
+ * @private {number}
1160
+ */
1161
+ shaka.util.Mp4Generator.UINT32_MAX_ = Math.pow(2, 32) - 1;
1162
+
1163
+ /**
1164
+ * @private {!Object.<string, !Array.<number>>}
1165
+ */
1166
+ shaka.util.Mp4Generator.BOX_TYPES_ = {};
1167
+
1168
+ /**
1169
+ * @private {{video: !Uint8Array, audio: !Uint8Array}}
1170
+ */
1171
+ shaka.util.Mp4Generator.HDLR_TYPES_ = {
1172
+ video: new Uint8Array([
1173
+ 0x00, // version 0
1174
+ 0x00, 0x00, 0x00, // flags
1175
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
1176
+ 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
1177
+ 0x00, 0x00, 0x00, 0x00, // reserved
1178
+ 0x00, 0x00, 0x00, 0x00, // reserved
1179
+ 0x00, 0x00, 0x00, 0x00, // reserved
1180
+ 0x56, 0x69, 0x64, 0x65,
1181
+ 0x6f, 0x48, 0x61, 0x6e,
1182
+ 0x64, 0x6c, 0x65, 0x72, 0x00, // name: 'VideoHandler'
1183
+ ]),
1184
+ audio: new Uint8Array([
1185
+ 0x00, // version 0
1186
+ 0x00, 0x00, 0x00, // flags
1187
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
1188
+ 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun'
1189
+ 0x00, 0x00, 0x00, 0x00, // reserved
1190
+ 0x00, 0x00, 0x00, 0x00, // reserved
1191
+ 0x00, 0x00, 0x00, 0x00, // reserved
1192
+ 0x53, 0x6f, 0x75, 0x6e,
1193
+ 0x64, 0x48, 0x61, 0x6e,
1194
+ 0x64, 0x6c, 0x65, 0x72, 0x00, // name: 'SoundHandler'
1195
+ ]),
1196
+ };
1197
+
1198
+ /**
1199
+ * @private {!Uint8Array}
1200
+ */
1201
+ shaka.util.Mp4Generator.STTS_ = new Uint8Array([
1202
+ 0x00, // version
1203
+ 0x00, 0x00, 0x00, // flags
1204
+ 0x00, 0x00, 0x00, 0x00, // entry_count
1205
+ ]);
1206
+
1207
+ /**
1208
+ * @private {!Uint8Array}
1209
+ */
1210
+ shaka.util.Mp4Generator.STSC_ = new Uint8Array([
1211
+ 0x00, // version
1212
+ 0x00, 0x00, 0x00, // flags
1213
+ 0x00, 0x00, 0x00, 0x00, // entry_count
1214
+ ]);
1215
+
1216
+ /**
1217
+ * @private {!Uint8Array}
1218
+ */
1219
+ shaka.util.Mp4Generator.STCO_ = new Uint8Array([
1220
+ 0x00, // version
1221
+ 0x00, 0x00, 0x00, // flags
1222
+ 0x00, 0x00, 0x00, 0x00, // entry_count
1223
+ ]);
1224
+
1225
+ /**
1226
+ * @private {!Uint8Array}
1227
+ */
1228
+ shaka.util.Mp4Generator.STSZ_ = new Uint8Array([
1229
+ 0x00, // version
1230
+ 0x00, 0x00, 0x00, // flags
1231
+ 0x00, 0x00, 0x00, 0x00, // sample_size
1232
+ 0x00, 0x00, 0x00, 0x00, // sample_count
1233
+ ]);
1234
+
1235
+ /**
1236
+ * @private {!Uint8Array}
1237
+ */
1238
+ shaka.util.Mp4Generator.VMHD_ = new Uint8Array([
1239
+ 0x00, // version
1240
+ 0x00, 0x00, 0x01, // flags
1241
+ 0x00, 0x00, // graphicsmode
1242
+ 0x00, 0x00,
1243
+ 0x00, 0x00,
1244
+ 0x00, 0x00, // opcolor
1245
+ ]);
1246
+
1247
+ /**
1248
+ * @private {!Uint8Array}
1249
+ */
1250
+ shaka.util.Mp4Generator.SMHD_ = new Uint8Array([
1251
+ 0x00, // version
1252
+ 0x00, 0x00, 0x00, // flags
1253
+ 0x00, 0x00, // balance, 0 means centered
1254
+ 0x00, 0x00, // reserved
1255
+ ]);
1256
+
1257
+ /**
1258
+ * @private {!Uint8Array}
1259
+ */
1260
+ shaka.util.Mp4Generator.STSD_ = new Uint8Array([
1261
+ 0x00, // version 0
1262
+ 0x00, 0x00, 0x00, // flags
1263
+ 0x00, 0x00, 0x00, 0x01, // entry_count
1264
+ ]);
1265
+
1266
+ /**
1267
+ * @private {!Uint8Array}
1268
+ */
1269
+ shaka.util.Mp4Generator.FTYP_ = new Uint8Array([]);
1270
+
1271
+ /**
1272
+ * @private {!Uint8Array}
1273
+ */
1274
+ shaka.util.Mp4Generator.DREF_ = new Uint8Array([
1275
+ 0x00, // version 0
1276
+ 0x00, 0x00, 0x00, // flags
1277
+ 0x00, 0x00, 0x00, 0x01, // entry_count
1278
+ 0x00, 0x00, 0x00, 0x0c, // entry_size
1279
+ 0x75, 0x72, 0x6c, 0x20, // 'url' type
1280
+ 0x00, // version 0
1281
+ 0x00, 0x00, 0x01, // entry_flags
1282
+ ]);
1283
+
1284
+ /**
1285
+ * @private {!Uint8Array}
1286
+ */
1287
+ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
1288
+
1289
+ /**
1290
+ * @typedef {{
1291
+ * id: number,
1292
+ * type: string,
1293
+ * encrypted: boolean,
1294
+ * timescale: number,
1295
+ * duration: number,
1296
+ * videoNalus: !Array.<string>,
1297
+ * audioConfig: !Uint8Array,
1298
+ * videoConfig: !Uint8Array,
1299
+ * data: ?shaka.util.Mp4Generator.Data,
1300
+ * stream: !shaka.extern.Stream
1301
+ * }}
1302
+ *
1303
+ * @property {number} id
1304
+ * A unique ID
1305
+ * @property {string} type
1306
+ * Indicate the content type: 'video' or 'audio'.
1307
+ * @property {boolean} encrypted
1308
+ * Indicate if the stream is encrypted.
1309
+ * @property {number} timescale
1310
+ * The Stream's timescale.
1311
+ * @property {number} duration
1312
+ * The Stream's duration.
1313
+ * @property {!Array.<string>} videoNalus
1314
+ * The stream's video nalus.
1315
+ * @property {!Uint8Array} audioConfig
1316
+ * The stream's audio config.
1317
+ * @property {!Uint8Array} videoConfig
1318
+ * The stream's video config.
1319
+ * @property {?shaka.util.Mp4Generator.Data} data
1320
+ * The stream's data.
1321
+ * @property {!shaka.extern.Stream} stream
1322
+ * The Stream.
1323
+ */
1324
+ shaka.util.Mp4Generator.StreamInfo;
1325
+
1326
+ /**
1327
+ * @typedef {{
1328
+ * sequenceNumber: number,
1329
+ * baseMediaDecodeTime: number,
1330
+ * samples: !Array.<shaka.util.Mp4Generator.Mp4Sample>
1331
+ * }}
1332
+ *
1333
+ * @property {number} sequenceNumber
1334
+ * The sequence number.
1335
+ * @property {number} baseMediaDecodeTime
1336
+ * The base media decode time.
1337
+ * @property {!Array.<shaka.util.Mp4Generator.Mp4Sample>} samples
1338
+ * The data samples.
1339
+ */
1340
+ shaka.util.Mp4Generator.Data;
1341
+
1342
+ /**
1343
+ * @typedef {{
1344
+ * data: !Uint8Array,
1345
+ * size: number,
1346
+ * duration: number,
1347
+ * cts: number,
1348
+ * flags: !shaka.util.Mp4Generator.Mp4SampleFlags
1349
+ * }}
1350
+ *
1351
+ * @property {!Uint8Array} data
1352
+ * The sample data.
1353
+ * @property {number} size
1354
+ * The sample size.
1355
+ * @property {number} duration
1356
+ * The sample duration.
1357
+ * @property {number} cts
1358
+ * The sample composition time.
1359
+ * @property {!shaka.util.Mp4Generator.Mp4SampleFlags} flags
1360
+ * The sample flags.
1361
+ */
1362
+ shaka.util.Mp4Generator.Mp4Sample;
1363
+
1364
+ /**
1365
+ * @typedef {{
1366
+ * isLeading: number,
1367
+ * isDependedOn: number,
1368
+ * hasRedundancy: number,
1369
+ * degradPrio: number,
1370
+ * dependsOn: number,
1371
+ * isNonSync: number
1372
+ * }}
1373
+ *
1374
+ * @property {number} isLeading
1375
+ * @property {number} isDependedOn
1376
+ * @property {number} hasRedundancy
1377
+ * @property {number} degradPrio
1378
+ * @property {number} dependsOn
1379
+ * @property {number} isNonSync
1380
+ */
1381
+ shaka.util.Mp4Generator.Mp4SampleFlags;