@osmo.inc/cli 0.1.15

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 (949) hide show
  1. package/DEPLOY.md +87 -0
  2. package/README.md +243 -0
  3. package/RELEASE.md +164 -0
  4. package/SETUP.md +60 -0
  5. package/THIRD_PARTY_NOTICES.md +18 -0
  6. package/bin/osmo.mjs +12 -0
  7. package/dist/osmo.js +7817 -0
  8. package/node_modules/@esbuild/darwin-arm64/README.md +3 -0
  9. package/node_modules/@esbuild/darwin-arm64/bin/esbuild +0 -0
  10. package/node_modules/@esbuild/darwin-arm64/package.json +20 -0
  11. package/node_modules/esbuild/LICENSE.md +21 -0
  12. package/node_modules/esbuild/README.md +3 -0
  13. package/node_modules/esbuild/bin/esbuild +223 -0
  14. package/node_modules/esbuild/install.js +289 -0
  15. package/node_modules/esbuild/lib/main.d.ts +716 -0
  16. package/node_modules/esbuild/lib/main.js +2532 -0
  17. package/node_modules/esbuild/package.json +49 -0
  18. package/node_modules/fflate/LICENSE +21 -0
  19. package/node_modules/fflate/esm/index.mjs +2710 -0
  20. package/node_modules/fflate/package.json +128 -0
  21. package/node_modules/typescript/LICENSE.txt +55 -0
  22. package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  23. package/node_modules/typescript/lib/lib.d.ts +22 -0
  24. package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  25. package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  26. package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  27. package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  28. package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  29. package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  30. package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  31. package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  32. package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  33. package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  34. package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  35. package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  36. package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  37. package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  38. package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  39. package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  40. package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  41. package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  42. package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  43. package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  44. package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  45. package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  46. package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  47. package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  48. package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  49. package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  50. package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  51. package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  52. package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  53. package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  54. package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  55. package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  56. package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  57. package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  58. package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  59. package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  60. package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  61. package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  62. package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  63. package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  64. package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  65. package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  66. package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  67. package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  68. package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  69. package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  70. package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  71. package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  72. package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  73. package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  74. package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  75. package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  76. package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  77. package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  78. package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  79. package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  80. package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  81. package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  82. package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  83. package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  84. package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  85. package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  86. package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  87. package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  88. package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  89. package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  90. package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  91. package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  92. package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  93. package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  94. package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  95. package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  96. package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  97. package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  98. package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  99. package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  100. package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  101. package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  102. package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  103. package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  104. package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  105. package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  106. package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  107. package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  108. package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  109. package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  110. package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  111. package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  112. package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  113. package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  114. package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  115. package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  116. package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  117. package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  118. package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  119. package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  120. package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  121. package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  122. package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  123. package/node_modules/typescript/lib/typescript.js +382 -0
  124. package/node_modules/typescript/package.json +57 -0
  125. package/package.json +54 -0
  126. package/release.json +136 -0
  127. package/runtime/apps/native/tools/compile.mjs +217 -0
  128. package/runtime/packages/scene/scripts/validate-strict.mjs +246 -0
  129. package/runtime/packages/scene/src/clip.d.mts +14 -0
  130. package/runtime/packages/scene/src/clip.mjs +15 -0
  131. package/runtime/packages/scene/src/color-value.d.mts +5 -0
  132. package/runtime/packages/scene/src/color-value.mjs +19 -0
  133. package/runtime/packages/scene/src/color.ts +1 -0
  134. package/runtime/packages/scene/src/effects.ts +213 -0
  135. package/runtime/packages/scene/src/elements.ts +491 -0
  136. package/runtime/packages/scene/src/evaluate.ts +919 -0
  137. package/runtime/packages/scene/src/index.ts +69 -0
  138. package/runtime/packages/scene/src/jsx-runtime.ts +73 -0
  139. package/runtime/packages/scene/src/knob-schema.ts +115 -0
  140. package/runtime/packages/scene/src/knobs.ts +118 -0
  141. package/runtime/packages/scene/src/mask.d.mts +6 -0
  142. package/runtime/packages/scene/src/mask.mjs +17 -0
  143. package/runtime/packages/scene/src/metadata.d.mts +23 -0
  144. package/runtime/packages/scene/src/metadata.mjs +44 -0
  145. package/runtime/packages/scene/src/motion-sampling.d.mts +2 -0
  146. package/runtime/packages/scene/src/motion-sampling.mjs +50 -0
  147. package/runtime/packages/scene/src/motion.ts +121 -0
  148. package/runtime/packages/scene/src/shader.ts +57 -0
  149. package/src/resource-examples/example-image/landscape.svg +7 -0
  150. package/src/resource-examples/example-image/resource.json +8 -0
  151. package/src/resource-examples/example-model/gem.glb +0 -0
  152. package/src/resource-examples/example-model/preview.svg +1 -0
  153. package/src/resource-examples/example-model/resource.json +7 -0
  154. package/src/resource-examples/example-scene/resource.json +1 -0
  155. package/src/resource-examples/example-scene/scene.tsx +8 -0
  156. package/src/resource-examples/example-shader/effect.wgsl +7 -0
  157. package/src/resource-examples/example-shader/preview.svg +1 -0
  158. package/src/resource-examples/example-shader/resource.json +27 -0
  159. package/src/resource-examples/example-shader/tint.wgsl +7 -0
  160. package/src/resource-examples/example-video/ambient.mp4 +0 -0
  161. package/src/resource-examples/example-video/resource.json +9 -0
  162. package/src/starter/scene.tsx +20 -0
  163. package/studio/index.html +2 -0
  164. package/studio/public/check-circle-filled.svg +3 -0
  165. package/studio/public/comment-cursor/active-outer.svg +3 -0
  166. package/studio/public/comment-cursor/default.svg +6 -0
  167. package/studio/public/osmo-studio-logo.svg +12 -0
  168. package/studio/public/pencil-simple.svg +5 -0
  169. package/studio/src/active-outer-TVYUEURE.svg +3 -0
  170. package/studio/src/app.css +4 -0
  171. package/studio/src/app.js +705 -0
  172. package/studio/src/default-6CTRH4V5.svg +6 -0
  173. package/studio/src/engine_bg.wasm +0 -0
  174. package/studio/src/inter-cyrillic-ext-wght-normal-IYF56FF6.woff2 +0 -0
  175. package/studio/src/inter-cyrillic-wght-normal-JEOLYBOO.woff2 +0 -0
  176. package/studio/src/inter-greek-ext-wght-normal-EOVOK2B5.woff2 +0 -0
  177. package/studio/src/inter-greek-wght-normal-IRE366VL.woff2 +0 -0
  178. package/studio/src/inter-latin-ext-wght-normal-HA22NDSG.woff2 +0 -0
  179. package/studio/src/inter-latin-wght-normal-NRMW37G5.woff2 +0 -0
  180. package/studio/src/inter-vietnamese-wght-normal-CE5GGD3W.woff2 +0 -0
  181. package/studio/src/osmo-studio-logo-D5R2V77B.svg +12 -0
  182. package/third-party/cargo/adler2@2.0.1/Cargo.toml +91 -0
  183. package/third-party/cargo/adler2@2.0.1/LICENSE-0BSD +12 -0
  184. package/third-party/cargo/adler2@2.0.1/LICENSE-APACHE +201 -0
  185. package/third-party/cargo/adler2@2.0.1/LICENSE-MIT +23 -0
  186. package/third-party/cargo/allocator-api2@0.2.21/Cargo.toml +48 -0
  187. package/third-party/cargo/allocator-api2@0.2.21/LICENSE-APACHE +176 -0
  188. package/third-party/cargo/allocator-api2@0.2.21/LICENSE-MIT +23 -0
  189. package/third-party/cargo/arrayref@0.3.9/Cargo.toml +23 -0
  190. package/third-party/cargo/arrayref@0.3.9/LICENSE +26 -0
  191. package/third-party/cargo/arrayvec@0.7.8/Cargo.toml +112 -0
  192. package/third-party/cargo/arrayvec@0.7.8/LICENSE-APACHE +201 -0
  193. package/third-party/cargo/arrayvec@0.7.8/LICENSE-MIT +25 -0
  194. package/third-party/cargo/ascii@1.1.0/Cargo.toml +41 -0
  195. package/third-party/cargo/ascii@1.1.0/LICENSE-APACHE +201 -0
  196. package/third-party/cargo/ascii@1.1.0/LICENSE-MIT +22 -0
  197. package/third-party/cargo/ash@0.38.0+1.3.281/Cargo.toml +66 -0
  198. package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-APACHE +67 -0
  199. package/third-party/cargo/ash@0.38.0+1.3.281/LICENSE-MIT +25 -0
  200. package/third-party/cargo/autocfg@1.5.1/Cargo.toml +75 -0
  201. package/third-party/cargo/autocfg@1.5.1/LICENSE-APACHE +201 -0
  202. package/third-party/cargo/autocfg@1.5.1/LICENSE-MIT +25 -0
  203. package/third-party/cargo/base64@0.13.1/Cargo.toml +53 -0
  204. package/third-party/cargo/base64@0.13.1/LICENSE-APACHE +201 -0
  205. package/third-party/cargo/base64@0.13.1/LICENSE-MIT +21 -0
  206. package/third-party/cargo/base64@0.22.1/Cargo.toml +85 -0
  207. package/third-party/cargo/base64@0.22.1/LICENSE-APACHE +201 -0
  208. package/third-party/cargo/base64@0.22.1/LICENSE-MIT +21 -0
  209. package/third-party/cargo/bit-set@0.10.0/Cargo.toml +108 -0
  210. package/third-party/cargo/bit-set@0.10.0/LICENSE-APACHE +201 -0
  211. package/third-party/cargo/bit-set@0.10.0/LICENSE-MIT +25 -0
  212. package/third-party/cargo/bit-vec@0.9.1/Cargo.toml +94 -0
  213. package/third-party/cargo/bit-vec@0.9.1/LICENSE-APACHE +201 -0
  214. package/third-party/cargo/bit-vec@0.9.1/LICENSE-MIT +25 -0
  215. package/third-party/cargo/bitflags@2.13.0/Cargo.toml +120 -0
  216. package/third-party/cargo/bitflags@2.13.0/LICENSE-APACHE +201 -0
  217. package/third-party/cargo/bitflags@2.13.0/LICENSE-MIT +25 -0
  218. package/third-party/cargo/block2@0.6.2/Cargo.toml +115 -0
  219. package/third-party/cargo/block2@0.6.2/MIT-terms.txt +22 -0
  220. package/third-party/cargo/block2@0.6.2/madsmtm-objc2-b4167b582b2f-LICENSE.md +34 -0
  221. package/third-party/cargo/bumpalo@3.20.3/Cargo.toml +99 -0
  222. package/third-party/cargo/bumpalo@3.20.3/LICENSE-APACHE +201 -0
  223. package/third-party/cargo/bumpalo@3.20.3/LICENSE-MIT +25 -0
  224. package/third-party/cargo/bytemuck@1.25.1/Cargo.toml +153 -0
  225. package/third-party/cargo/bytemuck@1.25.1/LICENSE-APACHE +61 -0
  226. package/third-party/cargo/bytemuck@1.25.1/LICENSE-MIT +9 -0
  227. package/third-party/cargo/bytemuck@1.25.1/LICENSE-ZLIB +11 -0
  228. package/third-party/cargo/bytemuck_derive@1.11.0/Cargo.toml +60 -0
  229. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-APACHE +61 -0
  230. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-MIT +9 -0
  231. package/third-party/cargo/bytemuck_derive@1.11.0/LICENSE-ZLIB +11 -0
  232. package/third-party/cargo/byteorder-lite@0.1.0/Cargo.toml +57 -0
  233. package/third-party/cargo/byteorder-lite@0.1.0/LICENSE-MIT +21 -0
  234. package/third-party/cargo/byteorder-lite@0.1.0/UNLICENSE +24 -0
  235. package/third-party/cargo/byteorder@1.5.0/COPYING +3 -0
  236. package/third-party/cargo/byteorder@1.5.0/Cargo.toml +54 -0
  237. package/third-party/cargo/byteorder@1.5.0/LICENSE-MIT +21 -0
  238. package/third-party/cargo/byteorder@1.5.0/UNLICENSE +24 -0
  239. package/third-party/cargo/cfg-if@1.0.4/Cargo.toml +47 -0
  240. package/third-party/cargo/cfg-if@1.0.4/LICENSE-APACHE +201 -0
  241. package/third-party/cargo/cfg-if@1.0.4/LICENSE-MIT +25 -0
  242. package/third-party/cargo/cfg_aliases@0.2.1/Cargo.toml +43 -0
  243. package/third-party/cargo/cfg_aliases@0.2.1/LICENSE +9 -0
  244. package/third-party/cargo/chunked_transfer@1.5.0/Cargo.toml +27 -0
  245. package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-APACHE +201 -0
  246. package/third-party/cargo/chunked_transfer@1.5.0/LICENSE-MIT +22 -0
  247. package/third-party/cargo/codespan-reporting@0.13.1/Cargo.toml +115 -0
  248. package/third-party/cargo/codespan-reporting@0.13.1/LICENSE +201 -0
  249. package/third-party/cargo/color_quant@1.1.0/Cargo.toml +20 -0
  250. package/third-party/cargo/color_quant@1.1.0/LICENSE +21 -0
  251. package/third-party/cargo/console_error_panic_hook@0.1.7/Cargo.toml +27 -0
  252. package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-APACHE +201 -0
  253. package/third-party/cargo/console_error_panic_hook@0.1.7/LICENSE-MIT +25 -0
  254. package/third-party/cargo/core_maths@0.1.1/Cargo.toml +37 -0
  255. package/third-party/cargo/core_maths@0.1.1/LICENSE +21 -0
  256. package/third-party/cargo/cosmic-text@0.19.0/Cargo.toml +214 -0
  257. package/third-party/cargo/cosmic-text@0.19.0/LICENSE-APACHE +201 -0
  258. package/third-party/cargo/cosmic-text@0.19.0/LICENSE-MIT +21 -0
  259. package/third-party/cargo/crc32fast@1.5.0/Cargo.toml +68 -0
  260. package/third-party/cargo/crc32fast@1.5.0/LICENSE-APACHE +202 -0
  261. package/third-party/cargo/crc32fast@1.5.0/LICENSE-MIT +21 -0
  262. package/third-party/cargo/data-url@0.3.2/Cargo.toml +63 -0
  263. package/third-party/cargo/data-url@0.3.2/LICENSE-APACHE +201 -0
  264. package/third-party/cargo/data-url@0.3.2/LICENSE-MIT +25 -0
  265. package/third-party/cargo/dispatch2@0.3.1/Cargo.toml +122 -0
  266. package/third-party/cargo/dispatch2@0.3.1/MIT-terms.txt +22 -0
  267. package/third-party/cargo/dispatch2@0.3.1/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
  268. package/third-party/cargo/dlib@0.5.3/Cargo.toml +43 -0
  269. package/third-party/cargo/dlib@0.5.3/LICENSE.txt +19 -0
  270. package/third-party/cargo/document-features@0.2.12/Cargo.toml +51 -0
  271. package/third-party/cargo/document-features@0.2.12/LICENSE-APACHE +73 -0
  272. package/third-party/cargo/document-features@0.2.12/LICENSE-MIT +19 -0
  273. package/third-party/cargo/equivalent@1.0.2/Cargo.toml +37 -0
  274. package/third-party/cargo/equivalent@1.0.2/LICENSE-APACHE +201 -0
  275. package/third-party/cargo/equivalent@1.0.2/LICENSE-MIT +25 -0
  276. package/third-party/cargo/errno@0.3.14/Cargo.toml +67 -0
  277. package/third-party/cargo/errno@0.3.14/LICENSE-APACHE +201 -0
  278. package/third-party/cargo/errno@0.3.14/LICENSE-MIT +25 -0
  279. package/third-party/cargo/etagere@0.3.0/Cargo.toml +57 -0
  280. package/third-party/cargo/etagere@0.3.0/LICENSE-APACHE +13 -0
  281. package/third-party/cargo/etagere@0.3.0/LICENSE-MIT +20 -0
  282. package/third-party/cargo/euclid@0.22.14/COPYRIGHT +5 -0
  283. package/third-party/cargo/euclid@0.22.14/Cargo.toml +66 -0
  284. package/third-party/cargo/euclid@0.22.14/LICENSE-APACHE +201 -0
  285. package/third-party/cargo/euclid@0.22.14/LICENSE-MIT +25 -0
  286. package/third-party/cargo/fastrand@2.5.0/Cargo.toml +89 -0
  287. package/third-party/cargo/fastrand@2.5.0/LICENSE-APACHE +201 -0
  288. package/third-party/cargo/fastrand@2.5.0/LICENSE-MIT +23 -0
  289. package/third-party/cargo/fdeflate@0.3.7/Cargo.toml +55 -0
  290. package/third-party/cargo/fdeflate@0.3.7/LICENSE-APACHE +177 -0
  291. package/third-party/cargo/fdeflate@0.3.7/LICENSE-MIT +25 -0
  292. package/third-party/cargo/flate2@1.1.9/Cargo.toml +274 -0
  293. package/third-party/cargo/flate2@1.1.9/LICENSE-APACHE +201 -0
  294. package/third-party/cargo/flate2@1.1.9/LICENSE-MIT +25 -0
  295. package/third-party/cargo/float-cmp@0.9.0/Cargo.toml +39 -0
  296. package/third-party/cargo/float-cmp@0.9.0/LICENSE +19 -0
  297. package/third-party/cargo/float_next_after@1.0.0/Cargo.toml +43 -0
  298. package/third-party/cargo/float_next_after@1.0.0/LICENSE +23 -0
  299. package/third-party/cargo/foldhash@0.2.0/Cargo.toml +80 -0
  300. package/third-party/cargo/foldhash@0.2.0/LICENSE +19 -0
  301. package/third-party/cargo/font-types@0.11.3/Cargo.toml +55 -0
  302. package/third-party/cargo/font-types@0.11.3/LICENSE-APACHE +67 -0
  303. package/third-party/cargo/font-types@0.11.3/LICENSE-MIT +25 -0
  304. package/third-party/cargo/fontdb@0.23.0/Cargo.toml +83 -0
  305. package/third-party/cargo/fontdb@0.23.0/LICENSE +21 -0
  306. package/third-party/cargo/futures-core@0.3.32/Cargo.toml +66 -0
  307. package/third-party/cargo/futures-core@0.3.32/LICENSE-APACHE +202 -0
  308. package/third-party/cargo/futures-core@0.3.32/LICENSE-MIT +26 -0
  309. package/third-party/cargo/futures-task@0.3.32/Cargo.toml +58 -0
  310. package/third-party/cargo/futures-task@0.3.32/LICENSE-APACHE +202 -0
  311. package/third-party/cargo/futures-task@0.3.32/LICENSE-MIT +26 -0
  312. package/third-party/cargo/futures-util@0.3.32/Cargo.toml +181 -0
  313. package/third-party/cargo/futures-util@0.3.32/LICENSE-APACHE +202 -0
  314. package/third-party/cargo/futures-util@0.3.32/LICENSE-MIT +26 -0
  315. package/third-party/cargo/getrandom@0.4.3/Cargo.toml +165 -0
  316. package/third-party/cargo/getrandom@0.4.3/LICENSE-APACHE +201 -0
  317. package/third-party/cargo/getrandom@0.4.3/LICENSE-MIT +26 -0
  318. package/third-party/cargo/gif@0.14.2/Cargo.toml +84 -0
  319. package/third-party/cargo/gif@0.14.2/LICENSE-APACHE +201 -0
  320. package/third-party/cargo/gif@0.14.2/LICENSE-MIT +21 -0
  321. package/third-party/cargo/glam@0.33.2/Cargo.toml +354 -0
  322. package/third-party/cargo/glam@0.33.2/LICENSE-APACHE +201 -0
  323. package/third-party/cargo/glam@0.33.2/LICENSE-MIT +23 -0
  324. package/third-party/cargo/glow@0.17.0/Cargo.toml +122 -0
  325. package/third-party/cargo/glow@0.17.0/LICENSE-APACHE +201 -0
  326. package/third-party/cargo/glow@0.17.0/LICENSE-MIT +23 -0
  327. package/third-party/cargo/glow@0.17.0/LICENSE-ZLIB +15 -0
  328. package/third-party/cargo/gltf-derive@1.4.1/Cargo.toml +34 -0
  329. package/third-party/cargo/gltf-derive@1.4.1/LICENSE-APACHE +202 -0
  330. package/third-party/cargo/gltf-derive@1.4.1/LICENSE-MIT +26 -0
  331. package/third-party/cargo/gltf-json@1.4.1/Cargo.toml +50 -0
  332. package/third-party/cargo/gltf-json@1.4.1/LICENSE-APACHE +202 -0
  333. package/third-party/cargo/gltf-json@1.4.1/LICENSE-MIT +26 -0
  334. package/third-party/cargo/gltf@1.4.1/Cargo.toml +122 -0
  335. package/third-party/cargo/gltf@1.4.1/LICENSE-APACHE +202 -0
  336. package/third-party/cargo/gltf@1.4.1/LICENSE-MIT +26 -0
  337. package/third-party/cargo/glyphon@0.12.0/Cargo.toml +35 -0
  338. package/third-party/cargo/glyphon@0.12.0/LICENSE-APACHE +201 -0
  339. package/third-party/cargo/glyphon@0.12.0/LICENSE-MIT +23 -0
  340. package/third-party/cargo/glyphon@0.12.0/LICENSE-ZLIB +15 -0
  341. package/third-party/cargo/gpu-allocator@0.28.0/Cargo.toml +180 -0
  342. package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-APACHE +201 -0
  343. package/third-party/cargo/gpu-allocator@0.28.0/LICENSE-MIT +7 -0
  344. package/third-party/cargo/grid@1.0.1/Cargo.toml +77 -0
  345. package/third-party/cargo/grid@1.0.1/LICENSE +21 -0
  346. package/third-party/cargo/half@2.7.1/Cargo.toml +137 -0
  347. package/third-party/cargo/half@2.7.1/LICENSE-APACHE +176 -0
  348. package/third-party/cargo/half@2.7.1/LICENSE-MIT +19 -0
  349. package/third-party/cargo/harfrust@0.5.2/Cargo.toml +115 -0
  350. package/third-party/cargo/harfrust@0.5.2/harfbuzz-harfrust-efdae3142ab7-LICENSE +22 -0
  351. package/third-party/cargo/hashbrown@0.16.1/Cargo.toml +180 -0
  352. package/third-party/cargo/hashbrown@0.16.1/LICENSE-APACHE +201 -0
  353. package/third-party/cargo/hashbrown@0.16.1/LICENSE-MIT +25 -0
  354. package/third-party/cargo/hashbrown@0.17.1/Cargo.toml +201 -0
  355. package/third-party/cargo/hashbrown@0.17.1/LICENSE-APACHE +201 -0
  356. package/third-party/cargo/hashbrown@0.17.1/LICENSE-MIT +25 -0
  357. package/third-party/cargo/httpdate@1.0.3/Cargo.toml +35 -0
  358. package/third-party/cargo/httpdate@1.0.3/LICENSE-APACHE +201 -0
  359. package/third-party/cargo/httpdate@1.0.3/LICENSE-MIT +19 -0
  360. package/third-party/cargo/image-webp@0.2.4/Cargo.toml +63 -0
  361. package/third-party/cargo/image-webp@0.2.4/LICENSE-APACHE +177 -0
  362. package/third-party/cargo/image-webp@0.2.4/LICENSE-MIT +25 -0
  363. package/third-party/cargo/image@0.25.10/Cargo.toml +248 -0
  364. package/third-party/cargo/image@0.25.10/LICENSE-APACHE +177 -0
  365. package/third-party/cargo/image@0.25.10/LICENSE-MIT +25 -0
  366. package/third-party/cargo/imagesize@0.14.0/Cargo.toml +104 -0
  367. package/third-party/cargo/imagesize@0.14.0/LICENSE +21 -0
  368. package/third-party/cargo/indexmap@2.14.0/Cargo.toml +167 -0
  369. package/third-party/cargo/indexmap@2.14.0/LICENSE-APACHE +201 -0
  370. package/third-party/cargo/indexmap@2.14.0/LICENSE-MIT +25 -0
  371. package/third-party/cargo/inflections@1.1.1/Cargo.toml +21 -0
  372. package/third-party/cargo/inflections@1.1.1/LICENSE +20 -0
  373. package/third-party/cargo/itoa@1.0.18/Cargo.toml +66 -0
  374. package/third-party/cargo/itoa@1.0.18/LICENSE-APACHE +176 -0
  375. package/third-party/cargo/itoa@1.0.18/LICENSE-MIT +23 -0
  376. package/third-party/cargo/js-sys@0.3.103/Cargo.toml +98 -0
  377. package/third-party/cargo/js-sys@0.3.103/LICENSE-APACHE +201 -0
  378. package/third-party/cargo/js-sys@0.3.103/LICENSE-MIT +25 -0
  379. package/third-party/cargo/khronos-egl@6.0.0/Cargo.toml +82 -0
  380. package/third-party/cargo/khronos-egl@6.0.0/LICENSE-APACHE +201 -0
  381. package/third-party/cargo/khronos-egl@6.0.0/LICENSE-MIT +23 -0
  382. package/third-party/cargo/kurbo@0.13.1/Cargo.toml +230 -0
  383. package/third-party/cargo/kurbo@0.13.1/LICENSE-APACHE +202 -0
  384. package/third-party/cargo/kurbo@0.13.1/LICENSE-MIT +25 -0
  385. package/third-party/cargo/lazy_static@1.5.0/Cargo.toml +46 -0
  386. package/third-party/cargo/lazy_static@1.5.0/LICENSE-APACHE +201 -0
  387. package/third-party/cargo/lazy_static@1.5.0/LICENSE-MIT +25 -0
  388. package/third-party/cargo/libc@0.2.186/Cargo.toml +229 -0
  389. package/third-party/cargo/libc@0.2.186/LICENSE-APACHE +176 -0
  390. package/third-party/cargo/libc@0.2.186/LICENSE-MIT +25 -0
  391. package/third-party/cargo/libloading@0.8.9/Cargo.toml +90 -0
  392. package/third-party/cargo/libloading@0.8.9/LICENSE +12 -0
  393. package/third-party/cargo/libm@0.2.16/Cargo.toml +61 -0
  394. package/third-party/cargo/libm@0.2.16/LICENSE.txt +258 -0
  395. package/third-party/cargo/linebender_resource_handle@0.1.1/Cargo.toml +107 -0
  396. package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-APACHE +176 -0
  397. package/third-party/cargo/linebender_resource_handle@0.1.1/LICENSE-MIT +19 -0
  398. package/third-party/cargo/litrs@1.0.0/Cargo.toml +63 -0
  399. package/third-party/cargo/litrs@1.0.0/LICENSE-APACHE +176 -0
  400. package/third-party/cargo/litrs@1.0.0/LICENSE-MIT +25 -0
  401. package/third-party/cargo/lock_api@0.4.14/Cargo.toml +68 -0
  402. package/third-party/cargo/lock_api@0.4.14/LICENSE-APACHE +201 -0
  403. package/third-party/cargo/lock_api@0.4.14/LICENSE-MIT +25 -0
  404. package/third-party/cargo/log@0.4.33/Cargo.toml +152 -0
  405. package/third-party/cargo/log@0.4.33/LICENSE-APACHE +201 -0
  406. package/third-party/cargo/log@0.4.33/LICENSE-MIT +25 -0
  407. package/third-party/cargo/lru@0.16.4/Cargo.toml +47 -0
  408. package/third-party/cargo/lru@0.16.4/LICENSE +21 -0
  409. package/third-party/cargo/lyon_geom@1.0.19/Cargo.toml +69 -0
  410. package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
  411. package/third-party/cargo/lyon_geom@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
  412. package/third-party/cargo/lyon_path@1.0.19/Cargo.toml +58 -0
  413. package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-APACHE +13 -0
  414. package/third-party/cargo/lyon_path@1.0.19/nical-lyon-56219c95c658-LICENSE-MIT +20 -0
  415. package/third-party/cargo/lyon_tessellation@1.0.20/Cargo.toml +71 -0
  416. package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-APACHE +13 -0
  417. package/third-party/cargo/lyon_tessellation@1.0.20/nical-lyon-7fa75ea8eea3-LICENSE-MIT +20 -0
  418. package/third-party/cargo/memchr@2.8.3/COPYING +3 -0
  419. package/third-party/cargo/memchr@2.8.3/Cargo.toml +89 -0
  420. package/third-party/cargo/memchr@2.8.3/LICENSE-MIT +21 -0
  421. package/third-party/cargo/memchr@2.8.3/UNLICENSE +24 -0
  422. package/third-party/cargo/memmap2@0.9.11/Cargo.toml +59 -0
  423. package/third-party/cargo/memmap2@0.9.11/LICENSE-APACHE +201 -0
  424. package/third-party/cargo/memmap2@0.9.11/LICENSE-MIT +26 -0
  425. package/third-party/cargo/miniz_oxide@0.8.9/Cargo.toml +91 -0
  426. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE +25 -0
  427. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-APACHE.md +177 -0
  428. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-MIT.md +24 -0
  429. package/third-party/cargo/miniz_oxide@0.8.9/LICENSE-ZLIB.md +14 -0
  430. package/third-party/cargo/moxcms@0.8.1/Cargo.toml +113 -0
  431. package/third-party/cargo/moxcms@0.8.1/LICENSE-APACHE.md +201 -0
  432. package/third-party/cargo/moxcms@0.8.1/LICENSE.md +26 -0
  433. package/third-party/cargo/naga-types@30.0.0/Cargo.toml +94 -0
  434. package/third-party/cargo/naga-types@30.0.0/LICENSE.APACHE +176 -0
  435. package/third-party/cargo/naga-types@30.0.0/LICENSE.MIT +21 -0
  436. package/third-party/cargo/naga@30.0.0/Cargo.toml +246 -0
  437. package/third-party/cargo/naga@30.0.0/LICENSE.APACHE +176 -0
  438. package/third-party/cargo/naga@30.0.0/LICENSE.MIT +21 -0
  439. package/third-party/cargo/num-traits@0.2.19/Cargo.toml +54 -0
  440. package/third-party/cargo/num-traits@0.2.19/LICENSE-APACHE +201 -0
  441. package/third-party/cargo/num-traits@0.2.19/LICENSE-MIT +25 -0
  442. package/third-party/cargo/objc2-core-foundation@0.3.2/Cargo.toml +221 -0
  443. package/third-party/cargo/objc2-core-foundation@0.3.2/MIT-terms.txt +22 -0
  444. package/third-party/cargo/objc2-core-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  445. package/third-party/cargo/objc2-core-graphics@0.3.2/Cargo.toml +331 -0
  446. package/third-party/cargo/objc2-core-graphics@0.3.2/MIT-terms.txt +22 -0
  447. package/third-party/cargo/objc2-core-graphics@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  448. package/third-party/cargo/objc2-encode@4.1.0/Cargo.toml +81 -0
  449. package/third-party/cargo/objc2-encode@4.1.0/MIT-terms.txt +22 -0
  450. package/third-party/cargo/objc2-encode@4.1.0/madsmtm-objc2-8d214f547736-LICENSE.md +34 -0
  451. package/third-party/cargo/objc2-foundation@0.3.2/Cargo.toml +529 -0
  452. package/third-party/cargo/objc2-foundation@0.3.2/MIT-terms.txt +22 -0
  453. package/third-party/cargo/objc2-foundation@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  454. package/third-party/cargo/objc2-io-surface@0.3.2/Cargo.toml +139 -0
  455. package/third-party/cargo/objc2-io-surface@0.3.2/MIT-terms.txt +22 -0
  456. package/third-party/cargo/objc2-io-surface@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  457. package/third-party/cargo/objc2-metal@0.3.2/Cargo.toml +601 -0
  458. package/third-party/cargo/objc2-metal@0.3.2/MIT-terms.txt +22 -0
  459. package/third-party/cargo/objc2-metal@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  460. package/third-party/cargo/objc2-quartz-core@0.3.2/Cargo.toml +302 -0
  461. package/third-party/cargo/objc2-quartz-core@0.3.2/MIT-terms.txt +22 -0
  462. package/third-party/cargo/objc2-quartz-core@0.3.2/madsmtm-objc2-7b1abfd750a2-LICENSE.md +34 -0
  463. package/third-party/cargo/objc2@0.6.4/Cargo.toml +232 -0
  464. package/third-party/cargo/objc2@0.6.4/MIT-terms.txt +22 -0
  465. package/third-party/cargo/objc2@0.6.4/madsmtm-objc2-8852b424193c-LICENSE.md +34 -0
  466. package/third-party/cargo/once_cell@1.21.4/Cargo.toml +119 -0
  467. package/third-party/cargo/once_cell@1.21.4/LICENSE-APACHE +201 -0
  468. package/third-party/cargo/once_cell@1.21.4/LICENSE-MIT +23 -0
  469. package/third-party/cargo/ordered-float@5.3.0/Cargo.toml +162 -0
  470. package/third-party/cargo/ordered-float@5.3.0/LICENSE-MIT +25 -0
  471. package/third-party/cargo/parking_lot@0.12.5/Cargo.toml +87 -0
  472. package/third-party/cargo/parking_lot@0.12.5/LICENSE-APACHE +201 -0
  473. package/third-party/cargo/parking_lot@0.12.5/LICENSE-MIT +25 -0
  474. package/third-party/cargo/parking_lot_core@0.9.12/Cargo.toml +72 -0
  475. package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-APACHE +201 -0
  476. package/third-party/cargo/parking_lot_core@0.9.12/LICENSE-MIT +25 -0
  477. package/third-party/cargo/pico-args@0.5.0/Cargo.toml +32 -0
  478. package/third-party/cargo/pico-args@0.5.0/LICENSE +20 -0
  479. package/third-party/cargo/pin-project-lite@0.2.17/Cargo.toml +198 -0
  480. package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-APACHE +177 -0
  481. package/third-party/cargo/pin-project-lite@0.2.17/LICENSE-MIT +23 -0
  482. package/third-party/cargo/pkg-config@0.3.33/Cargo.toml +43 -0
  483. package/third-party/cargo/pkg-config@0.3.33/LICENSE-APACHE +201 -0
  484. package/third-party/cargo/pkg-config@0.3.33/LICENSE-MIT +25 -0
  485. package/third-party/cargo/png@0.18.1/Cargo.toml +130 -0
  486. package/third-party/cargo/png@0.18.1/LICENSE-APACHE +201 -0
  487. package/third-party/cargo/png@0.18.1/LICENSE-MIT +25 -0
  488. package/third-party/cargo/pollster@0.4.0/Cargo.toml +53 -0
  489. package/third-party/cargo/pollster@0.4.0/LICENSE-APACHE +201 -0
  490. package/third-party/cargo/pollster@0.4.0/LICENSE-MIT +25 -0
  491. package/third-party/cargo/polycool@0.4.0/Cargo.toml +83 -0
  492. package/third-party/cargo/polycool@0.4.0/LICENSE-APACHE +202 -0
  493. package/third-party/cargo/polycool@0.4.0/LICENSE-MIT +25 -0
  494. package/third-party/cargo/pp-rs@0.2.1/Cargo.toml +23 -0
  495. package/third-party/cargo/pp-rs@0.2.1/LICENSE +29 -0
  496. package/third-party/cargo/presser@0.3.1/Cargo.toml +58 -0
  497. package/third-party/cargo/presser@0.3.1/LICENSE-APACHE +201 -0
  498. package/third-party/cargo/presser@0.3.1/LICENSE-MIT +25 -0
  499. package/third-party/cargo/proc-macro2@1.0.106/Cargo.toml +105 -0
  500. package/third-party/cargo/proc-macro2@1.0.106/LICENSE-APACHE +176 -0
  501. package/third-party/cargo/proc-macro2@1.0.106/LICENSE-MIT +23 -0
  502. package/third-party/cargo/profiling@1.0.18/Cargo.toml +96 -0
  503. package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-APACHE +201 -0
  504. package/third-party/cargo/profiling@1.0.18/aclysma-profiling-8271551172eb-LICENSE-MIT +21 -0
  505. package/third-party/cargo/pxfm@0.1.30/Cargo.toml +53 -0
  506. package/third-party/cargo/pxfm@0.1.30/LICENSE-APACHE.md +201 -0
  507. package/third-party/cargo/pxfm@0.1.30/LICENSE.md +26 -0
  508. package/third-party/cargo/quick-error@2.0.1/Cargo.toml +24 -0
  509. package/third-party/cargo/quick-error@2.0.1/LICENSE-APACHE +202 -0
  510. package/third-party/cargo/quick-error@2.0.1/LICENSE-MIT +19 -0
  511. package/third-party/cargo/quote@1.0.46/Cargo.toml +70 -0
  512. package/third-party/cargo/quote@1.0.46/LICENSE-APACHE +176 -0
  513. package/third-party/cargo/quote@1.0.46/LICENSE-MIT +23 -0
  514. package/third-party/cargo/rangemap@1.7.1/Cargo.toml +91 -0
  515. package/third-party/cargo/rangemap@1.7.1/LICENSE-APACHE +191 -0
  516. package/third-party/cargo/rangemap@1.7.1/LICENSE-MIT +7 -0
  517. package/third-party/cargo/raw-window-handle@0.6.2/Cargo.toml +56 -0
  518. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-APACHE.md +177 -0
  519. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-MIT.md +21 -0
  520. package/third-party/cargo/raw-window-handle@0.6.2/LICENSE-ZLIB.md +11 -0
  521. package/third-party/cargo/raw-window-metal@1.1.0/Cargo.toml +111 -0
  522. package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-APACHE +202 -0
  523. package/third-party/cargo/raw-window-metal@1.1.0/LICENSE-MIT +17 -0
  524. package/third-party/cargo/read-fonts@0.37.0/Cargo.toml +95 -0
  525. package/third-party/cargo/read-fonts@0.37.0/LICENSE-APACHE +67 -0
  526. package/third-party/cargo/read-fonts@0.37.0/LICENSE-MIT +25 -0
  527. package/third-party/cargo/read-fonts@0.39.2/Cargo.toml +96 -0
  528. package/third-party/cargo/read-fonts@0.39.2/LICENSE-APACHE +67 -0
  529. package/third-party/cargo/read-fonts@0.39.2/LICENSE-MIT +25 -0
  530. package/third-party/cargo/renderdoc-sys@1.1.0/Cargo.toml +39 -0
  531. package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-APACHE +201 -0
  532. package/third-party/cargo/renderdoc-sys@1.1.0/LICENSE-MIT +25 -0
  533. package/third-party/cargo/resvg@0.47.0/Cargo.toml +112 -0
  534. package/third-party/cargo/resvg@0.47.0/LICENSE-APACHE +176 -0
  535. package/third-party/cargo/resvg@0.47.0/LICENSE-MIT +25 -0
  536. package/third-party/cargo/rgb@0.8.53/Cargo.toml +110 -0
  537. package/third-party/cargo/rgb@0.8.53/LICENSE +21 -0
  538. package/third-party/cargo/roxmltree@0.21.1/Cargo.toml +75 -0
  539. package/third-party/cargo/roxmltree@0.21.1/LICENSE-APACHE +201 -0
  540. package/third-party/cargo/roxmltree@0.21.1/LICENSE-MIT +21 -0
  541. package/third-party/cargo/rustc-hash@1.1.0/Cargo.toml +25 -0
  542. package/third-party/cargo/rustc-hash@1.1.0/LICENSE-APACHE +201 -0
  543. package/third-party/cargo/rustc-hash@1.1.0/LICENSE-MIT +23 -0
  544. package/third-party/cargo/rustc-hash@2.1.3/Cargo.toml +50 -0
  545. package/third-party/cargo/rustc-hash@2.1.3/LICENSE-APACHE +176 -0
  546. package/third-party/cargo/rustc-hash@2.1.3/LICENSE-MIT +23 -0
  547. package/third-party/cargo/rustix@1.1.4/COPYRIGHT +29 -0
  548. package/third-party/cargo/rustix@1.1.4/Cargo.toml +292 -0
  549. package/third-party/cargo/rustix@1.1.4/LICENSE-APACHE +201 -0
  550. package/third-party/cargo/rustix@1.1.4/LICENSE-Apache-2.0_WITH_LLVM-exception +220 -0
  551. package/third-party/cargo/rustix@1.1.4/LICENSE-MIT +23 -0
  552. package/third-party/cargo/rustversion@1.0.23/Cargo.toml +69 -0
  553. package/third-party/cargo/rustversion@1.0.23/LICENSE-APACHE +176 -0
  554. package/third-party/cargo/rustversion@1.0.23/LICENSE-MIT +23 -0
  555. package/third-party/cargo/rustybuzz@0.20.1/Cargo.toml +110 -0
  556. package/third-party/cargo/rustybuzz@0.20.1/LICENSE +22 -0
  557. package/third-party/cargo/scopeguard@1.2.0/Cargo.toml +43 -0
  558. package/third-party/cargo/scopeguard@1.2.0/LICENSE-APACHE +201 -0
  559. package/third-party/cargo/scopeguard@1.2.0/LICENSE-MIT +25 -0
  560. package/third-party/cargo/self_cell@1.2.2/Cargo.toml +33 -0
  561. package/third-party/cargo/self_cell@1.2.2/LICENSE-APACHE +201 -0
  562. package/third-party/cargo/self_cell@1.2.2/LICENSE-GPLv2 +339 -0
  563. package/third-party/cargo/self_cell@1.3.0/Cargo.toml +33 -0
  564. package/third-party/cargo/self_cell@1.3.0/LICENSE-APACHE +201 -0
  565. package/third-party/cargo/self_cell@1.3.0/LICENSE-GPLv2 +339 -0
  566. package/third-party/cargo/serde@1.0.228/Cargo.toml +84 -0
  567. package/third-party/cargo/serde@1.0.228/LICENSE-APACHE +176 -0
  568. package/third-party/cargo/serde@1.0.228/LICENSE-MIT +23 -0
  569. package/third-party/cargo/serde_core@1.0.228/Cargo.toml +87 -0
  570. package/third-party/cargo/serde_core@1.0.228/LICENSE-APACHE +176 -0
  571. package/third-party/cargo/serde_core@1.0.228/LICENSE-MIT +23 -0
  572. package/third-party/cargo/serde_derive@1.0.228/Cargo.toml +87 -0
  573. package/third-party/cargo/serde_derive@1.0.228/LICENSE-APACHE +176 -0
  574. package/third-party/cargo/serde_derive@1.0.228/LICENSE-MIT +23 -0
  575. package/third-party/cargo/serde_json@1.0.150/Cargo.toml +162 -0
  576. package/third-party/cargo/serde_json@1.0.150/LICENSE-APACHE +176 -0
  577. package/third-party/cargo/serde_json@1.0.150/LICENSE-MIT +23 -0
  578. package/third-party/cargo/simd-adler32@0.3.10/Cargo.toml +68 -0
  579. package/third-party/cargo/simd-adler32@0.3.10/LICENSE.md +21 -0
  580. package/third-party/cargo/simplecss@0.2.2/Cargo.toml +146 -0
  581. package/third-party/cargo/simplecss@0.2.2/LICENSE-APACHE +201 -0
  582. package/third-party/cargo/simplecss@0.2.2/LICENSE-MIT +21 -0
  583. package/third-party/cargo/siphasher@1.0.3/COPYING +7 -0
  584. package/third-party/cargo/siphasher@1.0.3/Cargo.toml +64 -0
  585. package/third-party/cargo/skrifa@0.40.0/Cargo.toml +86 -0
  586. package/third-party/cargo/skrifa@0.40.0/LICENSE-APACHE +67 -0
  587. package/third-party/cargo/skrifa@0.40.0/LICENSE-MIT +25 -0
  588. package/third-party/cargo/skrifa@0.42.1/Cargo.toml +86 -0
  589. package/third-party/cargo/skrifa@0.42.1/LICENSE-APACHE +67 -0
  590. package/third-party/cargo/skrifa@0.42.1/LICENSE-MIT +25 -0
  591. package/third-party/cargo/slab@0.4.12/Cargo.toml +67 -0
  592. package/third-party/cargo/slab@0.4.12/LICENSE +25 -0
  593. package/third-party/cargo/slotmap@1.1.1/Cargo.toml +83 -0
  594. package/third-party/cargo/slotmap@1.1.1/LICENSE +19 -0
  595. package/third-party/cargo/smallvec@1.15.2/Cargo.toml +103 -0
  596. package/third-party/cargo/smallvec@1.15.2/LICENSE-APACHE +201 -0
  597. package/third-party/cargo/smallvec@1.15.2/LICENSE-MIT +25 -0
  598. package/third-party/cargo/smol_str@0.3.6/Cargo.toml +155 -0
  599. package/third-party/cargo/smol_str@0.3.6/LICENSE-APACHE +201 -0
  600. package/third-party/cargo/smol_str@0.3.6/LICENSE-MIT +23 -0
  601. package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/Cargo.toml +56 -0
  602. package/third-party/cargo/spirv@0.4.0+sdk-1.4.341.0/gfx-rs-rspirv-8afc3d0ac8e1-LICENSE +202 -0
  603. package/third-party/cargo/static_assertions@1.1.0/Cargo.toml +39 -0
  604. package/third-party/cargo/static_assertions@1.1.0/LICENSE-APACHE +202 -0
  605. package/third-party/cargo/static_assertions@1.1.0/LICENSE-MIT +21 -0
  606. package/third-party/cargo/strict-num@0.1.1/Cargo.toml +35 -0
  607. package/third-party/cargo/strict-num@0.1.1/LICENSE +19 -0
  608. package/third-party/cargo/svgtypes@0.16.1/Cargo.toml +57 -0
  609. package/third-party/cargo/svgtypes@0.16.1/LICENSE-APACHE +201 -0
  610. package/third-party/cargo/svgtypes@0.16.1/LICENSE-MIT +20 -0
  611. package/third-party/cargo/swash@0.2.9/Cargo.toml +93 -0
  612. package/third-party/cargo/swash@0.2.9/LICENSE-APACHE +201 -0
  613. package/third-party/cargo/swash@0.2.9/LICENSE-MIT +25 -0
  614. package/third-party/cargo/syn@2.0.118/Cargo.toml +272 -0
  615. package/third-party/cargo/syn@2.0.118/LICENSE-APACHE +176 -0
  616. package/third-party/cargo/syn@2.0.118/LICENSE-MIT +23 -0
  617. package/third-party/cargo/sys-locale@0.3.2/Cargo.toml +73 -0
  618. package/third-party/cargo/sys-locale@0.3.2/LICENSE-APACHE +201 -0
  619. package/third-party/cargo/sys-locale@0.3.2/LICENSE-MIT +21 -0
  620. package/third-party/cargo/taffy@0.12.1/Cargo.toml +171 -0
  621. package/third-party/cargo/taffy@0.12.1/DioxusLabs-taffy-1c9e37a0a1cf-LICENSE.md +25 -0
  622. package/third-party/cargo/tempfile@3.27.0/Cargo.toml +105 -0
  623. package/third-party/cargo/tempfile@3.27.0/LICENSE-APACHE +201 -0
  624. package/third-party/cargo/tempfile@3.27.0/LICENSE-MIT +25 -0
  625. package/third-party/cargo/termcolor@1.4.1/COPYING +3 -0
  626. package/third-party/cargo/termcolor@1.4.1/Cargo.toml +40 -0
  627. package/third-party/cargo/termcolor@1.4.1/LICENSE-MIT +21 -0
  628. package/third-party/cargo/termcolor@1.4.1/UNLICENSE +24 -0
  629. package/third-party/cargo/thiserror-impl@2.0.18/Cargo.toml +52 -0
  630. package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-APACHE +176 -0
  631. package/third-party/cargo/thiserror-impl@2.0.18/LICENSE-MIT +23 -0
  632. package/third-party/cargo/thiserror@2.0.18/Cargo.toml +119 -0
  633. package/third-party/cargo/thiserror@2.0.18/LICENSE-APACHE +176 -0
  634. package/third-party/cargo/thiserror@2.0.18/LICENSE-MIT +23 -0
  635. package/third-party/cargo/tiny-skia-path@0.12.0/Cargo.toml +58 -0
  636. package/third-party/cargo/tiny-skia-path@0.12.0/LICENSE +30 -0
  637. package/third-party/cargo/tiny-skia@0.12.0/Cargo.toml +116 -0
  638. package/third-party/cargo/tiny-skia@0.12.0/LICENSE +30 -0
  639. package/third-party/cargo/tiny_http@0.12.0/Cargo.toml +82 -0
  640. package/third-party/cargo/tiny_http@0.12.0/LICENSE-APACHE +201 -0
  641. package/third-party/cargo/tiny_http@0.12.0/LICENSE-MIT +25 -0
  642. package/third-party/cargo/tinyvec@1.12.0/Cargo.toml +184 -0
  643. package/third-party/cargo/tinyvec@1.12.0/LICENSE-APACHE.md +202 -0
  644. package/third-party/cargo/tinyvec@1.12.0/LICENSE-MIT.md +5 -0
  645. package/third-party/cargo/tinyvec@1.12.0/LICENSE-ZLIB.md +11 -0
  646. package/third-party/cargo/tinyvec_macros@0.1.1/Cargo.toml +19 -0
  647. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-APACHE.md +202 -0
  648. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-MIT.md +21 -0
  649. package/third-party/cargo/tinyvec_macros@0.1.1/LICENSE-ZLIB.md +20 -0
  650. package/third-party/cargo/ttf-parser@0.25.1/Cargo.toml +101 -0
  651. package/third-party/cargo/ttf-parser@0.25.1/LICENSE-APACHE +201 -0
  652. package/third-party/cargo/ttf-parser@0.25.1/LICENSE-MIT +20 -0
  653. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/Cargo.toml +22 -0
  654. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-APACHE +201 -0
  655. package/third-party/cargo/unicode-bidi-mirroring@0.4.0/LICENSE-MIT +21 -0
  656. package/third-party/cargo/unicode-bidi@0.3.18/COPYRIGHT +8 -0
  657. package/third-party/cargo/unicode-bidi@0.3.18/Cargo.toml +90 -0
  658. package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-APACHE +201 -0
  659. package/third-party/cargo/unicode-bidi@0.3.18/LICENSE-MIT +25 -0
  660. package/third-party/cargo/unicode-ccc@0.4.0/Cargo.toml +22 -0
  661. package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-APACHE +201 -0
  662. package/third-party/cargo/unicode-ccc@0.4.0/LICENSE-MIT +21 -0
  663. package/third-party/cargo/unicode-ident@1.0.24/Cargo.toml +84 -0
  664. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-APACHE +176 -0
  665. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-MIT +23 -0
  666. package/third-party/cargo/unicode-ident@1.0.24/LICENSE-UNICODE +39 -0
  667. package/third-party/cargo/unicode-linebreak@0.1.5/Cargo.toml +32 -0
  668. package/third-party/cargo/unicode-linebreak@0.1.5/LICENSE +201 -0
  669. package/third-party/cargo/unicode-properties@0.1.4/COPYRIGHT +7 -0
  670. package/third-party/cargo/unicode-properties@0.1.4/Cargo.toml +65 -0
  671. package/third-party/cargo/unicode-properties@0.1.4/LICENSE-APACHE +201 -0
  672. package/third-party/cargo/unicode-properties@0.1.4/LICENSE-MIT +25 -0
  673. package/third-party/cargo/unicode-script@0.5.8/Cargo.toml +63 -0
  674. package/third-party/cargo/unicode-script@0.5.8/LICENSE-APACHE +201 -0
  675. package/third-party/cargo/unicode-script@0.5.8/LICENSE-MIT +27 -0
  676. package/third-party/cargo/unicode-segmentation@1.13.3/COPYRIGHT +7 -0
  677. package/third-party/cargo/unicode-segmentation@1.13.3/Cargo.toml +91 -0
  678. package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-APACHE +201 -0
  679. package/third-party/cargo/unicode-segmentation@1.13.3/LICENSE-MIT +25 -0
  680. package/third-party/cargo/unicode-vo@0.1.0/Cargo.toml +22 -0
  681. package/third-party/cargo/unicode-vo@0.1.0/LICENSE-APACHE +201 -0
  682. package/third-party/cargo/unicode-vo@0.1.0/LICENSE-MIT +21 -0
  683. package/third-party/cargo/unicode-width@0.2.2/COPYRIGHT +7 -0
  684. package/third-party/cargo/unicode-width@0.2.2/Cargo.toml +77 -0
  685. package/third-party/cargo/unicode-width@0.2.2/LICENSE-APACHE +201 -0
  686. package/third-party/cargo/unicode-width@0.2.2/LICENSE-MIT +25 -0
  687. package/third-party/cargo/unicode-xid@0.2.6/COPYRIGHT +7 -0
  688. package/third-party/cargo/unicode-xid@0.2.6/Cargo.toml +65 -0
  689. package/third-party/cargo/unicode-xid@0.2.6/LICENSE-APACHE +201 -0
  690. package/third-party/cargo/unicode-xid@0.2.6/LICENSE-MIT +25 -0
  691. package/third-party/cargo/urlencoding@2.1.3/Cargo.toml +41 -0
  692. package/third-party/cargo/urlencoding@2.1.3/LICENSE +20 -0
  693. package/third-party/cargo/usvg@0.47.0/Cargo.toml +138 -0
  694. package/third-party/cargo/usvg@0.47.0/LICENSE-APACHE +176 -0
  695. package/third-party/cargo/usvg@0.47.0/LICENSE-MIT +25 -0
  696. package/third-party/cargo/version_check@0.9.5/Cargo.toml +38 -0
  697. package/third-party/cargo/version_check@0.9.5/LICENSE-APACHE +201 -0
  698. package/third-party/cargo/version_check@0.9.5/LICENSE-MIT +19 -0
  699. package/third-party/cargo/wasm-bindgen-futures@0.4.76/Cargo.toml +88 -0
  700. package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-APACHE +201 -0
  701. package/third-party/cargo/wasm-bindgen-futures@0.4.76/LICENSE-MIT +25 -0
  702. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/Cargo.toml +83 -0
  703. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-APACHE +201 -0
  704. package/third-party/cargo/wasm-bindgen-macro-support@0.2.126/LICENSE-MIT +25 -0
  705. package/third-party/cargo/wasm-bindgen-macro@0.2.126/Cargo.toml +73 -0
  706. package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-APACHE +201 -0
  707. package/third-party/cargo/wasm-bindgen-macro@0.2.126/LICENSE-MIT +25 -0
  708. package/third-party/cargo/wasm-bindgen-shared@0.2.126/Cargo.toml +66 -0
  709. package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-APACHE +201 -0
  710. package/third-party/cargo/wasm-bindgen-shared@0.2.126/LICENSE-MIT +25 -0
  711. package/third-party/cargo/wasm-bindgen@0.2.126/Cargo.toml +122 -0
  712. package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-APACHE +201 -0
  713. package/third-party/cargo/wasm-bindgen@0.2.126/LICENSE-MIT +25 -0
  714. package/third-party/cargo/wayland-sys@0.31.11/Cargo.toml +81 -0
  715. package/third-party/cargo/wayland-sys@0.31.11/LICENSE.txt +19 -0
  716. package/third-party/cargo/web-sys@0.3.103/Cargo.toml +2823 -0
  717. package/third-party/cargo/web-sys@0.3.103/LICENSE-APACHE +201 -0
  718. package/third-party/cargo/web-sys@0.3.103/LICENSE-MIT +25 -0
  719. package/third-party/cargo/weezl@0.1.12/Cargo.toml +120 -0
  720. package/third-party/cargo/weezl@0.1.12/LICENSE-APACHE +201 -0
  721. package/third-party/cargo/weezl@0.1.12/LICENSE-MIT +22 -0
  722. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/Cargo.toml +53 -0
  723. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.APACHE +176 -0
  724. package/third-party/cargo/wgpu-core-deps-apple@30.0.0/LICENSE.MIT +21 -0
  725. package/third-party/cargo/wgpu-core@30.0.0/Cargo.toml +237 -0
  726. package/third-party/cargo/wgpu-core@30.0.0/LICENSE.APACHE +176 -0
  727. package/third-party/cargo/wgpu-core@30.0.0/LICENSE.MIT +21 -0
  728. package/third-party/cargo/wgpu-hal@30.0.0/Cargo.toml +541 -0
  729. package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.APACHE +176 -0
  730. package/third-party/cargo/wgpu-hal@30.0.0/LICENSE.MIT +21 -0
  731. package/third-party/cargo/wgpu-naga-bridge@30.0.0/Cargo.toml +46 -0
  732. package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.APACHE +176 -0
  733. package/third-party/cargo/wgpu-naga-bridge@30.0.0/LICENSE.MIT +21 -0
  734. package/third-party/cargo/wgpu-types@30.0.0/Cargo.toml +161 -0
  735. package/third-party/cargo/wgpu-types@30.0.0/LICENSE.APACHE +176 -0
  736. package/third-party/cargo/wgpu-types@30.0.0/LICENSE.MIT +21 -0
  737. package/third-party/cargo/wgpu@30.0.0/Cargo.toml +278 -0
  738. package/third-party/cargo/wgpu@30.0.0/LICENSE.APACHE +176 -0
  739. package/third-party/cargo/wgpu@30.0.0/LICENSE.MIT +21 -0
  740. package/third-party/cargo/xmlwriter@0.1.0/Cargo.toml +23 -0
  741. package/third-party/cargo/xmlwriter@0.1.0/LICENSE +21 -0
  742. package/third-party/cargo/yazi@0.2.1/Cargo.toml +45 -0
  743. package/third-party/cargo/yazi@0.2.1/LICENSE-APACHE +201 -0
  744. package/third-party/cargo/yazi@0.2.1/LICENSE-MIT +19 -0
  745. package/third-party/cargo/zeno@0.3.3/Cargo.toml +65 -0
  746. package/third-party/cargo/zeno@0.3.3/LICENSE-APACHE +201 -0
  747. package/third-party/cargo/zeno@0.3.3/LICENSE-MIT +25 -0
  748. package/third-party/cargo/zerocopy-derive@0.8.54/Cargo.toml +209 -0
  749. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-APACHE +202 -0
  750. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-BSD +24 -0
  751. package/third-party/cargo/zerocopy-derive@0.8.54/LICENSE-MIT +26 -0
  752. package/third-party/cargo/zerocopy@0.8.54/Cargo.toml +419 -0
  753. package/third-party/cargo/zerocopy@0.8.54/LICENSE-APACHE +202 -0
  754. package/third-party/cargo/zerocopy@0.8.54/LICENSE-BSD +24 -0
  755. package/third-party/cargo/zerocopy@0.8.54/LICENSE-MIT +26 -0
  756. package/third-party/cargo/zmij@1.0.23/Cargo.toml +90 -0
  757. package/third-party/cargo/zmij@1.0.23/LICENSE-MIT +23 -0
  758. package/third-party/cargo/zune-core@0.5.1/Cargo.toml +47 -0
  759. package/third-party/cargo/zune-core@0.5.1/LICENSE-APACHE +201 -0
  760. package/third-party/cargo/zune-core@0.5.1/LICENSE-MIT +21 -0
  761. package/third-party/cargo/zune-core@0.5.1/LICENSE-ZLIB +19 -0
  762. package/third-party/cargo/zune-jpeg@0.5.15/Cargo.toml +67 -0
  763. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-APACHE +201 -0
  764. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-MIT +21 -0
  765. package/third-party/cargo/zune-jpeg@0.5.15/LICENSE-ZLIB +19 -0
  766. package/third-party/inventory.json +3614 -0
  767. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/esbuild-0.27.4-LICENSE.md +21 -0
  768. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/go-LICENSE +27 -0
  769. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/golang-x-sys-c0bba94af5f8-LICENSE +27 -0
  770. package/third-party/npm/@esbuild__darwin-arm64@0.27.4/package.json +20 -0
  771. package/third-party/npm/@floating-ui__core@1.7.5/LICENSE +20 -0
  772. package/third-party/npm/@floating-ui__core@1.7.5/package.json +63 -0
  773. package/third-party/npm/@floating-ui__dom@1.7.6/LICENSE +20 -0
  774. package/third-party/npm/@floating-ui__dom@1.7.6/package.json +71 -0
  775. package/third-party/npm/@floating-ui__react-dom@2.1.8/LICENSE +20 -0
  776. package/third-party/npm/@floating-ui__react-dom@2.1.8/package.json +76 -0
  777. package/third-party/npm/@floating-ui__utils@0.2.11/LICENSE +20 -0
  778. package/third-party/npm/@floating-ui__utils@0.2.11/package.json +70 -0
  779. package/third-party/npm/@radix-ui__primitive@1.1.7/LICENSE +21 -0
  780. package/third-party/npm/@radix-ui__primitive@1.1.7/package.json +79 -0
  781. package/third-party/npm/@radix-ui__react-arrow@1.1.15/LICENSE +21 -0
  782. package/third-party/npm/@radix-ui__react-arrow@1.1.15/package.json +68 -0
  783. package/third-party/npm/@radix-ui__react-collection@1.1.15/LICENSE +21 -0
  784. package/third-party/npm/@radix-ui__react-collection@1.1.15/package.json +71 -0
  785. package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/LICENSE +21 -0
  786. package/third-party/npm/@radix-ui__react-compose-refs@1.1.5/package.json +60 -0
  787. package/third-party/npm/@radix-ui__react-context-menu@2.3.7/LICENSE +21 -0
  788. package/third-party/npm/@radix-ui__react-context-menu@2.3.7/package.json +73 -0
  789. package/third-party/npm/@radix-ui__react-context@1.2.2/LICENSE +21 -0
  790. package/third-party/npm/@radix-ui__react-context@1.2.2/package.json +60 -0
  791. package/third-party/npm/@radix-ui__react-direction@1.1.4/LICENSE +21 -0
  792. package/third-party/npm/@radix-ui__react-direction@1.1.4/package.json +60 -0
  793. package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/LICENSE +21 -0
  794. package/third-party/npm/@radix-ui__react-dismissable-layer@1.1.19/package.json +74 -0
  795. package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/LICENSE +21 -0
  796. package/third-party/npm/@radix-ui__react-focus-guards@1.1.6/package.json +60 -0
  797. package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/LICENSE +21 -0
  798. package/third-party/npm/@radix-ui__react-focus-scope@1.1.16/package.json +71 -0
  799. package/third-party/npm/@radix-ui__react-id@1.1.4/LICENSE +21 -0
  800. package/third-party/npm/@radix-ui__react-id@1.1.4/package.json +63 -0
  801. package/third-party/npm/@radix-ui__react-menu@2.1.24/LICENSE +21 -0
  802. package/third-party/npm/@radix-ui__react-menu@2.1.24/package.json +86 -0
  803. package/third-party/npm/@radix-ui__react-popper@1.3.7/LICENSE +21 -0
  804. package/third-party/npm/@radix-ui__react-popper@1.3.7/package.json +78 -0
  805. package/third-party/npm/@radix-ui__react-portal@1.1.17/LICENSE +21 -0
  806. package/third-party/npm/@radix-ui__react-portal@1.1.17/package.json +69 -0
  807. package/third-party/npm/@radix-ui__react-presence@1.1.10/LICENSE +21 -0
  808. package/third-party/npm/@radix-ui__react-presence@1.1.10/package.json +68 -0
  809. package/third-party/npm/@radix-ui__react-primitive@2.1.10/LICENSE +21 -0
  810. package/third-party/npm/@radix-ui__react-primitive@2.1.10/package.json +68 -0
  811. package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/LICENSE +21 -0
  812. package/third-party/npm/@radix-ui__react-roving-focus@1.1.19/package.json +78 -0
  813. package/third-party/npm/@radix-ui__react-slot@1.3.3/LICENSE +21 -0
  814. package/third-party/npm/@radix-ui__react-slot@1.3.3/package.json +63 -0
  815. package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/LICENSE +21 -0
  816. package/third-party/npm/@radix-ui__react-use-callback-ref@1.1.4/package.json +60 -0
  817. package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/LICENSE +21 -0
  818. package/third-party/npm/@radix-ui__react-use-controllable-state@1.2.6/package.json +65 -0
  819. package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/LICENSE +21 -0
  820. package/third-party/npm/@radix-ui__react-use-effect-event@0.0.5/package.json +65 -0
  821. package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/LICENSE +21 -0
  822. package/third-party/npm/@radix-ui__react-use-is-hydrated@0.1.3/package.json +61 -0
  823. package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/LICENSE +21 -0
  824. package/third-party/npm/@radix-ui__react-use-layout-effect@1.1.4/package.json +60 -0
  825. package/third-party/npm/@radix-ui__react-use-size@1.1.4/LICENSE +21 -0
  826. package/third-party/npm/@radix-ui__react-use-size@1.1.4/package.json +63 -0
  827. package/third-party/npm/aria-hidden@1.2.6/LICENSE +21 -0
  828. package/third-party/npm/aria-hidden@1.2.6/package.json +71 -0
  829. package/third-party/npm/detect-node-es@1.1.0/LICENSE +21 -0
  830. package/third-party/npm/detect-node-es@1.1.0/package.json +29 -0
  831. package/third-party/npm/esbuild@0.27.4/LICENSE.md +21 -0
  832. package/third-party/npm/esbuild@0.27.4/package.json +49 -0
  833. package/third-party/npm/fflate@0.8.3/LICENSE +21 -0
  834. package/third-party/npm/fflate@0.8.3/package.json +128 -0
  835. package/third-party/npm/get-nonce@1.0.1/LICENSE +21 -0
  836. package/third-party/npm/get-nonce@1.0.1/package.json +68 -0
  837. package/third-party/npm/mediabunny@1.52.2/LICENSE +373 -0
  838. package/third-party/npm/mediabunny@1.52.2/package.json +136 -0
  839. package/third-party/npm/mediabunny@1.52.2/source/LICENSE +373 -0
  840. package/third-party/npm/mediabunny@1.52.2/source/package.json +136 -0
  841. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-demuxer.ts +400 -0
  842. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-muxer.ts +124 -0
  843. package/third-party/npm/mediabunny@1.52.2/source/src/adts/adts-reader.ts +85 -0
  844. package/third-party/npm/mediabunny@1.52.2/source/src/aes.ts +307 -0
  845. package/third-party/npm/mediabunny@1.52.2/source/src/codec-data.ts +3178 -0
  846. package/third-party/npm/mediabunny@1.52.2/source/src/codec.ts +1154 -0
  847. package/third-party/npm/mediabunny@1.52.2/source/src/conversion.ts +2042 -0
  848. package/third-party/npm/mediabunny@1.52.2/source/src/custom-coder.ts +212 -0
  849. package/third-party/npm/mediabunny@1.52.2/source/src/decode.ts +263 -0
  850. package/third-party/npm/mediabunny@1.52.2/source/src/demuxer.ts +43 -0
  851. package/third-party/npm/mediabunny@1.52.2/source/src/encode.ts +1412 -0
  852. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-demuxer.ts +813 -0
  853. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-misc.ts +165 -0
  854. package/third-party/npm/mediabunny@1.52.2/source/src/flac/flac-muxer.ts +350 -0
  855. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-demuxer.ts +995 -0
  856. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-misc.ts +81 -0
  857. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-muxer.ts +1529 -0
  858. package/third-party/npm/mediabunny@1.52.2/source/src/hls/hls-segmented-input.ts +772 -0
  859. package/third-party/npm/mediabunny@1.52.2/source/src/id3.ts +972 -0
  860. package/third-party/npm/mediabunny@1.52.2/source/src/index.ts +319 -0
  861. package/third-party/npm/mediabunny@1.52.2/source/src/input-format.ts +819 -0
  862. package/third-party/npm/mediabunny@1.52.2/source/src/input-track.ts +1141 -0
  863. package/third-party/npm/mediabunny@1.52.2/source/src/input.ts +571 -0
  864. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-boxes.ts +1911 -0
  865. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-demuxer.ts +3953 -0
  866. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-misc.ts +90 -0
  867. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-muxer.ts +1595 -0
  868. package/third-party/npm/mediabunny@1.52.2/source/src/isobmff/isobmff-reader.ts +91 -0
  869. package/third-party/npm/mediabunny@1.52.2/source/src/logging.ts +120 -0
  870. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/ebml.ts +770 -0
  871. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-demuxer.ts +2598 -0
  872. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-misc.ts +29 -0
  873. package/third-party/npm/mediabunny@1.52.2/source/src/matroska/matroska-muxer.ts +1360 -0
  874. package/third-party/npm/mediabunny@1.52.2/source/src/media-sink.ts +2589 -0
  875. package/third-party/npm/mediabunny@1.52.2/source/src/media-source.ts +3041 -0
  876. package/third-party/npm/mediabunny@1.52.2/source/src/metadata.ts +335 -0
  877. package/third-party/npm/mediabunny@1.52.2/source/src/misc.ts +1336 -0
  878. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-demuxer.ts +469 -0
  879. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-muxer.ts +169 -0
  880. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-reader.ts +61 -0
  881. package/third-party/npm/mediabunny@1.52.2/source/src/mp3/mp3-writer.ts +121 -0
  882. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-demuxer.ts +2519 -0
  883. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-misc.ts +32 -0
  884. package/third-party/npm/mediabunny@1.52.2/source/src/mpeg-ts/mpeg-ts-muxer.ts +842 -0
  885. package/third-party/npm/mediabunny@1.52.2/source/src/muxer.ts +80 -0
  886. package/third-party/npm/mediabunny@1.52.2/source/src/node.ts +11 -0
  887. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-demuxer.ts +1087 -0
  888. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-misc.ts +116 -0
  889. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-muxer.ts +527 -0
  890. package/third-party/npm/mediabunny@1.52.2/source/src/ogg/ogg-reader.ts +93 -0
  891. package/third-party/npm/mediabunny@1.52.2/source/src/output-format.ts +1425 -0
  892. package/third-party/npm/mediabunny@1.52.2/source/src/output.ts +940 -0
  893. package/third-party/npm/mediabunny@1.52.2/source/src/packet.ts +287 -0
  894. package/third-party/npm/mediabunny@1.52.2/source/src/pcm.ts +112 -0
  895. package/third-party/npm/mediabunny@1.52.2/source/src/reader.ts +391 -0
  896. package/third-party/npm/mediabunny@1.52.2/source/src/resample.ts +287 -0
  897. package/third-party/npm/mediabunny@1.52.2/source/src/sample.ts +3231 -0
  898. package/third-party/npm/mediabunny@1.52.2/source/src/segmented-input.ts +575 -0
  899. package/third-party/npm/mediabunny@1.52.2/source/src/source.ts +2588 -0
  900. package/third-party/npm/mediabunny@1.52.2/source/src/subtitles.ts +131 -0
  901. package/third-party/npm/mediabunny@1.52.2/source/src/target.ts +871 -0
  902. package/third-party/npm/mediabunny@1.52.2/source/src/tsconfig.json +16 -0
  903. package/third-party/npm/mediabunny@1.52.2/source/src/wave/riff-writer.ts +36 -0
  904. package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-demuxer.ts +583 -0
  905. package/third-party/npm/mediabunny@1.52.2/source/src/wave/wave-muxer.ts +375 -0
  906. package/third-party/npm/mediabunny@1.52.2/source/src/writer.ts +128 -0
  907. package/third-party/npm/react-dom@19.3.0/LICENSE +21 -0
  908. package/third-party/npm/react-dom@19.3.0/package.json +117 -0
  909. package/third-party/npm/react-remove-scroll-bar@2.3.8/package.json +85 -0
  910. package/third-party/npm/react-remove-scroll-bar@2.3.8/react-remove-scroll-bar-LICENSE +21 -0
  911. package/third-party/npm/react-remove-scroll@2.7.2/LICENSE +21 -0
  912. package/third-party/npm/react-remove-scroll@2.7.2/package.json +98 -0
  913. package/third-party/npm/react-style-singleton@2.2.3/LICENSE +21 -0
  914. package/third-party/npm/react-style-singleton@2.2.3/package.json +90 -0
  915. package/third-party/npm/react@19.3.0/LICENSE +21 -0
  916. package/third-party/npm/react@19.3.0/package.json +51 -0
  917. package/third-party/npm/scheduler@0.28.0/LICENSE +21 -0
  918. package/third-party/npm/scheduler@0.28.0/package.json +27 -0
  919. package/third-party/npm/tslib@2.8.1/LICENSE.txt +12 -0
  920. package/third-party/npm/tslib@2.8.1/package.json +47 -0
  921. package/third-party/npm/typescript@5.9.3/LICENSE.txt +55 -0
  922. package/third-party/npm/typescript@5.9.3/ThirdPartyNoticeText.txt +193 -0
  923. package/third-party/npm/typescript@5.9.3/package.json +120 -0
  924. package/third-party/npm/use-callback-ref@1.3.3/LICENSE +21 -0
  925. package/third-party/npm/use-callback-ref@1.3.3/package.json +85 -0
  926. package/third-party/npm/use-sidecar@1.1.3/LICENSE +21 -0
  927. package/third-party/npm/use-sidecar@1.1.3/package.json +93 -0
  928. package/third-party/packages/render-engine/assets/OFL.txt +93 -0
  929. package/third-party/packages/studio/public/fonts/OFL.txt +93 -0
  930. package/third-party/packages/studio/vendor/osmo-icons/LICENSE +21 -0
  931. package/third-party/packages/studio/vendor/shadcn/LICENSE +21 -0
  932. package/third-party/repository-notices.md +41 -0
  933. package/third-party/rust-standard-library/COPYRIGHT-library.html +5556 -0
  934. package/third-party/rust-standard-library/licenses/Apache-2.0.txt +73 -0
  935. package/third-party/rust-standard-library/licenses/BSD-2-Clause.txt +9 -0
  936. package/third-party/rust-standard-library/licenses/CC-BY-SA-4.0.txt +427 -0
  937. package/third-party/rust-standard-library/licenses/GCC-exception-3.1.txt +30 -0
  938. package/third-party/rust-standard-library/licenses/GPL-2.0-only.txt +133 -0
  939. package/third-party/rust-standard-library/licenses/GPL-3.0-or-later.txt +202 -0
  940. package/third-party/rust-standard-library/licenses/ISC.txt +7 -0
  941. package/third-party/rust-standard-library/licenses/LLVM-exception.txt +15 -0
  942. package/third-party/rust-standard-library/licenses/MIT.txt +9 -0
  943. package/third-party/rust-standard-library/licenses/NCSA.txt +29 -0
  944. package/third-party/rust-standard-library/licenses/OFL-1.1.txt +43 -0
  945. package/third-party/rust-standard-library/licenses/Unicode-3.0.txt +39 -0
  946. package/third-party/rust-standard-library/version.txt +1 -0
  947. package/vendor/osmo-lite +0 -0
  948. package/vendor/osmo-scene-0.1.0.tgz +0 -0
  949. package/vendor/platform.json +1 -0
