@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,3178 @@
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 { AVC_LEVEL_TABLE, VideoCodec, VP9_LEVEL_TABLE } from './codec';
10
+ import {
11
+ assert,
12
+ assertNever,
13
+ base64ToBytes,
14
+ bytesToBase64,
15
+ keyValueIterator,
16
+ getUint24,
17
+ last,
18
+ readExpGolomb,
19
+ readSignedExpGolomb,
20
+ Rational,
21
+ textDecoder,
22
+ textEncoder,
23
+ toDataView,
24
+ toUint8Array,
25
+ getChromiumVersion,
26
+ isChromium,
27
+ setUint24,
28
+ } from './misc';
29
+ import { Logging } from './logging';
30
+ import { PacketType } from './packet';
31
+ import { MetadataTags } from './metadata';
32
+ import { AC3_SAMPLE_RATES, EAC3_REDUCED_SAMPLE_RATES } from '../shared/ac3-misc';
33
+ import { Bitstream } from '../shared/bitstream';
34
+
35
+ // References for AVC/HEVC code:
36
+ // ISO 14496-15
37
+ // Rec. ITU-T H.264
38
+ // Rec. ITU-T H.265
39
+ // https://stackoverflow.com/questions/24884827
40
+
41
+ export enum AvcNalUnitType {
42
+ NON_IDR_SLICE = 1,
43
+ SLICE_DPA = 2,
44
+ SLICE_DPB = 3,
45
+ SLICE_DPC = 4,
46
+ IDR = 5,
47
+ SEI = 6,
48
+ SPS = 7,
49
+ PPS = 8,
50
+ AUD = 9,
51
+ SPS_EXT = 13,
52
+ }
53
+
54
+ export enum HevcNalUnitType {
55
+ RASL_N = 8,
56
+ RASL_R = 9,
57
+ BLA_W_LP = 16,
58
+ RSV_IRAP_VCL23 = 23,
59
+ VPS_NUT = 32,
60
+ SPS_NUT = 33,
61
+ PPS_NUT = 34,
62
+ AUD_NUT = 35,
63
+ PREFIX_SEI_NUT = 39,
64
+ SUFFIX_SEI_NUT = 40,
65
+ }
66
+
67
+ export type NalUnitLocation = {
68
+ offset: number;
69
+ length: number;
70
+ };
71
+
72
+ export const iterateNalUnitsInAnnexB = function* (packetData: Uint8Array): Generator<NalUnitLocation> {
73
+ let i = 0;
74
+ let nalStart = -1;
75
+
76
+ while (i < packetData.length - 2) {
77
+ const zeroIndex = packetData.indexOf(0, i);
78
+ if (zeroIndex === -1 || zeroIndex >= packetData.length - 2) {
79
+ break;
80
+ }
81
+ i = zeroIndex;
82
+
83
+ let startCodeLength = 0;
84
+
85
+ // Check for 4-byte start code (0x00000001)
86
+ if (
87
+ i + 3 < packetData.length
88
+ && packetData[i + 1] === 0
89
+ && packetData[i + 2] === 0
90
+ && packetData[i + 3] === 1
91
+ ) {
92
+ startCodeLength = 4;
93
+ } else if (packetData[i + 1] === 0 && packetData[i + 2] === 1) {
94
+ // Check for 3-byte start code (0x000001)
95
+ startCodeLength = 3;
96
+ }
97
+
98
+ if (startCodeLength === 0) {
99
+ i++;
100
+ continue;
101
+ }
102
+
103
+ // If we had a previous NAL unit, yield it
104
+ if (nalStart !== -1 && i > nalStart) {
105
+ yield {
106
+ offset: nalStart,
107
+ length: i - nalStart,
108
+ };
109
+ }
110
+
111
+ nalStart = i + startCodeLength;
112
+ i = nalStart;
113
+ }
114
+
115
+ // Yield the last NAL unit if there is one
116
+ if (nalStart !== -1 && nalStart < packetData.length) {
117
+ yield {
118
+ offset: nalStart,
119
+ length: packetData.length - nalStart,
120
+ };
121
+ }
122
+ };
123
+
124
+ export const iterateNalUnitsInLengthPrefixed = function* (
125
+ packetData: Uint8Array,
126
+ lengthSize: 1 | 2 | 3 | 4,
127
+ ): Generator<NalUnitLocation> {
128
+ let offset = 0;
129
+ const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength);
130
+
131
+ while (offset + lengthSize <= packetData.length) {
132
+ let nalUnitLength: number;
133
+ if (lengthSize === 1) {
134
+ nalUnitLength = dataView.getUint8(offset);
135
+ } else if (lengthSize === 2) {
136
+ nalUnitLength = dataView.getUint16(offset, false);
137
+ } else if (lengthSize === 3) {
138
+ nalUnitLength = getUint24(dataView, offset, false);
139
+ } else {
140
+ assert(lengthSize === 4);
141
+ nalUnitLength = dataView.getUint32(offset, false);
142
+ }
143
+
144
+ offset += lengthSize;
145
+
146
+ yield {
147
+ offset,
148
+ length: nalUnitLength,
149
+ };
150
+
151
+ offset += nalUnitLength;
152
+ }
153
+ };
154
+
155
+ export const iterateAvcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
156
+ if (decoderConfig.description) {
157
+ const bytes = toUint8Array(decoderConfig.description);
158
+ const lengthSizeMinusOne = bytes[4]! & 0b11;
159
+ const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
160
+
161
+ return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);
162
+ } else {
163
+ return iterateNalUnitsInAnnexB(packetData);
164
+ }
165
+ };
166
+
167
+ export const extractNalUnitTypeForAvc = (byte: number) => {
168
+ return byte & 0x1F;
169
+ };
170
+
171
+ const removeEmulationPreventionBytes = (data: Uint8Array) => {
172
+ const result: number[] = [];
173
+ const len = data.length;
174
+
175
+ for (let i = 0; i < len; i++) {
176
+ // Look for the 0x000003 pattern
177
+ if (i + 2 < len && data[i] === 0x00 && data[i + 1] === 0x00 && data[i + 2] === 0x03) {
178
+ result.push(0x00, 0x00); // Push the first two bytes
179
+ i += 2; // Skip the 0x03 byte
180
+ } else {
181
+ result.push(data[i]!);
182
+ }
183
+ }
184
+
185
+ return new Uint8Array(result);
186
+ };
187
+
188
+ const ANNEX_B_START_CODE = new Uint8Array([0, 0, 0, 1]);
189
+
190
+ export const concatNalUnitsInAnnexB = (nalUnits: Uint8Array[]) => {
191
+ const totalLength = nalUnits.reduce((a, b) => a + ANNEX_B_START_CODE.byteLength + b.byteLength, 0);
192
+ const result = new Uint8Array(totalLength);
193
+ let offset = 0;
194
+
195
+ for (const nalUnit of nalUnits) {
196
+ result.set(ANNEX_B_START_CODE, offset);
197
+ offset += ANNEX_B_START_CODE.byteLength;
198
+
199
+ result.set(nalUnit, offset);
200
+ offset += nalUnit.byteLength;
201
+ }
202
+
203
+ return result;
204
+ };
205
+
206
+ export const concatNalUnitsInLengthPrefixed = (nalUnits: Uint8Array[], lengthSize: 1 | 2 | 3 | 4) => {
207
+ const totalLength = nalUnits.reduce((a, b) => a + lengthSize + b.byteLength, 0);
208
+ const result = new Uint8Array(totalLength);
209
+ let offset = 0;
210
+
211
+ for (const nalUnit of nalUnits) {
212
+ const dataView = new DataView(result.buffer, result.byteOffset, result.byteLength);
213
+
214
+ switch (lengthSize) {
215
+ case 1:
216
+ dataView.setUint8(offset, nalUnit.byteLength);
217
+ break;
218
+ case 2:
219
+ dataView.setUint16(offset, nalUnit.byteLength, false);
220
+ break;
221
+ case 3:
222
+ setUint24(dataView, offset, nalUnit.byteLength, false);
223
+ break;
224
+ case 4:
225
+ dataView.setUint32(offset, nalUnit.byteLength, false);
226
+ break;
227
+ }
228
+
229
+ offset += lengthSize;
230
+
231
+ result.set(nalUnit, offset);
232
+ offset += nalUnit.byteLength;
233
+ }
234
+
235
+ return result;
236
+ };
237
+
238
+ // Data specified in ISO 14496-15
239
+ export type AvcDecoderConfigurationRecord = {
240
+ configurationVersion: number;
241
+ avcProfileIndication: number;
242
+ profileCompatibility: number;
243
+ avcLevelIndication: number;
244
+ lengthSizeMinusOne: number;
245
+ sequenceParameterSets: Uint8Array[];
246
+ pictureParameterSets: Uint8Array[];
247
+
248
+ // Fields only for specific profiles:
249
+ chromaFormat: number | null;
250
+ bitDepthLumaMinus8: number | null;
251
+ bitDepthChromaMinus8: number | null;
252
+ sequenceParameterSetExt: Uint8Array[] | null;
253
+ };
254
+
255
+ export const concatAvcNalUnits = (nalUnits: Uint8Array[], decoderConfig: VideoDecoderConfig) => {
256
+ if (decoderConfig.description) {
257
+ // Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
258
+
259
+ const bytes = toUint8Array(decoderConfig.description);
260
+ const lengthSizeMinusOne = bytes[4]! & 0b11;
261
+ const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
262
+
263
+ return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
264
+ } else {
265
+ // Stream is in Annex B format
266
+ return concatNalUnitsInAnnexB(nalUnits);
267
+ }
268
+ };
269
+
270
+ /** Builds an AvcDecoderConfigurationRecord from an AVC packet in Annex B format. */
271
+ export const extractAvcDecoderConfigurationRecord = (packetData: Uint8Array): AvcDecoderConfigurationRecord | null => {
272
+ try {
273
+ const spsUnits: Uint8Array[] = [];
274
+ const ppsUnits: Uint8Array[] = [];
275
+ const spsExtUnits: Uint8Array[] = [];
276
+
277
+ for (const loc of iterateNalUnitsInAnnexB(packetData)) {
278
+ const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
279
+ const type = extractNalUnitTypeForAvc(nalUnit[0]!);
280
+
281
+ if (type === AvcNalUnitType.SPS) {
282
+ spsUnits.push(nalUnit);
283
+ } else if (type === AvcNalUnitType.PPS) {
284
+ ppsUnits.push(nalUnit);
285
+ } else if (type === AvcNalUnitType.SPS_EXT) {
286
+ spsExtUnits.push(nalUnit);
287
+ }
288
+ }
289
+
290
+ if (spsUnits.length === 0) {
291
+ return null;
292
+ }
293
+
294
+ if (ppsUnits.length === 0) {
295
+ return null;
296
+ }
297
+
298
+ // Let's get the first SPS for profile and level information
299
+ const spsData = spsUnits[0]!;
300
+ const spsInfo = parseAvcSps(spsData);
301
+ assert(spsInfo !== null);
302
+
303
+ const hasExtendedData = spsInfo.profileIdc === 100
304
+ || spsInfo.profileIdc === 110
305
+ || spsInfo.profileIdc === 122
306
+ || spsInfo.profileIdc === 144;
307
+
308
+ return {
309
+ configurationVersion: 1,
310
+ avcProfileIndication: spsInfo.profileIdc,
311
+ profileCompatibility: spsInfo.constraintFlags,
312
+ avcLevelIndication: spsInfo.levelIdc,
313
+ lengthSizeMinusOne: 3, // Typically 4 bytes for length field
314
+ sequenceParameterSets: spsUnits,
315
+ pictureParameterSets: ppsUnits,
316
+ chromaFormat: hasExtendedData ? spsInfo.chromaFormatIdc : null,
317
+ bitDepthLumaMinus8: hasExtendedData ? spsInfo.bitDepthLumaMinus8 : null,
318
+ bitDepthChromaMinus8: hasExtendedData ? spsInfo.bitDepthChromaMinus8 : null,
319
+ sequenceParameterSetExt: hasExtendedData ? spsExtUnits : null,
320
+ };
321
+ } catch (error) {
322
+ Logging._error('Error building AVC Decoder Configuration Record:', error);
323
+ return null;
324
+ }
325
+ };
326
+
327
+ /** Serializes an AvcDecoderConfigurationRecord into the format specified in Section 5.3.3.1 of ISO 14496-15. */
328
+ export const serializeAvcDecoderConfigurationRecord = (record: AvcDecoderConfigurationRecord) => {
329
+ const bytes: number[] = [];
330
+
331
+ // Write header
332
+ bytes.push(record.configurationVersion);
333
+ bytes.push(record.avcProfileIndication);
334
+ bytes.push(record.profileCompatibility);
335
+ bytes.push(record.avcLevelIndication);
336
+ bytes.push(0xFC | (record.lengthSizeMinusOne & 0x03)); // Reserved bits (6) + lengthSizeMinusOne (2)
337
+
338
+ // Reserved bits (3) + numOfSequenceParameterSets (5)
339
+ bytes.push(0xE0 | (record.sequenceParameterSets.length & 0x1F));
340
+
341
+ // Write SPS
342
+ for (const sps of record.sequenceParameterSets) {
343
+ const length = sps.byteLength;
344
+ bytes.push(length >> 8); // High byte
345
+ bytes.push(length & 0xFF); // Low byte
346
+
347
+ for (let i = 0; i < length; i++) {
348
+ bytes.push(sps[i]!);
349
+ }
350
+ }
351
+
352
+ bytes.push(record.pictureParameterSets.length);
353
+
354
+ // Write PPS
355
+ for (const pps of record.pictureParameterSets) {
356
+ const length = pps.byteLength;
357
+ bytes.push(length >> 8); // High byte
358
+ bytes.push(length & 0xFF); // Low byte
359
+
360
+ for (let i = 0; i < length; i++) {
361
+ bytes.push(pps[i]!);
362
+ }
363
+ }
364
+
365
+ if (
366
+ record.avcProfileIndication === 100
367
+ || record.avcProfileIndication === 110
368
+ || record.avcProfileIndication === 122
369
+ || record.avcProfileIndication === 144
370
+ ) {
371
+ assert(record.chromaFormat !== null);
372
+ assert(record.bitDepthLumaMinus8 !== null);
373
+ assert(record.bitDepthChromaMinus8 !== null);
374
+ assert(record.sequenceParameterSetExt !== null);
375
+
376
+ bytes.push(0xFC | (record.chromaFormat & 0x03)); // Reserved bits + chroma_format
377
+ bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07)); // Reserved bits + bit_depth_luma_minus8
378
+ bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07)); // Reserved bits + bit_depth_chroma_minus8
379
+
380
+ bytes.push(record.sequenceParameterSetExt.length);
381
+
382
+ // Write SPS Ext
383
+ for (const spsExt of record.sequenceParameterSetExt) {
384
+ const length = spsExt.byteLength;
385
+ bytes.push(length >> 8); // High byte
386
+ bytes.push(length & 0xFF); // Low byte
387
+
388
+ for (let i = 0; i < length; i++) {
389
+ bytes.push(spsExt[i]!);
390
+ }
391
+ }
392
+ }
393
+
394
+ return new Uint8Array(bytes);
395
+ };
396
+
397
+ /** Deserializes an AvcDecoderConfigurationRecord from the format specified in Section 5.3.3.1 of ISO 14496-15. */
398
+ export const deserializeAvcDecoderConfigurationRecord = (data: Uint8Array): AvcDecoderConfigurationRecord | null => {
399
+ try {
400
+ const view = toDataView(data);
401
+ let offset = 0;
402
+
403
+ // Read header
404
+ const configurationVersion = view.getUint8(offset++);
405
+ const avcProfileIndication = view.getUint8(offset++);
406
+ const profileCompatibility = view.getUint8(offset++);
407
+ const avcLevelIndication = view.getUint8(offset++);
408
+ const lengthSizeMinusOne = view.getUint8(offset++) & 0x03;
409
+
410
+ const numOfSequenceParameterSets = view.getUint8(offset++) & 0x1F;
411
+
412
+ // Read SPS
413
+ const sequenceParameterSets: Uint8Array[] = [];
414
+ for (let i = 0; i < numOfSequenceParameterSets; i++) {
415
+ const length = view.getUint16(offset, false);
416
+ offset += 2;
417
+
418
+ sequenceParameterSets.push(data.subarray(offset, offset + length));
419
+ offset += length;
420
+ }
421
+
422
+ const numOfPictureParameterSets = view.getUint8(offset++);
423
+
424
+ // Read PPS
425
+ const pictureParameterSets: Uint8Array[] = [];
426
+ for (let i = 0; i < numOfPictureParameterSets; i++) {
427
+ const length = view.getUint16(offset, false);
428
+ offset += 2;
429
+
430
+ pictureParameterSets.push(data.subarray(offset, offset + length));
431
+ offset += length;
432
+ }
433
+
434
+ const record: AvcDecoderConfigurationRecord = {
435
+ configurationVersion,
436
+ avcProfileIndication,
437
+ profileCompatibility,
438
+ avcLevelIndication,
439
+ lengthSizeMinusOne,
440
+ sequenceParameterSets,
441
+ pictureParameterSets,
442
+ chromaFormat: null,
443
+ bitDepthLumaMinus8: null,
444
+ bitDepthChromaMinus8: null,
445
+ sequenceParameterSetExt: null,
446
+ };
447
+
448
+ // Check if there are extended profile fields
449
+ if (
450
+ (
451
+ avcProfileIndication === 100
452
+ || avcProfileIndication === 110
453
+ || avcProfileIndication === 122
454
+ || avcProfileIndication === 144
455
+ )
456
+ && offset + 4 <= data.length
457
+ ) {
458
+ const chromaFormat = view.getUint8(offset++) & 0x03;
459
+ const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;
460
+ const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;
461
+ const numOfSequenceParameterSetExt = view.getUint8(offset++);
462
+
463
+ record.chromaFormat = chromaFormat;
464
+ record.bitDepthLumaMinus8 = bitDepthLumaMinus8;
465
+ record.bitDepthChromaMinus8 = bitDepthChromaMinus8;
466
+
467
+ // Read SPS Ext
468
+ const sequenceParameterSetExt: Uint8Array[] = [];
469
+ for (let i = 0; i < numOfSequenceParameterSetExt; i++) {
470
+ const length = view.getUint16(offset, false);
471
+ offset += 2;
472
+
473
+ sequenceParameterSetExt.push(data.subarray(offset, offset + length));
474
+ offset += length;
475
+ }
476
+
477
+ record.sequenceParameterSetExt = sequenceParameterSetExt;
478
+ }
479
+
480
+ return record;
481
+ } catch (error) {
482
+ Logging._error('Error deserializing AVC Decoder Configuration Record:', error);
483
+ return null;
484
+ }
485
+ };
486
+
487
+ export type AvcSpsInfo = {
488
+ profileIdc: number;
489
+ constraintFlags: number;
490
+ levelIdc: number;
491
+ frameMbsOnlyFlag: number;
492
+ chromaFormatIdc: number;
493
+ bitDepthLumaMinus8: number;
494
+ bitDepthChromaMinus8: number;
495
+ codedWidth: number;
496
+ codedHeight: number;
497
+ displayWidth: number;
498
+ displayHeight: number;
499
+ pixelAspectRatio: Rational;
500
+ colourPrimaries: number;
501
+ transferCharacteristics: number;
502
+ matrixCoefficients: number;
503
+ fullRangeFlag: number;
504
+ numReorderFrames: number;
505
+ maxDecFrameBuffering: number;
506
+ };
507
+
508
+ const AVC_HEVC_ASPECT_RATIO_IDC_TABLE: Partial<Record<number, Rational>> = {
509
+ 1: { num: 1, den: 1 },
510
+ 2: { num: 12, den: 11 },
511
+ 3: { num: 10, den: 11 },
512
+ 4: { num: 16, den: 11 },
513
+ 5: { num: 40, den: 33 },
514
+ 6: { num: 24, den: 11 },
515
+ 7: { num: 20, den: 11 },
516
+ 8: { num: 32, den: 11 },
517
+ 9: { num: 80, den: 33 },
518
+ 10: { num: 18, den: 11 },
519
+ 11: { num: 15, den: 11 },
520
+ 12: { num: 64, den: 33 },
521
+ 13: { num: 160, den: 99 },
522
+ 14: { num: 4, den: 3 },
523
+ 15: { num: 3, den: 2 },
524
+ 16: { num: 2, den: 1 },
525
+ };
526
+
527
+ /** Parses an AVC SPS (Sequence Parameter Set) to extract basic information. */
528
+ export const parseAvcSps = (sps: Uint8Array): AvcSpsInfo | null => {
529
+ try {
530
+ const bitstream = new Bitstream(removeEmulationPreventionBytes(sps));
531
+
532
+ bitstream.skipBits(1); // forbidden_zero_bit
533
+ bitstream.skipBits(2); // nal_ref_idc
534
+ const nalUnitType = bitstream.readBits(5);
535
+
536
+ if (nalUnitType !== 7) { // SPS NAL unit type is 7
537
+ return null;
538
+ }
539
+
540
+ const profileIdc = bitstream.readAlignedByte();
541
+ const constraintFlags = bitstream.readAlignedByte();
542
+ const levelIdc = bitstream.readAlignedByte();
543
+
544
+ readExpGolomb(bitstream); // seq_parameter_set_id
545
+
546
+ // "When chroma_format_idc is not present, it shall be inferred to be equal to 1 (4:2:0 chroma format)."
547
+ let chromaFormatIdc = 1;
548
+ // "When bit_depth_luma_minus8 is not present, it shall be inferred to be equal to 0.""
549
+ let bitDepthLumaMinus8 = 0;
550
+ // "When bit_depth_chroma_minus8 is not present, it shall be inferred to be equal to 0."
551
+ let bitDepthChromaMinus8 = 0;
552
+ // "When separate_colour_plane_flag is not present, it shall be inferred to be equal to 0."
553
+ let separateColourPlaneFlag = 0;
554
+
555
+ // Handle high profile chroma_format_idc
556
+ if (
557
+ profileIdc === 100
558
+ || profileIdc === 110
559
+ || profileIdc === 122
560
+ || profileIdc === 244
561
+ || profileIdc === 44
562
+ || profileIdc === 83
563
+ || profileIdc === 86
564
+ || profileIdc === 118
565
+ || profileIdc === 128
566
+ ) {
567
+ chromaFormatIdc = readExpGolomb(bitstream);
568
+ if (chromaFormatIdc === 3) {
569
+ separateColourPlaneFlag = bitstream.readBits(1);
570
+ }
571
+ bitDepthLumaMinus8 = readExpGolomb(bitstream);
572
+ bitDepthChromaMinus8 = readExpGolomb(bitstream);
573
+ bitstream.skipBits(1); // qpprime_y_zero_transform_bypass_flag
574
+ const seqScalingMatrixPresentFlag = bitstream.readBits(1);
575
+ if (seqScalingMatrixPresentFlag) {
576
+ for (let i = 0; i < (chromaFormatIdc !== 3 ? 8 : 12); i++) {
577
+ const seqScalingListPresentFlag = bitstream.readBits(1);
578
+ if (seqScalingListPresentFlag) {
579
+ const sizeOfScalingList = i < 6 ? 16 : 64;
580
+ let lastScale = 8;
581
+ let nextScale = 8;
582
+ for (let j = 0; j < sizeOfScalingList; j++) {
583
+ if (nextScale !== 0) {
584
+ const deltaScale = readSignedExpGolomb(bitstream);
585
+ nextScale = (lastScale + deltaScale + 256) % 256;
586
+ }
587
+ lastScale = nextScale === 0 ? lastScale : nextScale;
588
+ }
589
+ }
590
+ }
591
+ }
592
+ }
593
+
594
+ readExpGolomb(bitstream); // log2_max_frame_num_minus4
595
+
596
+ const picOrderCntType = readExpGolomb(bitstream);
597
+ if (picOrderCntType === 0) {
598
+ readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4
599
+ } else if (picOrderCntType === 1) {
600
+ bitstream.skipBits(1); // delta_pic_order_always_zero_flag
601
+ readSignedExpGolomb(bitstream); // offset_for_non_ref_pic
602
+ readSignedExpGolomb(bitstream); // offset_for_top_to_bottom_field
603
+ const numRefFramesInPicOrderCntCycle = readExpGolomb(bitstream);
604
+ for (let i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
605
+ readSignedExpGolomb(bitstream); // offset_for_ref_frame[i]
606
+ }
607
+ }
608
+
609
+ readExpGolomb(bitstream); // max_num_ref_frames
610
+ bitstream.skipBits(1); // gaps_in_frame_num_value_allowed_flag
611
+
612
+ const picWidthInMbsMinus1 = readExpGolomb(bitstream);
613
+ const picHeightInMapUnitsMinus1 = readExpGolomb(bitstream);
614
+ const codedWidth = 16 * (picWidthInMbsMinus1 + 1);
615
+ const codedHeight = 16 * (picHeightInMapUnitsMinus1 + 1);
616
+ let displayWidth = codedWidth;
617
+ let displayHeight = codedHeight;
618
+
619
+ const frameMbsOnlyFlag = bitstream.readBits(1);
620
+ if (!frameMbsOnlyFlag) {
621
+ bitstream.skipBits(1); // mb_adaptive_frame_field_flag
622
+ }
623
+
624
+ bitstream.skipBits(1); // direct_8x8_inference_flag
625
+ const frameCroppingFlag = bitstream.readBits(1);
626
+
627
+ if (frameCroppingFlag) {
628
+ const frameCropLeftOffset = readExpGolomb(bitstream);
629
+ const frameCropRightOffset = readExpGolomb(bitstream);
630
+ const frameCropTopOffset = readExpGolomb(bitstream);
631
+ const frameCropBottomOffset = readExpGolomb(bitstream);
632
+
633
+ let cropUnitX: number;
634
+ let cropUnitY: number;
635
+
636
+ const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;
637
+ if (chromaArrayType === 0) {
638
+ // "If ChromaArrayType is equal to 0, CropUnitX and CropUnitY are derived as:"
639
+ cropUnitX = 1;
640
+ cropUnitY = 2 - frameMbsOnlyFlag;
641
+ } else {
642
+ // "Otherwise (ChromaArrayType is equal to 1, 2, or 3), CropUnitX and CropUnitY are derived as:"
643
+ const subWidthC = chromaFormatIdc === 3 ? 1 : 2;
644
+ const subHeightC = chromaFormatIdc === 1 ? 2 : 1;
645
+
646
+ cropUnitX = subWidthC;
647
+ cropUnitY = subHeightC * (2 - frameMbsOnlyFlag);
648
+ }
649
+
650
+ displayWidth -= (cropUnitX * (frameCropLeftOffset + frameCropRightOffset));
651
+ displayHeight -= (cropUnitY * (frameCropTopOffset + frameCropBottomOffset));
652
+ }
653
+
654
+ // 2 = unspecified
655
+ let colourPrimaries = 2;
656
+ let transferCharacteristics = 2;
657
+ let matrixCoefficients = 2;
658
+ let fullRangeFlag = 0;
659
+ let pixelAspectRatio: Rational = { num: 1, den: 1 };
660
+
661
+ let numReorderFrames: number | null = null;
662
+ let maxDecFrameBuffering: number | null = null;
663
+
664
+ const vuiParametersPresentFlag = bitstream.readBits(1);
665
+ if (vuiParametersPresentFlag) {
666
+ const aspectRatioInfoPresentFlag = bitstream.readBits(1);
667
+ if (aspectRatioInfoPresentFlag) {
668
+ const aspectRatioIdc = bitstream.readBits(8);
669
+
670
+ if (aspectRatioIdc === 255) { // Extended_SAR
671
+ pixelAspectRatio = {
672
+ num: bitstream.readBits(16),
673
+ den: bitstream.readBits(16),
674
+ };
675
+ } else {
676
+ const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspectRatioIdc];
677
+ if (aspectRatio) {
678
+ pixelAspectRatio = aspectRatio;
679
+ }
680
+ }
681
+ }
682
+
683
+ const overscanInfoPresentFlag = bitstream.readBits(1);
684
+ if (overscanInfoPresentFlag) {
685
+ bitstream.skipBits(1); // overscan_appropriate_flag
686
+ }
687
+
688
+ const videoSignalTypePresentFlag = bitstream.readBits(1);
689
+ if (videoSignalTypePresentFlag) {
690
+ bitstream.skipBits(3); // video_format
691
+ fullRangeFlag = bitstream.readBits(1);
692
+ const colourDescriptionPresentFlag = bitstream.readBits(1);
693
+ if (colourDescriptionPresentFlag) {
694
+ colourPrimaries = bitstream.readBits(8);
695
+ transferCharacteristics = bitstream.readBits(8);
696
+ matrixCoefficients = bitstream.readBits(8);
697
+ }
698
+ }
699
+
700
+ const chromaLocInfoPresentFlag = bitstream.readBits(1);
701
+ if (chromaLocInfoPresentFlag) {
702
+ readExpGolomb(bitstream); // chroma_sample_loc_type_top_field
703
+ readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field
704
+ }
705
+
706
+ const timingInfoPresentFlag = bitstream.readBits(1);
707
+ if (timingInfoPresentFlag) {
708
+ bitstream.skipBits(32); // num_units_in_tick
709
+ bitstream.skipBits(32); // time_scale
710
+ bitstream.skipBits(1); // fixed_frame_rate_flag
711
+ }
712
+
713
+ const nalHrdParametersPresentFlag = bitstream.readBits(1);
714
+ if (nalHrdParametersPresentFlag) {
715
+ skipAvcHrdParameters(bitstream);
716
+ }
717
+
718
+ const vclHrdParametersPresentFlag = bitstream.readBits(1);
719
+ if (vclHrdParametersPresentFlag) {
720
+ skipAvcHrdParameters(bitstream);
721
+ }
722
+
723
+ if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) {
724
+ bitstream.skipBits(1); // low_delay_hrd_flag
725
+ }
726
+
727
+ bitstream.skipBits(1); // pic_struct_present_flag
728
+
729
+ const bitstreamRestrictionFlag = bitstream.readBits(1);
730
+ if (bitstreamRestrictionFlag) {
731
+ bitstream.skipBits(1); // motion_vectors_over_pic_boundaries_flag
732
+ readExpGolomb(bitstream); // max_bytes_per_pic_denom
733
+ readExpGolomb(bitstream); // max_bits_per_mb_denom
734
+ readExpGolomb(bitstream); // log2_max_mv_length_horizontal
735
+ readExpGolomb(bitstream); // log2_max_mv_length_vertical
736
+ numReorderFrames = readExpGolomb(bitstream);
737
+ maxDecFrameBuffering = readExpGolomb(bitstream);
738
+ }
739
+ }
740
+
741
+ if (numReorderFrames === null) {
742
+ assert(maxDecFrameBuffering === null);
743
+ const constraintSet3Flag = constraintFlags & 0b00010000;
744
+
745
+ if (
746
+ (profileIdc === 44 || profileIdc === 86 || profileIdc === 100
747
+ || profileIdc === 110 || profileIdc === 122 || profileIdc === 244
748
+ ) && constraintSet3Flag
749
+ ) {
750
+ // "If profile_idc is equal to 44, 86, 100, 110, 122, or 244 and constraint_set3_flag is equal to 1, the
751
+ // value of num_reorder_frames shall be inferred to be equal to 0."
752
+ numReorderFrames = 0;
753
+ maxDecFrameBuffering = 0;
754
+ } else {
755
+ const picWidthInMbs = picWidthInMbsMinus1 + 1;
756
+ const picHeightInMapUnits = picHeightInMapUnitsMinus1 + 1;
757
+ const frameHeightInMbs = (2 - frameMbsOnlyFlag) * picHeightInMapUnits;
758
+
759
+ const levelInfo = AVC_LEVEL_TABLE.find(
760
+ x => x.level >= levelIdc,
761
+ ) ?? last(AVC_LEVEL_TABLE)!;
762
+
763
+ // "MaxDpbFrames is equal to
764
+ // Min( MaxDpbMbs / ( picWidthInMbs * frameHeightInMbs ), 16 ) and MaxDpbMbs is given in Table A-1."
765
+ const maxDpbFrames = Math.min(
766
+ Math.floor(levelInfo.maxDpbMbs / (picWidthInMbs * frameHeightInMbs)),
767
+ 16,
768
+ );
769
+
770
+ // "Otherwise, [...] the value of num_reorder_frames shall be inferred to be equal to MaxDpbFrames."
771
+ numReorderFrames = maxDpbFrames;
772
+ maxDecFrameBuffering = maxDpbFrames;
773
+ }
774
+ }
775
+
776
+ assert(maxDecFrameBuffering !== null);
777
+
778
+ return {
779
+ profileIdc,
780
+ constraintFlags,
781
+ levelIdc,
782
+ frameMbsOnlyFlag,
783
+ chromaFormatIdc,
784
+ bitDepthLumaMinus8,
785
+ bitDepthChromaMinus8,
786
+ codedWidth,
787
+ codedHeight,
788
+ displayWidth,
789
+ displayHeight,
790
+ pixelAspectRatio,
791
+ colourPrimaries,
792
+ matrixCoefficients,
793
+ transferCharacteristics,
794
+ fullRangeFlag,
795
+ numReorderFrames,
796
+ maxDecFrameBuffering,
797
+ };
798
+ } catch (error) {
799
+ Logging._error('Error parsing AVC SPS:', error);
800
+ return null;
801
+ }
802
+ };
803
+
804
+ const skipAvcHrdParameters = (bitstream: Bitstream) => {
805
+ const cpb_cnt_minus1 = readExpGolomb(bitstream);
806
+ bitstream.skipBits(4); // bit_rate_scale
807
+ bitstream.skipBits(4); // cpb_size_scale
808
+
809
+ for (let i = 0; i <= cpb_cnt_minus1; i++) {
810
+ readExpGolomb(bitstream); // bit_rate_value_minus1[i]
811
+ readExpGolomb(bitstream); // cpb_size_value_minus1[i]
812
+ bitstream.skipBits(1); // cbr_flag[i]
813
+ }
814
+
815
+ bitstream.skipBits(5); // initial_cpb_removal_delay_length_minus1
816
+ bitstream.skipBits(5); // cpb_removal_delay_length_minus1
817
+ bitstream.skipBits(5); // dpb_output_delay_length_minus1
818
+ bitstream.skipBits(5); // time_offset_length
819
+ };
820
+
821
+ // Data specified in ISO 14496-15
822
+ export type HevcDecoderConfigurationRecord = {
823
+ configurationVersion: number;
824
+ generalProfileSpace: number;
825
+ generalTierFlag: number;
826
+ generalProfileIdc: number;
827
+ generalProfileCompatibilityFlags: number;
828
+ generalConstraintIndicatorFlags: Uint8Array; // 6 bytes long
829
+ generalLevelIdc: number;
830
+ minSpatialSegmentationIdc: number;
831
+ parallelismType: number;
832
+ chromaFormatIdc: number;
833
+ bitDepthLumaMinus8: number;
834
+ bitDepthChromaMinus8: number;
835
+ avgFrameRate: number;
836
+ constantFrameRate: number;
837
+ numTemporalLayers: number;
838
+ temporalIdNested: number;
839
+ lengthSizeMinusOne: number;
840
+ arrays: {
841
+ arrayCompleteness: number;
842
+ nalUnitType: number;
843
+ nalUnits: Uint8Array[];
844
+ }[];
845
+ };
846
+
847
+ export type HevcSpsInfo = {
848
+ displayWidth: number;
849
+ displayHeight: number;
850
+ pixelAspectRatio: Rational;
851
+ colourPrimaries: number;
852
+ transferCharacteristics: number;
853
+ matrixCoefficients: number;
854
+ fullRangeFlag: number;
855
+ maxDecFrameBuffering: number;
856
+ spsMaxSubLayersMinus1: number;
857
+ spsTemporalIdNestingFlag: number;
858
+ generalProfileSpace: number;
859
+ generalTierFlag: number;
860
+ generalProfileIdc: number;
861
+ generalProfileCompatibilityFlags: number;
862
+ generalConstraintIndicatorFlags: Uint8Array;
863
+ generalLevelIdc: number;
864
+ chromaFormatIdc: number;
865
+ bitDepthLumaMinus8: number;
866
+ bitDepthChromaMinus8: number;
867
+ minSpatialSegmentationIdc: number;
868
+ };
869
+
870
+ export const concatHevcNalUnits = (nalUnits: Uint8Array[], decoderConfig: VideoDecoderConfig) => {
871
+ if (decoderConfig.description) {
872
+ // Stream is length-prefixed. Let's extract the size of the length prefix from the decoder config
873
+
874
+ const bytes = toUint8Array(decoderConfig.description);
875
+ const lengthSizeMinusOne = bytes[21]! & 0b11;
876
+ const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
877
+
878
+ return concatNalUnitsInLengthPrefixed(nalUnits, lengthSize);
879
+ } else {
880
+ // Stream is in Annex B format
881
+ return concatNalUnitsInAnnexB(nalUnits);
882
+ }
883
+ };
884
+
885
+ export const iterateHevcNalUnits = (packetData: Uint8Array, decoderConfig: VideoDecoderConfig) => {
886
+ if (decoderConfig.description) {
887
+ const bytes = toUint8Array(decoderConfig.description);
888
+ const lengthSizeMinusOne = bytes[21]! & 0b11;
889
+ const lengthSize = (lengthSizeMinusOne + 1) as 1 | 2 | 3 | 4;
890
+
891
+ return iterateNalUnitsInLengthPrefixed(packetData, lengthSize);
892
+ } else {
893
+ return iterateNalUnitsInAnnexB(packetData);
894
+ }
895
+ };
896
+
897
+ export const extractNalUnitTypeForHevc = (byte: number) => {
898
+ return (byte >> 1) & 0x3F;
899
+ };
900
+
901
+ /** Parses an HEVC SPS (Sequence Parameter Set) to extract video information. */
902
+ export const parseHevcSps = (sps: Uint8Array): HevcSpsInfo | null => {
903
+ try {
904
+ const bitstream = new Bitstream(removeEmulationPreventionBytes(sps));
905
+
906
+ bitstream.skipBits(16); // NAL header
907
+
908
+ bitstream.readBits(4); // sps_video_parameter_set_id
909
+ const spsMaxSubLayersMinus1 = bitstream.readBits(3);
910
+ const spsTemporalIdNestingFlag = bitstream.readBits(1);
911
+
912
+ const {
913
+ general_profile_space,
914
+ general_tier_flag,
915
+ general_profile_idc,
916
+ general_profile_compatibility_flags,
917
+ general_constraint_indicator_flags,
918
+ general_level_idc,
919
+ } = parseProfileTierLevel(bitstream, spsMaxSubLayersMinus1);
920
+
921
+ readExpGolomb(bitstream); // sps_seq_parameter_set_id
922
+
923
+ const chromaFormatIdc = readExpGolomb(bitstream);
924
+ let separateColourPlaneFlag = 0;
925
+ if (chromaFormatIdc === 3) {
926
+ separateColourPlaneFlag = bitstream.readBits(1);
927
+ }
928
+
929
+ const picWidthInLumaSamples = readExpGolomb(bitstream);
930
+ const picHeightInLumaSamples = readExpGolomb(bitstream);
931
+
932
+ let displayWidth = picWidthInLumaSamples;
933
+ let displayHeight = picHeightInLumaSamples;
934
+
935
+ if (bitstream.readBits(1)) { // conformance_window_flag
936
+ const confWinLeftOffset = readExpGolomb(bitstream);
937
+ const confWinRightOffset = readExpGolomb(bitstream);
938
+ const confWinTopOffset = readExpGolomb(bitstream);
939
+ const confWinBottomOffset = readExpGolomb(bitstream);
940
+
941
+ // SubWidthC and SubHeightC depend on chroma_format_idc and separate_colour_plane_flag
942
+ let subWidthC = 1;
943
+ let subHeightC = 1;
944
+ const chromaArrayType = separateColourPlaneFlag === 0 ? chromaFormatIdc : 0;
945
+ if (chromaArrayType === 1) {
946
+ subWidthC = 2;
947
+ subHeightC = 2;
948
+ } else if (chromaArrayType === 2) {
949
+ subWidthC = 2;
950
+ subHeightC = 1;
951
+ }
952
+
953
+ displayWidth -= (confWinLeftOffset + confWinRightOffset) * subWidthC;
954
+ displayHeight -= (confWinTopOffset + confWinBottomOffset) * subHeightC;
955
+ }
956
+
957
+ const bitDepthLumaMinus8 = readExpGolomb(bitstream);
958
+ const bitDepthChromaMinus8 = readExpGolomb(bitstream);
959
+ readExpGolomb(bitstream); // log2_max_pic_order_cnt_lsb_minus4
960
+
961
+ const spsSubLayerOrderingInfoPresentFlag = bitstream.readBits(1);
962
+ const startI = spsSubLayerOrderingInfoPresentFlag ? 0 : spsMaxSubLayersMinus1;
963
+ let spsMaxNumReorderPics = 0;
964
+ for (let i = startI; i <= spsMaxSubLayersMinus1; i++) {
965
+ readExpGolomb(bitstream); // sps_max_dec_pic_buffering_minus1[i]
966
+ spsMaxNumReorderPics = readExpGolomb(bitstream); // sps_max_num_reorder_pics[i]
967
+ readExpGolomb(bitstream); // sps_max_latency_increase_plus1[i]
968
+ }
969
+
970
+ readExpGolomb(bitstream); // log2_min_luma_coding_block_size_minus3
971
+ readExpGolomb(bitstream); // log2_diff_max_min_luma_coding_block_size
972
+ readExpGolomb(bitstream); // log2_min_luma_transform_block_size_minus2
973
+ readExpGolomb(bitstream); // log2_diff_max_min_luma_transform_block_size
974
+ readExpGolomb(bitstream); // max_transform_hierarchy_depth_inter
975
+ readExpGolomb(bitstream); // max_transform_hierarchy_depth_intra
976
+
977
+ if (bitstream.readBits(1)) { // scaling_list_enabled_flag
978
+ if (bitstream.readBits(1)) {
979
+ skipScalingListData(bitstream);
980
+ }
981
+ }
982
+
983
+ bitstream.skipBits(1); // amp_enabled_flag
984
+ bitstream.skipBits(1); // sample_adaptive_offset_enabled_flag
985
+
986
+ if (bitstream.readBits(1)) { // pcm_enabled_flag
987
+ bitstream.skipBits(4); // pcm_sample_bit_depth_luma_minus1
988
+ bitstream.skipBits(4); // pcm_sample_bit_depth_chroma_minus1
989
+ readExpGolomb(bitstream); // log2_min_pcm_luma_coding_block_size_minus3
990
+ readExpGolomb(bitstream); // log2_diff_max_min_pcm_luma_coding_block_size
991
+ bitstream.skipBits(1); // pcm_loop_filter_disabled_flag
992
+ }
993
+
994
+ const numShortTermRefPicSets = readExpGolomb(bitstream);
995
+ skipAllStRefPicSets(bitstream, numShortTermRefPicSets);
996
+
997
+ if (bitstream.readBits(1)) { // long_term_ref_pics_present_flag
998
+ const numLongTermRefPicsSps = readExpGolomb(bitstream);
999
+ for (let i = 0; i < numLongTermRefPicsSps; i++) {
1000
+ readExpGolomb(bitstream); // lt_ref_pic_poc_lsb_sps[i]
1001
+ bitstream.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]
1002
+ }
1003
+ }
1004
+
1005
+ bitstream.skipBits(1); // sps_temporal_mvp_enabled_flag
1006
+ bitstream.skipBits(1); // strong_intra_smoothing_enabled_flag
1007
+
1008
+ let colourPrimaries = 2;
1009
+ let transferCharacteristics = 2;
1010
+ let matrixCoefficients = 2;
1011
+ let fullRangeFlag = 0;
1012
+ let minSpatialSegmentationIdc = 0;
1013
+ let pixelAspectRatio: Rational = { num: 1, den: 1 };
1014
+
1015
+ if (bitstream.readBits(1)) { // vui_parameters_present_flag
1016
+ const vui = parseHevcVui(bitstream, spsMaxSubLayersMinus1);
1017
+ pixelAspectRatio = vui.pixelAspectRatio;
1018
+ colourPrimaries = vui.colourPrimaries;
1019
+ transferCharacteristics = vui.transferCharacteristics;
1020
+ matrixCoefficients = vui.matrixCoefficients;
1021
+ fullRangeFlag = vui.fullRangeFlag;
1022
+ minSpatialSegmentationIdc = vui.minSpatialSegmentationIdc;
1023
+ }
1024
+
1025
+ return {
1026
+ displayWidth,
1027
+ displayHeight,
1028
+ pixelAspectRatio,
1029
+ colourPrimaries,
1030
+ transferCharacteristics,
1031
+ matrixCoefficients,
1032
+ fullRangeFlag,
1033
+ maxDecFrameBuffering: spsMaxNumReorderPics + 1,
1034
+ spsMaxSubLayersMinus1,
1035
+ spsTemporalIdNestingFlag,
1036
+ generalProfileSpace: general_profile_space,
1037
+ generalTierFlag: general_tier_flag,
1038
+ generalProfileIdc: general_profile_idc,
1039
+ generalProfileCompatibilityFlags: general_profile_compatibility_flags,
1040
+ generalConstraintIndicatorFlags: general_constraint_indicator_flags,
1041
+ generalLevelIdc: general_level_idc,
1042
+ chromaFormatIdc,
1043
+ bitDepthLumaMinus8,
1044
+ bitDepthChromaMinus8,
1045
+ minSpatialSegmentationIdc,
1046
+ };
1047
+ } catch (error) {
1048
+ Logging._error('Error parsing HEVC SPS:', error);
1049
+ return null;
1050
+ }
1051
+ };
1052
+
1053
+ /** Builds a HevcDecoderConfigurationRecord from an HEVC packet in Annex B format. */
1054
+ export const extractHevcDecoderConfigurationRecord = (packetData: Uint8Array) => {
1055
+ try {
1056
+ const vpsUnits: Uint8Array[] = [];
1057
+ const spsUnits: Uint8Array[] = [];
1058
+ const ppsUnits: Uint8Array[] = [];
1059
+ const seiUnits: Uint8Array[] = [];
1060
+
1061
+ for (const loc of iterateNalUnitsInAnnexB(packetData)) {
1062
+ const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
1063
+ const type = extractNalUnitTypeForHevc(nalUnit[0]!);
1064
+
1065
+ if (type === HevcNalUnitType.VPS_NUT) {
1066
+ vpsUnits.push(nalUnit);
1067
+ } else if (type === HevcNalUnitType.SPS_NUT) {
1068
+ spsUnits.push(nalUnit);
1069
+ } else if (type === HevcNalUnitType.PPS_NUT) {
1070
+ ppsUnits.push(nalUnit);
1071
+ } else if (type === HevcNalUnitType.PREFIX_SEI_NUT || type === HevcNalUnitType.SUFFIX_SEI_NUT) {
1072
+ seiUnits.push(nalUnit);
1073
+ }
1074
+ }
1075
+
1076
+ if (spsUnits.length === 0 || ppsUnits.length === 0) return null;
1077
+
1078
+ const spsInfo = parseHevcSps(spsUnits[0]!);
1079
+ if (!spsInfo) return null;
1080
+
1081
+ // Parse PPS for parallelismType
1082
+ let parallelismType = 0;
1083
+ if (ppsUnits.length > 0) {
1084
+ const pps = ppsUnits[0]!;
1085
+ const ppsBitstream = new Bitstream(removeEmulationPreventionBytes(pps));
1086
+
1087
+ ppsBitstream.skipBits(16); // NAL header
1088
+ readExpGolomb(ppsBitstream); // pps_pic_parameter_set_id
1089
+ readExpGolomb(ppsBitstream); // pps_seq_parameter_set_id
1090
+ ppsBitstream.skipBits(1); // dependent_slice_segments_enabled_flag
1091
+ ppsBitstream.skipBits(1); // output_flag_present_flag
1092
+ ppsBitstream.skipBits(3); // num_extra_slice_header_bits
1093
+ ppsBitstream.skipBits(1); // sign_data_hiding_enabled_flag
1094
+ ppsBitstream.skipBits(1); // cabac_init_present_flag
1095
+ readExpGolomb(ppsBitstream); // num_ref_idx_l0_default_active_minus1
1096
+ readExpGolomb(ppsBitstream); // num_ref_idx_l1_default_active_minus1
1097
+ readSignedExpGolomb(ppsBitstream); // init_qp_minus26
1098
+ ppsBitstream.skipBits(1); // constrained_intra_pred_flag
1099
+ ppsBitstream.skipBits(1); // transform_skip_enabled_flag
1100
+ if (ppsBitstream.readBits(1)) { // cu_qp_delta_enabled_flag
1101
+ readExpGolomb(ppsBitstream); // diff_cu_qp_delta_depth
1102
+ }
1103
+ readSignedExpGolomb(ppsBitstream); // pps_cb_qp_offset
1104
+ readSignedExpGolomb(ppsBitstream); // pps_cr_qp_offset
1105
+ ppsBitstream.skipBits(1); // pps_slice_chroma_qp_offsets_present_flag
1106
+ ppsBitstream.skipBits(1); // weighted_pred_flag
1107
+ ppsBitstream.skipBits(1); // weighted_bipred_flag
1108
+ ppsBitstream.skipBits(1); // transquant_bypass_enabled_flag
1109
+ const tiles_enabled_flag = ppsBitstream.readBits(1);
1110
+ const entropy_coding_sync_enabled_flag = ppsBitstream.readBits(1);
1111
+
1112
+ if (!tiles_enabled_flag && !entropy_coding_sync_enabled_flag) parallelismType = 0;
1113
+ else if (tiles_enabled_flag && !entropy_coding_sync_enabled_flag) parallelismType = 2;
1114
+ else if (!tiles_enabled_flag && entropy_coding_sync_enabled_flag) parallelismType = 3;
1115
+ else parallelismType = 0;
1116
+ }
1117
+
1118
+ const arrays = [
1119
+ ...(vpsUnits.length
1120
+ ? [
1121
+ {
1122
+ arrayCompleteness: 1,
1123
+ nalUnitType: HevcNalUnitType.VPS_NUT,
1124
+ nalUnits: vpsUnits,
1125
+ },
1126
+ ]
1127
+ : []),
1128
+ ...(spsUnits.length
1129
+ ? [
1130
+ {
1131
+ arrayCompleteness: 1,
1132
+ nalUnitType: HevcNalUnitType.SPS_NUT,
1133
+ nalUnits: spsUnits,
1134
+ },
1135
+ ]
1136
+ : []),
1137
+ ...(ppsUnits.length
1138
+ ? [
1139
+ {
1140
+ arrayCompleteness: 1,
1141
+ nalUnitType: HevcNalUnitType.PPS_NUT,
1142
+ nalUnits: ppsUnits,
1143
+ },
1144
+ ]
1145
+ : []),
1146
+ ...(seiUnits.length
1147
+ ? [
1148
+ {
1149
+ arrayCompleteness: 1,
1150
+ nalUnitType: extractNalUnitTypeForHevc(seiUnits[0]![0]!),
1151
+ nalUnits: seiUnits,
1152
+ },
1153
+ ]
1154
+ : []),
1155
+ ];
1156
+
1157
+ const record: HevcDecoderConfigurationRecord = {
1158
+ configurationVersion: 1,
1159
+ generalProfileSpace: spsInfo.generalProfileSpace,
1160
+ generalTierFlag: spsInfo.generalTierFlag,
1161
+ generalProfileIdc: spsInfo.generalProfileIdc,
1162
+ generalProfileCompatibilityFlags: spsInfo.generalProfileCompatibilityFlags,
1163
+ generalConstraintIndicatorFlags: spsInfo.generalConstraintIndicatorFlags,
1164
+ generalLevelIdc: spsInfo.generalLevelIdc,
1165
+ minSpatialSegmentationIdc: spsInfo.minSpatialSegmentationIdc,
1166
+ parallelismType,
1167
+ chromaFormatIdc: spsInfo.chromaFormatIdc,
1168
+ bitDepthLumaMinus8: spsInfo.bitDepthLumaMinus8,
1169
+ bitDepthChromaMinus8: spsInfo.bitDepthChromaMinus8,
1170
+ avgFrameRate: 0,
1171
+ constantFrameRate: 0,
1172
+ numTemporalLayers: spsInfo.spsMaxSubLayersMinus1 + 1,
1173
+ temporalIdNested: spsInfo.spsTemporalIdNestingFlag,
1174
+ lengthSizeMinusOne: 3,
1175
+ arrays,
1176
+ };
1177
+
1178
+ return record;
1179
+ } catch (error) {
1180
+ Logging._error('Error building HEVC Decoder Configuration Record:', error);
1181
+ return null;
1182
+ }
1183
+ };
1184
+
1185
+ const parseProfileTierLevel = (
1186
+ bitstream: Bitstream,
1187
+ maxNumSubLayersMinus1: number,
1188
+ ) => {
1189
+ const general_profile_space = bitstream.readBits(2);
1190
+ const general_tier_flag = bitstream.readBits(1);
1191
+ const general_profile_idc = bitstream.readBits(5);
1192
+
1193
+ let general_profile_compatibility_flags = 0;
1194
+ for (let i = 0; i < 32; i++) {
1195
+ general_profile_compatibility_flags = (general_profile_compatibility_flags << 1) | bitstream.readBits(1);
1196
+ }
1197
+
1198
+ const general_constraint_indicator_flags = new Uint8Array(6);
1199
+ for (let i = 0; i < 6; i++) {
1200
+ general_constraint_indicator_flags[i] = bitstream.readBits(8);
1201
+ }
1202
+
1203
+ const general_level_idc = bitstream.readBits(8);
1204
+
1205
+ const sub_layer_profile_present_flag: number[] = [];
1206
+ const sub_layer_level_present_flag: number[] = [];
1207
+ for (let i = 0; i < maxNumSubLayersMinus1; i++) {
1208
+ sub_layer_profile_present_flag.push(bitstream.readBits(1));
1209
+ sub_layer_level_present_flag.push(bitstream.readBits(1));
1210
+ }
1211
+ if (maxNumSubLayersMinus1 > 0) {
1212
+ for (let i = maxNumSubLayersMinus1; i < 8; i++) {
1213
+ bitstream.skipBits(2); // reserved_zero_2bits
1214
+ }
1215
+ }
1216
+ for (let i = 0; i < maxNumSubLayersMinus1; i++) {
1217
+ if (sub_layer_profile_present_flag[i]) bitstream.skipBits(88);
1218
+ if (sub_layer_level_present_flag[i]) bitstream.skipBits(8);
1219
+ }
1220
+
1221
+ return {
1222
+ general_profile_space,
1223
+ general_tier_flag,
1224
+ general_profile_idc,
1225
+ general_profile_compatibility_flags,
1226
+ general_constraint_indicator_flags,
1227
+ general_level_idc,
1228
+ };
1229
+ };
1230
+
1231
+ const skipScalingListData = (bitstream: Bitstream) => {
1232
+ for (let sizeId = 0; sizeId < 4; sizeId++) {
1233
+ for (let matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {
1234
+ const scaling_list_pred_mode_flag = bitstream.readBits(1);
1235
+ if (!scaling_list_pred_mode_flag) {
1236
+ readExpGolomb(bitstream); // scaling_list_pred_matrix_id_delta
1237
+ } else {
1238
+ const coefNum = Math.min(64, 1 << (4 + (sizeId << 1)));
1239
+ if (sizeId > 1) {
1240
+ readSignedExpGolomb(bitstream); // scaling_list_dc_coef_minus8
1241
+ }
1242
+ for (let i = 0; i < coefNum; i++) {
1243
+ readSignedExpGolomb(bitstream); // scaling_list_delta_coef
1244
+ }
1245
+ }
1246
+ }
1247
+ }
1248
+ };
1249
+
1250
+ const skipAllStRefPicSets = (bitstream: Bitstream, num_short_term_ref_pic_sets: number) => {
1251
+ const NumDeltaPocs: number[] = [];
1252
+ for (let stRpsIdx = 0; stRpsIdx < num_short_term_ref_pic_sets; stRpsIdx++) {
1253
+ NumDeltaPocs[stRpsIdx] = skipStRefPicSet(bitstream, stRpsIdx, num_short_term_ref_pic_sets, NumDeltaPocs);
1254
+ }
1255
+ };
1256
+
1257
+ const skipStRefPicSet = (
1258
+ bitstream: Bitstream,
1259
+ stRpsIdx: number,
1260
+ num_short_term_ref_pic_sets: number,
1261
+ NumDeltaPocs: number[],
1262
+ ) => {
1263
+ let NumDeltaPocsThis = 0;
1264
+ let inter_ref_pic_set_prediction_flag = 0;
1265
+ let RefRpsIdx = 0;
1266
+
1267
+ if (stRpsIdx !== 0) {
1268
+ inter_ref_pic_set_prediction_flag = bitstream.readBits(1);
1269
+ }
1270
+ if (inter_ref_pic_set_prediction_flag) {
1271
+ if (stRpsIdx === num_short_term_ref_pic_sets) {
1272
+ const delta_idx_minus1 = readExpGolomb(bitstream);
1273
+ RefRpsIdx = stRpsIdx - (delta_idx_minus1 + 1);
1274
+ } else {
1275
+ RefRpsIdx = stRpsIdx - 1;
1276
+ }
1277
+ bitstream.readBits(1); // delta_rps_sign
1278
+ readExpGolomb(bitstream); // abs_delta_rps_minus1
1279
+
1280
+ // The number of iterations is NumDeltaPocs[RefRpsIdx] + 1
1281
+ const numDelta = NumDeltaPocs[RefRpsIdx] ?? 0;
1282
+ for (let j = 0; j <= numDelta; j++) {
1283
+ const used_by_curr_pic_flag = bitstream.readBits(1);
1284
+ if (!used_by_curr_pic_flag) {
1285
+ bitstream.readBits(1); // use_delta_flag
1286
+ }
1287
+ }
1288
+ NumDeltaPocsThis = NumDeltaPocs[RefRpsIdx]!;
1289
+ } else {
1290
+ const num_negative_pics = readExpGolomb(bitstream);
1291
+ const num_positive_pics = readExpGolomb(bitstream);
1292
+
1293
+ for (let i = 0; i < num_negative_pics; i++) {
1294
+ readExpGolomb(bitstream); // delta_poc_s0_minus1[i]
1295
+ bitstream.readBits(1); // used_by_curr_pic_s0_flag[i]
1296
+ }
1297
+ for (let i = 0; i < num_positive_pics; i++) {
1298
+ readExpGolomb(bitstream); // delta_poc_s1_minus1[i]
1299
+ bitstream.readBits(1); // used_by_curr_pic_s1_flag[i]
1300
+ }
1301
+ NumDeltaPocsThis = num_negative_pics + num_positive_pics;
1302
+ }
1303
+ return NumDeltaPocsThis;
1304
+ };
1305
+
1306
+ const parseHevcVui = (bitstream: Bitstream, sps_max_sub_layers_minus1: number) => {
1307
+ // Defaults: 2 = unspecified
1308
+ let colourPrimaries = 2;
1309
+ let transferCharacteristics = 2;
1310
+ let matrixCoefficients = 2;
1311
+ let fullRangeFlag = 0;
1312
+ let minSpatialSegmentationIdc = 0;
1313
+ let pixelAspectRatio: Rational = { num: 1, den: 1 };
1314
+
1315
+ if (bitstream.readBits(1)) { // aspect_ratio_info_present_flag
1316
+ const aspect_ratio_idc = bitstream.readBits(8);
1317
+ if (aspect_ratio_idc === 255) {
1318
+ pixelAspectRatio = {
1319
+ num: bitstream.readBits(16),
1320
+ den: bitstream.readBits(16),
1321
+ };
1322
+ } else {
1323
+ const aspectRatio = AVC_HEVC_ASPECT_RATIO_IDC_TABLE[aspect_ratio_idc];
1324
+ if (aspectRatio) {
1325
+ pixelAspectRatio = aspectRatio;
1326
+ }
1327
+ }
1328
+ }
1329
+ if (bitstream.readBits(1)) { // overscan_info_present_flag
1330
+ bitstream.readBits(1); // overscan_appropriate_flag
1331
+ }
1332
+ if (bitstream.readBits(1)) { // video_signal_type_present_flag
1333
+ bitstream.readBits(3); // video_format
1334
+ fullRangeFlag = bitstream.readBits(1);
1335
+ if (bitstream.readBits(1)) { // colour_description_present_flag
1336
+ colourPrimaries = bitstream.readBits(8);
1337
+ transferCharacteristics = bitstream.readBits(8);
1338
+ matrixCoefficients = bitstream.readBits(8);
1339
+ }
1340
+ }
1341
+ if (bitstream.readBits(1)) { // chroma_loc_info_present_flag
1342
+ readExpGolomb(bitstream); // chroma_sample_loc_type_top_field
1343
+ readExpGolomb(bitstream); // chroma_sample_loc_type_bottom_field
1344
+ }
1345
+ bitstream.readBits(1); // neutral_chroma_indication_flag
1346
+ bitstream.readBits(1); // field_seq_flag
1347
+ bitstream.readBits(1); // frame_field_info_present_flag
1348
+ if (bitstream.readBits(1)) { // default_display_window_flag
1349
+ readExpGolomb(bitstream); // def_disp_win_left_offset
1350
+ readExpGolomb(bitstream); // def_disp_win_right_offset
1351
+ readExpGolomb(bitstream); // def_disp_win_top_offset
1352
+ readExpGolomb(bitstream); // def_disp_win_bottom_offset
1353
+ }
1354
+ if (bitstream.readBits(1)) { // vui_timing_info_present_flag
1355
+ bitstream.readBits(32); // vui_num_units_in_tick
1356
+ bitstream.readBits(32); // vui_time_scale
1357
+ if (bitstream.readBits(1)) { // vui_poc_proportional_to_timing_flag
1358
+ readExpGolomb(bitstream); // vui_num_ticks_poc_diff_one_minus1
1359
+ }
1360
+ if (bitstream.readBits(1)) {
1361
+ skipHevcHrdParameters(bitstream, true, sps_max_sub_layers_minus1);
1362
+ }
1363
+ }
1364
+ if (bitstream.readBits(1)) { // bitstream_restriction_flag
1365
+ bitstream.readBits(1); // tiles_fixed_structure_flag
1366
+ bitstream.readBits(1); // motion_vectors_over_pic_boundaries_flag
1367
+ bitstream.readBits(1); // restricted_ref_pic_lists_flag
1368
+ minSpatialSegmentationIdc = readExpGolomb(bitstream);
1369
+ readExpGolomb(bitstream); // max_bytes_per_pic_denom
1370
+ readExpGolomb(bitstream); // max_bits_per_min_cu_denom
1371
+ readExpGolomb(bitstream); // log2_max_mv_length_horizontal
1372
+ readExpGolomb(bitstream); // log2_max_mv_length_vertical
1373
+ }
1374
+
1375
+ return {
1376
+ pixelAspectRatio,
1377
+ colourPrimaries,
1378
+ transferCharacteristics,
1379
+ matrixCoefficients,
1380
+ fullRangeFlag,
1381
+ minSpatialSegmentationIdc,
1382
+ };
1383
+ };
1384
+
1385
+ const skipHevcHrdParameters = (
1386
+ bitstream: Bitstream,
1387
+ commonInfPresentFlag: boolean,
1388
+ maxNumSubLayersMinus1: number,
1389
+ ) => {
1390
+ let nal_hrd_parameters_present_flag = false;
1391
+ let vcl_hrd_parameters_present_flag = false;
1392
+ let sub_pic_hrd_params_present_flag = false;
1393
+
1394
+ if (commonInfPresentFlag) {
1395
+ nal_hrd_parameters_present_flag = bitstream.readBits(1) === 1;
1396
+ vcl_hrd_parameters_present_flag = bitstream.readBits(1) === 1;
1397
+ if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
1398
+ sub_pic_hrd_params_present_flag = bitstream.readBits(1) === 1;
1399
+ if (sub_pic_hrd_params_present_flag) {
1400
+ bitstream.readBits(8); // tick_divisor_minus2
1401
+ bitstream.readBits(5); // du_cpb_removal_delay_increment_length_minus1
1402
+ bitstream.readBits(1); // sub_pic_cpb_params_in_pic_timing_sei_flag
1403
+ bitstream.readBits(5); // dpb_output_delay_du_length_minus1
1404
+ }
1405
+ bitstream.readBits(4); // bit_rate_scale
1406
+ bitstream.readBits(4); // cpb_size_scale
1407
+ if (sub_pic_hrd_params_present_flag) {
1408
+ bitstream.readBits(4); // cpb_size_du_scale
1409
+ }
1410
+ bitstream.readBits(5); // initial_cpb_removal_delay_length_minus1
1411
+ bitstream.readBits(5); // au_cpb_removal_delay_length_minus1
1412
+ bitstream.readBits(5); // dpb_output_delay_length_minus1
1413
+ }
1414
+ }
1415
+
1416
+ for (let i = 0; i <= maxNumSubLayersMinus1; i++) {
1417
+ const fixed_pic_rate_general_flag = bitstream.readBits(1) === 1;
1418
+ let fixed_pic_rate_within_cvs_flag = true; // Default assumption if general is true
1419
+ if (!fixed_pic_rate_general_flag) {
1420
+ fixed_pic_rate_within_cvs_flag = bitstream.readBits(1) === 1;
1421
+ }
1422
+
1423
+ let low_delay_hrd_flag = false; // Default assumption
1424
+ if (fixed_pic_rate_within_cvs_flag) {
1425
+ readExpGolomb(bitstream); // elemental_duration_in_tc_minus1[i]
1426
+ } else {
1427
+ low_delay_hrd_flag = bitstream.readBits(1) === 1;
1428
+ }
1429
+
1430
+ let CpbCnt = 1; // Default if low_delay is true
1431
+ if (!low_delay_hrd_flag) {
1432
+ const cpb_cnt_minus1 = readExpGolomb(bitstream); // cpb_cnt_minus1[i]
1433
+ CpbCnt = cpb_cnt_minus1 + 1;
1434
+ }
1435
+
1436
+ if (nal_hrd_parameters_present_flag) {
1437
+ skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);
1438
+ }
1439
+ if (vcl_hrd_parameters_present_flag) {
1440
+ skipSubLayerHrdParameters(bitstream, CpbCnt, sub_pic_hrd_params_present_flag);
1441
+ }
1442
+ }
1443
+ };
1444
+
1445
+ const skipSubLayerHrdParameters = (
1446
+ bitstream: Bitstream,
1447
+ CpbCnt: number,
1448
+ sub_pic_hrd_params_present_flag: boolean,
1449
+ ) => {
1450
+ for (let i = 0; i < CpbCnt; i++) {
1451
+ readExpGolomb(bitstream); // bit_rate_value_minus1[i]
1452
+ readExpGolomb(bitstream); // cpb_size_value_minus1[i]
1453
+ if (sub_pic_hrd_params_present_flag) {
1454
+ readExpGolomb(bitstream); // cpb_size_du_value_minus1[i]
1455
+ readExpGolomb(bitstream); // bit_rate_du_value_minus1[i]
1456
+ }
1457
+ bitstream.readBits(1); // cbr_flag[i]
1458
+ }
1459
+ };
1460
+
1461
+ /** Serializes an HevcDecoderConfigurationRecord into the format specified in Section 8.3.3.1 of ISO 14496-15. */
1462
+ export const serializeHevcDecoderConfigurationRecord = (record: HevcDecoderConfigurationRecord) => {
1463
+ const bytes: number[] = [];
1464
+
1465
+ bytes.push(record.configurationVersion);
1466
+
1467
+ bytes.push(
1468
+ ((record.generalProfileSpace & 0x3) << 6)
1469
+ | ((record.generalTierFlag & 0x1) << 5)
1470
+ | (record.generalProfileIdc & 0x1F),
1471
+ );
1472
+
1473
+ bytes.push((record.generalProfileCompatibilityFlags >>> 24) & 0xFF);
1474
+ bytes.push((record.generalProfileCompatibilityFlags >>> 16) & 0xFF);
1475
+ bytes.push((record.generalProfileCompatibilityFlags >>> 8) & 0xFF);
1476
+ bytes.push(record.generalProfileCompatibilityFlags & 0xFF);
1477
+
1478
+ bytes.push(...record.generalConstraintIndicatorFlags);
1479
+
1480
+ bytes.push(record.generalLevelIdc & 0xFF);
1481
+
1482
+ bytes.push(0xF0 | ((record.minSpatialSegmentationIdc >> 8) & 0x0F)); // Reserved + high nibble
1483
+ bytes.push(record.minSpatialSegmentationIdc & 0xFF); // Low byte
1484
+
1485
+ bytes.push(0xFC | (record.parallelismType & 0x03));
1486
+
1487
+ bytes.push(0xFC | (record.chromaFormatIdc & 0x03));
1488
+
1489
+ bytes.push(0xF8 | (record.bitDepthLumaMinus8 & 0x07));
1490
+
1491
+ bytes.push(0xF8 | (record.bitDepthChromaMinus8 & 0x07));
1492
+
1493
+ bytes.push((record.avgFrameRate >> 8) & 0xFF); // High byte
1494
+ bytes.push(record.avgFrameRate & 0xFF); // Low byte
1495
+
1496
+ bytes.push(
1497
+ ((record.constantFrameRate & 0x03) << 6)
1498
+ | ((record.numTemporalLayers & 0x07) << 3)
1499
+ | ((record.temporalIdNested & 0x01) << 2)
1500
+ | (record.lengthSizeMinusOne & 0x03),
1501
+ );
1502
+
1503
+ bytes.push(record.arrays.length & 0xFF);
1504
+
1505
+ for (const arr of record.arrays) {
1506
+ bytes.push(
1507
+ ((arr.arrayCompleteness & 0x01) << 7)
1508
+ | (0 << 6)
1509
+ | (arr.nalUnitType & 0x3F),
1510
+ );
1511
+
1512
+ bytes.push((arr.nalUnits.length >> 8) & 0xFF); // High byte
1513
+ bytes.push(arr.nalUnits.length & 0xFF); // Low byte
1514
+
1515
+ for (const nal of arr.nalUnits) {
1516
+ bytes.push((nal.length >> 8) & 0xFF); // High byte
1517
+ bytes.push(nal.length & 0xFF); // Low byte
1518
+
1519
+ for (let i = 0; i < nal.length; i++) {
1520
+ bytes.push(nal[i]!);
1521
+ }
1522
+ }
1523
+ }
1524
+
1525
+ return new Uint8Array(bytes);
1526
+ };
1527
+
1528
+ /** Deserializes an HevcDecoderConfigurationRecord from the format specified in Section 8.3.3.1 of ISO 14496-15. */
1529
+ export const deserializeHevcDecoderConfigurationRecord = (data: Uint8Array): HevcDecoderConfigurationRecord | null => {
1530
+ try {
1531
+ const view = toDataView(data);
1532
+ let offset = 0;
1533
+
1534
+ const configurationVersion = view.getUint8(offset++);
1535
+
1536
+ const byte1 = view.getUint8(offset++);
1537
+ const generalProfileSpace = (byte1 >> 6) & 0x3;
1538
+ const generalTierFlag = (byte1 >> 5) & 0x1;
1539
+ const generalProfileIdc = byte1 & 0x1F;
1540
+
1541
+ const generalProfileCompatibilityFlags = view.getUint32(offset, false);
1542
+ offset += 4;
1543
+
1544
+ const generalConstraintIndicatorFlags = data.subarray(offset, offset + 6);
1545
+ offset += 6;
1546
+
1547
+ const generalLevelIdc = view.getUint8(offset++);
1548
+
1549
+ const minSpatialSegmentationIdc = ((view.getUint8(offset++) & 0x0F) << 8) | view.getUint8(offset++);
1550
+
1551
+ const parallelismType = view.getUint8(offset++) & 0x03;
1552
+
1553
+ const chromaFormatIdc = view.getUint8(offset++) & 0x03;
1554
+
1555
+ const bitDepthLumaMinus8 = view.getUint8(offset++) & 0x07;
1556
+
1557
+ const bitDepthChromaMinus8 = view.getUint8(offset++) & 0x07;
1558
+
1559
+ const avgFrameRate = view.getUint16(offset, false);
1560
+ offset += 2;
1561
+
1562
+ const byte21 = view.getUint8(offset++);
1563
+ const constantFrameRate = (byte21 >> 6) & 0x03;
1564
+ const numTemporalLayers = (byte21 >> 3) & 0x07;
1565
+ const temporalIdNested = (byte21 >> 2) & 0x01;
1566
+ const lengthSizeMinusOne = byte21 & 0x03;
1567
+
1568
+ const numOfArrays = view.getUint8(offset++);
1569
+
1570
+ const arrays: HevcDecoderConfigurationRecord['arrays'] = [];
1571
+ for (let i = 0; i < numOfArrays; i++) {
1572
+ const arrByte = view.getUint8(offset++);
1573
+ const arrayCompleteness = (arrByte >> 7) & 0x01;
1574
+ const nalUnitType = arrByte & 0x3F;
1575
+
1576
+ const numNalus = view.getUint16(offset, false);
1577
+ offset += 2;
1578
+
1579
+ const nalUnits: Uint8Array[] = [];
1580
+ for (let j = 0; j < numNalus; j++) {
1581
+ const nalUnitLength = view.getUint16(offset, false);
1582
+ offset += 2;
1583
+
1584
+ nalUnits.push(data.subarray(offset, offset + nalUnitLength));
1585
+ offset += nalUnitLength;
1586
+ }
1587
+
1588
+ arrays.push({
1589
+ arrayCompleteness,
1590
+ nalUnitType,
1591
+ nalUnits,
1592
+ });
1593
+ }
1594
+
1595
+ return {
1596
+ configurationVersion,
1597
+ generalProfileSpace,
1598
+ generalTierFlag,
1599
+ generalProfileIdc,
1600
+ generalProfileCompatibilityFlags,
1601
+ generalConstraintIndicatorFlags,
1602
+ generalLevelIdc,
1603
+ minSpatialSegmentationIdc,
1604
+ parallelismType,
1605
+ chromaFormatIdc,
1606
+ bitDepthLumaMinus8,
1607
+ bitDepthChromaMinus8,
1608
+ avgFrameRate,
1609
+ constantFrameRate,
1610
+ numTemporalLayers,
1611
+ temporalIdNested,
1612
+ lengthSizeMinusOne,
1613
+ arrays,
1614
+ };
1615
+ } catch (error) {
1616
+ Logging._error('Error deserializing HEVC Decoder Configuration Record:', error);
1617
+ return null;
1618
+ }
1619
+ };
1620
+
1621
+ enum HevcNaluOrderState {
1622
+ audAllowed,
1623
+ beforeFirstVcl,
1624
+ afterFirstVcl,
1625
+ eoBitstreamAllowed,
1626
+ noMoreDataAllowed,
1627
+ }
1628
+
1629
+ // This function sanitzes the contents of an HEVC packet such that
1630
+ // https://source.chromium.org/chromium/chromium/src/+/main:media/formats/mp4/hevc.cc's validation logic does not trip
1631
+ // up on its contents. The validation is often too strict and rejects packets that Chromium could decode just fine.
1632
+ // Chromium code retrieved on 2026-04-29.
1633
+ // See https://issues.chromium.org/issues/507611247.
1634
+ export const sanitizeHevcPacketForChromium = (
1635
+ packetData: Uint8Array,
1636
+ decoderConfig: VideoDecoderConfig,
1637
+ ): Uint8Array | null => {
1638
+ const removedNalUnits = new Set<number>();
1639
+ let orderState: HevcNaluOrderState = HevcNaluOrderState.audAllowed;
1640
+
1641
+ for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
1642
+ if (orderState === HevcNaluOrderState.noMoreDataAllowed) {
1643
+ removedNalUnits.add(loc.offset);
1644
+ continue;
1645
+ }
1646
+
1647
+ const type = extractNalUnitTypeForHevc(packetData[loc.offset]!);
1648
+
1649
+ if (orderState === HevcNaluOrderState.eoBitstreamAllowed && type !== 37 /* EOB_NUT */) {
1650
+ removedNalUnits.add(loc.offset);
1651
+ continue;
1652
+ }
1653
+
1654
+ let remove = false;
1655
+
1656
+ if (type === 35) { // AUD_NUT
1657
+ if (orderState > HevcNaluOrderState.audAllowed) {
1658
+ remove = true;
1659
+ } else {
1660
+ orderState = HevcNaluOrderState.beforeFirstVcl;
1661
+ }
1662
+ } else if (type <= 31) { // VCL (0-31)
1663
+ if (orderState > HevcNaluOrderState.afterFirstVcl) {
1664
+ remove = true;
1665
+ } else {
1666
+ orderState = HevcNaluOrderState.afterFirstVcl;
1667
+ }
1668
+ } else if (type === 36) { // EOS_NUT
1669
+ if (orderState !== HevcNaluOrderState.afterFirstVcl) {
1670
+ remove = true;
1671
+ } else {
1672
+ orderState = HevcNaluOrderState.eoBitstreamAllowed;
1673
+ }
1674
+ } else if (type === 37) { // EOB_NUT
1675
+ if (orderState < HevcNaluOrderState.afterFirstVcl) {
1676
+ remove = true;
1677
+ } else {
1678
+ orderState = HevcNaluOrderState.noMoreDataAllowed;
1679
+ }
1680
+ } else if (
1681
+ type === 32 || type === 33 || type === 34 || type === 39
1682
+ || (type >= 41 && type <= 44) || (type >= 48 && type <= 55)
1683
+ ) { // VPS, SPS, PPS, PREFIX_SEI, RSV_NVCL41..44, UNSPEC48..55
1684
+ if (orderState > HevcNaluOrderState.beforeFirstVcl) {
1685
+ remove = true;
1686
+ } else {
1687
+ orderState = HevcNaluOrderState.beforeFirstVcl;
1688
+ }
1689
+ } else if (
1690
+ type === 38 || type === 40
1691
+ || (type >= 45 && type <= 47) || (type >= 56 && type <= 63)
1692
+ ) { // FD, SUFFIX_SEI, RSV_NVCL45..47, UNSPEC56..63
1693
+ if (orderState < HevcNaluOrderState.afterFirstVcl) {
1694
+ remove = true;
1695
+ }
1696
+ }
1697
+
1698
+ if (remove) {
1699
+ removedNalUnits.add(loc.offset);
1700
+ }
1701
+ }
1702
+
1703
+ // If nothing violated the rules, return null to signal that
1704
+ if (removedNalUnits.size === 0) {
1705
+ return null;
1706
+ }
1707
+
1708
+ const filteredNalUnits: Uint8Array[] = [];
1709
+ for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
1710
+ if (!removedNalUnits.has(loc.offset)) {
1711
+ filteredNalUnits.push(packetData.subarray(loc.offset, loc.offset + loc.length));
1712
+ }
1713
+ }
1714
+
1715
+ return concatHevcNalUnits(filteredNalUnits, decoderConfig);
1716
+ };
1717
+
1718
+ export type Vp9CodecInfo = {
1719
+ profile: number;
1720
+ level: number;
1721
+ bitDepth: number;
1722
+ chromaSubsampling: number;
1723
+ videoFullRangeFlag: number;
1724
+ colourPrimaries: number;
1725
+ transferCharacteristics: number;
1726
+ matrixCoefficients: number;
1727
+ };
1728
+
1729
+ export const extractVp9CodecInfoFromPacket = (
1730
+ packet: Uint8Array,
1731
+ ): Vp9CodecInfo | null => {
1732
+ // eslint-disable-next-line @stylistic/max-len
1733
+ // https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.7-20170222-draft.pdf
1734
+ // http://downloads.webmproject.org/docs/vp9/vp9-bitstream_superframe-and-uncompressed-header_v1.0.pdf
1735
+
1736
+ const bitstream = new Bitstream(packet);
1737
+
1738
+ // Frame marker (0b10)
1739
+ const frameMarker = bitstream.readBits(2);
1740
+ if (frameMarker !== 2) {
1741
+ return null;
1742
+ }
1743
+
1744
+ // Profile
1745
+ const profileLowBit = bitstream.readBits(1);
1746
+ const profileHighBit = bitstream.readBits(1);
1747
+ const profile = (profileHighBit << 1) + profileLowBit;
1748
+
1749
+ // Skip reserved bit for profile 3
1750
+ if (profile === 3) {
1751
+ bitstream.skipBits(1);
1752
+ }
1753
+
1754
+ // show_existing_frame
1755
+ const showExistingFrame = bitstream.readBits(1);
1756
+
1757
+ if (showExistingFrame === 1) {
1758
+ return null;
1759
+ }
1760
+
1761
+ // frame_type (0 = key frame)
1762
+ const frameType = bitstream.readBits(1);
1763
+
1764
+ if (frameType !== 0) {
1765
+ return null;
1766
+ }
1767
+
1768
+ // Skip show_frame and error_resilient_mode
1769
+ bitstream.skipBits(2);
1770
+
1771
+ // Sync code (0x498342)
1772
+ const syncCode = bitstream.readBits(24);
1773
+ if (syncCode !== 0x498342) {
1774
+ return null;
1775
+ }
1776
+
1777
+ // Color config
1778
+ let bitDepth = 8;
1779
+ if (profile >= 2) {
1780
+ const tenOrTwelveBit = bitstream.readBits(1);
1781
+ bitDepth = tenOrTwelveBit ? 12 : 10;
1782
+ }
1783
+
1784
+ // Color space
1785
+ const colorSpace = bitstream.readBits(3);
1786
+
1787
+ let chromaSubsampling = 0;
1788
+ let videoFullRangeFlag = 0;
1789
+
1790
+ if (colorSpace !== 7) { // 7 is CS_RGB
1791
+ const colorRange = bitstream.readBits(1);
1792
+ videoFullRangeFlag = colorRange;
1793
+
1794
+ if (profile === 1 || profile === 3) {
1795
+ const subsamplingX = bitstream.readBits(1);
1796
+ const subsamplingY = bitstream.readBits(1);
1797
+
1798
+ // 0 = 4:2:0 vertical
1799
+ // 1 = 4:2:0 colocated
1800
+ // 2 = 4:2:2
1801
+ // 3 = 4:4:4
1802
+ chromaSubsampling = !subsamplingX && !subsamplingY
1803
+ ? 3 // 0,0 = 4:4:4
1804
+ : subsamplingX && !subsamplingY
1805
+ ? 2 // 1,0 = 4:2:2
1806
+ : 1; // 1,1 = 4:2:0 colocated (default)
1807
+
1808
+ // Skip reserved bit
1809
+ bitstream.skipBits(1);
1810
+ } else {
1811
+ // For profile 0 and 2, always 4:2:0
1812
+ chromaSubsampling = 1; // Using colocated as default
1813
+ }
1814
+ } else {
1815
+ // RGB is always 4:4:4
1816
+ chromaSubsampling = 3;
1817
+ videoFullRangeFlag = 1;
1818
+ }
1819
+
1820
+ // Parse frame size
1821
+ const widthMinusOne = bitstream.readBits(16);
1822
+ const heightMinusOne = bitstream.readBits(16);
1823
+
1824
+ const width = widthMinusOne + 1;
1825
+ const height = heightMinusOne + 1;
1826
+
1827
+ // Calculate level based on dimensions
1828
+ const pictureSize = width * height;
1829
+ let level = last(VP9_LEVEL_TABLE)!.level; // Default to highest level
1830
+ for (const entry of VP9_LEVEL_TABLE) {
1831
+ if (pictureSize <= entry.maxPictureSize) {
1832
+ level = entry.level;
1833
+ break;
1834
+ }
1835
+ }
1836
+
1837
+ // Map color_space to standard values
1838
+ const matrixCoefficients = colorSpace === 7
1839
+ ? 0
1840
+ : colorSpace === 2
1841
+ ? 1
1842
+ : colorSpace === 1
1843
+ ? 6
1844
+ : 2;
1845
+
1846
+ const colourPrimaries = colorSpace === 2
1847
+ ? 1
1848
+ : colorSpace === 1
1849
+ ? 6
1850
+ : 2;
1851
+
1852
+ const transferCharacteristics = colorSpace === 2
1853
+ ? 1
1854
+ : colorSpace === 1
1855
+ ? 6
1856
+ : 2;
1857
+
1858
+ return {
1859
+ profile,
1860
+ level,
1861
+ bitDepth,
1862
+ chromaSubsampling,
1863
+ videoFullRangeFlag,
1864
+ colourPrimaries,
1865
+ transferCharacteristics,
1866
+ matrixCoefficients,
1867
+ };
1868
+ };
1869
+
1870
+ export type Av1CodecInfo = {
1871
+ profile: number;
1872
+ level: number;
1873
+ tier: number;
1874
+ bitDepth: number;
1875
+ monochrome: number;
1876
+ chromaSubsamplingX: number;
1877
+ chromaSubsamplingY: number;
1878
+ chromaSamplePosition: number;
1879
+ };
1880
+
1881
+ /** Iterates over all OBUs in an AV1 packet bitstream. */
1882
+ export const iterateAv1PacketObus = function* (packet: Uint8Array) {
1883
+ // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
1884
+
1885
+ const bitstream = new Bitstream(packet);
1886
+
1887
+ const readLeb128 = (): number | null => {
1888
+ let value = 0;
1889
+
1890
+ for (let i = 0; i < 8; i++) {
1891
+ const byte = bitstream.readAlignedByte();
1892
+
1893
+ value |= ((byte & 0x7f) << (i * 7));
1894
+
1895
+ if (!(byte & 0x80)) {
1896
+ break;
1897
+ }
1898
+
1899
+ // Spec requirement
1900
+ if (i === 7 && (byte & 0x80)) {
1901
+ return null;
1902
+ }
1903
+ }
1904
+
1905
+ // Spec requirement
1906
+ if (value >= 2 ** 32 - 1) {
1907
+ return null;
1908
+ }
1909
+
1910
+ return value;
1911
+ };
1912
+
1913
+ while (bitstream.getBitsLeft() >= 8) {
1914
+ // Parse OBU header
1915
+ bitstream.skipBits(1);
1916
+ const obuType = bitstream.readBits(4);
1917
+ const obuExtension = bitstream.readBits(1);
1918
+ const obuHasSizeField = bitstream.readBits(1);
1919
+ bitstream.skipBits(1);
1920
+
1921
+ // Skip extension header if present
1922
+ if (obuExtension) {
1923
+ bitstream.skipBits(8);
1924
+ }
1925
+
1926
+ // Read OBU size if present
1927
+ let obuSize: number;
1928
+ if (obuHasSizeField) {
1929
+ const obuSizeValue = readLeb128();
1930
+ if (obuSizeValue === null) return; // It was invalid
1931
+ obuSize = obuSizeValue;
1932
+ } else {
1933
+ // Calculate remaining bits and convert to bytes, rounding down
1934
+ obuSize = Math.floor(bitstream.getBitsLeft() / 8);
1935
+ }
1936
+
1937
+ assert(bitstream.pos % 8 === 0);
1938
+
1939
+ yield {
1940
+ type: obuType,
1941
+ data: packet.subarray(bitstream.pos / 8, bitstream.pos / 8 + obuSize),
1942
+ };
1943
+
1944
+ // Move to next OBU
1945
+ bitstream.skipBits(obuSize * 8);
1946
+ }
1947
+ };
1948
+
1949
+ /**
1950
+ * When AV1 codec information is not provided by the container, we can still try to extract the information by digging
1951
+ * into the AV1 bitstream.
1952
+ */
1953
+ export const extractAv1CodecInfoFromPacket = (
1954
+ packet: Uint8Array,
1955
+ ): Av1CodecInfo | null => {
1956
+ // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
1957
+
1958
+ for (const { type, data } of iterateAv1PacketObus(packet)) {
1959
+ if (type !== 1) {
1960
+ continue; // 1 == OBU_SEQUENCE_HEADER
1961
+ }
1962
+
1963
+ const bitstream = new Bitstream(data);
1964
+
1965
+ // Read sequence header fields
1966
+ const seqProfile = bitstream.readBits(3);
1967
+
1968
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1969
+ const stillPicture = bitstream.readBits(1);
1970
+
1971
+ const reducedStillPictureHeader = bitstream.readBits(1);
1972
+
1973
+ let seqLevel = 0;
1974
+ let seqTier = 0;
1975
+ let bufferDelayLengthMinus1 = 0;
1976
+
1977
+ if (reducedStillPictureHeader) {
1978
+ seqLevel = bitstream.readBits(5);
1979
+ } else {
1980
+ // Parse timing_info_present_flag
1981
+ const timingInfoPresentFlag = bitstream.readBits(1);
1982
+
1983
+ if (timingInfoPresentFlag) {
1984
+ // Skip timing info (num_units_in_display_tick, time_scale, equal_picture_interval)
1985
+ bitstream.skipBits(32); // num_units_in_display_tick
1986
+ bitstream.skipBits(32); // time_scale
1987
+ const equalPictureInterval = bitstream.readBits(1);
1988
+
1989
+ if (equalPictureInterval) {
1990
+ // Skip num_ticks_per_picture_minus_1 (uvlc)
1991
+ // Since this is variable length, we'd need to implement uvlc reading
1992
+ // For now, we'll return null as this is rare
1993
+ return null;
1994
+ }
1995
+ }
1996
+
1997
+ // Parse decoder_model_info_present_flag
1998
+ const decoderModelInfoPresentFlag = bitstream.readBits(1);
1999
+
2000
+ if (decoderModelInfoPresentFlag) {
2001
+ // Store buffer_delay_length_minus_1 instead of just skipping
2002
+ bufferDelayLengthMinus1 = bitstream.readBits(5);
2003
+ bitstream.skipBits(32); // num_units_in_decoding_tick
2004
+ bitstream.skipBits(5); // buffer_removal_time_length_minus_1
2005
+ bitstream.skipBits(5); // frame_presentation_time_length_minus_1
2006
+ }
2007
+
2008
+ // Parse operating_points_cnt_minus_1
2009
+ const operatingPointsCntMinus1 = bitstream.readBits(5);
2010
+
2011
+ // For each operating point
2012
+ for (let i = 0; i <= operatingPointsCntMinus1; i++) {
2013
+ // operating_point_idc[i]
2014
+ bitstream.skipBits(12);
2015
+
2016
+ // seq_level_idx[i]
2017
+ const seqLevelIdx = bitstream.readBits(5);
2018
+
2019
+ if (i === 0) {
2020
+ seqLevel = seqLevelIdx;
2021
+ }
2022
+
2023
+ if (seqLevelIdx > 7) {
2024
+ // seq_tier[i]
2025
+ const seqTierTemp = bitstream.readBits(1);
2026
+ if (i === 0) {
2027
+ seqTier = seqTierTemp;
2028
+ }
2029
+ }
2030
+
2031
+ if (decoderModelInfoPresentFlag) {
2032
+ // decoder_model_present_for_this_op[i]
2033
+ const decoderModelPresentForThisOp = bitstream.readBits(1);
2034
+
2035
+ if (decoderModelPresentForThisOp) {
2036
+ const n = bufferDelayLengthMinus1 + 1;
2037
+ bitstream.skipBits(n); // decoder_buffer_delay[op]
2038
+ bitstream.skipBits(n); // encoder_buffer_delay[op]
2039
+ bitstream.skipBits(1); // low_delay_mode_flag[op]
2040
+ }
2041
+ }
2042
+
2043
+ // initial_display_delay_present_flag
2044
+ const initialDisplayDelayPresentFlag = bitstream.readBits(1);
2045
+
2046
+ if (initialDisplayDelayPresentFlag) {
2047
+ // initial_display_delay_minus_1[i]
2048
+ bitstream.skipBits(4);
2049
+ }
2050
+ }
2051
+ }
2052
+
2053
+ // Frame size
2054
+ const frameWidthBitsMinus1 = bitstream.readBits(4);
2055
+ const frameHeightBitsMinus1 = bitstream.readBits(4);
2056
+ const n1 = frameWidthBitsMinus1 + 1;
2057
+ bitstream.skipBits(n1); // max_frame_width_minus_1
2058
+ const n2 = frameHeightBitsMinus1 + 1;
2059
+ bitstream.skipBits(n2); // max_frame_height_minus_1
2060
+
2061
+ // Frame IDs
2062
+ let frameIdNumbersPresentFlag = 0;
2063
+ if (reducedStillPictureHeader) {
2064
+ frameIdNumbersPresentFlag = 0;
2065
+ } else {
2066
+ frameIdNumbersPresentFlag = bitstream.readBits(1);
2067
+ }
2068
+
2069
+ if (frameIdNumbersPresentFlag) {
2070
+ bitstream.skipBits(4); // delta_frame_id_length_minus_2
2071
+ bitstream.skipBits(3); // additional_frame_id_length_minus_1
2072
+ }
2073
+
2074
+ bitstream.skipBits(1); // use_128x128_superblock
2075
+ bitstream.skipBits(1); // enable_filter_intra
2076
+ bitstream.skipBits(1); // enable_intra_edge_filter
2077
+
2078
+ if (!reducedStillPictureHeader) {
2079
+ bitstream.skipBits(1); // enable_interintra_compound
2080
+ bitstream.skipBits(1); // enable_masked_compound
2081
+ bitstream.skipBits(1); // enable_warped_motion
2082
+ bitstream.skipBits(1); // enable_dual_filter
2083
+ const enableOrderHint = bitstream.readBits(1);
2084
+
2085
+ if (enableOrderHint) {
2086
+ bitstream.skipBits(1); // enable_jnt_comp
2087
+ bitstream.skipBits(1); // enable_ref_frame_mvs
2088
+ }
2089
+
2090
+ const seqChooseScreenContentTools = bitstream.readBits(1);
2091
+ let seqForceScreenContentTools = 0;
2092
+
2093
+ if (seqChooseScreenContentTools) {
2094
+ seqForceScreenContentTools = 2; // SELECT_SCREEN_CONTENT_TOOLS
2095
+ } else {
2096
+ seqForceScreenContentTools = bitstream.readBits(1);
2097
+ }
2098
+
2099
+ if (seqForceScreenContentTools > 0) {
2100
+ const seqChooseIntegerMv = bitstream.readBits(1);
2101
+ if (!seqChooseIntegerMv) {
2102
+ bitstream.skipBits(1); // seq_force_integer_mv
2103
+ }
2104
+ }
2105
+
2106
+ if (enableOrderHint) {
2107
+ bitstream.skipBits(3); // order_hint_bits_minus_1
2108
+ }
2109
+ }
2110
+
2111
+ bitstream.skipBits(1); // enable_superres
2112
+ bitstream.skipBits(1); // enable_cdef
2113
+ bitstream.skipBits(1); // enable_restoration
2114
+
2115
+ // color_config()
2116
+ const highBitdepth = bitstream.readBits(1);
2117
+
2118
+ let bitDepth = 8;
2119
+ if (seqProfile === 2 && highBitdepth) {
2120
+ const twelveBit = bitstream.readBits(1);
2121
+ bitDepth = twelveBit ? 12 : 10;
2122
+ } else if (seqProfile <= 2) {
2123
+ bitDepth = highBitdepth ? 10 : 8;
2124
+ }
2125
+
2126
+ let monochrome = 0;
2127
+ if (seqProfile !== 1) {
2128
+ monochrome = bitstream.readBits(1);
2129
+ }
2130
+
2131
+ let chromaSubsamplingX = 1;
2132
+ let chromaSubsamplingY = 1;
2133
+ let chromaSamplePosition = 0;
2134
+
2135
+ if (!monochrome) {
2136
+ if (seqProfile === 0) {
2137
+ chromaSubsamplingX = 1;
2138
+ chromaSubsamplingY = 1;
2139
+ } else if (seqProfile === 1) {
2140
+ chromaSubsamplingX = 0;
2141
+ chromaSubsamplingY = 0;
2142
+ } else {
2143
+ if (bitDepth === 12) {
2144
+ chromaSubsamplingX = bitstream.readBits(1);
2145
+ if (chromaSubsamplingX) {
2146
+ chromaSubsamplingY = bitstream.readBits(1);
2147
+ }
2148
+ }
2149
+ }
2150
+
2151
+ if (chromaSubsamplingX && chromaSubsamplingY) {
2152
+ chromaSamplePosition = bitstream.readBits(2);
2153
+ }
2154
+ }
2155
+
2156
+ return {
2157
+ profile: seqProfile,
2158
+ level: seqLevel,
2159
+ tier: seqTier,
2160
+ bitDepth,
2161
+ monochrome,
2162
+ chromaSubsamplingX,
2163
+ chromaSubsamplingY,
2164
+ chromaSamplePosition,
2165
+ };
2166
+ }
2167
+
2168
+ return null;
2169
+ };
2170
+
2171
+ export const parseOpusIdentificationHeader = (bytes: Uint8Array) => {
2172
+ const view = toDataView(bytes);
2173
+
2174
+ const outputChannelCount = view.getUint8(9);
2175
+ const preSkip = view.getUint16(10, true);
2176
+ const inputSampleRate = view.getUint32(12, true);
2177
+ const outputGain = view.getInt16(16, true);
2178
+ const channelMappingFamily = view.getUint8(18);
2179
+
2180
+ let channelMappingTable: Uint8Array | null = null;
2181
+ if (channelMappingFamily) {
2182
+ channelMappingTable = bytes.subarray(19, 19 + 2 + outputChannelCount);
2183
+ }
2184
+
2185
+ return {
2186
+ outputChannelCount,
2187
+ preSkip,
2188
+ inputSampleRate,
2189
+ outputGain,
2190
+ channelMappingFamily,
2191
+ channelMappingTable,
2192
+ };
2193
+ };
2194
+
2195
+ // From https://datatracker.ietf.org/doc/html/rfc6716, in 48 kHz samples
2196
+ const OPUS_FRAME_DURATION_TABLE = [
2197
+ 480, 960, 1920, 2880,
2198
+ 480, 960, 1920, 2880,
2199
+ 480, 960, 1920, 2880,
2200
+ 480, 960,
2201
+ 480, 960,
2202
+ 120, 240, 480, 960,
2203
+ 120, 240, 480, 960,
2204
+ 120, 240, 480, 960,
2205
+ 120, 240, 480, 960,
2206
+ ];
2207
+
2208
+ export const parseOpusTocByte = (packet: Uint8Array) => {
2209
+ const config = packet[0]! >> 3;
2210
+ const code = packet[0]! & 0b11;
2211
+
2212
+ // A packet may pack more than one frame, in which case its duration is the frame duration times the number of
2213
+ // frames it carries. See https://datatracker.ietf.org/doc/html/rfc6716, section 3.2.
2214
+ let frameCount: number;
2215
+ if (code === 0) {
2216
+ frameCount = 1;
2217
+ } else if (code === 1 || code === 2) {
2218
+ frameCount = 2;
2219
+ } else {
2220
+ // Code 3: the frame count sits in the six low bits of the frame count byte
2221
+ frameCount = packet[1]! & 0b111111;
2222
+ }
2223
+
2224
+ return {
2225
+ durationInSamples: OPUS_FRAME_DURATION_TABLE[config]! * frameCount,
2226
+ };
2227
+ };
2228
+
2229
+ // Based on vorbis_parser.c from FFmpeg.
2230
+ export const parseModesFromVorbisSetupPacket = (setupHeader: Uint8Array) => {
2231
+ // Verify that this is a Setup header.
2232
+ if (setupHeader.length < 7) {
2233
+ throw new Error('Setup header is too short.');
2234
+ }
2235
+ if (setupHeader[0] !== 5) {
2236
+ throw new Error('Wrong packet type in Setup header.');
2237
+ }
2238
+ const signature = String.fromCharCode(...setupHeader.slice(1, 7));
2239
+ if (signature !== 'vorbis') {
2240
+ throw new Error('Invalid packet signature in Setup header.');
2241
+ }
2242
+
2243
+ // Reverse the entire buffer.
2244
+ const bufSize = setupHeader.length;
2245
+ const revBuffer = new Uint8Array(bufSize);
2246
+ for (let i = 0; i < bufSize; i++) {
2247
+ revBuffer[i] = setupHeader[bufSize - 1 - i]!;
2248
+ }
2249
+
2250
+ // Initialize a Bitstream on the reversed buffer.
2251
+ const bitstream = new Bitstream(revBuffer);
2252
+
2253
+ // --- Find the framing bit.
2254
+ // In FFmpeg code, we scan until get_bits1() returns 1.
2255
+ let gotFramingBit = 0;
2256
+ while (bitstream.getBitsLeft() > 97) {
2257
+ if (bitstream.readBits(1) === 1) {
2258
+ gotFramingBit = bitstream.pos;
2259
+ break;
2260
+ }
2261
+ }
2262
+ if (gotFramingBit === 0) {
2263
+ throw new Error('Invalid Setup header: framing bit not found.');
2264
+ }
2265
+
2266
+ // --- Search backwards for a valid mode header.
2267
+ // We try to “guess” the number of modes by reading a fixed pattern.
2268
+ let modeCount = 0;
2269
+ let gotModeHeader = false;
2270
+ let lastModeCount = 0;
2271
+ while (bitstream.getBitsLeft() >= 97) {
2272
+ const tempPos = bitstream.pos;
2273
+ const a = bitstream.readBits(8);
2274
+ const b = bitstream.readBits(16);
2275
+ const c = bitstream.readBits(16);
2276
+ // If a > 63 or b or c nonzero, assume we’ve gone too far.
2277
+ if (a > 63 || b !== 0 || c !== 0) {
2278
+ bitstream.pos = tempPos;
2279
+ break;
2280
+ }
2281
+ bitstream.skipBits(1);
2282
+ modeCount++;
2283
+ if (modeCount > 64) {
2284
+ break;
2285
+ }
2286
+ const bsClone = bitstream.clone();
2287
+ const candidate = bsClone.readBits(6) + 1;
2288
+ if (candidate === modeCount) {
2289
+ gotModeHeader = true;
2290
+ lastModeCount = modeCount;
2291
+ }
2292
+ }
2293
+ if (!gotModeHeader) {
2294
+ throw new Error('Invalid Setup header: mode header not found.');
2295
+ }
2296
+ if (lastModeCount > 63) {
2297
+ throw new Error(`Unsupported mode count: ${lastModeCount}.`);
2298
+ }
2299
+ const finalModeCount = lastModeCount;
2300
+
2301
+ // --- Reinitialize the bitstream.
2302
+ bitstream.pos = 0;
2303
+ // Skip the bits up to the found framing bit.
2304
+ bitstream.skipBits(gotFramingBit);
2305
+
2306
+ // --- Now read, for each mode (in reverse order), 40 bits then one bit.
2307
+ // That one bit is the mode blockflag.
2308
+ const modeBlockflags = Array(finalModeCount).fill(0) as number[];
2309
+ for (let i = finalModeCount - 1; i >= 0; i--) {
2310
+ bitstream.skipBits(40);
2311
+ modeBlockflags[i] = bitstream.readBits(1);
2312
+ }
2313
+
2314
+ return { modeBlockflags };
2315
+ };
2316
+
2317
+ /** Determines a packet's type (key or delta) by digging into the packet bitstream. */
2318
+ export const determineVideoPacketType = (
2319
+ codec: VideoCodec,
2320
+ decoderConfig: VideoDecoderConfig,
2321
+ packetData: Uint8Array,
2322
+ ): PacketType | null => {
2323
+ switch (codec) {
2324
+ case 'avc': {
2325
+ for (const loc of iterateAvcNalUnits(packetData, decoderConfig)) {
2326
+ const nalTypeByte = packetData[loc.offset]!;
2327
+ const type = extractNalUnitTypeForAvc(nalTypeByte);
2328
+
2329
+ if (type >= AvcNalUnitType.NON_IDR_SLICE && type <= AvcNalUnitType.SLICE_DPC) {
2330
+ return 'delta';
2331
+ }
2332
+
2333
+ if (type === AvcNalUnitType.IDR) {
2334
+ return 'key';
2335
+ }
2336
+
2337
+ // In addition to IDR, Recovery Point SEI also counts as a valid H.264 keyframe by current consensus.
2338
+ // See https://github.com/w3c/webcodecs/issues/650 for the relevant discussion. WebKit and Firefox have
2339
+ // always supported them, but Chromium hasn't, therefore the (admittedly dirty) version check.
2340
+ if (type === AvcNalUnitType.SEI && (!isChromium() || getChromiumVersion()! >= 144)) {
2341
+ const nalUnit = packetData.subarray(loc.offset, loc.offset + loc.length);
2342
+ const bytes = removeEmulationPreventionBytes(nalUnit);
2343
+ let pos = 1; // Skip NALU header
2344
+
2345
+ // sei_rbsp()
2346
+ do {
2347
+ // sei_message()
2348
+ let payloadType = 0;
2349
+ while (true) {
2350
+ const nextByte = bytes[pos++];
2351
+ if (nextByte === undefined) break;
2352
+ payloadType += nextByte;
2353
+
2354
+ if (nextByte < 255) {
2355
+ break;
2356
+ }
2357
+ }
2358
+
2359
+ let payloadSize = 0;
2360
+ while (true) {
2361
+ const nextByte = bytes[pos++];
2362
+ if (nextByte === undefined) break;
2363
+ payloadSize += nextByte;
2364
+
2365
+ if (nextByte < 255) {
2366
+ break;
2367
+ }
2368
+ }
2369
+
2370
+ // sei_payload()
2371
+ const PAYLOAD_TYPE_RECOVERY_POINT = 6;
2372
+ if (payloadType === PAYLOAD_TYPE_RECOVERY_POINT) {
2373
+ const bitstream = new Bitstream(bytes);
2374
+ bitstream.pos = 8 * pos;
2375
+
2376
+ const recoveryFrameCount = readExpGolomb(bitstream);
2377
+ const exactMatchFlag = bitstream.readBits(1);
2378
+
2379
+ if (recoveryFrameCount === 0 && exactMatchFlag === 1) {
2380
+ // https://github.com/w3c/webcodecs/pull/910
2381
+ // "recovery_frame_cnt == 0 and exact_match_flag=1 in the SEI recovery payload"
2382
+ return 'key';
2383
+ }
2384
+ }
2385
+
2386
+ pos += payloadSize;
2387
+ } while (pos < bytes.length - 1);
2388
+ }
2389
+ }
2390
+
2391
+ return 'delta';
2392
+ };
2393
+
2394
+ case 'hevc': {
2395
+ for (const loc of iterateHevcNalUnits(packetData, decoderConfig)) {
2396
+ const type = extractNalUnitTypeForHevc(packetData[loc.offset]!);
2397
+ if (type < HevcNalUnitType.BLA_W_LP) {
2398
+ return 'delta';
2399
+ }
2400
+
2401
+ if (type <= HevcNalUnitType.RSV_IRAP_VCL23) {
2402
+ return 'key';
2403
+ }
2404
+ }
2405
+
2406
+ return 'delta';
2407
+ };
2408
+
2409
+ case 'vp8': {
2410
+ // VP8, once again, by far the easiest to deal with.
2411
+ const frameType = packetData[0]! & 0b1;
2412
+ return frameType === 0 ? 'key' : 'delta';
2413
+ };
2414
+
2415
+ case 'vp9': {
2416
+ const bitstream = new Bitstream(packetData);
2417
+
2418
+ if (bitstream.readBits(2) !== 2) {
2419
+ return null;
2420
+ };
2421
+
2422
+ const profileLowBit = bitstream.readBits(1);
2423
+ const profileHighBit = bitstream.readBits(1);
2424
+ const profile = (profileHighBit << 1) + profileLowBit;
2425
+
2426
+ // Skip reserved bit for profile 3
2427
+ if (profile === 3) {
2428
+ bitstream.skipBits(1);
2429
+ }
2430
+
2431
+ const showExistingFrame = bitstream.readBits(1);
2432
+ if (showExistingFrame) {
2433
+ return null;
2434
+ }
2435
+
2436
+ const frameType = bitstream.readBits(1);
2437
+ return frameType === 0 ? 'key' : 'delta';
2438
+ };
2439
+
2440
+ case 'av1': {
2441
+ let reducedStillPictureHeader = false;
2442
+
2443
+ for (const { type, data } of iterateAv1PacketObus(packetData)) {
2444
+ if (type === 1) { // OBU_SEQUENCE_HEADER
2445
+ const bitstream = new Bitstream(data);
2446
+
2447
+ bitstream.skipBits(4);
2448
+ reducedStillPictureHeader = !!bitstream.readBits(1);
2449
+ } else if (
2450
+ type === 3 // OBU_FRAME_HEADER
2451
+ || type === 6 // OBU_FRAME
2452
+ || type === 7 // OBU_REDUNDANT_FRAME_HEADER
2453
+ ) {
2454
+ if (reducedStillPictureHeader) {
2455
+ return 'key';
2456
+ }
2457
+
2458
+ const bitstream = new Bitstream(data);
2459
+ const showExistingFrame = bitstream.readBits(1);
2460
+ if (showExistingFrame) {
2461
+ return null;
2462
+ }
2463
+
2464
+ const frameType = bitstream.readBits(2);
2465
+ return frameType === 0 ? 'key' : 'delta';
2466
+ }
2467
+ }
2468
+
2469
+ return null;
2470
+ };
2471
+
2472
+ case 'prores': {
2473
+ return 'key';
2474
+ };
2475
+
2476
+ default: {
2477
+ assertNever(codec);
2478
+ assert(false);
2479
+ };
2480
+ }
2481
+ };
2482
+
2483
+ export enum FlacBlockType {
2484
+ STREAMINFO = 0,
2485
+ VORBIS_COMMENT = 4,
2486
+ PICTURE = 6,
2487
+ }
2488
+
2489
+ export const readVorbisComments = (bytes: Uint8Array, metadataTags: MetadataTags) => {
2490
+ // https://datatracker.ietf.org/doc/html/rfc7845#section-5.2
2491
+
2492
+ const commentView = toDataView(bytes);
2493
+ let commentPos = 0;
2494
+
2495
+ const vendorStringLength = commentView.getUint32(commentPos, true);
2496
+ commentPos += 4;
2497
+
2498
+ const vendorString = textDecoder.decode(
2499
+ bytes.subarray(commentPos, commentPos + vendorStringLength),
2500
+ );
2501
+ commentPos += vendorStringLength;
2502
+
2503
+ if (vendorStringLength > 0) {
2504
+ // Expose the vendor string in the raw metadata
2505
+ metadataTags.raw ??= {};
2506
+ metadataTags.raw['vendor'] ??= vendorString;
2507
+ }
2508
+
2509
+ const listLength = commentView.getUint32(commentPos, true);
2510
+ commentPos += 4;
2511
+
2512
+ // Loop over all metadata tags
2513
+ for (let i = 0; i < listLength; i++) {
2514
+ const stringLength = commentView.getUint32(commentPos, true);
2515
+ commentPos += 4;
2516
+
2517
+ const string = textDecoder.decode(
2518
+ bytes.subarray(commentPos, commentPos + stringLength),
2519
+ );
2520
+ commentPos += stringLength;
2521
+
2522
+ const separatorIndex = string.indexOf('=');
2523
+ if (separatorIndex === -1) {
2524
+ continue;
2525
+ }
2526
+
2527
+ const key = string.slice(0, separatorIndex).toUpperCase();
2528
+ const value = string.slice(separatorIndex + 1);
2529
+
2530
+ metadataTags.raw ??= {};
2531
+ metadataTags.raw[key] ??= value;
2532
+
2533
+ switch (key) {
2534
+ case 'TITLE': {
2535
+ metadataTags.title ??= value;
2536
+ }; break;
2537
+
2538
+ case 'DESCRIPTION': {
2539
+ metadataTags.description ??= value;
2540
+ }; break;
2541
+
2542
+ case 'ARTIST': {
2543
+ metadataTags.artist ??= value;
2544
+ }; break;
2545
+
2546
+ case 'ALBUM': {
2547
+ metadataTags.album ??= value;
2548
+ }; break;
2549
+
2550
+ case 'ALBUMARTIST': {
2551
+ metadataTags.albumArtist ??= value;
2552
+ }; break;
2553
+
2554
+ case 'COMMENT': {
2555
+ metadataTags.comment ??= value;
2556
+ }; break;
2557
+
2558
+ case 'LYRICS': {
2559
+ metadataTags.lyrics ??= value;
2560
+ }; break;
2561
+
2562
+ case 'TRACKNUMBER': {
2563
+ const parts = value.split('/');
2564
+ const trackNum = Number.parseInt(parts[0]!, 10);
2565
+ const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
2566
+
2567
+ if (Number.isInteger(trackNum) && trackNum > 0) {
2568
+ metadataTags.trackNumber ??= trackNum;
2569
+ }
2570
+ if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
2571
+ metadataTags.tracksTotal ??= tracksTotal;
2572
+ }
2573
+ }; break;
2574
+
2575
+ case 'TRACKTOTAL': {
2576
+ const tracksTotal = Number.parseInt(value, 10);
2577
+ if (Number.isInteger(tracksTotal) && tracksTotal > 0) {
2578
+ metadataTags.tracksTotal ??= tracksTotal;
2579
+ }
2580
+ }; break;
2581
+
2582
+ case 'DISCNUMBER': {
2583
+ const parts = value.split('/');
2584
+ const discNum = Number.parseInt(parts[0]!, 10);
2585
+ const discsTotal = parts[1] && Number.parseInt(parts[1], 10);
2586
+
2587
+ if (Number.isInteger(discNum) && discNum > 0) {
2588
+ metadataTags.discNumber ??= discNum;
2589
+ }
2590
+ if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {
2591
+ metadataTags.discsTotal ??= discsTotal;
2592
+ }
2593
+ }; break;
2594
+
2595
+ case 'DISCTOTAL': {
2596
+ const discsTotal = Number.parseInt(value, 10);
2597
+ if (Number.isInteger(discsTotal) && discsTotal > 0) {
2598
+ metadataTags.discsTotal ??= discsTotal;
2599
+ }
2600
+ }; break;
2601
+
2602
+ case 'DATE': {
2603
+ const date = new Date(value);
2604
+ if (!Number.isNaN(date.getTime())) {
2605
+ metadataTags.date ??= date;
2606
+ }
2607
+ }; break;
2608
+
2609
+ case 'GENRE': {
2610
+ metadataTags.genre ??= value;
2611
+ }; break;
2612
+
2613
+ case 'METADATA_BLOCK_PICTURE': {
2614
+ // https://datatracker.ietf.org/doc/rfc9639/ Section 8.8
2615
+ const decoded = base64ToBytes(value);
2616
+
2617
+ const view = toDataView(decoded);
2618
+ const pictureType = view.getUint32(0, false);
2619
+ const mediaTypeLength = view.getUint32(4, false);
2620
+ const mediaType = String.fromCharCode(...decoded.subarray(8, 8 + mediaTypeLength)); // ASCII
2621
+ const descriptionLength = view.getUint32(8 + mediaTypeLength, false);
2622
+ const description = textDecoder.decode(decoded.subarray(
2623
+ 12 + mediaTypeLength,
2624
+ 12 + mediaTypeLength + descriptionLength,
2625
+ ));
2626
+ const dataLength = view.getUint32(mediaTypeLength + descriptionLength + 28);
2627
+ const data = decoded.subarray(
2628
+ mediaTypeLength + descriptionLength + 32,
2629
+ mediaTypeLength + descriptionLength + 32 + dataLength,
2630
+ );
2631
+
2632
+ metadataTags.images ??= [];
2633
+ metadataTags.images.push({
2634
+ data,
2635
+ mimeType: mediaType,
2636
+ kind: pictureType === 3 ? 'coverFront' : pictureType === 4 ? 'coverBack' : 'unknown',
2637
+ name: undefined,
2638
+ description: description || undefined,
2639
+ });
2640
+ }; break;
2641
+ }
2642
+ }
2643
+ };
2644
+
2645
+ export const createVorbisComments = (headerBytes: Uint8Array, tags: MetadataTags, writeImages: boolean) => {
2646
+ // https://datatracker.ietf.org/doc/html/rfc7845#section-5.2
2647
+
2648
+ const commentHeaderParts: Uint8Array[] = [
2649
+ headerBytes,
2650
+ ];
2651
+
2652
+ const vendorString = 'Mediabunny';
2653
+ const encodedVendorString = textEncoder.encode(vendorString);
2654
+
2655
+ let currentBuffer = new Uint8Array(4 + encodedVendorString.length);
2656
+ let currentView = new DataView(currentBuffer.buffer);
2657
+ currentView.setUint32(0, encodedVendorString.length, true);
2658
+ currentBuffer.set(encodedVendorString, 4);
2659
+
2660
+ commentHeaderParts.push(currentBuffer);
2661
+
2662
+ const writtenTags = new Set<string>();
2663
+ const addCommentTag = (key: string, value: string) => {
2664
+ const joined = `${key}=${value}`;
2665
+ const encoded = textEncoder.encode(joined);
2666
+
2667
+ currentBuffer = new Uint8Array(4 + encoded.length);
2668
+ currentView = new DataView(currentBuffer.buffer);
2669
+
2670
+ currentView.setUint32(0, encoded.length, true);
2671
+ currentBuffer.set(encoded, 4);
2672
+
2673
+ commentHeaderParts.push(currentBuffer);
2674
+ writtenTags.add(key);
2675
+ };
2676
+
2677
+ for (const { key, value } of keyValueIterator(tags)) {
2678
+ switch (key) {
2679
+ case 'title': {
2680
+ addCommentTag('TITLE', value);
2681
+ }; break;
2682
+
2683
+ case 'description': {
2684
+ addCommentTag('DESCRIPTION', value);
2685
+ }; break;
2686
+
2687
+ case 'artist': {
2688
+ addCommentTag('ARTIST', value);
2689
+ }; break;
2690
+
2691
+ case 'album': {
2692
+ addCommentTag('ALBUM', value);
2693
+ }; break;
2694
+
2695
+ case 'albumArtist': {
2696
+ addCommentTag('ALBUMARTIST', value);
2697
+ }; break;
2698
+
2699
+ case 'genre': {
2700
+ addCommentTag('GENRE', value);
2701
+ }; break;
2702
+
2703
+ case 'date': {
2704
+ const rawVersion = tags.raw?.['DATE'] ?? tags.raw?.['date'];
2705
+ if (rawVersion && typeof rawVersion === 'string') {
2706
+ addCommentTag('DATE', rawVersion);
2707
+ } else {
2708
+ addCommentTag('DATE', value.toISOString().slice(0, 10));
2709
+ }
2710
+ }; break;
2711
+
2712
+ case 'comment': {
2713
+ addCommentTag('COMMENT', value);
2714
+ }; break;
2715
+
2716
+ case 'lyrics': {
2717
+ addCommentTag('LYRICS', value);
2718
+ }; break;
2719
+
2720
+ case 'trackNumber': {
2721
+ addCommentTag('TRACKNUMBER', value.toString());
2722
+ }; break;
2723
+
2724
+ case 'tracksTotal': {
2725
+ addCommentTag('TRACKTOTAL', value.toString());
2726
+ }; break;
2727
+
2728
+ case 'discNumber': {
2729
+ addCommentTag('DISCNUMBER', value.toString());
2730
+ }; break;
2731
+
2732
+ case 'discsTotal': {
2733
+ addCommentTag('DISCTOTAL', value.toString());
2734
+ }; break;
2735
+
2736
+ case 'images': {
2737
+ // For example, in .flac, we put the pictures in a different section,
2738
+ // not in the Vorbis comment header.
2739
+ if (!writeImages) {
2740
+ break;
2741
+ }
2742
+ for (const image of value) {
2743
+ // https://datatracker.ietf.org/doc/rfc9639/ Section 8.8
2744
+ const pictureType = image.kind === 'coverFront' ? 3 : image.kind === 'coverBack' ? 4 : 0;
2745
+ const encodedMediaType = new Uint8Array(image.mimeType.length);
2746
+
2747
+ for (let i = 0; i < image.mimeType.length; i++) {
2748
+ encodedMediaType[i] = image.mimeType.charCodeAt(i);
2749
+ }
2750
+
2751
+ const encodedDescription = textEncoder.encode(image.description ?? '');
2752
+
2753
+ const buffer = new Uint8Array(
2754
+ 4 // Picture type
2755
+ + 4 // MIME type length
2756
+ + encodedMediaType.length // MIME type
2757
+ + 4 // Description length
2758
+ + encodedDescription.length // Description
2759
+ + 16 // Width, height, color depth, number of colors
2760
+ + 4 // Picture data length
2761
+ + image.data.length, // Picture data
2762
+ );
2763
+ const view = toDataView(buffer);
2764
+
2765
+ view.setUint32(0, pictureType, false);
2766
+ view.setUint32(4, encodedMediaType.length, false);
2767
+ buffer.set(encodedMediaType, 8);
2768
+ view.setUint32(8 + encodedMediaType.length, encodedDescription.length, false);
2769
+ buffer.set(encodedDescription, 12 + encodedMediaType.length);
2770
+ // Skip a bunch of fields (width, height, color depth, number of colors)
2771
+ view.setUint32(
2772
+ 28 + encodedMediaType.length + encodedDescription.length, image.data.length, false,
2773
+ );
2774
+ buffer.set(
2775
+ image.data,
2776
+ 32 + encodedMediaType.length + encodedDescription.length,
2777
+ );
2778
+
2779
+ const encoded = bytesToBase64(buffer);
2780
+ addCommentTag('METADATA_BLOCK_PICTURE', encoded);
2781
+ }
2782
+ }; break;
2783
+
2784
+ case 'raw': {
2785
+ // Handled later
2786
+ }; break;
2787
+
2788
+ default: assertNever(key);
2789
+ }
2790
+ }
2791
+
2792
+ if (tags.raw) {
2793
+ for (const key in tags.raw) {
2794
+ const value = tags.raw[key] ?? tags.raw[key.toLowerCase()];
2795
+ if (key === 'vendor' || value == null || writtenTags.has(key)) {
2796
+ continue;
2797
+ }
2798
+
2799
+ if (typeof value === 'string') {
2800
+ addCommentTag(key, value);
2801
+ }
2802
+ }
2803
+ }
2804
+
2805
+ const listLengthBuffer = new Uint8Array(4);
2806
+ toDataView(listLengthBuffer).setUint32(0, writtenTags.size, true);
2807
+ commentHeaderParts.splice(2, 0, listLengthBuffer); // Insert after the header and vendor section
2808
+
2809
+ // Merge all comment header parts into a single buffer
2810
+ const commentHeaderLength = commentHeaderParts.reduce((a, b) => a + b.length, 0);
2811
+ const commentHeader = new Uint8Array(commentHeaderLength);
2812
+
2813
+ let pos = 0;
2814
+ for (const part of commentHeaderParts) {
2815
+ commentHeader.set(part, pos);
2816
+ pos += part.length;
2817
+ }
2818
+
2819
+ return commentHeader;
2820
+ };
2821
+
2822
+ // ============================================================================
2823
+ // AC-3 / E-AC-3 Parsing
2824
+ // Reference: ETSI TS 102 366 V1.4.1
2825
+ // ============================================================================
2826
+
2827
+ /**
2828
+ * Channel counts indexed by acmod (Table 4.3).
2829
+ * Does NOT include LFE - add lfeon to get total channel count.
2830
+ */
2831
+ export const AC3_ACMOD_CHANNEL_COUNTS = [2, 1, 2, 3, 3, 4, 4, 5];
2832
+
2833
+ export interface Ac3FrameInfo {
2834
+ /** Sample rate code */
2835
+ fscod: number;
2836
+ /** Bitstream ID */
2837
+ bsid: number;
2838
+ /** Bitstream mode */
2839
+ bsmod: number;
2840
+ /** Audio coding mode */
2841
+ acmod: number;
2842
+ /** LFE channel on */
2843
+ lfeon: number;
2844
+ /** Bit rate code (0-18, maps to bitrate via Table F.4.1) */
2845
+ bitRateCode: number;
2846
+ }
2847
+
2848
+ /**
2849
+ * Parse an AC-3 syncframe to extract BSI (Bit Stream Information) fields.
2850
+ * Section 4.3
2851
+ */
2852
+ export const parseAc3SyncFrame = (data: Uint8Array): Ac3FrameInfo | null => {
2853
+ if (data.length < 7) {
2854
+ return null;
2855
+ }
2856
+
2857
+ // Check sync word (0x0B77)
2858
+ if (data[0] !== 0x0B || data[1] !== 0x77) {
2859
+ return null;
2860
+ }
2861
+
2862
+ const bitstream = new Bitstream(data);
2863
+ bitstream.skipBits(16); // sync word
2864
+ bitstream.skipBits(16); // crc1
2865
+
2866
+ const fscod = bitstream.readBits(2);
2867
+ if (fscod === 3) {
2868
+ return null; // Reserved, invalid
2869
+ }
2870
+
2871
+ const frmsizecod = bitstream.readBits(6);
2872
+ const bsid = bitstream.readBits(5);
2873
+
2874
+ // Verify this is AC-3
2875
+ if (bsid > 8) {
2876
+ return null;
2877
+ }
2878
+
2879
+ const bsmod = bitstream.readBits(3);
2880
+ const acmod = bitstream.readBits(3);
2881
+
2882
+ // Skip cmixlev (center downmix level) if three front channels are in use (L, C, R).
2883
+ if ((acmod & 0x1) !== 0 && acmod !== 0x1) {
2884
+ bitstream.skipBits(2);
2885
+ }
2886
+
2887
+ // Skip surmixlev (surround downmix level) if surround channels are in use.
2888
+ if ((acmod & 0x4) !== 0) {
2889
+ bitstream.skipBits(2);
2890
+ }
2891
+
2892
+ // Skip dsurmod if stereo (acmod === 2)
2893
+ if (acmod === 0x2) {
2894
+ bitstream.skipBits(2);
2895
+ }
2896
+
2897
+ const lfeon = bitstream.readBits(1);
2898
+ const bitRateCode = Math.floor(frmsizecod / 2);
2899
+
2900
+ return { fscod, bsid, bsmod, acmod, lfeon, bitRateCode };
2901
+ };
2902
+
2903
+ /**
2904
+ * AC-3 frame sizes in bytes, indexed by [3 * frmsizecod + fscod].
2905
+ * fscod: 0=48kHz, 1=44.1kHz, 2=32kHz
2906
+ * Values are 16-bit words * 2 (to convert to bytes).
2907
+ * Table 4.13
2908
+ */
2909
+ export const AC3_FRAME_SIZES = [
2910
+ // frmsizecod, [48kHz, 44.1kHz, 32kHz] in bytes
2911
+ 64 * 2, 69 * 2, 96 * 2,
2912
+ 64 * 2, 70 * 2, 96 * 2,
2913
+ 80 * 2, 87 * 2, 120 * 2,
2914
+ 80 * 2, 88 * 2, 120 * 2,
2915
+ 96 * 2, 104 * 2, 144 * 2,
2916
+ 96 * 2, 105 * 2, 144 * 2,
2917
+ 112 * 2, 121 * 2, 168 * 2,
2918
+ 112 * 2, 122 * 2, 168 * 2,
2919
+ 128 * 2, 139 * 2, 192 * 2,
2920
+ 128 * 2, 140 * 2, 192 * 2,
2921
+ 160 * 2, 174 * 2, 240 * 2,
2922
+ 160 * 2, 175 * 2, 240 * 2,
2923
+ 192 * 2, 208 * 2, 288 * 2,
2924
+ 192 * 2, 209 * 2, 288 * 2,
2925
+ 224 * 2, 243 * 2, 336 * 2,
2926
+ 224 * 2, 244 * 2, 336 * 2,
2927
+ 256 * 2, 278 * 2, 384 * 2,
2928
+ 256 * 2, 279 * 2, 384 * 2,
2929
+ 320 * 2, 348 * 2, 480 * 2,
2930
+ 320 * 2, 349 * 2, 480 * 2,
2931
+ 384 * 2, 417 * 2, 576 * 2,
2932
+ 384 * 2, 418 * 2, 576 * 2,
2933
+ 448 * 2, 487 * 2, 672 * 2,
2934
+ 448 * 2, 488 * 2, 672 * 2,
2935
+ 512 * 2, 557 * 2, 768 * 2,
2936
+ 512 * 2, 558 * 2, 768 * 2,
2937
+ 640 * 2, 696 * 2, 960 * 2,
2938
+ 640 * 2, 697 * 2, 960 * 2,
2939
+ 768 * 2, 835 * 2, 1152 * 2,
2940
+ 768 * 2, 836 * 2, 1152 * 2,
2941
+ 896 * 2, 975 * 2, 1344 * 2,
2942
+ 896 * 2, 976 * 2, 1344 * 2,
2943
+ 1024 * 2, 1114 * 2, 1536 * 2,
2944
+ 1024 * 2, 1115 * 2, 1536 * 2,
2945
+ 1152 * 2, 1253 * 2, 1728 * 2,
2946
+ 1152 * 2, 1254 * 2, 1728 * 2,
2947
+ 1280 * 2, 1393 * 2, 1920 * 2,
2948
+ 1280 * 2, 1394 * 2, 1920 * 2,
2949
+ ];
2950
+
2951
+ /** Number of samples per AC-3 syncframe (always 1536) */
2952
+ export const AC3_SAMPLES_PER_FRAME = 1536;
2953
+
2954
+ /**
2955
+ * AC-3 registration_descriptor for MPEG-TS.
2956
+ * Section A.2.3
2957
+ */
2958
+ export const AC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x41, 0x43, 0x2d, 0x33]);
2959
+
2960
+ /** E-AC-3 registration_descriptor for MPEG-TS/ */
2961
+ export const EAC3_REGISTRATION_DESCRIPTOR = new Uint8Array([0x05, 0x04, 0x45, 0x41, 0x43, 0x33]);
2962
+
2963
+ /** Number of audio blocks per syncframe, indexed by numblkscod */
2964
+ export const EAC3_NUMBLKS_TABLE = [1, 2, 3, 6];
2965
+
2966
+ /**
2967
+ * E-AC-3 independent substream info.
2968
+ * Each independent substream represents a separate audio program.
2969
+ */
2970
+ export interface Eac3SubstreamInfo {
2971
+ /** Sample rate code */
2972
+ fscod: number;
2973
+ /** Sample rate code 2 (ATSC A/52:2018) */
2974
+ fscod2: number | null;
2975
+ /** Bitstream ID */
2976
+ bsid: number;
2977
+ /** Bitstream mode */
2978
+ bsmod: number;
2979
+ /** Audio coding mode */
2980
+ acmod: number;
2981
+ /** LFE channel on */
2982
+ lfeon: number;
2983
+ /** Number of dependent substreams */
2984
+ numDepSub: number;
2985
+ /** Channel locations for dependent substreams */
2986
+ chanLoc: number;
2987
+ }
2988
+
2989
+ /**
2990
+ * E-AC-3 decoder configuration (dec3 box contents).
2991
+ */
2992
+ export interface Eac3FrameInfo {
2993
+ /** Data rate in kbps */
2994
+ dataRate: number;
2995
+ /** Independent substreams */
2996
+ substreams: Eac3SubstreamInfo[];
2997
+ }
2998
+
2999
+ /**
3000
+ * Parse an E-AC-3 syncframe to extract BSI fields.
3001
+ * Section E.1.2
3002
+ */
3003
+ export const parseEac3SyncFrame = (data: Uint8Array): Eac3FrameInfo | null => {
3004
+ if (data.length < 6) {
3005
+ return null;
3006
+ }
3007
+
3008
+ // Check sync word (0x0B77)
3009
+ if (data[0] !== 0x0B || data[1] !== 0x77) {
3010
+ return null;
3011
+ }
3012
+
3013
+ const bitstream = new Bitstream(data);
3014
+ bitstream.skipBits(16); // sync word
3015
+
3016
+ const strmtyp = bitstream.readBits(2);
3017
+ bitstream.skipBits(3); // substreamid
3018
+
3019
+ // Only parse independent substreams (strmtyp 0 or 2)
3020
+ if (strmtyp !== 0 && strmtyp !== 2) {
3021
+ return null;
3022
+ }
3023
+
3024
+ const frmsiz = bitstream.readBits(11);
3025
+ const fscod = bitstream.readBits(2);
3026
+
3027
+ let fscod2 = 0;
3028
+ let numblkscod: number;
3029
+
3030
+ if (fscod === 3) {
3031
+ // fscod2 enables reduced sample rates (24/22.05/16 kHz) per ATSC A/52:2018
3032
+ fscod2 = bitstream.readBits(2);
3033
+ numblkscod = 3; // Implicitly 6 blocks when fscod=3
3034
+ } else {
3035
+ numblkscod = bitstream.readBits(2);
3036
+ }
3037
+
3038
+ const acmod = bitstream.readBits(3);
3039
+ const lfeon = bitstream.readBits(1);
3040
+ const bsid = bitstream.readBits(5);
3041
+
3042
+ // Verify this is E-AC-3
3043
+ if (bsid < 11 || bsid > 16) {
3044
+ return null;
3045
+ }
3046
+
3047
+ // Calculate data rate: ((frmsiz + 1) * fs) / (numblks * 16)
3048
+ const numblks = EAC3_NUMBLKS_TABLE[numblkscod]!;
3049
+ let fs: number;
3050
+ if (fscod < 3) {
3051
+ fs = AC3_SAMPLE_RATES[fscod]! / 1000;
3052
+ } else {
3053
+ fs = EAC3_REDUCED_SAMPLE_RATES[fscod2]! / 1000;
3054
+ }
3055
+ const dataRate = Math.round(((frmsiz + 1) * fs) / (numblks * 16));
3056
+
3057
+ // These fields require parsing beyond the first frame.
3058
+ // Defaults are correct for almost all content.
3059
+ const bsmod = 0;
3060
+ const numDepSub = 0;
3061
+ const chanLoc = 0;
3062
+
3063
+ const substream: Eac3SubstreamInfo = {
3064
+ fscod,
3065
+ fscod2,
3066
+ bsid,
3067
+ bsmod,
3068
+ acmod,
3069
+ lfeon,
3070
+ numDepSub,
3071
+ chanLoc,
3072
+ };
3073
+
3074
+ return {
3075
+ dataRate,
3076
+ substreams: [substream],
3077
+ };
3078
+ };
3079
+
3080
+ /**
3081
+ * Parse a dec3 box to extract E-AC-3 parameters.
3082
+ * Section F.6
3083
+ */
3084
+ export const parseEac3Config = (data: Uint8Array): Eac3FrameInfo | null => {
3085
+ if (data.length < 2) {
3086
+ return null;
3087
+ }
3088
+
3089
+ const bitstream = new Bitstream(data);
3090
+
3091
+ const dataRate = bitstream.readBits(13);
3092
+ const numIndSub = bitstream.readBits(3);
3093
+
3094
+ const substreams: Eac3SubstreamInfo[] = [];
3095
+
3096
+ for (let i = 0; i <= numIndSub; i++) {
3097
+ // Check we have enough data for this substream
3098
+ // Each substream needs at least 24 bits (3 bytes) without dependent subs
3099
+ if (Math.ceil(bitstream.pos / 8) + 3 > data.length) {
3100
+ break;
3101
+ }
3102
+
3103
+ const fscod = bitstream.readBits(2);
3104
+ const bsid = bitstream.readBits(5);
3105
+ bitstream.skipBits(1); // reserved
3106
+ bitstream.skipBits(1); // asvc
3107
+ const bsmod = bitstream.readBits(3);
3108
+ const acmod = bitstream.readBits(3);
3109
+ const lfeon = bitstream.readBits(1);
3110
+ bitstream.skipBits(3); // reserved
3111
+ const numDepSub = bitstream.readBits(4);
3112
+
3113
+ let chanLoc = 0;
3114
+
3115
+ if (numDepSub > 0) {
3116
+ chanLoc = bitstream.readBits(9);
3117
+ } else {
3118
+ bitstream.skipBits(1); // reserved
3119
+ }
3120
+
3121
+ substreams.push({
3122
+ fscod,
3123
+ fscod2: null,
3124
+ bsid,
3125
+ bsmod,
3126
+ acmod,
3127
+ lfeon,
3128
+ numDepSub,
3129
+ chanLoc,
3130
+ });
3131
+ }
3132
+
3133
+ if (substreams.length === 0) {
3134
+ return null;
3135
+ }
3136
+
3137
+ return { dataRate, substreams };
3138
+ };
3139
+
3140
+ /**
3141
+ * Get sample rate from E-AC-3 config.
3142
+ * See ATSC A/52:2018 for handling fscod2.
3143
+ */
3144
+ export const getEac3SampleRate = (config: Eac3FrameInfo): number | null => {
3145
+ const sub = config.substreams[0];
3146
+ assert(sub);
3147
+
3148
+ if (sub.fscod < 3) {
3149
+ return AC3_SAMPLE_RATES[sub.fscod]!;
3150
+ } else if (sub.fscod2 !== null && sub.fscod2 < 3) {
3151
+ return EAC3_REDUCED_SAMPLE_RATES[sub.fscod2]!;
3152
+ }
3153
+
3154
+ return null;
3155
+ };
3156
+
3157
+ /**
3158
+ * Get channel count from E-AC-3 config (first independent substream only).
3159
+ */
3160
+ export const getEac3ChannelCount = (config: Eac3FrameInfo): number => {
3161
+ const sub = config.substreams[0];
3162
+ assert(sub);
3163
+
3164
+ let channels = AC3_ACMOD_CHANNEL_COUNTS[sub.acmod]! + sub.lfeon;
3165
+
3166
+ // Add channels from dependent substreams
3167
+ if (sub.numDepSub > 0) {
3168
+ const CHAN_LOC_COUNTS = [2, 2, 1, 1, 2, 2, 2, 1, 1];
3169
+
3170
+ for (let bit = 0; bit < 9; bit++) {
3171
+ if (sub.chanLoc & (1 << (8 - bit))) {
3172
+ channels += CHAN_LOC_COUNTS[bit]!;
3173
+ }
3174
+ }
3175
+ }
3176
+
3177
+ return channels;
3178
+ };