@@ -0,0 +1,1911 @@
1
+ /*!
2
+ * Copyright (c) 2026-present, Vanilagy and contributors
3
+ *
4
+ * This Source Code Form is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+
9
+ import {
10
+ toUint8Array,
11
+ assert,
12
+ isU32,
13
+ last,
14
+ TransformationMatrix,
15
+ textEncoder,
16
+ COLOR_PRIMARIES_MAP,
17
+ TRANSFER_CHARACTERISTICS_MAP,
18
+ MATRIX_COEFFICIENTS_MAP,
19
+ colorSpaceIsComplete,
20
+ UNDETERMINED_LANGUAGE,
21
+ assertNever,
22
+ keyValueIterator,
23
+ } from '../misc';
24
+ import {
25
+ AudioCodec,
26
+ generateAv1CodecConfigurationFromCodecString,
27
+ parsePcmCodec,
28
+ PCM_AUDIO_CODECS,
29
+ PcmAudioCodec,
30
+ SubtitleCodec,
31
+ VideoCodec,
32
+ } from '../codec';
33
+ import { formatSubtitleTimestamp } from '../subtitles';
34
+ import { Writer } from '../writer';
35
+ import {
36
+ getTrackMetadata,
37
+ GLOBAL_TIMESCALE,
38
+ intoTimescale,
39
+ IsobmffAudioTrackData,
40
+ IsobmffMuxer,
41
+ IsobmffSubtitleTrackData,
42
+ IsobmffTrackData,
43
+ IsobmffVideoTrackData,
44
+ Sample,
45
+ } from './isobmff-muxer';
46
+ import { parseAc3SyncFrame, parseEac3SyncFrame, parseOpusIdentificationHeader } from '../codec-data';
47
+ import { MetadataTags, RichImageData } from '../metadata';
48
+ import { Bitstream } from '../../shared/bitstream';
49
+
50
+ export class IsobmffBoxWriter {
51
+ private helper = new Uint8Array(8);
52
+ private helperView = new DataView(this.helper.buffer);
53
+
54
+ /**
55
+ * Stores the position from the start of the file to where boxes elements have been written. This is used to
56
+ * rewrite/edit elements that were already added before, and to measure sizes of things.
57
+ */
58
+ offsets = new WeakMap<Box, number>();
59
+
60
+ constructor(public writer: Writer) {}
61
+
62
+ writeU32(value: number) {
63
+ this.helperView.setUint32(0, value, false);
64
+ this.writer.write(this.helper.subarray(0, 4));
65
+ }
66
+
67
+ writeU64(value: number) {
68
+ this.helperView.setUint32(0, Math.floor(value / 2 ** 32), false);
69
+ this.helperView.setUint32(4, value, false);
70
+ this.writer.write(this.helper.subarray(0, 8));
71
+ }
72
+
73
+ writeAscii(text: string) {
74
+ for (let i = 0; i < text.length; i++) {
75
+ this.helperView.setUint8(i % 8, text.charCodeAt(i));
76
+ if (i % 8 === 7) this.writer.write(this.helper);
77
+ }
78
+
79
+ if (text.length % 8 !== 0) {
80
+ this.writer.write(this.helper.subarray(0, text.length % 8));
81
+ }
82
+ }
83
+
84
+ writeBox(box: Box) {
85
+ this.offsets.set(box, this.writer.getPos());
86
+
87
+ if (box.contents && !box.children) {
88
+ this.writeBoxHeader(box, box.size ?? box.contents.byteLength + 8);
89
+ this.writer.write(box.contents);
90
+ } else {
91
+ const startPos = this.writer.getPos();
92
+ this.writeBoxHeader(box, 0);
93
+
94
+ if (box.contents) this.writer.write(box.contents);
95
+ if (box.children) for (const child of box.children) if (child) this.writeBox(child);
96
+
97
+ const endPos = this.writer.getPos();
98
+ const size = box.size ?? endPos - startPos;
99
+ this.writer.seek(startPos);
100
+ this.writeBoxHeader(box, size);
101
+ this.writer.seek(endPos);
102
+ }
103
+ }
104
+
105
+ writeBoxHeader(box: Box, size: number) {
106
+ this.writeU32(box.largeSize ? 1 : size);
107
+ this.writeAscii(box.type);
108
+ if (box.largeSize) this.writeU64(size);
109
+ }
110
+
111
+ measureBoxHeader(box: Box) {
112
+ return 8 + (box.largeSize ? 8 : 0);
113
+ }
114
+
115
+ patchBox(box: Box) {
116
+ const boxOffset = this.offsets.get(box);
117
+ assert(boxOffset !== undefined);
118
+
119
+ const endPos = this.writer.getPos();
120
+ this.writer.seek(boxOffset);
121
+ this.writeBox(box);
122
+ this.writer.seek(endPos);
123
+ }
124
+
125
+ measureBox(box: Box) {
126
+ if (box.contents && !box.children) {
127
+ const headerSize = this.measureBoxHeader(box);
128
+ return headerSize + box.contents.byteLength;
129
+ } else {
130
+ let result = this.measureBoxHeader(box);
131
+ if (box.contents) result += box.contents.byteLength;
132
+ if (box.children) for (const child of box.children) if (child) result += this.measureBox(child);
133
+
134
+ return result;
135
+ }
136
+ }
137
+ }
138
+
139
+ const bytes = /* #__PURE__ */ new Uint8Array(8);
140
+ const view = /* #__PURE__ */ new DataView(bytes.buffer);
141
+
142
+ const u8 = (value: number) => {
143
+ return [(value % 0x100 + 0x100) % 0x100];
144
+ };
145
+
146
+ const u16 = (value: number) => {
147
+ view.setUint16(0, value, false);
148
+ return [bytes[0], bytes[1]] as number[];
149
+ };
150
+
151
+ const i16 = (value: number) => {
152
+ view.setInt16(0, value, false);
153
+ return [bytes[0], bytes[1]] as number[];
154
+ };
155
+
156
+ const u24 = (value: number) => {
157
+ view.setUint32(0, value, false);
158
+ return [bytes[1], bytes[2], bytes[3]] as number[];
159
+ };
160
+
161
+ const u32 = (value: number) => {
162
+ view.setUint32(0, value, false);
163
+ return [bytes[0], bytes[1], bytes[2], bytes[3]] as number[];
164
+ };
165
+
166
+ const i32 = (value: number) => {
167
+ view.setInt32(0, value, false);
168
+ return [bytes[0], bytes[1], bytes[2], bytes[3]] as number[];
169
+ };
170
+
171
+ const u64 = (value: number) => {
172
+ view.setUint32(0, Math.floor(value / 2 ** 32), false);
173
+ view.setUint32(4, value, false);
174
+ return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]] as number[];
175
+ };
176
+
177
+ const i64 = (value: number) => {
178
+ view.setInt32(0, Math.floor(value / 2 ** 32), false);
179
+ view.setUint32(4, value, false);
180
+ return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]] as number[];
181
+ };
182
+
183
+ const fixed_8_8 = (value: number) => {
184
+ view.setInt16(0, 2 ** 8 * value, false);
185
+ return [bytes[0], bytes[1]] as number[];
186
+ };
187
+
188
+ const fixed_16_16 = (value: number) => {
189
+ view.setInt32(0, 2 ** 16 * value, false);
190
+ return [bytes[0], bytes[1], bytes[2], bytes[3]] as number[];
191
+ };
192
+
193
+ const fixed_2_30 = (value: number) => {
194
+ view.setInt32(0, 2 ** 30 * value, false);
195
+ return [bytes[0], bytes[1], bytes[2], bytes[3]] as number[];
196
+ };
197
+
198
+ const variableUnsignedInt = (value: number, byteLength?: number) => {
199
+ const bytes: number[] = [];
200
+ let remaining = value;
201
+
202
+ do {
203
+ let byte = remaining & 0x7f;
204
+ remaining >>= 7;
205
+
206
+ // If this isn't the first byte we're adding (meaning there will be more bytes after it
207
+ // when we reverse the array), set the continuation bit
208
+ if (bytes.length > 0) {
209
+ byte |= 0x80;
210
+ }
211
+
212
+ bytes.push(byte);
213
+
214
+ if (byteLength !== undefined) {
215
+ byteLength--;
216
+ }
217
+ } while (remaining > 0 || byteLength);
218
+
219
+ // Reverse the array since we built it backwards
220
+ return bytes.reverse();
221
+ };
222
+
223
+ const ascii = (text: string, nullTerminated = false) => {
224
+ const bytes = Array(text.length).fill(null).map((_, i) => text.charCodeAt(i));
225
+ if (nullTerminated) bytes.push(0x00);
226
+ return bytes;
227
+ };
228
+
229
+ const rotationMatrix = (rotationInDegrees: number): TransformationMatrix => {
230
+ const theta = rotationInDegrees * (Math.PI / 180);
231
+ const cosTheta = Math.round(Math.cos(theta));
232
+ const sinTheta = Math.round(Math.sin(theta));
233
+
234
+ // Matrices are post-multiplied in ISOBMFF, meaning this is the transpose of your typical rotation matrix
235
+ return [
236
+ cosTheta, sinTheta, 0,
237
+ -sinTheta, cosTheta, 0,
238
+ 0, 0, 1,
239
+ ];
240
+ };
241
+ const IDENTITY_MATRIX = /* #__PURE__ */ rotationMatrix(0);
242
+
243
+ const matrixToBytes = (matrix: TransformationMatrix) => {
244
+ return [
245
+ fixed_16_16(matrix[0]), fixed_16_16(matrix[1]), fixed_2_30(matrix[2]),
246
+ fixed_16_16(matrix[3]), fixed_16_16(matrix[4]), fixed_2_30(matrix[5]),
247
+ fixed_16_16(matrix[6]), fixed_16_16(matrix[7]), fixed_2_30(matrix[8]),
248
+ ];
249
+ };
250
+
251
+ export interface Box {
252
+ type: string;
253
+ contents?: Uint8Array;
254
+ children?: (Box | null)[];
255
+ size?: number;
256
+ largeSize?: boolean;
257
+ }
258
+
259
+ type NestedNumberArray = (number | NestedNumberArray)[];
260
+
261
+ export const box = (type: string, contents?: NestedNumberArray, children?: (Box | null)[]): Box => ({
262
+ type,
263
+ contents: contents && new Uint8Array(contents.flat(10) as number[]),
264
+ children,
265
+ });
266
+
267
+ /** A FullBox always starts with a version byte, followed by three flag bytes. */
268
+ export const fullBox = (
269
+ type: string,
270
+ version: number,
271
+ flags: number,
272
+ contents?: NestedNumberArray,
273
+ children?: Box[],
274
+ ) => box(
275
+ type,
276
+ [u8(version), u24(flags), contents ?? []],
277
+ children,
278
+ );
279
+
280
+ /**
281
+ * File Type Compatibility Box: Allows the reader to determine whether this is a type of file that the
282
+ * reader understands.
283
+ */
284
+ export const ftyp = (details: {
285
+ isQuickTime: boolean;
286
+ holdsAvc: boolean;
287
+ fragmented: boolean;
288
+ cmaf: boolean;
289
+ }) => {
290
+ // You can find the full logic for this at
291
+ // https://github.com/FFmpeg/FFmpeg/blob/de2fb43e785773738c660cdafb9309b1ef1bc80d/libavformat/movenc.c#L5518
292
+ // Obviously, this lib only needs a small subset of that logic.
293
+
294
+ const minorVersion = 0x200;
295
+
296
+ if (details.isQuickTime) {
297
+ return box('ftyp', [
298
+ ascii('qt '), // Major brand
299
+ u32(minorVersion), // Minor version
300
+ // Compatible brands
301
+ ascii('qt '),
302
+ ]);
303
+ }
304
+
305
+ if (details.fragmented) {
306
+ if (details.cmaf) {
307
+ return box('ftyp', [
308
+ ascii('iso5'), // Major brand
309
+ u32(minorVersion), // Minor version
310
+ // Compatible brands
311
+ ascii('iso5'),
312
+ ascii('iso6'),
313
+ ascii('mp41'),
314
+ ascii('cmfc'),
315
+ ascii('dash'),
316
+ ]);
317
+ } else {
318
+ return box('ftyp', [
319
+ ascii('iso5'), // Major brand
320
+ u32(minorVersion), // Minor version
321
+ // Compatible brands
322
+ ascii('iso5'),
323
+ ascii('iso6'),
324
+ ascii('mp41'),
325
+ ]);
326
+ }
327
+ }
328
+
329
+ return box('ftyp', [
330
+ ascii('isom'), // Major brand
331
+ u32(minorVersion), // Minor version
332
+ // Compatible brands
333
+ ascii('isom'),
334
+ details.holdsAvc ? ascii('avc1') : [],
335
+ ascii('mp41'),
336
+ ]);
337
+ };
338
+
339
+ /** Segment Type Box */
340
+ export const styp = () => box('styp', [
341
+ ascii('iso5'), // Major brand
342
+ u32(0), // Minor version
343
+ // Compatible brands
344
+ ascii('iso5'),
345
+ ascii('iso6'),
346
+ ascii('mp41'),
347
+ ascii('cmfc'),
348
+ ascii('dash'),
349
+ ]);
350
+
351
+ /** Segment Index Box */
352
+ export const sidx = (muxer: IsobmffMuxer, referencedSize: number) => {
353
+ let duration = muxer.maxWrittenEndTimestamp - muxer.minWrittenTimestamp;
354
+ if (!Number.isFinite(duration)) {
355
+ duration = 0;
356
+ }
357
+
358
+ return fullBox('sidx', 1, 0, [
359
+ u32(1), // Reference ID
360
+ u32(GLOBAL_TIMESCALE), // Timescale
361
+ u64(intoTimescale(muxer.minWrittenTimestamp, GLOBAL_TIMESCALE)), // Earliest presentation time
362
+ u64(0), // First offset
363
+ u16(0), // Reserved
364
+ u16(1), // Reference count
365
+ u32(referencedSize & 0x7fffffff), // Reference type (0) + referenced size
366
+ u32(intoTimescale(duration, GLOBAL_TIMESCALE)), // Subsegment duration
367
+ u32(0), // Starts with SAP + SAP type + SAP delta time (no information provided)
368
+ ]);
369
+ };
370
+
371
+ /** Movie Sample Data Box. Contains the actual frames/samples of the media. */
372
+ export const mdat = (reserveLargeSize: boolean): Box => ({ type: 'mdat', largeSize: reserveLargeSize });
373
+
374
+ /** Free Space Box: A box that designates unused space in the movie data file. */
375
+ export const free = (size: number): Box => ({ type: 'free', size });
376
+
377
+ /**
378
+ * Movie Box: Used to specify the information that defines a movie - that is, the information that allows
379
+ * an application to interpret the sample data that is stored elsewhere.
380
+ */
381
+ export const moov = (muxer: IsobmffMuxer) => {
382
+ return box('moov', undefined, [
383
+ mvhd(muxer.creationTime, muxer.trackDatas),
384
+ ...muxer.trackDatas.map(x => trak(x, muxer.creationTime)),
385
+ muxer.isFragmented ? mvex(muxer.trackDatas) : null,
386
+ udta(muxer),
387
+ ]);
388
+ };
389
+
390
+ /** Movie Header Box: Used to specify the characteristics of the entire movie, such as timescale and duration. */
391
+ export const mvhd = (
392
+ creationTime: number,
393
+ trackDatas: IsobmffTrackData[],
394
+ ) => {
395
+ const duration = Math.max(
396
+ 0,
397
+ ...trackDatas
398
+ .map(trackData => (
399
+ intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE)
400
+ + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE)
401
+ )),
402
+ );
403
+ const nextTrackId = Math.max(0, ...trackDatas.map(x => x.track.id)) + 1;
404
+
405
+ // Conditionally use u64 if u32 isn't enough
406
+ const needsU64 = !isU32(creationTime) || !isU32(duration);
407
+ const u32OrU64 = needsU64 ? u64 : u32;
408
+
409
+ return fullBox('mvhd', +needsU64, 0, [
410
+ u32OrU64(creationTime), // Creation time
411
+ u32OrU64(creationTime), // Modification time
412
+ u32(GLOBAL_TIMESCALE), // Timescale
413
+ u32OrU64(duration), // Duration
414
+ fixed_16_16(1), // Preferred rate
415
+ fixed_8_8(1), // Preferred volume
416
+ Array(10).fill(0), // Reserved
417
+ matrixToBytes(IDENTITY_MATRIX), // Matrix
418
+ Array(24).fill(0), // Pre-defined
419
+ u32(nextTrackId), // Next track ID
420
+ ]);
421
+ };
422
+
423
+ const presentationSpan = (trackData: IsobmffTrackData) => {
424
+ if (trackData.samples.length === 0) {
425
+ return 0;
426
+ }
427
+
428
+ let minTimestamp = Infinity;
429
+ let maxEndTimestamp = -Infinity;
430
+
431
+ for (let i = 0; i < trackData.samples.length; i++) {
432
+ const sample = trackData.samples[i]!;
433
+
434
+ if (sample.timestamp < minTimestamp) {
435
+ minTimestamp = sample.timestamp;
436
+ }
437
+ if (sample.timestamp + sample.duration > maxEndTimestamp) {
438
+ maxEndTimestamp = sample.timestamp + sample.duration;
439
+ }
440
+ }
441
+
442
+ if (minTimestamp === Infinity) {
443
+ return 0;
444
+ }
445
+
446
+ return maxEndTimestamp - minTimestamp;
447
+ };
448
+
449
+ /**
450
+ * Track Box: Defines a single track of a movie. A movie may consist of one or more tracks. Each track is
451
+ * independent of the other tracks in the movie and carries its own temporal and spatial information. Each Track Box
452
+ * contains its associated Media Box.
453
+ */
454
+ export const trak = (trackData: IsobmffTrackData, creationTime: number) => {
455
+ const trackMetadata = getTrackMetadata(trackData);
456
+ const needsEditList = trackData.startTimestampOffset !== null && trackData.startTimestampOffset > 0;
457
+
458
+ return box('trak', undefined, [
459
+ tkhd(trackData, creationTime),
460
+ needsEditList ? edts(trackData, trackData.startTimestampOffset!) : null,
461
+ mdia(trackData, creationTime),
462
+ trackMetadata.name !== undefined
463
+ ? box('udta', undefined, [
464
+ box('name', [ // VLC (and Mediabunny) also recognize ©nam
465
+ ...textEncoder.encode(trackMetadata.name),
466
+ ]),
467
+ ])
468
+ : null,
469
+ ]);
470
+ };
471
+
472
+ /** Track Header Box: Specifies the characteristics of a single track within a movie. */
473
+ export const tkhd = (
474
+ trackData: IsobmffTrackData,
475
+ creationTime: number,
476
+ ) => {
477
+ const durationInGlobalTimescale = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE)
478
+ + intoTimescale(trackData.startTimestampOffset ?? 0, GLOBAL_TIMESCALE);
479
+
480
+ const needsU64 = !isU32(creationTime) || !isU32(durationInGlobalTimescale);
481
+ const u32OrU64 = needsU64 ? u64 : u32;
482
+
483
+ let matrix: TransformationMatrix;
484
+ if (trackData.type === 'video') {
485
+ const rotation = trackData.track.metadata.rotation;
486
+ matrix = rotationMatrix(rotation ?? 0);
487
+ } else {
488
+ matrix = IDENTITY_MATRIX;
489
+ }
490
+
491
+ let flags = 0x2; // Track in movie
492
+ if (trackData.track.metadata.disposition?.default !== false) {
493
+ flags |= 0x1; // Track enabled
494
+ }
495
+
496
+ return fullBox('tkhd', +needsU64, flags, [
497
+ u32OrU64(creationTime), // Creation time
498
+ u32OrU64(creationTime), // Modification time
499
+ u32(trackData.track.id), // Track ID
500
+ u32(0), // Reserved
501
+ u32OrU64(durationInGlobalTimescale), // Duration
502
+ Array(8).fill(0), // Reserved
503
+ u16(0), // Layer
504
+ u16(trackData.track.id), // Alternate group
505
+ fixed_8_8(trackData.type === 'audio' ? 1 : 0), // Volume
506
+ u16(0), // Reserved
507
+ matrixToBytes(matrix), // Matrix
508
+ fixed_16_16(trackData.type === 'video' ? trackData.info.width : 0), // Track width
509
+ fixed_16_16(trackData.type === 'video' ? trackData.info.height : 0), // Track height
510
+ ]);
511
+ };
512
+
513
+ /** Edit Box: Specifies edits to the track's media. */
514
+ export const edts = (trackData: IsobmffTrackData, offset: number) => {
515
+ const startOffset = intoTimescale(offset, GLOBAL_TIMESCALE);
516
+ const mediaDuration = intoTimescale(presentationSpan(trackData), GLOBAL_TIMESCALE);
517
+
518
+ const needs64Bits = !isU32(startOffset) || !isU32(mediaDuration);
519
+ const u32OrU64 = needs64Bits ? u64 : u32;
520
+ const i32OrI64 = needs64Bits ? i64 : i32;
521
+
522
+ return box('edts', undefined, [
523
+ fullBox('elst', needs64Bits ? 1 : 0, 0, [
524
+ u32(2), // Entry count
525
+
526
+ // #1
527
+ u32OrU64(startOffset), // Segment duration
528
+ i32OrI64(-1), // Media time
529
+ fixed_16_16(1), // Media rate
530
+
531
+ // #2
532
+ u32OrU64(mediaDuration), // Segment duration
533
+ i32OrI64(0), // Media time
534
+ fixed_16_16(1), // Media rate
535
+ ]),
536
+ ]);
537
+ };
538
+
539
+ /** Media Box: Describes and define a track's media type and sample data. */
540
+ export const mdia = (trackData: IsobmffTrackData, creationTime: number) => box('mdia', undefined, [
541
+ mdhd(trackData, creationTime),
542
+ hdlr(true, TRACK_TYPE_TO_COMPONENT_SUBTYPE[trackData.type], TRACK_TYPE_TO_HANDLER_NAME[trackData.type]),
543
+ minf(trackData),
544
+ ]);
545
+
546
+ /** Media Header Box: Specifies the characteristics of a media, including timescale and duration. */
547
+ export const mdhd = (
548
+ trackData: IsobmffTrackData,
549
+ creationTime: number,
550
+ ) => {
551
+ // Since the duration represents the raw media duration, edit list offsets are not taken into account here
552
+ const localDuration = intoTimescale(
553
+ presentationSpan(trackData),
554
+ trackData.timescale,
555
+ );
556
+
557
+ const needsU64 = !isU32(creationTime) || !isU32(localDuration);
558
+ const u32OrU64 = needsU64 ? u64 : u32;
559
+
560
+ return fullBox('mdhd', +needsU64, 0, [
561
+ u32OrU64(creationTime), // Creation time
562
+ u32OrU64(creationTime), // Modification time
563
+ u32(trackData.timescale), // Timescale
564
+ u32OrU64(localDuration), // Duration
565
+ u16(getLanguageCodeInt(trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE)), // Language
566
+ u16(0), // Quality
567
+ ]);
568
+ };
569
+
570
+ const TRACK_TYPE_TO_COMPONENT_SUBTYPE: Record<IsobmffTrackData['type'], string> = {
571
+ video: 'vide',
572
+ audio: 'soun',
573
+ subtitle: 'text',
574
+ };
575
+
576
+ const TRACK_TYPE_TO_HANDLER_NAME: Record<IsobmffTrackData['type'], string> = {
577
+ video: 'MediabunnyVideoHandler',
578
+ audio: 'MediabunnySoundHandler',
579
+ subtitle: 'MediabunnyTextHandler',
580
+ };
581
+
582
+ /** Handler Reference Box. */
583
+ export const hdlr = (
584
+ hasComponentType: boolean,
585
+ handlerType: string,
586
+ name: string,
587
+ manufacturer = '\0\0\0\0',
588
+ ) => fullBox('hdlr', 0, 0, [
589
+ hasComponentType ? ascii('mhlr') : u32(0), // Component type
590
+ ascii(handlerType), // Component subtype
591
+ ascii(manufacturer), // Component manufacturer
592
+ u32(0), // Component flags
593
+ u32(0), // Component flags mask
594
+ ascii(name, true), // Component name
595
+ ]);
596
+
597
+ /**
598
+ * Media Information Box: Stores handler-specific information for a track's media data. The media handler uses this
599
+ * information to map from media time to media data and to process the media data.
600
+ */
601
+ export const minf = (trackData: IsobmffTrackData) => box('minf', undefined, [
602
+ TRACK_TYPE_TO_HEADER_BOX[trackData.type](),
603
+ dinf(),
604
+ stbl(trackData),
605
+ ]);
606
+
607
+ /** Video Media Information Header Box: Defines specific color and graphics mode information. */
608
+ export const vmhd = () => fullBox('vmhd', 0, 1, [
609
+ u16(0), // Graphics mode
610
+ u16(0), // Opcolor R
611
+ u16(0), // Opcolor G
612
+ u16(0), // Opcolor B
613
+ ]);
614
+
615
+ /** Sound Media Information Header Box: Stores the sound media's control information, such as balance. */
616
+ export const smhd = () => fullBox('smhd', 0, 0, [
617
+ u16(0), // Balance
618
+ u16(0), // Reserved
619
+ ]);
620
+
621
+ /** Null Media Header Box. */
622
+ export const nmhd = () => fullBox('nmhd', 0, 0);
623
+
624
+ const TRACK_TYPE_TO_HEADER_BOX: Record<IsobmffTrackData['type'], () => Box> = {
625
+ video: vmhd,
626
+ audio: smhd,
627
+ subtitle: nmhd,
628
+ };
629
+
630
+ /**
631
+ * Data Information Box: Contains information specifying the data handler component that provides access to the
632
+ * media data. The data handler component uses the Data Information Box to interpret the media's data.
633
+ */
634
+ export const dinf = () => box('dinf', undefined, [
635
+ dref(),
636
+ ]);
637
+
638
+ /**
639
+ * Data Reference Box: Contains tabular data that instructs the data handler component how to access the media's data.
640
+ */
641
+ export const dref = () => fullBox('dref', 0, 0, [
642
+ u32(1), // Entry count
643
+ ], [
644
+ url(),
645
+ ]);
646
+
647
+ export const url = () => fullBox('url ', 0, 1); // Self-reference flag enabled
648
+
649
+ /**
650
+ * Sample Table Box: Contains information for converting from media time to sample number to sample location. This box
651
+ * also indicates how to interpret the sample (for example, whether to decompress the video data and, if so, how).
652
+ */
653
+ export const stbl = (trackData: IsobmffTrackData) => {
654
+ const needsCtts = trackData.compositionTimeOffsetTable.length > 1
655
+ || trackData.compositionTimeOffsetTable.some(x => x.sampleCompositionTimeOffset !== 0);
656
+
657
+ return box('stbl', undefined, [
658
+ stsd(trackData),
659
+ stts(trackData),
660
+ needsCtts ? ctts(trackData) : null,
661
+ needsCtts ? cslg(trackData) : null,
662
+ stsc(trackData),
663
+ stsz(trackData),
664
+ stco(trackData),
665
+ stss(trackData),
666
+ ]);
667
+ };
668
+
669
+ /**
670
+ * Sample Description Box: Stores information that allows you to decode samples in the media. The data stored in the
671
+ * sample description varies, depending on the media type.
672
+ */
673
+ export const stsd = (trackData: IsobmffTrackData) => {
674
+ let sampleDescription: Box;
675
+
676
+ if (trackData.type === 'video') {
677
+ sampleDescription = videoSampleDescription(
678
+ videoCodecToBoxName(trackData.track.source._codec, trackData.info.decoderConfig.codec),
679
+ trackData,
680
+ );
681
+ } else if (trackData.type === 'audio') {
682
+ const boxName = audioCodecToBoxName(trackData.track.source._codec, trackData.muxer.isQuickTime);
683
+ assert(boxName);
684
+
685
+ sampleDescription = soundSampleDescription(
686
+ boxName,
687
+ trackData,
688
+ );
689
+ } else if (trackData.type === 'subtitle') {
690
+ sampleDescription = subtitleSampleDescription(
691
+ SUBTITLE_CODEC_TO_BOX_NAME[trackData.track.source._codec],
692
+ trackData,
693
+ );
694
+ }
695
+
696
+ assert(sampleDescription!);
697
+
698
+ return fullBox('stsd', 0, 0, [
699
+ u32(1), // Entry count
700
+ ], [
701
+ sampleDescription,
702
+ ]);
703
+ };
704
+
705
+ /** Video Sample Description Box: Contains information that defines how to interpret video media data. */
706
+ export const videoSampleDescription = (
707
+ compressionType: string,
708
+ trackData: IsobmffVideoTrackData,
709
+ ) => box(compressionType, [
710
+ Array(6).fill(0), // Reserved
711
+ u16(1), // Data reference index
712
+ u16(0), // Pre-defined
713
+ u16(0), // Reserved
714
+ Array(12).fill(0), // Pre-defined
715
+ u16(trackData.info.width), // Width
716
+ u16(trackData.info.height), // Height
717
+ u32(0x00480000), // Horizontal resolution
718
+ u32(0x00480000), // Vertical resolution
719
+ u32(0), // Reserved
720
+ u16(1), // Frame count
721
+
722
+ // Compressor name
723
+ u8('Mediabunny'.length), // Weird Pascal-style string
724
+ ascii('Mediabunny'),
725
+ Array(31 - 'Mediabunny'.length).fill(0),
726
+
727
+ u16(trackData.info.hasAlphaChannel ? 32 : 24), // Depth
728
+ i16(0xffff), // Pre-defined
729
+ ], [
730
+ VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec]?.(trackData) ?? null,
731
+ pasp(trackData),
732
+ colorSpaceIsComplete(trackData.info.decoderConfig.colorSpace) ? colr(trackData) : null,
733
+ ]);
734
+
735
+ /** Pixel Aspect Ratio Box: Specifies pixel width:height spacing for non-square pixels. */
736
+ export const pasp = (trackData: IsobmffVideoTrackData) => {
737
+ if (trackData.info.pixelAspectRatio.num === trackData.info.pixelAspectRatio.den) {
738
+ return null;
739
+ }
740
+
741
+ return box('pasp', [
742
+ u32(trackData.info.pixelAspectRatio.num),
743
+ u32(trackData.info.pixelAspectRatio.den),
744
+ ]);
745
+ };
746
+
747
+ /** Colour Information Box: Specifies the color space of the video. */
748
+ export const colr = (trackData: IsobmffVideoTrackData) => box('colr', [
749
+ ascii(trackData.muxer.isQuickTime ? 'nclc' : 'nclx'), // Colour type
750
+ u16(COLOR_PRIMARIES_MAP[trackData.info.decoderConfig.colorSpace!.primaries!]), // Colour primaries
751
+ u16(TRANSFER_CHARACTERISTICS_MAP[trackData.info.decoderConfig.colorSpace!.transfer!]), // Transfer characteristics
752
+ u16(MATRIX_COEFFICIENTS_MAP[trackData.info.decoderConfig.colorSpace!.matrix!]), // Matrix coefficients
753
+ trackData.muxer.isQuickTime
754
+ ? [] // Doesn't have it
755
+ : u8((trackData.info.decoderConfig.colorSpace!.fullRange ? 1 : 0) << 7), // Full range flag
756
+ ]);
757
+
758
+ /** AVC Configuration Box: Provides additional information to the decoder. */
759
+ export const avcC = (trackData: IsobmffVideoTrackData) => trackData.info.decoderConfig && box('avcC', [
760
+ // For AVC, description is an AVCDecoderConfigurationRecord, so nothing else to do here
761
+ ...toUint8Array(trackData.info.decoderConfig.description!),
762
+ ]);
763
+
764
+ /** HEVC Configuration Box: Provides additional information to the decoder. */
765
+ export const hvcC = (trackData: IsobmffVideoTrackData) => trackData.info.decoderConfig && box('hvcC', [
766
+ // For HEVC, description is an HEVCDecoderConfigurationRecord, so nothing else to do here
767
+ ...toUint8Array(trackData.info.decoderConfig.description!),
768
+ ]);
769
+
770
+ /** VP Configuration Box: Provides additional information to the decoder. */
771
+ export const vpcC = (trackData: IsobmffVideoTrackData) => {
772
+ // Reference: https://www.webmproject.org/vp9/mp4/
773
+
774
+ if (!trackData.info.decoderConfig) {
775
+ return null;
776
+ }
777
+
778
+ const decoderConfig = trackData.info.decoderConfig;
779
+
780
+ const parts = decoderConfig.codec.split('.'); // We can derive the required values from the codec string
781
+ const profile = Number(parts[1]);
782
+ const level = Number(parts[2]);
783
+
784
+ const bitDepth = Number(parts[3]);
785
+ const chromaSubsampling = parts[4] ? Number(parts[4]) : 1; // 4:2:0 colocated with luma (0,0)
786
+ const videoFullRangeFlag = parts[8] ? Number(parts[8]) : Number(decoderConfig.colorSpace?.fullRange ?? 0);
787
+ const thirdByte = (bitDepth << 4) + (chromaSubsampling << 1) + videoFullRangeFlag;
788
+
789
+ const colourPrimaries = parts[5]
790
+ ? Number(parts[5])
791
+ : decoderConfig.colorSpace?.primaries
792
+ ? COLOR_PRIMARIES_MAP[decoderConfig.colorSpace.primaries]
793
+ : 2; // Default to undetermined
794
+ const transferCharacteristics = parts[6]
795
+ ? Number(parts[6])
796
+ : decoderConfig.colorSpace?.transfer
797
+ ? TRANSFER_CHARACTERISTICS_MAP[decoderConfig.colorSpace.transfer]
798
+ : 2;
799
+ const matrixCoefficients = parts[7]
800
+ ? Number(parts[7])
801
+ : decoderConfig.colorSpace?.matrix
802
+ ? MATRIX_COEFFICIENTS_MAP[decoderConfig.colorSpace.matrix]
803
+ : 2;
804
+
805
+ return fullBox('vpcC', 1, 0, [
806
+ u8(profile), // Profile
807
+ u8(level), // Level
808
+ u8(thirdByte), // Bit depth, chroma subsampling, full range
809
+ u8(colourPrimaries), // Colour primaries
810
+ u8(transferCharacteristics), // Transfer characteristics
811
+ u8(matrixCoefficients), // Matrix coefficients
812
+ u16(0), // Codec initialization data size
813
+ ]);
814
+ };
815
+
816
+ /** AV1 Configuration Box: Provides additional information to the decoder. */
817
+ export const av1C = (trackData: IsobmffVideoTrackData) => {
818
+ return box('av1C', generateAv1CodecConfigurationFromCodecString(trackData.info.decoderConfig.codec));
819
+ };
820
+
821
+ /** Sound Sample Description Box: Contains information that defines how to interpret sound media data. */
822
+ export const soundSampleDescription = (
823
+ compressionType: string,
824
+ trackData: IsobmffAudioTrackData,
825
+ ) => {
826
+ let version = 0;
827
+ let contents: NestedNumberArray;
828
+ let sampleSizeInBits = 16;
829
+
830
+ const isPcmCodec = (PCM_AUDIO_CODECS as readonly AudioCodec[]).includes(trackData.track.source._codec);
831
+ if (isPcmCodec) {
832
+ const codec = trackData.track.source._codec as PcmAudioCodec;
833
+ const { sampleSize } = parsePcmCodec(codec);
834
+ sampleSizeInBits = 8 * sampleSize;
835
+
836
+ if (sampleSizeInBits > 16) {
837
+ version = 1;
838
+ }
839
+ }
840
+
841
+ if (trackData.muxer.isQuickTime) {
842
+ version = 1;
843
+ }
844
+
845
+ if (version === 0) {
846
+ contents = [
847
+ Array(6).fill(0), // Reserved
848
+ u16(1), // Data reference index
849
+ u16(version), // Version
850
+ u16(0), // Revision level
851
+ u32(0), // Vendor
852
+ u16(trackData.info.numberOfChannels), // Number of channels
853
+ u16(sampleSizeInBits), // Sample size (bits)
854
+ u16(0), // Compression ID
855
+ u16(0), // Packet size
856
+ u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), // Sample rate (upper)
857
+ u16(0), // Sample rate (lower)
858
+ ];
859
+ } else {
860
+ const compressionId = isPcmCodec ? 0 : -2;
861
+
862
+ contents = [
863
+ Array(6).fill(0), // Reserved
864
+ u16(1), // Data reference index
865
+ u16(version), // Version
866
+ u16(0), // Revision level
867
+ u32(0), // Vendor
868
+ u16(trackData.info.numberOfChannels), // Number of channels
869
+ u16(Math.min(sampleSizeInBits, 16)), // Sample size (bits)
870
+ i16(compressionId), // Compression ID
871
+ u16(0), // Packet size
872
+ u16(trackData.info.sampleRate < 2 ** 16 ? trackData.info.sampleRate : 0), // Sample rate (upper)
873
+ u16(0), // Sample rate (lower)
874
+ isPcmCodec
875
+ ? [
876
+ u32(1), // Samples per packet (must be 1 for uncompressed formats)
877
+ u32(sampleSizeInBits / 8), // Bytes per packet
878
+ u32(trackData.info.numberOfChannels * sampleSizeInBits / 8), // Bytes per frame
879
+ ]
880
+ : [
881
+ u32(0), // Samples per packet (don't bother, still works with 0)
882
+ u32(0), // Bytes per packet (variable)
883
+ u32(0), // Bytes per frame (variable)
884
+ ],
885
+ u32(2), // Bytes per sample (constant in FFmpeg)
886
+ ];
887
+ }
888
+
889
+ return box(compressionType, contents, [
890
+ audioCodecToConfigurationBox(trackData.track.source._codec, trackData.muxer.isQuickTime)?.(trackData) ?? null,
891
+ ]);
892
+ };
893
+
894
+ /** MPEG-4 Elementary Stream Descriptor Box. */
895
+ export const esds = (trackData: IsobmffAudioTrackData) => {
896
+ // We build up the bytes in a layered way which reflects the nested structure
897
+
898
+ let objectTypeIndication: number;
899
+ switch (trackData.track.source._codec) {
900
+ case 'aac': {
901
+ objectTypeIndication = 0x40;
902
+ }; break;
903
+ case 'mp3': {
904
+ objectTypeIndication = 0x6b;
905
+ }; break;
906
+ case 'vorbis': {
907
+ objectTypeIndication = 0xdd;
908
+ }; break;
909
+ default: throw new Error(`Unhandled audio codec: ${trackData.track.source._codec}`);
910
+ }
911
+
912
+ let bytes = [
913
+ ...u8(objectTypeIndication), // Object type indication
914
+ ...u8(0x15), // stream type(6bits)=5 audio, flags(2bits)=1
915
+ ...u24(0), // 24bit buffer size
916
+ ...u32(0), // max bitrate
917
+ ...u32(0), // avg bitrate
918
+ ];
919
+ if (trackData.info.decoderConfig.description) {
920
+ const description = toUint8Array(trackData.info.decoderConfig.description);
921
+
922
+ // Add the decoder description to the end
923
+ bytes = [
924
+ ...bytes,
925
+ ...u8(0x05), // TAG(5) = DecoderSpecificInfo
926
+ ...variableUnsignedInt(description.byteLength),
927
+ ...description,
928
+ ];
929
+ }
930
+
931
+ bytes = [
932
+ ...u16(1), // ES_ID = 1
933
+ ...u8(0x00), // flags etc = 0
934
+ ...u8(0x04), // TAG(4) = ES Descriptor
935
+ ...variableUnsignedInt(bytes.length),
936
+ ...bytes,
937
+ ...u8(0x06), // TAG(6)
938
+ ...u8(0x01), // length
939
+ ...u8(0x02), // data
940
+ ];
941
+ bytes = [
942
+ ...u8(0x03), // TAG(3) = Object Descriptor
943
+ ...variableUnsignedInt(bytes.length),
944
+ ...bytes,
945
+ ];
946
+
947
+ return fullBox('esds', 0, 0, bytes);
948
+ };
949
+
950
+ export const wave = (trackData: IsobmffAudioTrackData) => {
951
+ return box('wave', undefined, [
952
+ frma(trackData),
953
+ enda(trackData),
954
+ box('\x00\x00\x00\x00'), // NULL tag at the end
955
+ ]);
956
+ };
957
+
958
+ export const frma = (trackData: IsobmffAudioTrackData) => {
959
+ return box('frma', [
960
+ ascii(audioCodecToBoxName(trackData.track.source._codec, trackData.muxer.isQuickTime)),
961
+ ]);
962
+ };
963
+
964
+ // This box specifies PCM endianness
965
+ export const enda = (trackData: IsobmffAudioTrackData) => {
966
+ const { littleEndian } = parsePcmCodec(trackData.track.source._codec as PcmAudioCodec);
967
+
968
+ return box('enda', [
969
+ u16(+littleEndian),
970
+ ]);
971
+ };
972
+
973
+ /** Opus Specific Box. */
974
+ export const dOps = (trackData: IsobmffAudioTrackData) => {
975
+ let outputChannelCount = trackData.info.numberOfChannels;
976
+ // Default PreSkip, should be at least 80 milliseconds worth of playback, measured in 48000 Hz samples
977
+ let preSkip = 3840;
978
+ let inputSampleRate = trackData.info.sampleRate;
979
+ let outputGain = 0;
980
+ let channelMappingFamily = 0;
981
+ let channelMappingTable: Uint8Array<ArrayBufferLike> = new Uint8Array(0);
982
+
983
+ // Read preskip and from codec private data from the encoder
984
+ // https://www.rfc-editor.org/rfc/rfc7845#section-5
985
+ const description = trackData.info.decoderConfig?.description;
986
+ if (description) {
987
+ assert(description.byteLength >= 18);
988
+
989
+ const bytes = toUint8Array(description);
990
+ const header = parseOpusIdentificationHeader(bytes);
991
+
992
+ outputChannelCount = header.outputChannelCount;
993
+ preSkip = header.preSkip;
994
+ inputSampleRate = header.inputSampleRate;
995
+ outputGain = header.outputGain;
996
+ channelMappingFamily = header.channelMappingFamily;
997
+
998
+ if (header.channelMappingTable) {
999
+ channelMappingTable = header.channelMappingTable;
1000
+ }
1001
+ }
1002
+
1003
+ // https://www.opus-codec.org/docs/opus_in_isobmff.html
1004
+ return box('dOps', [
1005
+ u8(0), // Version
1006
+ u8(outputChannelCount), // OutputChannelCount
1007
+ u16(preSkip), // PreSkip
1008
+ u32(inputSampleRate), // InputSampleRate
1009
+ i16(outputGain), // OutputGain
1010
+ u8(channelMappingFamily), // ChannelMappingFamily
1011
+ ...channelMappingTable,
1012
+ ]);
1013
+ };
1014
+
1015
+ /** FLAC specific box. */
1016
+ export const dfLa = (trackData: IsobmffAudioTrackData) => {
1017
+ const description = trackData.info.decoderConfig?.description;
1018
+ assert(description);
1019
+
1020
+ const bytes = toUint8Array(description);
1021
+
1022
+ return fullBox('dfLa', 0, 0, [
1023
+ ...bytes.subarray(4),
1024
+ ]);
1025
+ };
1026
+
1027
+ /** PCM Configuration Box, ISO/IEC 23003-5. */
1028
+ const pcmC = (trackData: IsobmffAudioTrackData) => {
1029
+ const { littleEndian, sampleSize } = parsePcmCodec(trackData.track.source._codec as PcmAudioCodec);
1030
+ const formatFlags = +littleEndian;
1031
+
1032
+ return fullBox('pcmC', 0, 0, [
1033
+ u8(formatFlags),
1034
+ u8(8 * sampleSize),
1035
+ ]);
1036
+ };
1037
+
1038
+ /** AC3SpecificBox */
1039
+ const dac3 = (trackData: IsobmffAudioTrackData) => {
1040
+ const frameInfo = parseAc3SyncFrame(trackData.info.firstPacket.data);
1041
+ if (!frameInfo) {
1042
+ throw new Error(
1043
+ 'Couldn\'t extract AC-3 frame info from the audio packet. '
1044
+ + 'Ensure the packets contain valid AC-3 sync frames (as specified in ETSI TS 102 366).',
1045
+ );
1046
+ }
1047
+
1048
+ const bytes = new Uint8Array(3);
1049
+ const bitstream = new Bitstream(bytes);
1050
+
1051
+ bitstream.writeBits(2, frameInfo.fscod);
1052
+ bitstream.writeBits(5, frameInfo.bsid);
1053
+ bitstream.writeBits(3, frameInfo.bsmod);
1054
+ bitstream.writeBits(3, frameInfo.acmod);
1055
+ bitstream.writeBits(1, frameInfo.lfeon);
1056
+ bitstream.writeBits(5, frameInfo.bitRateCode);
1057
+ bitstream.writeBits(5, 0); // reserved
1058
+
1059
+ return box('dac3', [...bytes]);
1060
+ };
1061
+
1062
+ /** EC3SpecificBox */
1063
+ const dec3 = (trackData: IsobmffAudioTrackData) => {
1064
+ const frameInfo = parseEac3SyncFrame(trackData.info.firstPacket.data);
1065
+ if (!frameInfo) {
1066
+ throw new Error(
1067
+ 'Couldn\'t extract E-AC-3 frame info from the audio packet. '
1068
+ + 'Ensure the packets contain valid E-AC-3 sync frames (as specified in ETSI TS 102 366).',
1069
+ );
1070
+ }
1071
+
1072
+ // Calculate size
1073
+ let totalBits = 16; // header: data_rate (13) + num_ind_sub (3)
1074
+ for (const sub of frameInfo.substreams) {
1075
+ totalBits += 23; // fixed fields per substream
1076
+ if (sub.numDepSub > 0) {
1077
+ totalBits += 9; // chan_loc
1078
+ } else {
1079
+ totalBits += 1; // reserved
1080
+ }
1081
+ }
1082
+ const size = Math.ceil(totalBits / 8);
1083
+
1084
+ const bytes = new Uint8Array(size);
1085
+ const bitstream = new Bitstream(bytes);
1086
+
1087
+ bitstream.writeBits(13, frameInfo.dataRate);
1088
+ bitstream.writeBits(3, frameInfo.substreams.length - 1); // num_ind_sub
1089
+
1090
+ for (const sub of frameInfo.substreams) {
1091
+ bitstream.writeBits(2, sub.fscod);
1092
+ bitstream.writeBits(5, sub.bsid);
1093
+ bitstream.writeBits(1, 0); // reserved
1094
+ bitstream.writeBits(1, 0); // asvc = 0
1095
+ bitstream.writeBits(3, sub.bsmod);
1096
+ bitstream.writeBits(3, sub.acmod);
1097
+ bitstream.writeBits(1, sub.lfeon);
1098
+ bitstream.writeBits(3, 0); // reserved
1099
+ bitstream.writeBits(4, sub.numDepSub);
1100
+
1101
+ if (sub.numDepSub > 0) {
1102
+ bitstream.writeBits(9, sub.chanLoc);
1103
+ } else {
1104
+ bitstream.writeBits(1, 0); // reserved
1105
+ }
1106
+ }
1107
+
1108
+ return box('dec3', [...bytes]);
1109
+ };
1110
+
1111
+ export const subtitleSampleDescription = (
1112
+ compressionType: string,
1113
+ trackData: IsobmffSubtitleTrackData,
1114
+ ) => box(compressionType, [
1115
+ Array(6).fill(0), // Reserved
1116
+ u16(1), // Data reference index
1117
+ ], [
1118
+ SUBTITLE_CODEC_TO_CONFIGURATION_BOX[trackData.track.source._codec](trackData),
1119
+ ]);
1120
+
1121
+ export const vttC = (trackData: IsobmffSubtitleTrackData) => box('vttC', [
1122
+ ...textEncoder.encode(trackData.info.config.description),
1123
+ ]);
1124
+
1125
+ export const txtC = (textConfig: Uint8Array) => fullBox('txtC', 0, 0, [
1126
+ ...textConfig, 0, // Text config (null-terminated)
1127
+ ]);
1128
+
1129
+ /**
1130
+ * Time-To-Sample Box: Stores duration information for a media's samples, providing a mapping from a time in a media
1131
+ * to the corresponding data sample. The table is compact, meaning that consecutive samples with the same time delta
1132
+ * will be grouped.
1133
+ */
1134
+ export const stts = (trackData: IsobmffTrackData) => {
1135
+ return fullBox('stts', 0, 0, [
1136
+ u32(trackData.timeToSampleTable.length), // Number of entries
1137
+ trackData.timeToSampleTable.map(x => [ // Time-to-sample table
1138
+ u32(x.sampleCount), // Sample count
1139
+ u32(x.sampleDelta), // Sample duration
1140
+ ]),
1141
+ ]);
1142
+ };
1143
+
1144
+ /** Sync Sample Box: Identifies the key frames in the media, marking the random access points within a stream. */
1145
+ export const stss = (trackData: IsobmffTrackData) => {
1146
+ if (trackData.samples.every(x => x.type === 'key')) return null; // No stss box -> every frame is a key frame
1147
+
1148
+ const keySamples = [...trackData.samples.entries()].filter(([, sample]) => sample.type === 'key');
1149
+ return fullBox('stss', 0, 0, [
1150
+ u32(keySamples.length), // Number of entries
1151
+ keySamples.map(([index]) => u32(index + 1)), // Sync sample table
1152
+ ]);
1153
+ };
1154
+
1155
+ /**
1156
+ * Sample-To-Chunk Box: As samples are added to a media, they are collected into chunks that allow optimized data
1157
+ * access. A chunk contains one or more samples. Chunks in a media may have different sizes, and the samples within a
1158
+ * chunk may have different sizes. The Sample-To-Chunk Box stores chunk information for the samples in a media, stored
1159
+ * in a compactly-coded fashion.
1160
+ */
1161
+ export const stsc = (trackData: IsobmffTrackData) => {
1162
+ return fullBox('stsc', 0, 0, [
1163
+ u32(trackData.compactlyCodedChunkTable.length), // Number of entries
1164
+ trackData.compactlyCodedChunkTable.map(x => [ // Sample-to-chunk table
1165
+ u32(x.firstChunk), // First chunk
1166
+ u32(x.samplesPerChunk), // Samples per chunk
1167
+ u32(1), // Sample description index
1168
+ ]),
1169
+ ]);
1170
+ };
1171
+
1172
+ /** Sample Size Box: Specifies the byte size of each sample in the media. */
1173
+ export const stsz = (trackData: IsobmffTrackData) => {
1174
+ if (trackData.type === 'audio' && trackData.info.requiresPcmTransformation) {
1175
+ const { sampleSize } = parsePcmCodec(trackData.track.source._codec as PcmAudioCodec);
1176
+
1177
+ // With PCM, every sample has the same size
1178
+ return fullBox('stsz', 0, 0, [
1179
+ u32(sampleSize * trackData.info.numberOfChannels), // Sample size
1180
+ u32(trackData.samples.reduce((acc, x) => acc + intoTimescale(x.duration, trackData.timescale), 0)),
1181
+ ]);
1182
+ }
1183
+
1184
+ return fullBox('stsz', 0, 0, [
1185
+ u32(0), // Sample size (0 means non-constant size)
1186
+ u32(trackData.samples.length), // Number of entries
1187
+ trackData.samples.map(x => u32(x.size)), // Sample size table
1188
+ ]);
1189
+ };
1190
+
1191
+ /** Chunk Offset Box: Identifies the location of each chunk of data in the media's data stream, relative to the file. */
1192
+ export const stco = (trackData: IsobmffTrackData) => {
1193
+ if (trackData.finalizedChunks.length > 0 && last(trackData.finalizedChunks)!.offset! >= 2 ** 32) {
1194
+ // If the file is large, use the co64 box
1195
+ return fullBox('co64', 0, 0, [
1196
+ u32(trackData.finalizedChunks.length), // Number of entries
1197
+ trackData.finalizedChunks.map(x => u64(x.offset!)), // Chunk offset table
1198
+ ]);
1199
+ }
1200
+
1201
+ return fullBox('stco', 0, 0, [
1202
+ u32(trackData.finalizedChunks.length), // Number of entries
1203
+ trackData.finalizedChunks.map(x => u32(x.offset!)), // Chunk offset table
1204
+ ]);
1205
+ };
1206
+
1207
+ /**
1208
+ * Composition Time to Sample Box: Stores composition time offset information (PTS-DTS) for a
1209
+ * media's samples. The table is compact, meaning that consecutive samples with the same time
1210
+ * composition time offset will be grouped.
1211
+ */
1212
+ export const ctts = (trackData: IsobmffTrackData) => {
1213
+ return fullBox('ctts', 1, 0, [
1214
+ u32(trackData.compositionTimeOffsetTable.length), // Number of entries
1215
+ trackData.compositionTimeOffsetTable.map(x => [ // Time-to-sample table
1216
+ u32(x.sampleCount), // Sample count
1217
+ i32(x.sampleCompositionTimeOffset), // Sample offset
1218
+ ]),
1219
+ ]);
1220
+ };
1221
+
1222
+ /**
1223
+ * Composition to Decode Box: Stores information about the composition and display times of the media samples.
1224
+ */
1225
+ export const cslg = (trackData: IsobmffTrackData) => {
1226
+ let leastDecodeToDisplayDelta = Infinity;
1227
+ let greatestDecodeToDisplayDelta = -Infinity;
1228
+ let compositionStartTime = Infinity;
1229
+ let compositionEndTime = -Infinity;
1230
+
1231
+ assert(trackData.compositionTimeOffsetTable.length > 0);
1232
+ assert(trackData.samples.length > 0);
1233
+
1234
+ for (let i = 0; i < trackData.compositionTimeOffsetTable.length; i++) {
1235
+ const entry = trackData.compositionTimeOffsetTable[i]!;
1236
+ leastDecodeToDisplayDelta = Math.min(leastDecodeToDisplayDelta, entry.sampleCompositionTimeOffset);
1237
+ greatestDecodeToDisplayDelta = Math.max(greatestDecodeToDisplayDelta, entry.sampleCompositionTimeOffset);
1238
+ }
1239
+
1240
+ for (let i = 0; i < trackData.samples.length; i++) {
1241
+ const sample = trackData.samples[i]!;
1242
+ compositionStartTime = Math.min(
1243
+ compositionStartTime,
1244
+ intoTimescale(sample.timestamp, trackData.timescale),
1245
+ );
1246
+ compositionEndTime = Math.max(
1247
+ compositionEndTime,
1248
+ intoTimescale(sample.timestamp + sample.duration, trackData.timescale),
1249
+ );
1250
+ }
1251
+
1252
+ const compositionToDtsShift = Math.max(-leastDecodeToDisplayDelta, 0);
1253
+
1254
+ if (compositionEndTime >= 2 ** 31) {
1255
+ // For very large files, the composition end time can't be represented in i32, so let's just scrap the box in
1256
+ // that case. QuickTime fails to read the file if there's a cslg box with version 1, so that's sadly not an
1257
+ // option.
1258
+ return null;
1259
+ }
1260
+
1261
+ return fullBox('cslg', 0, 0, [
1262
+ i32(compositionToDtsShift), // Composition to DTS shift
1263
+ i32(leastDecodeToDisplayDelta), // Least decode to display delta
1264
+ i32(greatestDecodeToDisplayDelta), // Greatest decode to display delta
1265
+ i32(compositionStartTime), // Composition start time
1266
+ i32(compositionEndTime), // Composition end time
1267
+ ]);
1268
+ };
1269
+
1270
+ /**
1271
+ * Movie Extends Box: This box signals to readers that the file is fragmented. Contains a single Track Extends Box
1272
+ * for each track in the movie.
1273
+ */
1274
+ export const mvex = (trackDatas: IsobmffTrackData[]) => {
1275
+ return box('mvex', undefined, trackDatas.map(trex));
1276
+ };
1277
+
1278
+ /** Track Extends Box: Contains the default values used by the movie fragments. */
1279
+ export const trex = (trackData: IsobmffTrackData) => {
1280
+ return fullBox('trex', 0, 0, [
1281
+ u32(trackData.track.id), // Track ID
1282
+ u32(1), // Default sample description index
1283
+ u32(0), // Default sample duration
1284
+ u32(0), // Default sample size
1285
+ u32(0), // Default sample flags
1286
+ ]);
1287
+ };
1288
+
1289
+ /**
1290
+ * Movie Fragment Box: The movie fragments extend the presentation in time. They provide the information that would
1291
+ * previously have been in the Movie Box.
1292
+ */
1293
+ export const moof = (sequenceNumber: number, trackDatas: IsobmffTrackData[]) => {
1294
+ return box('moof', undefined, [
1295
+ mfhd(sequenceNumber),
1296
+ ...trackDatas.map(traf),
1297
+ ]);
1298
+ };
1299
+
1300
+ /** Movie Fragment Header Box: Contains a sequence number as a safety check. */
1301
+ export const mfhd = (sequenceNumber: number) => {
1302
+ return fullBox('mfhd', 0, 0, [
1303
+ u32(sequenceNumber), // Sequence number
1304
+ ]);
1305
+ };
1306
+
1307
+ const fragmentSampleFlags = (sample: Sample) => {
1308
+ let byte1 = 0;
1309
+ let byte2 = 0;
1310
+ const byte3 = 0;
1311
+ const byte4 = 0;
1312
+
1313
+ const sampleIsDifferenceSample = sample.type === 'delta';
1314
+ byte2 |= +sampleIsDifferenceSample;
1315
+
1316
+ if (sampleIsDifferenceSample) {
1317
+ byte1 |= 1; // There is redundant coding in this sample
1318
+ } else {
1319
+ byte1 |= 2; // There is no redundant coding in this sample
1320
+ }
1321
+
1322
+ // Note that there are a lot of other flags to potentially set here, but most are irrelevant / non-necessary
1323
+ return byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4;
1324
+ };
1325
+
1326
+ /** Track Fragment Box */
1327
+ export const traf = (trackData: IsobmffTrackData) => {
1328
+ return box('traf', undefined, [
1329
+ tfhd(trackData),
1330
+ tfdt(trackData),
1331
+ trun(trackData),
1332
+ ]);
1333
+ };
1334
+
1335
+ /** Track Fragment Header Box: Provides a reference to the extended track, and flags. */
1336
+ export const tfhd = (trackData: IsobmffTrackData) => {
1337
+ assert(trackData.currentChunk);
1338
+
1339
+ let tfFlags = 0;
1340
+ tfFlags |= 0x00008; // Default sample duration present
1341
+ tfFlags |= 0x00010; // Default sample size present
1342
+ tfFlags |= 0x00020; // Default sample flags present
1343
+ tfFlags |= 0x20000; // Default base is moof
1344
+
1345
+ // Prefer the second sample over the first one, as the first one is a sync sample and therefore the "odd one out"
1346
+ const referenceSample = trackData.currentChunk.samples[1] ?? trackData.currentChunk.samples[0]!;
1347
+ const referenceSampleInfo = {
1348
+ duration: referenceSample.timescaleUnitsToNextSample,
1349
+ size: referenceSample.size,
1350
+ flags: fragmentSampleFlags(referenceSample),
1351
+ };
1352
+
1353
+ return fullBox('tfhd', 0, tfFlags, [
1354
+ u32(trackData.track.id), // Track ID
1355
+ u32(referenceSampleInfo.duration), // Default sample duration
1356
+ u32(referenceSampleInfo.size), // Default sample size
1357
+ u32(referenceSampleInfo.flags), // Default sample flags
1358
+ ]);
1359
+ };
1360
+
1361
+ /**
1362
+ * Track Fragment Decode Time Box: Provides the absolute decode time of the first sample of the fragment. This is
1363
+ * useful for performing random access on the media file.
1364
+ */
1365
+ export const tfdt = (trackData: IsobmffTrackData) => {
1366
+ assert(trackData.currentChunk);
1367
+
1368
+ return fullBox('tfdt', 1, 0, [
1369
+ u64(intoTimescale(trackData.currentChunk.startTimestamp, trackData.timescale)), // Base Media Decode Time
1370
+ ]);
1371
+ };
1372
+
1373
+ /** Track Run Box: Specifies a run of contiguous samples for a given track. */
1374
+ export const trun = (trackData: IsobmffTrackData) => {
1375
+ assert(trackData.currentChunk);
1376
+
1377
+ const allSampleDurations = trackData.currentChunk.samples.map(x => x.timescaleUnitsToNextSample);
1378
+ const allSampleSizes = trackData.currentChunk.samples.map(x => x.size);
1379
+ const allSampleFlags = trackData.currentChunk.samples.map(fragmentSampleFlags);
1380
+ const allSampleCompositionTimeOffsets = trackData.currentChunk.samples
1381
+ .map(x => intoTimescale(x.timestamp - x.decodeTimestamp, trackData.timescale));
1382
+
1383
+ const uniqueSampleDurations = new Set(allSampleDurations);
1384
+ const uniqueSampleSizes = new Set(allSampleSizes);
1385
+ const uniqueSampleFlags = new Set(allSampleFlags);
1386
+ const uniqueSampleCompositionTimeOffsets = new Set(allSampleCompositionTimeOffsets);
1387
+
1388
+ const firstSampleFlagsPresent = uniqueSampleFlags.size === 2 && allSampleFlags[0] !== allSampleFlags[1];
1389
+ const sampleDurationPresent = uniqueSampleDurations.size > 1;
1390
+ const sampleSizePresent = uniqueSampleSizes.size > 1;
1391
+ const sampleFlagsPresent = !firstSampleFlagsPresent && uniqueSampleFlags.size > 1;
1392
+ const sampleCompositionTimeOffsetsPresent
1393
+ = uniqueSampleCompositionTimeOffsets.size > 1 || [...uniqueSampleCompositionTimeOffsets].some(x => x !== 0);
1394
+
1395
+ let flags = 0;
1396
+ flags |= 0x0001; // Data offset present
1397
+ flags |= 0x0004 * +firstSampleFlagsPresent; // First sample flags present
1398
+ flags |= 0x0100 * +sampleDurationPresent; // Sample duration present
1399
+ flags |= 0x0200 * +sampleSizePresent; // Sample size present
1400
+ flags |= 0x0400 * +sampleFlagsPresent; // Sample flags present
1401
+ flags |= 0x0800 * +sampleCompositionTimeOffsetsPresent; // Sample composition time offsets present
1402
+
1403
+ return fullBox('trun', 1, flags, [
1404
+ u32(trackData.currentChunk.samples.length), // Sample count
1405
+ u32(trackData.currentChunk.offset! - trackData.currentChunk.moofOffset! || 0), // Data offset
1406
+ firstSampleFlagsPresent ? u32(allSampleFlags[0]!) : [],
1407
+ trackData.currentChunk.samples.map((_, i) => [
1408
+ sampleDurationPresent ? u32(allSampleDurations[i]!) : [], // Sample duration
1409
+ sampleSizePresent ? u32(allSampleSizes[i]!) : [], // Sample size
1410
+ sampleFlagsPresent ? u32(allSampleFlags[i]!) : [], // Sample flags
1411
+ // Sample composition time offsets
1412
+ sampleCompositionTimeOffsetsPresent ? i32(allSampleCompositionTimeOffsets[i]!) : [],
1413
+ ]),
1414
+ ]);
1415
+ };
1416
+
1417
+ /**
1418
+ * Movie Fragment Random Access Box: For each track, provides pointers to sync samples within the file
1419
+ * for random access.
1420
+ */
1421
+ export const mfra = (trackDatas: IsobmffTrackData[]) => {
1422
+ return box('mfra', undefined, [
1423
+ ...trackDatas.map(tfra),
1424
+ mfro(),
1425
+ ]);
1426
+ };
1427
+
1428
+ /** Track Fragment Random Access Box: Provides pointers to sync samples within the file for random access. */
1429
+ export const tfra = (trackData: IsobmffTrackData, trackIndex: number) => {
1430
+ const version = 1; // Using this version allows us to use 64-bit time and offset values
1431
+
1432
+ return fullBox('tfra', version, 0, [
1433
+ u32(trackData.track.id), // Track ID
1434
+ u32(0b111111), // This specifies that traf number, trun number and sample number are 32-bit ints
1435
+ u32(trackData.finalizedChunks.length), // Number of entries
1436
+ trackData.finalizedChunks.map(chunk => [
1437
+ u64(intoTimescale(chunk.samples[0]!.timestamp, trackData.timescale)), // Time (in presentation time)
1438
+ u64(chunk.moofOffset!), // moof offset
1439
+ u32(trackIndex + 1), // traf number
1440
+ u32(1), // trun number
1441
+ u32(1), // Sample number
1442
+ ]),
1443
+ ]);
1444
+ };
1445
+
1446
+ /**
1447
+ * Movie Fragment Random Access Offset Box: Provides the size of the enclosing mfra box. This box can be used by readers
1448
+ * to quickly locate the mfra box by searching from the end of the file.
1449
+ */
1450
+ export const mfro = () => {
1451
+ return fullBox('mfro', 0, 0, [
1452
+ // This value needs to be overwritten manually from the outside, where the actual size of the enclosing mfra box
1453
+ // is known
1454
+ u32(0), // Size
1455
+ ]);
1456
+ };
1457
+
1458
+ /** VTT Empty Cue Box */
1459
+ export const vtte = () => box('vtte');
1460
+
1461
+ /** VTT Cue Box */
1462
+ export const vttc = (
1463
+ payload: string,
1464
+ timestamp: number | null,
1465
+ identifier: string | null,
1466
+ settings: string | null,
1467
+ sourceId: number | null,
1468
+ ) => box('vttc', undefined, [
1469
+ sourceId !== null ? box('vsid', [i32(sourceId)]) : null,
1470
+ identifier !== null ? box('iden', [...textEncoder.encode(identifier)]) : null,
1471
+ timestamp !== null ? box('ctim', [...textEncoder.encode(formatSubtitleTimestamp(timestamp))]) : null,
1472
+ settings !== null ? box('sttg', [...textEncoder.encode(settings)]) : null,
1473
+ box('payl', [...textEncoder.encode(payload)]),
1474
+ ]);
1475
+
1476
+ /** VTT Additional Text Box */
1477
+ export const vtta = (notes: string) => box('vtta', [...textEncoder.encode(notes)]);
1478
+
1479
+ /** User Data Box */
1480
+ const udta = (muxer: IsobmffMuxer) => {
1481
+ const boxes: Box[] = [];
1482
+
1483
+ const metadataFormat = muxer.format._options.metadataFormat ?? 'auto';
1484
+ const metadataTags = muxer.output._metadataTags;
1485
+
1486
+ // Depending on the format, metadata tags are written differently
1487
+ if (metadataFormat === 'mdir' || (metadataFormat === 'auto' && !muxer.isQuickTime)) {
1488
+ const metaBox = metaMdir(metadataTags);
1489
+ if (metaBox) boxes.push(metaBox);
1490
+ } else if (metadataFormat === 'mdta') {
1491
+ const metaBox = metaMdta(metadataTags);
1492
+ if (metaBox) boxes.push(metaBox);
1493
+ } else if (metadataFormat === 'udta' || (metadataFormat === 'auto' && muxer.isQuickTime)) {
1494
+ addQuickTimeMetadataTagBoxes(boxes, muxer.output._metadataTags);
1495
+ }
1496
+
1497
+ if (boxes.length === 0) {
1498
+ return null;
1499
+ }
1500
+
1501
+ return box('udta', undefined, boxes);
1502
+ };
1503
+
1504
+ const addQuickTimeMetadataTagBoxes = (boxes: Box[], tags: MetadataTags) => {
1505
+ // https://exiftool.org/TagNames/QuickTime.html (QuickTime UserData Tags)
1506
+ // For QuickTime files, metadata tags are dumped into the udta box
1507
+
1508
+ for (const { key, value } of keyValueIterator(tags)) {
1509
+ switch (key) {
1510
+ case 'title': {
1511
+ boxes.push(metadataTagStringBoxShort('©nam', value));
1512
+ }; break;
1513
+
1514
+ case 'description': {
1515
+ boxes.push(metadataTagStringBoxShort('©des', value));
1516
+ }; break;
1517
+
1518
+ case 'artist': {
1519
+ boxes.push(metadataTagStringBoxShort('©ART', value));
1520
+ }; break;
1521
+
1522
+ case 'album': {
1523
+ boxes.push(metadataTagStringBoxShort('©alb', value));
1524
+ }; break;
1525
+
1526
+ case 'albumArtist': {
1527
+ boxes.push(metadataTagStringBoxShort('albr', value));
1528
+ }; break;
1529
+
1530
+ case 'genre': {
1531
+ boxes.push(metadataTagStringBoxShort('©gen', value));
1532
+ }; break;
1533
+
1534
+ case 'date': {
1535
+ boxes.push(metadataTagStringBoxShort('©day', value.toISOString().slice(0, 10)));
1536
+ }; break;
1537
+
1538
+ case 'comment': {
1539
+ boxes.push(metadataTagStringBoxShort('©cmt', value));
1540
+ }; break;
1541
+
1542
+ case 'lyrics': {
1543
+ boxes.push(metadataTagStringBoxShort('©lyr', value));
1544
+ }; break;
1545
+
1546
+ case 'raw': {
1547
+ // Handled later
1548
+ }; break;
1549
+
1550
+ case 'discNumber':
1551
+ case 'discsTotal':
1552
+ case 'trackNumber':
1553
+ case 'tracksTotal':
1554
+ case 'images': {
1555
+ // Not written for QuickTime (common Apple L)
1556
+ }; break;
1557
+
1558
+ default: assertNever(key);
1559
+ }
1560
+ }
1561
+
1562
+ if (tags.raw) {
1563
+ for (const key in tags.raw) {
1564
+ const value = tags.raw[key];
1565
+ if (value == null || key.length !== 4 || boxes.some(x => x.type === key)) {
1566
+ continue;
1567
+ }
1568
+
1569
+ if (typeof value === 'string') {
1570
+ boxes.push(metadataTagStringBoxShort(key, value));
1571
+ } else if (value instanceof Uint8Array) {
1572
+ boxes.push(box(key, Array.from(value)));
1573
+ }
1574
+ }
1575
+ }
1576
+ };
1577
+
1578
+ const metadataTagStringBoxShort = (name: string, value: string) => {
1579
+ const encoded = textEncoder.encode(value);
1580
+
1581
+ return box(name, [
1582
+ u16(encoded.length),
1583
+ u16(getLanguageCodeInt('und')),
1584
+ Array.from(encoded),
1585
+ ]);
1586
+ };
1587
+
1588
+ const DATA_BOX_MIME_TYPE_MAP: Record<string, number> = {
1589
+ 'image/jpeg': 13,
1590
+ 'image/png': 14,
1591
+ 'image/bmp': 27,
1592
+ };
1593
+
1594
+ /**
1595
+ * Generates key-value metadata for inclusion in the "meta" box.
1596
+ */
1597
+ const generateMetadataPairs = (tags: MetadataTags, isMdta: boolean) => {
1598
+ const pairs: {
1599
+ key: string;
1600
+ value: Box;
1601
+ }[] = [];
1602
+
1603
+ // https://exiftool.org/TagNames/QuickTime.html (QuickTime ItemList Tags)
1604
+ // This is the metadata format used for MP4 files
1605
+
1606
+ for (const { key, value } of keyValueIterator(tags)) {
1607
+ switch (key) {
1608
+ case 'title': {
1609
+ pairs.push({ key: isMdta ? 'title' : '©nam', value: dataStringBoxLong(value) });
1610
+ }; break;
1611
+
1612
+ case 'description': {
1613
+ pairs.push({ key: isMdta ? 'description' : '©des', value: dataStringBoxLong(value) });
1614
+ }; break;
1615
+
1616
+ case 'artist': {
1617
+ pairs.push({ key: isMdta ? 'artist' : '©ART', value: dataStringBoxLong(value) });
1618
+ }; break;
1619
+
1620
+ case 'album': {
1621
+ pairs.push({ key: isMdta ? 'album' : '©alb', value: dataStringBoxLong(value) });
1622
+ }; break;
1623
+
1624
+ case 'albumArtist': {
1625
+ pairs.push({ key: isMdta ? 'album_artist' : 'aART', value: dataStringBoxLong(value) });
1626
+ }; break;
1627
+
1628
+ case 'comment': {
1629
+ pairs.push({ key: isMdta ? 'comment' : '©cmt', value: dataStringBoxLong(value) });
1630
+ }; break;
1631
+
1632
+ case 'genre': {
1633
+ pairs.push({ key: isMdta ? 'genre' : '©gen', value: dataStringBoxLong(value) });
1634
+ }; break;
1635
+
1636
+ case 'lyrics': {
1637
+ pairs.push({ key: isMdta ? 'lyrics' : '©lyr', value: dataStringBoxLong(value) });
1638
+ }; break;
1639
+
1640
+ case 'date': {
1641
+ pairs.push({
1642
+ key: isMdta ? 'date' : '©day',
1643
+ value: dataStringBoxLong(value.toISOString().slice(0, 10)),
1644
+ });
1645
+ }; break;
1646
+
1647
+ case 'images': {
1648
+ for (const image of value) {
1649
+ if (image.kind !== 'coverFront') {
1650
+ continue;
1651
+ }
1652
+
1653
+ pairs.push({ key: 'covr', value: box('data', [
1654
+ u32(DATA_BOX_MIME_TYPE_MAP[image.mimeType] ?? 0), // Type indicator
1655
+ u32(0), // Locale indicator
1656
+ Array.from(image.data), // Kinda slow, hopefully temp
1657
+ ]) });
1658
+ }
1659
+ }; break;
1660
+
1661
+ case 'trackNumber': {
1662
+ if (isMdta) {
1663
+ const string = tags.tracksTotal !== undefined
1664
+ ? `${value}/${tags.tracksTotal}`
1665
+ : value.toString();
1666
+
1667
+ pairs.push({ key: 'track', value: dataStringBoxLong(string) });
1668
+ } else {
1669
+ pairs.push({ key: 'trkn', value: box('data', [
1670
+ u32(0), // 8 bytes empty
1671
+ u32(0),
1672
+ u16(0), // Empty
1673
+ u16(value),
1674
+ u16(tags.tracksTotal ?? 0),
1675
+ u16(0), // Empty
1676
+ ]) });
1677
+ }
1678
+ }; break;
1679
+
1680
+ case 'discNumber': {
1681
+ if (!isMdta) {
1682
+ // Only written for mdir
1683
+ pairs.push({ key: 'disc', value: box('data', [
1684
+ u32(0), // 8 bytes empty
1685
+ u32(0),
1686
+ u16(0), // Empty
1687
+ u16(value),
1688
+ u16(tags.discsTotal ?? 0),
1689
+ u16(0), // Empty
1690
+ ]) });
1691
+ }
1692
+ }; break;
1693
+
1694
+ case 'tracksTotal':
1695
+ case 'discsTotal':{
1696
+ // These are included with 'trackNumber' and 'discNumber' respectively
1697
+ }; break;
1698
+
1699
+ case 'raw': {
1700
+ // Handled later
1701
+ }; break;
1702
+
1703
+ default: assertNever(key);
1704
+ }
1705
+ }
1706
+
1707
+ if (tags.raw) {
1708
+ for (const key in tags.raw) {
1709
+ const value = tags.raw[key];
1710
+ if (value == null || (!isMdta && key.length !== 4) || pairs.some(x => x.key === key)) {
1711
+ continue;
1712
+ }
1713
+
1714
+ if (typeof value === 'string') {
1715
+ pairs.push({ key, value: dataStringBoxLong(value) });
1716
+ } else if (value instanceof Uint8Array) {
1717
+ pairs.push({ key, value: box('data', [
1718
+ u32(0), // Type indicator
1719
+ u32(0), // Locale indicator
1720
+ Array.from(value),
1721
+ ]) });
1722
+ } else if (value instanceof RichImageData) {
1723
+ pairs.push({ key, value: box('data', [
1724
+ u32(DATA_BOX_MIME_TYPE_MAP[value.mimeType] ?? 0), // Type indicator
1725
+ u32(0), // Locale indicator
1726
+ Array.from(value.data), // Kinda slow, hopefully temp
1727
+ ]) });
1728
+ }
1729
+ }
1730
+ }
1731
+
1732
+ return pairs;
1733
+ };
1734
+
1735
+ /** Metadata Box (mdir format) */
1736
+ const metaMdir = (tags: MetadataTags) => {
1737
+ const pairs = generateMetadataPairs(tags, false);
1738
+
1739
+ if (pairs.length === 0) {
1740
+ return null;
1741
+ }
1742
+
1743
+ // fullBox format
1744
+ return fullBox('meta', 0, 0, undefined, [
1745
+ hdlr(false, 'mdir', '', 'appl'), // mdir handler
1746
+ box('ilst', undefined, pairs.map(pair => box(pair.key, undefined, [pair.value]))), // Item list without keys box
1747
+ ]);
1748
+ };
1749
+
1750
+ /** Metadata Box (mdta format with keys box) */
1751
+ const metaMdta = (tags: MetadataTags) => {
1752
+ const pairs = generateMetadataPairs(tags, true);
1753
+
1754
+ if (pairs.length === 0) {
1755
+ return null;
1756
+ }
1757
+
1758
+ // box without version and flags
1759
+ return box('meta', undefined, [
1760
+ hdlr(false, 'mdta', ''), // mdta handler
1761
+ fullBox('keys', 0, 0, [
1762
+ u32(pairs.length),
1763
+ ], pairs.map(pair => box('mdta', [ // Hacky since these aren't boxes technically, but if not box why box-shaped?
1764
+ ...textEncoder.encode(pair.key),
1765
+ ]))),
1766
+ box('ilst', undefined, pairs.map((pair, i) => {
1767
+ const boxName = String.fromCharCode(...u32(i + 1));
1768
+ return box(boxName, undefined, [pair.value]);
1769
+ })),
1770
+ ]);
1771
+ };
1772
+
1773
+ const dataStringBoxLong = (value: string) => {
1774
+ return box('data', [
1775
+ u32(1), // Type indicator (UTF-8)
1776
+ u32(0), // Locale indicator
1777
+ ...textEncoder.encode(value),
1778
+ ]);
1779
+ };
1780
+
1781
+ const videoCodecToBoxName = (codec: VideoCodec, fullCodecString: string) => {
1782
+ switch (codec) {
1783
+ case 'avc': return fullCodecString.startsWith('avc3') ? 'avc3' : 'avc1';
1784
+ case 'hevc': return 'hvc1';
1785
+ case 'vp8': return 'vp08';
1786
+ case 'vp9': return 'vp09';
1787
+ case 'av1': return 'av01';
1788
+ case 'prores': return fullCodecString;
1789
+ }
1790
+ };
1791
+
1792
+ const VIDEO_CODEC_TO_CONFIGURATION_BOX: Record<
1793
+ VideoCodec,
1794
+ ((trackData: IsobmffVideoTrackData) => Box | null) | null
1795
+ > = {
1796
+ avc: avcC,
1797
+ hevc: hvcC,
1798
+ vp8: vpcC,
1799
+ vp9: vpcC,
1800
+ av1: av1C,
1801
+ prores: null,
1802
+ };
1803
+
1804
+ const audioCodecToBoxName = (codec: AudioCodec, isQuickTime: boolean): string => {
1805
+ switch (codec) {
1806
+ case 'aac': return 'mp4a';
1807
+ case 'mp3': return 'mp4a';
1808
+ case 'opus': return 'Opus';
1809
+ case 'vorbis': return 'mp4a';
1810
+ case 'flac': return 'fLaC';
1811
+ case 'ulaw': return 'ulaw';
1812
+ case 'alaw': return 'alaw';
1813
+ case 'pcm-u8': return 'raw ';
1814
+ case 'pcm-s8': return 'sowt';
1815
+ case 'ac3': return 'ac-3';
1816
+ case 'eac3': return 'ec-3';
1817
+ }
1818
+
1819
+ // Logic diverges here
1820
+ if (isQuickTime) {
1821
+ switch (codec) {
1822
+ case 'pcm-s16': return 'sowt';
1823
+ case 'pcm-s16be': return 'twos';
1824
+ case 'pcm-s24': return 'in24';
1825
+ case 'pcm-s24be': return 'in24';
1826
+ case 'pcm-s32': return 'in32';
1827
+ case 'pcm-s32be': return 'in32';
1828
+ case 'pcm-f32': return 'fl32';
1829
+ case 'pcm-f32be': return 'fl32';
1830
+ case 'pcm-f64': return 'fl64';
1831
+ case 'pcm-f64be': return 'fl64';
1832
+ }
1833
+ } else {
1834
+ switch (codec) {
1835
+ case 'pcm-s16': return 'ipcm';
1836
+ case 'pcm-s16be': return 'ipcm';
1837
+ case 'pcm-s24': return 'ipcm';
1838
+ case 'pcm-s24be': return 'ipcm';
1839
+ case 'pcm-s32': return 'ipcm';
1840
+ case 'pcm-s32be': return 'ipcm';
1841
+ case 'pcm-f32': return 'fpcm';
1842
+ case 'pcm-f32be': return 'fpcm';
1843
+ case 'pcm-f64': return 'fpcm';
1844
+ case 'pcm-f64be': return 'fpcm';
1845
+ }
1846
+ }
1847
+ };
1848
+
1849
+ const audioCodecToConfigurationBox = (codec: AudioCodec, isQuickTime: boolean) => {
1850
+ switch (codec) {
1851
+ case 'aac': return esds;
1852
+ case 'mp3': return esds;
1853
+ case 'opus': return dOps;
1854
+ case 'vorbis': return esds;
1855
+ case 'flac': return dfLa;
1856
+ case 'ac3': return dac3;
1857
+ case 'eac3': return dec3;
1858
+ }
1859
+
1860
+ // Logic diverges here
1861
+ if (isQuickTime) {
1862
+ switch (codec) {
1863
+ case 'pcm-s24': return wave;
1864
+ case 'pcm-s24be': return wave;
1865
+ case 'pcm-s32': return wave;
1866
+ case 'pcm-s32be': return wave;
1867
+ case 'pcm-f32': return wave;
1868
+ case 'pcm-f32be': return wave;
1869
+ case 'pcm-f64': return wave;
1870
+ case 'pcm-f64be': return wave;
1871
+ }
1872
+ } else {
1873
+ switch (codec) {
1874
+ case 'pcm-s16': return pcmC;
1875
+ case 'pcm-s16be': return pcmC;
1876
+ case 'pcm-s24': return pcmC;
1877
+ case 'pcm-s24be': return pcmC;
1878
+ case 'pcm-s32': return pcmC;
1879
+ case 'pcm-s32be': return pcmC;
1880
+ case 'pcm-f32': return pcmC;
1881
+ case 'pcm-f32be': return pcmC;
1882
+ case 'pcm-f64': return pcmC;
1883
+ case 'pcm-f64be': return pcmC;
1884
+ }
1885
+ }
1886
+
1887
+ return null;
1888
+ };
1889
+
1890
+ const SUBTITLE_CODEC_TO_BOX_NAME: Record<SubtitleCodec, string> = {
1891
+ webvtt: 'wvtt',
1892
+ };
1893
+
1894
+ const SUBTITLE_CODEC_TO_CONFIGURATION_BOX: Record<
1895
+ SubtitleCodec,
1896
+ (trackData: IsobmffSubtitleTrackData) => Box | null
1897
+ > = {
1898
+ webvtt: vttC,
1899
+ };
1900
+
1901
+ const getLanguageCodeInt = (code: string) => {
1902
+ assert(code.length === 3); ;
1903
+
1904
+ let language = 0;
1905
+ for (let i = 0; i < 3; i++) {
1906
+ language <<= 5;
1907
+ language += code.charCodeAt(i) - 0x60;
1908
+ }
1909
+
1910
+ return language;
1911
+ };