@blockcast/mmt-container 0.1.0-main.149f78a4adae

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 (678) hide show
  1. package/README.md +432 -0
  2. package/dist/.build-stamp +0 -0
  3. package/dist/__tests__/test-utils.d.ts +71 -0
  4. package/dist/__tests__/test-utils.d.ts.map +1 -0
  5. package/dist/align.d.ts +148 -0
  6. package/dist/align.d.ts.map +1 -0
  7. package/dist/align.js +88 -0
  8. package/dist/align.js.map +7 -0
  9. package/dist/audio-init-parser.d.ts +66 -0
  10. package/dist/audio-init-parser.d.ts.map +1 -0
  11. package/dist/audio-init-parser.js +118 -0
  12. package/dist/audio-init-parser.js.map +7 -0
  13. package/dist/audio-ring-buffer.d.ts +50 -0
  14. package/dist/audio-ring-buffer.d.ts.map +1 -0
  15. package/dist/audio-ring-buffer.js +93 -0
  16. package/dist/audio-ring-buffer.js.map +7 -0
  17. package/dist/authored-timing.d.ts +32 -0
  18. package/dist/authored-timing.d.ts.map +1 -0
  19. package/dist/authored-timing.js +32 -0
  20. package/dist/authored-timing.js.map +7 -0
  21. package/dist/browser-runtime.js +17109 -0
  22. package/dist/browser-runtime.js.map +7 -0
  23. package/dist/carp-catalog.d.ts +318 -0
  24. package/dist/carp-catalog.d.ts.map +1 -0
  25. package/dist/carp-catalog.js +549 -0
  26. package/dist/carp-catalog.js.map +7 -0
  27. package/dist/catalog-fec-params.d.ts +82 -0
  28. package/dist/catalog-fec-params.d.ts.map +1 -0
  29. package/dist/catalog-fec-params.js +66 -0
  30. package/dist/catalog-fec-params.js.map +7 -0
  31. package/dist/catalog-network-source.d.ts +19 -0
  32. package/dist/catalog-network-source.d.ts.map +1 -0
  33. package/dist/catalog-network-source.js +22 -0
  34. package/dist/catalog-network-source.js.map +7 -0
  35. package/dist/catalog-validator.d.ts +18 -0
  36. package/dist/catalog-validator.d.ts.map +1 -0
  37. package/dist/catalog-validator.js +7747 -0
  38. package/dist/catalog-validator.js.map +7 -0
  39. package/dist/cmaf-block-assembler.d.ts +168 -0
  40. package/dist/cmaf-block-assembler.d.ts.map +1 -0
  41. package/dist/cmaf-block-assembler.js +1755 -0
  42. package/dist/cmaf-block-assembler.js.map +7 -0
  43. package/dist/cmaf-group-batcher.d.ts +38 -0
  44. package/dist/cmaf-group-batcher.d.ts.map +1 -0
  45. package/dist/cmaf-group-batcher.js +195 -0
  46. package/dist/cmaf-group-batcher.js.map +7 -0
  47. package/dist/cmcd-producer.d.ts +104 -0
  48. package/dist/cmcd-producer.d.ts.map +1 -0
  49. package/dist/cmcd-producer.js +207 -0
  50. package/dist/cmcd-producer.js.map +7 -0
  51. package/dist/codec-utils.d.ts +235 -0
  52. package/dist/codec-utils.d.ts.map +1 -0
  53. package/dist/codec-utils.js +1225 -0
  54. package/dist/codec-utils.js.map +7 -0
  55. package/dist/fec-codec.d.ts +32 -0
  56. package/dist/fec-codec.d.ts.map +1 -0
  57. package/dist/fec-codec.js +47 -0
  58. package/dist/fec-codec.js.map +7 -0
  59. package/dist/fec-manager.d.ts +266 -0
  60. package/dist/fec-manager.d.ts.map +1 -0
  61. package/dist/fec-manager.js +1447 -0
  62. package/dist/fec-manager.js.map +7 -0
  63. package/dist/fec-starvation-detector.d.ts +59 -0
  64. package/dist/fec-starvation-detector.d.ts.map +1 -0
  65. package/dist/fec-starvation-detector.js +75 -0
  66. package/dist/fec-starvation-detector.js.map +7 -0
  67. package/dist/fec-worker-setup.d.ts +76 -0
  68. package/dist/fec-worker-setup.d.ts.map +1 -0
  69. package/dist/fec-worker-setup.js +603 -0
  70. package/dist/fec-worker-setup.js.map +7 -0
  71. package/dist/fmp4-completion.d.ts +30 -0
  72. package/dist/fmp4-completion.d.ts.map +1 -0
  73. package/dist/fmp4-completion.js +21 -0
  74. package/dist/fmp4-completion.js.map +7 -0
  75. package/dist/fmp4-reader.d.ts +37 -0
  76. package/dist/fmp4-reader.d.ts.map +1 -0
  77. package/dist/fmp4-reader.js +100 -0
  78. package/dist/fmp4-reader.js.map +7 -0
  79. package/dist/index.d.ts +47 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +330 -0
  82. package/dist/index.js.map +7 -0
  83. package/dist/iso-bmff-timing.d.ts +47 -0
  84. package/dist/iso-bmff-timing.d.ts.map +1 -0
  85. package/dist/iso-bmff-timing.js +526 -0
  86. package/dist/iso-bmff-timing.js.map +7 -0
  87. package/dist/loc.d.ts +68 -0
  88. package/dist/loc.d.ts.map +1 -0
  89. package/dist/loc.js +143 -0
  90. package/dist/loc.js.map +7 -0
  91. package/dist/manifest-auth-plan.d.ts +30 -0
  92. package/dist/manifest-auth-plan.d.ts.map +1 -0
  93. package/dist/manifest-auth-plan.js +1267 -0
  94. package/dist/manifest-auth-plan.js.map +7 -0
  95. package/dist/media-router.d.ts +338 -0
  96. package/dist/media-router.d.ts.map +1 -0
  97. package/dist/media-router.js +802 -0
  98. package/dist/media-router.js.map +7 -0
  99. package/dist/mfu-reassembler.d.ts +264 -0
  100. package/dist/mfu-reassembler.d.ts.map +1 -0
  101. package/dist/mfu-reassembler.js +2668 -0
  102. package/dist/mfu-reassembler.js.map +7 -0
  103. package/dist/mfu-reassembly-policy.d.ts +24 -0
  104. package/dist/mfu-reassembly-policy.d.ts.map +1 -0
  105. package/dist/mfu-reassembly-policy.js +99 -0
  106. package/dist/mfu-reassembly-policy.js.map +7 -0
  107. package/dist/mmtp-container-parser.d.ts +304 -0
  108. package/dist/mmtp-container-parser.d.ts.map +1 -0
  109. package/dist/mmtp-container-parser.js +5378 -0
  110. package/dist/mmtp-container-parser.js.map +7 -0
  111. package/dist/mmtp-container-parser.no-modules.js +7853 -0
  112. package/dist/mmtp-container-parser.no-modules.js.map +7 -0
  113. package/dist/mmtp-decode-pipeline.d.ts +96 -0
  114. package/dist/mmtp-decode-pipeline.d.ts.map +1 -0
  115. package/dist/mmtp-decode-pipeline.js +5589 -0
  116. package/dist/mmtp-decode-pipeline.js.map +7 -0
  117. package/dist/mmtp-router.d.ts +383 -0
  118. package/dist/mmtp-router.d.ts.map +1 -0
  119. package/dist/mmtp-router.js +8384 -0
  120. package/dist/mmtp-router.js.map +7 -0
  121. package/dist/mmtp-to-cmaf.d.ts +166 -0
  122. package/dist/mmtp-to-cmaf.d.ts.map +1 -0
  123. package/dist/mmtp-to-cmaf.js +781 -0
  124. package/dist/mmtp-to-cmaf.js.map +7 -0
  125. package/dist/multicast-auth-catalog.d.ts +115 -0
  126. package/dist/multicast-auth-catalog.d.ts.map +1 -0
  127. package/dist/multicast-auth-catalog.js +202 -0
  128. package/dist/multicast-auth-catalog.js.map +7 -0
  129. package/dist/multicast-input.d.ts +107 -0
  130. package/dist/multicast-input.d.ts.map +1 -0
  131. package/dist/multicast-input.js +256 -0
  132. package/dist/multicast-input.js.map +7 -0
  133. package/dist/multicast-manager.d.ts +330 -0
  134. package/dist/multicast-manager.d.ts.map +1 -0
  135. package/dist/multicast-manager.js +11032 -0
  136. package/dist/multicast-manager.js.map +7 -0
  137. package/dist/multicast-transport.d.ts +62 -0
  138. package/dist/multicast-transport.d.ts.map +1 -0
  139. package/dist/multicast-transport.js +338 -0
  140. package/dist/multicast-transport.js.map +7 -0
  141. package/dist/multicast-unwrap.d.ts +57 -0
  142. package/dist/multicast-unwrap.d.ts.map +1 -0
  143. package/dist/multicast-unwrap.js +384 -0
  144. package/dist/multicast-unwrap.js.map +7 -0
  145. package/dist/no-modules.d.ts +9 -0
  146. package/dist/no-modules.d.ts.map +1 -0
  147. package/dist/no-modules.js +7819 -0
  148. package/dist/no-modules.js.map +7 -0
  149. package/dist/phase14-catalog-override.d.ts +126 -0
  150. package/dist/phase14-catalog-override.d.ts.map +1 -0
  151. package/dist/phase14-catalog-override.js +155 -0
  152. package/dist/phase14-catalog-override.js.map +7 -0
  153. package/dist/repair-fetch.d.ts +58 -0
  154. package/dist/repair-fetch.d.ts.map +1 -0
  155. package/dist/repair-fetch.js +117 -0
  156. package/dist/repair-fetch.js.map +7 -0
  157. package/dist/sample-combiner.d.ts +182 -0
  158. package/dist/sample-combiner.d.ts.map +1 -0
  159. package/dist/sample-combiner.js +571 -0
  160. package/dist/sample-combiner.js.map +7 -0
  161. package/dist/signaling.d.ts +29 -0
  162. package/dist/signaling.d.ts.map +1 -0
  163. package/dist/signaling.js +232 -0
  164. package/dist/signaling.js.map +7 -0
  165. package/dist/source-auth.d.ts +2 -0
  166. package/dist/source-auth.d.ts.map +1 -0
  167. package/dist/source-auth.js +1220 -0
  168. package/dist/source-auth.js.map +7 -0
  169. package/dist/switching-set-alignment.d.ts +61 -0
  170. package/dist/switching-set-alignment.d.ts.map +1 -0
  171. package/dist/switching-set-alignment.js +85 -0
  172. package/dist/switching-set-alignment.js.map +7 -0
  173. package/dist/timestamp-codec.d.ts +34 -0
  174. package/dist/timestamp-codec.d.ts.map +1 -0
  175. package/dist/timestamp-codec.js +456 -0
  176. package/dist/timestamp-codec.js.map +7 -0
  177. package/dist/track-pipeline-setup.d.ts +72 -0
  178. package/dist/track-pipeline-setup.d.ts.map +1 -0
  179. package/dist/track-pipeline-setup.js +306 -0
  180. package/dist/track-pipeline-setup.js.map +7 -0
  181. package/dist/track-pipeline.d.ts +121 -0
  182. package/dist/track-pipeline.d.ts.map +1 -0
  183. package/dist/track-pipeline.js +229 -0
  184. package/dist/track-pipeline.js.map +7 -0
  185. package/dist/track-session.d.ts +269 -0
  186. package/dist/track-session.d.ts.map +1 -0
  187. package/dist/track-session.js +597 -0
  188. package/dist/track-session.js.map +7 -0
  189. package/dist/transport-pool.d.ts +69 -0
  190. package/dist/transport-pool.d.ts.map +1 -0
  191. package/dist/transport-pool.js +88 -0
  192. package/dist/transport-pool.js.map +7 -0
  193. package/dist/wasm-mfu-reassembler.d.ts +81 -0
  194. package/dist/wasm-mfu-reassembler.d.ts.map +1 -0
  195. package/dist/wasm-mfu-reassembler.js +1915 -0
  196. package/dist/wasm-mfu-reassembler.js.map +7 -0
  197. package/dist/wasm-mmtp-container-parser.d.ts +10 -0
  198. package/dist/wasm-mmtp-container-parser.d.ts.map +1 -0
  199. package/dist/wasm-mmtp-container-parser.js +5635 -0
  200. package/dist/wasm-mmtp-container-parser.js.map +7 -0
  201. package/node_modules/@blockcast/fec-worker/README.md +213 -0
  202. package/node_modules/@blockcast/fec-worker/dist/.build-stamp +0 -0
  203. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +80 -0
  204. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts.map +1 -0
  205. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +270 -0
  206. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js.map +1 -0
  207. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +252 -0
  208. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -0
  209. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js +11 -0
  210. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js.map +1 -0
  211. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts +14 -0
  212. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts.map +1 -0
  213. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +565 -0
  214. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +7 -0
  215. package/node_modules/@blockcast/fec-worker/dist/index.d.ts +10 -0
  216. package/node_modules/@blockcast/fec-worker/dist/index.d.ts.map +1 -0
  217. package/node_modules/@blockcast/fec-worker/dist/index.js +8 -0
  218. package/node_modules/@blockcast/fec-worker/dist/index.js.map +1 -0
  219. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts +20 -0
  220. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts.map +1 -0
  221. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js +349 -0
  222. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js.map +7 -0
  223. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts +104 -0
  224. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts.map +1 -0
  225. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js +181 -0
  226. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js.map +1 -0
  227. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts +179 -0
  228. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts.map +1 -0
  229. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js +47 -0
  230. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js.map +1 -0
  231. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts +9 -0
  232. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts.map +1 -0
  233. package/node_modules/@blockcast/fec-worker/dist/transfer.js +13 -0
  234. package/node_modules/@blockcast/fec-worker/dist/transfer.js.map +1 -0
  235. package/node_modules/@blockcast/fec-worker/package.json +59 -0
  236. package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +309 -0
  237. package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +268 -0
  238. package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +1048 -0
  239. package/node_modules/@blockcast/fec-worker/src/index.ts +32 -0
  240. package/node_modules/@blockcast/fec-worker/src/shred-fec-worker.ts +558 -0
  241. package/node_modules/@blockcast/fec-worker/src/shred-worker-client.ts +222 -0
  242. package/node_modules/@blockcast/fec-worker/src/shred-worker-types.ts +194 -0
  243. package/node_modules/@blockcast/fec-worker/src/transfer.ts +12 -0
  244. package/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  245. package/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  246. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  247. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  248. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  249. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  250. package/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  251. package/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  252. package/node_modules/@blockcast/mmt-base/README.md +120 -0
  253. package/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  254. package/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
  255. package/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  256. package/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
  257. package/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  258. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
  259. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  260. package/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
  261. package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  262. package/node_modules/@blockcast/mmt-base/package.json +49 -0
  263. package/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
  264. package/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
  265. package/node_modules/@blockcast/mmt-fec/README.md +270 -0
  266. package/node_modules/@blockcast/mmt-fec/dist/.build-stamp +0 -0
  267. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +80 -0
  268. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -0
  269. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +294 -0
  270. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -0
  271. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts +72 -0
  272. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts.map +1 -0
  273. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js +192 -0
  274. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js.map +1 -0
  275. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts +46 -0
  276. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts.map +1 -0
  277. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js +96 -0
  278. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js.map +1 -0
  279. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts +33 -0
  280. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts.map +1 -0
  281. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js +57 -0
  282. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js.map +1 -0
  283. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +185 -0
  284. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts.map +1 -0
  285. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +273 -0
  286. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js.map +1 -0
  287. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts +22 -0
  288. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts.map +1 -0
  289. package/node_modules/@blockcast/mmt-fec/dist/index.js +22 -0
  290. package/node_modules/@blockcast/mmt-fec/dist/index.js.map +1 -0
  291. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts +20 -0
  292. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts.map +1 -0
  293. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js +28 -0
  294. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js.map +1 -0
  295. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +174 -0
  296. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -0
  297. package/node_modules/@blockcast/mmt-fec/dist/oti.js +256 -0
  298. package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -0
  299. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts +41 -0
  300. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts.map +1 -0
  301. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js +81 -0
  302. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js.map +1 -0
  303. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  304. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  305. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  306. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  307. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  308. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  309. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  310. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  311. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/README.md +120 -0
  312. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  313. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
  314. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  315. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
  316. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  317. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
  318. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  319. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
  320. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  321. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/package.json +49 -0
  322. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
  323. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
  324. package/node_modules/@blockcast/mmt-fec/package.json +79 -0
  325. package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +369 -0
  326. package/node_modules/@blockcast/mmt-fec/src/block-processor.ts +277 -0
  327. package/node_modules/@blockcast/mmt-fec/src/cmaf-recovery.ts +127 -0
  328. package/node_modules/@blockcast/mmt-fec/src/cmaf-symbols.ts +68 -0
  329. package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +332 -0
  330. package/node_modules/@blockcast/mmt-fec/src/index.ts +77 -0
  331. package/node_modules/@blockcast/mmt-fec/src/loc-symbols.ts +34 -0
  332. package/node_modules/@blockcast/mmt-fec/src/oti.ts +319 -0
  333. package/node_modules/@blockcast/mmt-fec/src/reorder-buffer.ts +101 -0
  334. package/node_modules/@blockcast/mmt-manifest-verify/dist/.build-stamp +0 -0
  335. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts +28 -0
  336. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts.map +1 -0
  337. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js +128 -0
  338. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js.map +1 -0
  339. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts +4 -0
  340. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts.map +1 -0
  341. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js +4 -0
  342. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js.map +1 -0
  343. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts +37 -0
  344. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts.map +1 -0
  345. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js +179 -0
  346. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js.map +1 -0
  347. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +90 -0
  348. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -0
  349. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +462 -0
  350. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -0
  351. package/node_modules/@blockcast/mmt-manifest-verify/package.json +45 -0
  352. package/node_modules/@blockcast/mmt-manifest-verify/src/admission.ts +171 -0
  353. package/node_modules/@blockcast/mmt-manifest-verify/src/index.ts +3 -0
  354. package/node_modules/@blockcast/mmt-manifest-verify/src/source-auth.ts +230 -0
  355. package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +636 -0
  356. package/node_modules/@noble/hashes/LICENSE +21 -0
  357. package/node_modules/@noble/hashes/README.md +521 -0
  358. package/node_modules/@noble/hashes/_assert.d.ts +17 -0
  359. package/node_modules/@noble/hashes/_assert.d.ts.map +1 -0
  360. package/node_modules/@noble/hashes/_assert.js +18 -0
  361. package/node_modules/@noble/hashes/_assert.js.map +1 -0
  362. package/node_modules/@noble/hashes/_blake.d.ts +14 -0
  363. package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
  364. package/node_modules/@noble/hashes/_blake.js +50 -0
  365. package/node_modules/@noble/hashes/_blake.js.map +1 -0
  366. package/node_modules/@noble/hashes/_md.d.ts +51 -0
  367. package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
  368. package/node_modules/@noble/hashes/_md.js +162 -0
  369. package/node_modules/@noble/hashes/_md.js.map +1 -0
  370. package/node_modules/@noble/hashes/_u64.d.ts +55 -0
  371. package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
  372. package/node_modules/@noble/hashes/_u64.js +90 -0
  373. package/node_modules/@noble/hashes/_u64.js.map +1 -0
  374. package/node_modules/@noble/hashes/argon2.d.ts +32 -0
  375. package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
  376. package/node_modules/@noble/hashes/argon2.js +401 -0
  377. package/node_modules/@noble/hashes/argon2.js.map +1 -0
  378. package/node_modules/@noble/hashes/blake1.d.ts +106 -0
  379. package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
  380. package/node_modules/@noble/hashes/blake1.js +459 -0
  381. package/node_modules/@noble/hashes/blake1.js.map +1 -0
  382. package/node_modules/@noble/hashes/blake2.d.ts +116 -0
  383. package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
  384. package/node_modules/@noble/hashes/blake2.js +420 -0
  385. package/node_modules/@noble/hashes/blake2.js.map +1 -0
  386. package/node_modules/@noble/hashes/blake2b.d.ts +11 -0
  387. package/node_modules/@noble/hashes/blake2b.d.ts.map +1 -0
  388. package/node_modules/@noble/hashes/blake2b.js +14 -0
  389. package/node_modules/@noble/hashes/blake2b.js.map +1 -0
  390. package/node_modules/@noble/hashes/blake2s.d.ts +20 -0
  391. package/node_modules/@noble/hashes/blake2s.d.ts.map +1 -0
  392. package/node_modules/@noble/hashes/blake2s.js +24 -0
  393. package/node_modules/@noble/hashes/blake2s.js.map +1 -0
  394. package/node_modules/@noble/hashes/blake3.d.ts +54 -0
  395. package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
  396. package/node_modules/@noble/hashes/blake3.js +255 -0
  397. package/node_modules/@noble/hashes/blake3.js.map +1 -0
  398. package/node_modules/@noble/hashes/crypto.d.ts +2 -0
  399. package/node_modules/@noble/hashes/crypto.d.ts.map +1 -0
  400. package/node_modules/@noble/hashes/crypto.js +5 -0
  401. package/node_modules/@noble/hashes/crypto.js.map +1 -0
  402. package/node_modules/@noble/hashes/cryptoNode.d.ts +2 -0
  403. package/node_modules/@noble/hashes/cryptoNode.d.ts.map +1 -0
  404. package/node_modules/@noble/hashes/cryptoNode.js +18 -0
  405. package/node_modules/@noble/hashes/cryptoNode.js.map +1 -0
  406. package/node_modules/@noble/hashes/eskdf.d.ts +47 -0
  407. package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
  408. package/node_modules/@noble/hashes/eskdf.js +166 -0
  409. package/node_modules/@noble/hashes/eskdf.js.map +1 -0
  410. package/node_modules/@noble/hashes/esm/_assert.d.ts +17 -0
  411. package/node_modules/@noble/hashes/esm/_assert.d.ts.map +1 -0
  412. package/node_modules/@noble/hashes/esm/_assert.js +15 -0
  413. package/node_modules/@noble/hashes/esm/_assert.js.map +1 -0
  414. package/node_modules/@noble/hashes/esm/_blake.d.ts +14 -0
  415. package/node_modules/@noble/hashes/esm/_blake.d.ts.map +1 -0
  416. package/node_modules/@noble/hashes/esm/_blake.js +45 -0
  417. package/node_modules/@noble/hashes/esm/_blake.js.map +1 -0
  418. package/node_modules/@noble/hashes/esm/_md.d.ts +51 -0
  419. package/node_modules/@noble/hashes/esm/_md.d.ts.map +1 -0
  420. package/node_modules/@noble/hashes/esm/_md.js +155 -0
  421. package/node_modules/@noble/hashes/esm/_md.js.map +1 -0
  422. package/node_modules/@noble/hashes/esm/_u64.d.ts +55 -0
  423. package/node_modules/@noble/hashes/esm/_u64.d.ts.map +1 -0
  424. package/node_modules/@noble/hashes/esm/_u64.js +67 -0
  425. package/node_modules/@noble/hashes/esm/_u64.js.map +1 -0
  426. package/node_modules/@noble/hashes/esm/argon2.d.ts +32 -0
  427. package/node_modules/@noble/hashes/esm/argon2.d.ts.map +1 -0
  428. package/node_modules/@noble/hashes/esm/argon2.js +392 -0
  429. package/node_modules/@noble/hashes/esm/argon2.js.map +1 -0
  430. package/node_modules/@noble/hashes/esm/blake1.d.ts +106 -0
  431. package/node_modules/@noble/hashes/esm/blake1.d.ts.map +1 -0
  432. package/node_modules/@noble/hashes/esm/blake1.js +452 -0
  433. package/node_modules/@noble/hashes/esm/blake1.js.map +1 -0
  434. package/node_modules/@noble/hashes/esm/blake2.d.ts +116 -0
  435. package/node_modules/@noble/hashes/esm/blake2.d.ts.map +1 -0
  436. package/node_modules/@noble/hashes/esm/blake2.js +413 -0
  437. package/node_modules/@noble/hashes/esm/blake2.js.map +1 -0
  438. package/node_modules/@noble/hashes/esm/blake2b.d.ts +11 -0
  439. package/node_modules/@noble/hashes/esm/blake2b.d.ts.map +1 -0
  440. package/node_modules/@noble/hashes/esm/blake2b.js +11 -0
  441. package/node_modules/@noble/hashes/esm/blake2b.js.map +1 -0
  442. package/node_modules/@noble/hashes/esm/blake2s.d.ts +20 -0
  443. package/node_modules/@noble/hashes/esm/blake2s.d.ts.map +1 -0
  444. package/node_modules/@noble/hashes/esm/blake2s.js +21 -0
  445. package/node_modules/@noble/hashes/esm/blake2s.js.map +1 -0
  446. package/node_modules/@noble/hashes/esm/blake3.d.ts +54 -0
  447. package/node_modules/@noble/hashes/esm/blake3.d.ts.map +1 -0
  448. package/node_modules/@noble/hashes/esm/blake3.js +251 -0
  449. package/node_modules/@noble/hashes/esm/blake3.js.map +1 -0
  450. package/node_modules/@noble/hashes/esm/crypto.d.ts +2 -0
  451. package/node_modules/@noble/hashes/esm/crypto.d.ts.map +1 -0
  452. package/node_modules/@noble/hashes/esm/crypto.js +2 -0
  453. package/node_modules/@noble/hashes/esm/crypto.js.map +1 -0
  454. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts +2 -0
  455. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts.map +1 -0
  456. package/node_modules/@noble/hashes/esm/cryptoNode.js +15 -0
  457. package/node_modules/@noble/hashes/esm/cryptoNode.js.map +1 -0
  458. package/node_modules/@noble/hashes/esm/eskdf.d.ts +47 -0
  459. package/node_modules/@noble/hashes/esm/eskdf.d.ts.map +1 -0
  460. package/node_modules/@noble/hashes/esm/eskdf.js +160 -0
  461. package/node_modules/@noble/hashes/esm/eskdf.js.map +1 -0
  462. package/node_modules/@noble/hashes/esm/hkdf.d.ts +36 -0
  463. package/node_modules/@noble/hashes/esm/hkdf.d.ts.map +1 -0
  464. package/node_modules/@noble/hashes/esm/hkdf.js +82 -0
  465. package/node_modules/@noble/hashes/esm/hkdf.js.map +1 -0
  466. package/node_modules/@noble/hashes/esm/hmac.d.ts +35 -0
  467. package/node_modules/@noble/hashes/esm/hmac.d.ts.map +1 -0
  468. package/node_modules/@noble/hashes/esm/hmac.js +86 -0
  469. package/node_modules/@noble/hashes/esm/hmac.js.map +1 -0
  470. package/node_modules/@noble/hashes/esm/index.d.ts +2 -0
  471. package/node_modules/@noble/hashes/esm/index.d.ts.map +1 -0
  472. package/node_modules/@noble/hashes/esm/index.js +33 -0
  473. package/node_modules/@noble/hashes/esm/index.js.map +1 -0
  474. package/node_modules/@noble/hashes/esm/legacy.d.ts +71 -0
  475. package/node_modules/@noble/hashes/esm/legacy.d.ts.map +1 -0
  476. package/node_modules/@noble/hashes/esm/legacy.js +281 -0
  477. package/node_modules/@noble/hashes/esm/legacy.js.map +1 -0
  478. package/node_modules/@noble/hashes/esm/package.json +10 -0
  479. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts +23 -0
  480. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts.map +1 -0
  481. package/node_modules/@noble/hashes/esm/pbkdf2.js +97 -0
  482. package/node_modules/@noble/hashes/esm/pbkdf2.js.map +1 -0
  483. package/node_modules/@noble/hashes/esm/ripemd160.d.ts +13 -0
  484. package/node_modules/@noble/hashes/esm/ripemd160.d.ts.map +1 -0
  485. package/node_modules/@noble/hashes/esm/ripemd160.js +13 -0
  486. package/node_modules/@noble/hashes/esm/ripemd160.js.map +1 -0
  487. package/node_modules/@noble/hashes/esm/scrypt.d.ts +34 -0
  488. package/node_modules/@noble/hashes/esm/scrypt.d.ts.map +1 -0
  489. package/node_modules/@noble/hashes/esm/scrypt.js +228 -0
  490. package/node_modules/@noble/hashes/esm/scrypt.js.map +1 -0
  491. package/node_modules/@noble/hashes/esm/sha1.d.ts +11 -0
  492. package/node_modules/@noble/hashes/esm/sha1.d.ts.map +1 -0
  493. package/node_modules/@noble/hashes/esm/sha1.js +11 -0
  494. package/node_modules/@noble/hashes/esm/sha1.js.map +1 -0
  495. package/node_modules/@noble/hashes/esm/sha2.d.ts +159 -0
  496. package/node_modules/@noble/hashes/esm/sha2.d.ts.map +1 -0
  497. package/node_modules/@noble/hashes/esm/sha2.js +375 -0
  498. package/node_modules/@noble/hashes/esm/sha2.js.map +1 -0
  499. package/node_modules/@noble/hashes/esm/sha256.d.ts +20 -0
  500. package/node_modules/@noble/hashes/esm/sha256.d.ts.map +1 -0
  501. package/node_modules/@noble/hashes/esm/sha256.js +20 -0
  502. package/node_modules/@noble/hashes/esm/sha256.js.map +1 -0
  503. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts +142 -0
  504. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts.map +1 -0
  505. package/node_modules/@noble/hashes/esm/sha3-addons.js +393 -0
  506. package/node_modules/@noble/hashes/esm/sha3-addons.js.map +1 -0
  507. package/node_modules/@noble/hashes/esm/sha3.d.ts +53 -0
  508. package/node_modules/@noble/hashes/esm/sha3.d.ts.map +1 -0
  509. package/node_modules/@noble/hashes/esm/sha3.js +234 -0
  510. package/node_modules/@noble/hashes/esm/sha3.js.map +1 -0
  511. package/node_modules/@noble/hashes/esm/sha512.d.ts +26 -0
  512. package/node_modules/@noble/hashes/esm/sha512.d.ts.map +1 -0
  513. package/node_modules/@noble/hashes/esm/sha512.js +26 -0
  514. package/node_modules/@noble/hashes/esm/sha512.js.map +1 -0
  515. package/node_modules/@noble/hashes/esm/utils.d.ts +161 -0
  516. package/node_modules/@noble/hashes/esm/utils.d.ts.map +1 -0
  517. package/node_modules/@noble/hashes/esm/utils.js +281 -0
  518. package/node_modules/@noble/hashes/esm/utils.js.map +1 -0
  519. package/node_modules/@noble/hashes/hkdf.d.ts +36 -0
  520. package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
  521. package/node_modules/@noble/hashes/hkdf.js +88 -0
  522. package/node_modules/@noble/hashes/hkdf.js.map +1 -0
  523. package/node_modules/@noble/hashes/hmac.d.ts +35 -0
  524. package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
  525. package/node_modules/@noble/hashes/hmac.js +91 -0
  526. package/node_modules/@noble/hashes/hmac.js.map +1 -0
  527. package/node_modules/@noble/hashes/index.d.ts +1 -0
  528. package/node_modules/@noble/hashes/index.d.ts.map +1 -0
  529. package/node_modules/@noble/hashes/index.js +33 -0
  530. package/node_modules/@noble/hashes/index.js.map +1 -0
  531. package/node_modules/@noble/hashes/legacy.d.ts +71 -0
  532. package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
  533. package/node_modules/@noble/hashes/legacy.js +287 -0
  534. package/node_modules/@noble/hashes/legacy.js.map +1 -0
  535. package/node_modules/@noble/hashes/package.json +266 -0
  536. package/node_modules/@noble/hashes/pbkdf2.d.ts +23 -0
  537. package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
  538. package/node_modules/@noble/hashes/pbkdf2.js +101 -0
  539. package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
  540. package/node_modules/@noble/hashes/ripemd160.d.ts +13 -0
  541. package/node_modules/@noble/hashes/ripemd160.d.ts.map +1 -0
  542. package/node_modules/@noble/hashes/ripemd160.js +16 -0
  543. package/node_modules/@noble/hashes/ripemd160.js.map +1 -0
  544. package/node_modules/@noble/hashes/scrypt.d.ts +34 -0
  545. package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
  546. package/node_modules/@noble/hashes/scrypt.js +232 -0
  547. package/node_modules/@noble/hashes/scrypt.js.map +1 -0
  548. package/node_modules/@noble/hashes/sha1.d.ts +11 -0
  549. package/node_modules/@noble/hashes/sha1.d.ts.map +1 -0
  550. package/node_modules/@noble/hashes/sha1.js +14 -0
  551. package/node_modules/@noble/hashes/sha1.js.map +1 -0
  552. package/node_modules/@noble/hashes/sha2.d.ts +159 -0
  553. package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
  554. package/node_modules/@noble/hashes/sha2.js +384 -0
  555. package/node_modules/@noble/hashes/sha2.js.map +1 -0
  556. package/node_modules/@noble/hashes/sha256.d.ts +20 -0
  557. package/node_modules/@noble/hashes/sha256.d.ts.map +1 -0
  558. package/node_modules/@noble/hashes/sha256.js +23 -0
  559. package/node_modules/@noble/hashes/sha256.js.map +1 -0
  560. package/node_modules/@noble/hashes/sha3-addons.d.ts +142 -0
  561. package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
  562. package/node_modules/@noble/hashes/sha3-addons.js +402 -0
  563. package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
  564. package/node_modules/@noble/hashes/sha3.d.ts +53 -0
  565. package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
  566. package/node_modules/@noble/hashes/sha3.js +239 -0
  567. package/node_modules/@noble/hashes/sha3.js.map +1 -0
  568. package/node_modules/@noble/hashes/sha512.d.ts +26 -0
  569. package/node_modules/@noble/hashes/sha512.d.ts.map +1 -0
  570. package/node_modules/@noble/hashes/sha512.js +29 -0
  571. package/node_modules/@noble/hashes/sha512.js.map +1 -0
  572. package/node_modules/@noble/hashes/src/_assert.ts +22 -0
  573. package/node_modules/@noble/hashes/src/_blake.ts +50 -0
  574. package/node_modules/@noble/hashes/src/_md.ts +176 -0
  575. package/node_modules/@noble/hashes/src/_u64.ts +91 -0
  576. package/node_modules/@noble/hashes/src/argon2.ts +497 -0
  577. package/node_modules/@noble/hashes/src/blake1.ts +534 -0
  578. package/node_modules/@noble/hashes/src/blake2.ts +486 -0
  579. package/node_modules/@noble/hashes/src/blake2b.ts +10 -0
  580. package/node_modules/@noble/hashes/src/blake2s.ts +20 -0
  581. package/node_modules/@noble/hashes/src/blake3.ts +272 -0
  582. package/node_modules/@noble/hashes/src/crypto.ts +9 -0
  583. package/node_modules/@noble/hashes/src/cryptoNode.ts +15 -0
  584. package/node_modules/@noble/hashes/src/eskdf.ts +187 -0
  585. package/node_modules/@noble/hashes/src/hkdf.ts +88 -0
  586. package/node_modules/@noble/hashes/src/hmac.ts +94 -0
  587. package/node_modules/@noble/hashes/src/index.ts +31 -0
  588. package/node_modules/@noble/hashes/src/legacy.ts +293 -0
  589. package/node_modules/@noble/hashes/src/pbkdf2.ts +122 -0
  590. package/node_modules/@noble/hashes/src/ripemd160.ts +12 -0
  591. package/node_modules/@noble/hashes/src/scrypt.ts +257 -0
  592. package/node_modules/@noble/hashes/src/sha1.ts +10 -0
  593. package/node_modules/@noble/hashes/src/sha2.ts +402 -0
  594. package/node_modules/@noble/hashes/src/sha256.ts +24 -0
  595. package/node_modules/@noble/hashes/src/sha3-addons.ts +499 -0
  596. package/node_modules/@noble/hashes/src/sha3.ts +258 -0
  597. package/node_modules/@noble/hashes/src/sha512.ts +34 -0
  598. package/node_modules/@noble/hashes/src/utils.ts +395 -0
  599. package/node_modules/@noble/hashes/utils.d.ts +161 -0
  600. package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
  601. package/node_modules/@noble/hashes/utils.js +313 -0
  602. package/node_modules/@noble/hashes/utils.js.map +1 -0
  603. package/package.json +203 -0
  604. package/schemas/catalog.schema.json +283 -0
  605. package/src/align.ts +235 -0
  606. package/src/audio-init-parser.ts +189 -0
  607. package/src/audio-ring-buffer.ts +120 -0
  608. package/src/authored-timing.ts +63 -0
  609. package/src/carp-catalog.ts +776 -0
  610. package/src/catalog-fec-params.ts +167 -0
  611. package/src/catalog-network-source.ts +49 -0
  612. package/src/catalog-validator.ts +34 -0
  613. package/src/cmaf-block-assembler.ts +1058 -0
  614. package/src/cmaf-group-batcher.ts +104 -0
  615. package/src/cmcd-producer.ts +329 -0
  616. package/src/codec-utils.ts +1539 -0
  617. package/src/fec-codec.ts +61 -0
  618. package/src/fec-manager.ts +1939 -0
  619. package/src/fec-starvation-detector.ts +128 -0
  620. package/src/fec-worker-setup.ts +177 -0
  621. package/src/fmp4-completion.ts +47 -0
  622. package/src/fmp4-reader.ts +112 -0
  623. package/src/index.ts +443 -0
  624. package/src/iso-bmff-timing.ts +688 -0
  625. package/src/loc.ts +181 -0
  626. package/src/manifest-auth-plan.ts +107 -0
  627. package/src/media-router.ts +1185 -0
  628. package/src/mfu-reassembler.ts +2842 -0
  629. package/src/mfu-reassembly-policy.ts +134 -0
  630. package/src/mmtp-container-parser.ts +1498 -0
  631. package/src/mmtp-decode-pipeline.ts +315 -0
  632. package/src/mmtp-router.ts +3027 -0
  633. package/src/mmtp-to-cmaf.ts +956 -0
  634. package/src/multicast-auth-catalog.ts +340 -0
  635. package/src/multicast-input.ts +439 -0
  636. package/src/multicast-manager.ts +1503 -0
  637. package/src/multicast-transport.ts +320 -0
  638. package/src/multicast-unwrap.ts +132 -0
  639. package/src/no-modules.ts +20 -0
  640. package/src/phase14-catalog-override.ts +336 -0
  641. package/src/repair-fetch.ts +217 -0
  642. package/src/sample-combiner.ts +846 -0
  643. package/src/signaling.ts +78 -0
  644. package/src/source-auth.ts +1 -0
  645. package/src/switching-set-alignment.ts +109 -0
  646. package/src/timestamp-codec.ts +265 -0
  647. package/src/track-pipeline-setup.ts +189 -0
  648. package/src/track-pipeline.ts +332 -0
  649. package/src/track-session.ts +778 -0
  650. package/src/transport-pool.ts +128 -0
  651. package/src/wasm-mfu-reassembler.ts +372 -0
  652. package/src/wasm-mmtp-container-parser.ts +23 -0
  653. package/test-vectors/align.json +199 -0
  654. package/test-vectors/catalog/README.md +25 -0
  655. package/test-vectors/catalog/negative/legacy-selection-params.json +15 -0
  656. package/test-vectors/catalog/negative/missing-mmtp-fields.json +12 -0
  657. package/test-vectors/catalog/negative/multicast-auth-padded-key.json +37 -0
  658. package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +53 -0
  659. package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +37 -0
  660. package/test-vectors/catalog/negative/multicast-endpoint-missing-protocol-and-source.json +24 -0
  661. package/test-vectors/catalog/negative/network-source-object.json +25 -0
  662. package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +26 -0
  663. package/test-vectors/catalog/negative/repair-track-legacy-shape.json +18 -0
  664. package/test-vectors/catalog/negative/track-role-empty.json +16 -0
  665. package/test-vectors/catalog/negative/track-role-non-string.json +16 -0
  666. package/test-vectors/catalog/positive/fec-multicast.json +51 -0
  667. package/test-vectors/catalog/positive/flat-av.json +30 -0
  668. package/test-vectors/catalog/positive/multicast-auth-rotation.json +55 -0
  669. package/test-vectors/catalog/positive/ticks-and-mixed-timescales.json +39 -0
  670. package/test-vectors/catalog/positive/track-role.json +49 -0
  671. package/test-vectors/catalog/releases/moqcast-native-v16-v1/catalog.json +65 -0
  672. package/test-vectors/catalog/releases/moqcast-native-v16-v1.archive.sha256 +1 -0
  673. package/test-vectors/catalog-multicast-auth-v1.json +26 -0
  674. package/test-vectors/catalog-validation.json +148 -0
  675. package/test-vectors/catalog-validator-public-api.mjs +25 -0
  676. package/test-vectors/generate-source-auth-fixture.mjs +114 -0
  677. package/test-vectors/source-auth-v1.json +61 -0
  678. package/test-vectors/subsample-placement-v1.json +230 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/mmtp-to-cmaf.ts", "../src/codec-utils.ts", "../src/authored-timing.ts", "../src/cmaf-block-assembler.ts"],
4
+ "sourcesContent": ["/**\n * MMTP \u2192 CMAF converter per draft-ramadan-moq-mmt \u00A75.3.\n *\n * Converts reassembled MFU frames (raw codec samples from MMTP) into\n * fMP4 segments (moof+mdat) suitable for MSE SourceBuffer.appendBuffer().\n *\n * MPU metadata (fragment_type=0) packets from FFmpeg are complete\n * ftyp+moov init segments and can be used directly as MSE init data.\n *\n * MFU data (fragment_type=2) contains raw AVCC samples that must be\n * wrapped in moof+mdat boxes for MSE consumption.\n *\n * ISO 14496-12 (ISOBMFF) box construction is inline \u2014 no dependencies.\n */\n\n// \u2500\u2500 ISOBMFF box helpers \u2500\u2500\n\nfunction box(type: string, ...children: Uint8Array[]): Uint8Array {\n let size = 8\n for (const c of children) size += c.length\n const buf = new Uint8Array(size)\n new DataView(buf.buffer).setUint32(0, size)\n buf[4] = type.charCodeAt(0)\n buf[5] = type.charCodeAt(1)\n buf[6] = type.charCodeAt(2)\n buf[7] = type.charCodeAt(3)\n let pos = 8\n for (const c of children) {\n buf.set(c, pos)\n pos += c.length\n }\n return buf\n}\n\nfunction fullBox(type: string, version: number, flags: number, ...children: Uint8Array[]): Uint8Array {\n let size = 12\n for (const c of children) size += c.length\n const buf = new Uint8Array(size)\n const dv = new DataView(buf.buffer)\n dv.setUint32(0, size)\n buf[4] = type.charCodeAt(0)\n buf[5] = type.charCodeAt(1)\n buf[6] = type.charCodeAt(2)\n buf[7] = type.charCodeAt(3)\n dv.setUint32(8, (version << 24) | (flags & 0xffffff))\n let pos = 12\n for (const c of children) {\n buf.set(c, pos)\n pos += c.length\n }\n return buf\n}\n\nfunction u32(v: number): Uint8Array {\n const b = new Uint8Array(4)\n new DataView(b.buffer).setUint32(0, v)\n return b\n}\n\n// \u2500\u2500 Sample flags per ISO 14496-12 \u00A78.8.3.1 \u2500\u2500\nconst KEYFRAME_FLAGS = 0x02000000\nconst DELTA_FLAGS = 0x01010000\n\n// \u2500\u2500 Track geometry field ranges per ISO 14496-12 \u2500\u2500\n// tkhd/trex/tfhd track_ID and the mdhd/mvhd timescales are all unsigned 32-bit\n// fields, written below with DataView.setUint32. That call takes the value\n// modulo 2^32 without complaint, so an out-of-range configuration does not\n// fail \u2014 it silently emits different geometry than the caller asked for\n// (trackId 2^32 becomes track 0, which no fragment can ever reference).\nconst UINT32_MAX = 0xffffffff\n// mvhd next_track_ID is emitted as track_ID + 1 by both buildVideoInitSegment\n// and buildAudioInitSegment (ISO 14496-12 \u00A78.2.2.3, \"a non-zero integer\"). At\n// track_ID = UINT32_MAX that sum wraps to 0, which is both invalid and\n// indistinguishable from an unset field, so the largest usable track_ID is one\n// below the field maximum. (Cited by symbol, not line: this repo's docs gate\n// exists because line anchors rot silently \u2014 see rustfmt.yml's citation check.)\nconst MAX_TRACK_ID = UINT32_MAX - 1\nconst INT32_MIN = -0x80000000\nconst INT32_MAX = 0x7fffffff\n\n/**\n * Fail closed on a track_ID the fMP4 writers below cannot serialize faithfully.\n *\n * Called from both low-level encoders (encodeDataSegment,\n * encodeMultiSampleSegment) so every fragment path is covered by construction\n * rather than by enumerating callers. The class wrappers and init builders call\n * it earlier as well \u2014 partly for a clearer label, partly because the encoders\n * receive an already-incremented sequence number, so their throw would gap the\n * sequence on a call that emitted nothing.\n */\nfunction assertTrackId(trackId: number, label: string): void {\n if (!Number.isInteger(trackId) || trackId <= 0 || trackId > MAX_TRACK_ID) {\n throw new RangeError(`${label} must be an integer in 1..${MAX_TRACK_ID}, got ${trackId}`)\n }\n}\n\n/** Fail closed on a timescale the mdhd/mvhd uint32 fields cannot hold. */\nfunction assertTimescale(timescale: number, label: string): void {\n if (!Number.isInteger(timescale) || timescale <= 0 || timescale > UINT32_MAX) {\n throw new RangeError(`${label} must be an integer in 1..${UINT32_MAX}, got ${timescale}`)\n }\n}\n\n/** Fail closed on a signed trun sample_composition_time_offset. */\nfunction assertCompositionTimeOffsets(\n samples: Array<{ compositionTimeOffset?: number }>,\n): void {\n for (let i = 0; i < samples.length; i++) {\n const offset = samples[i]!.compositionTimeOffset\n if (offset !== undefined &&\n (!Number.isInteger(offset) || offset < INT32_MIN || offset > INT32_MAX)) {\n throw new RangeError(\n `sample ${i} compositionTimeOffset must be an integer in ${INT32_MIN}..${INT32_MAX}, got ${offset}`,\n )\n }\n }\n}\n\n/**\n * Wrap multiple samples in a single moof+mdat fMP4 segment.\n *\n * Builds a trun with N sample entries (duration + size + flags each).\n * Used by CmafBlockAssembler to emit one segment per FEC source block.\n *\n * @param samples - Array of samples with data, duration (timescale units), keyframe flag,\n * and an optional signed composition-time offset (same timescale units)\n * @param baseDecodeTime - Decode time of the first sample in timescale units\n * @param sequence - moof sequence number\n * @param trackId - ISO track ID (default 1)\n * @returns moof+mdat bytes ready for SourceBuffer.appendBuffer()\n */\nexport function encodeMultiSampleSegment(\n samples: Array<{\n data: Uint8Array\n duration: number\n keyframe: boolean\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n sequence: number,\n trackId = 1,\n): Uint8Array {\n if (samples.length === 0) return new Uint8Array(0)\n assertTrackId(trackId, 'trackId')\n assertCompositionTimeOffsets(samples)\n\n const mfhd = fullBox('mfhd', 0, 0, u32(sequence))\n const tfhd = fullBox('tfhd', 0, 0x020000, u32(trackId))\n\n // tfdt version=1 for 64-bit baseMediaDecodeTime\n const tfdtBody = new Uint8Array(8)\n const tfdtView = new DataView(tfdtBody.buffer)\n tfdtView.setUint32(0, Math.floor(baseDecodeTime / 0x100000000))\n tfdtView.setUint32(4, baseDecodeTime >>> 0)\n const tfdt = fullBox('tfdt', 1, 0, tfdtBody)\n\n // A composition-time offset is signed only in trun version 1. When one is\n // present, every sample gets the field; omitted offsets are encoded as zero.\n const hasCompositionTimeOffset = samples.some(sample => sample.compositionTimeOffset !== undefined)\n const trunVersion = hasCompositionTimeOffset ? 1 : 0\n const trunFlags = 0x000701 | (hasCompositionTimeOffset ? 0x000800 : 0)\n // 4 bytes sample_count + 4 bytes data_offset + N * (4+4+4 [+4]) per sample\n const sampleCount = samples.length\n const sampleEntrySize = hasCompositionTimeOffset ? 16 : 12\n const trunBody = new Uint8Array(8 + sampleCount * sampleEntrySize)\n const trunView = new DataView(trunBody.buffer)\n trunView.setUint32(0, sampleCount)\n trunView.setUint32(4, 0) // dataOffset placeholder\n for (let i = 0; i < sampleCount; i++) {\n const s = samples[i]!\n const off = 8 + i * sampleEntrySize\n trunView.setUint32(off, s.duration >>> 0)\n trunView.setUint32(off + 4, s.data.length)\n trunView.setUint32(off + 8, s.keyframe ? KEYFRAME_FLAGS : DELTA_FLAGS)\n if (hasCompositionTimeOffset) {\n trunView.setInt32(off + 12, s.compositionTimeOffset ?? 0)\n }\n }\n const trun = fullBox('trun', trunVersion, trunFlags, trunBody)\n\n const traf = box('traf', tfhd, tfdt, trun)\n const moof = box('moof', mfhd, traf)\n\n // Concatenate all sample data into mdat\n let mdatSize = 0\n for (const s of samples) mdatSize += s.data.length\n const mdatPayload = new Uint8Array(mdatSize)\n let pos = 0\n for (const s of samples) {\n mdatPayload.set(s.data, pos)\n pos += s.data.length\n }\n const mdat = box('mdat', mdatPayload)\n\n // Fix trun.dataOffset: moof size + 8 (mdat box header)\n const dataOffsetPos = 8 + mfhd.length + 8 + tfhd.length + tfdt.length + 12 + 4\n new DataView(moof.buffer).setUint32(dataOffsetPos, moof.length + 8)\n\n const result = new Uint8Array(moof.length + mdat.length)\n result.set(moof, 0)\n result.set(mdat, moof.length)\n return result\n}\n\n// \u2500\u2500 Green fill / silence generators \u2500\u2500\n\n/**\n * Generate a minimal H.264 IDR slice NAL for green fill (YUV 0,128,128).\n *\n * Reuses SPS/PPS from the stream's avcC so the fill frame is compatible\n * with the existing decoder configuration. Returns AVCC-framed data\n * (4-byte length prefix per NAL) ready for moof+mdat wrapping.\n *\n * @param avcC - Raw avcC payload from catalog description\n * @param width - Video width in pixels\n * @param height - Video height in pixels\n */\nexport function generateGreenFillNAL(avcC: Uint8Array, width: number, height: number): Uint8Array {\n // Parse SPS and PPS from avcC box payload\n // avcC layout: version(1) + profile(1) + compat(1) + level(1) + lengthSizeMinusOne(1)\n // + numSPS(1) + [spsLen(2) + spsData]... + numPPS(1) + [ppsLen(2) + ppsData]...\n if (avcC.length < 8) return new Uint8Array(0)\n\n const lengthSize = (avcC[4]! & 0x03) + 1 // NAL length field size (usually 4)\n let offset = 5\n const numSPS = avcC[offset++]! & 0x1f\n const nals: Uint8Array[] = []\n\n // Extract SPS NAL(s)\n for (let i = 0; i < numSPS; i++) {\n if (offset + 2 > avcC.length) break\n const spsLen = (avcC[offset]! << 8) | avcC[offset + 1]!\n offset += 2\n if (offset + spsLen > avcC.length) break\n const sps = avcC.subarray(offset, offset + spsLen)\n // AVCC frame: 4-byte length + NAL\n const framed = new Uint8Array(4 + sps.length)\n new DataView(framed.buffer).setUint32(0, sps.length)\n framed.set(sps, 4)\n nals.push(framed)\n offset += spsLen\n }\n\n // Extract PPS NAL(s)\n if (offset < avcC.length) {\n const numPPS = avcC[offset++]!\n for (let i = 0; i < numPPS; i++) {\n if (offset + 2 > avcC.length) break\n const ppsLen = (avcC[offset]! << 8) | avcC[offset + 1]!\n offset += 2\n if (offset + ppsLen > avcC.length) break\n const pps = avcC.subarray(offset, offset + ppsLen)\n const framed = new Uint8Array(4 + pps.length)\n new DataView(framed.buffer).setUint32(0, pps.length)\n framed.set(pps, 4)\n nals.push(framed)\n offset += ppsLen\n }\n }\n\n // Build minimal IDR slice NAL (NAL type 5)\n // Slice header: first_mb_in_slice=0, slice_type=7 (I), pic_parameter_set_id=0\n // Exp-Golomb coded: 0(1 bit) + 0001000(slice_type=7=I-all, ue(v)) + 1(pps_id=0, ue(v))\n // Then fill with green macroblocks.\n //\n // For a minimal valid IDR that decodes to green, we use:\n // nal_type=5 (IDR), slice_type=I, then CABAC/CAVLC all-intra-16x16\n // with luma DC=0, chroma DC=128. Exact encoding depends on SPS entropy mode.\n //\n // Simplified approach: generate a very small IDR slice that MSE will accept.\n // The slice header + minimal macroblock data. The decoder fills with the\n // predicted values which default to mid-gray/green.\n const mbWidth = Math.ceil(width / 16)\n const mbHeight = Math.ceil(height / 16)\n const totalMBs = mbWidth * mbHeight\n\n // Minimal IDR slice: nal_ref_idc=3, nal_type=5\n // Slice header bits: first_mb=0 (1 bit ue), slice_type=7 (I-all, 0001000 ue),\n // pps_id=0 (1 bit ue), frame_num=0 (depends on SPS log2_max)\n // We construct a minimal bitstream that encodes an all-skip I-slice.\n // For simplicity, build a fixed small IDR payload \u2014 the decoder will\n // pad/error-conceal remaining MBs producing a solid fill frame.\n const idrSlice = new Uint8Array([\n 0x65, // nal_ref_idc=3, nal_type=5 (IDR)\n 0x88, // slice header: first_mb_in_slice=0, slice_type=7 (I)\n 0x80, // pps_id=0, frame_num=0, idr_pic_id=0\n 0x40, // slice data: mb_skip_run covering remaining MBs\n // Truncated \u2014 decoder will error-conceal remaining MBs as green/gray\n ])\n const idrFramed = new Uint8Array(4 + idrSlice.length)\n new DataView(idrFramed.buffer).setUint32(0, idrSlice.length)\n idrFramed.set(idrSlice, 4)\n nals.push(idrFramed)\n\n // Concatenate all NALs: SPS + PPS + IDR\n let totalLen = 0\n for (const n of nals) totalLen += n.length\n const result = new Uint8Array(totalLen)\n let p = 0\n for (const n of nals) {\n result.set(n, p)\n p += n.length\n }\n return result\n}\n\n/**\n * Generate a minimal silent audio frame for FEC fill.\n *\n * Supports AAC (mp4a) and Opus codecs. Returns raw frame data (no ADTS/OBU\n * header) suitable for fMP4/CMAF wrapping.\n *\n * @param codec - Audio codec string (e.g. 'mp4a.40.2', 'opus')\n * @param sampleRate - Audio sample rate (e.g. 48000)\n * @param channels - Channel count (e.g. 1 or 2)\n */\nexport function generateSilenceFrame(codec: string, sampleRate: number, channels: number): Uint8Array {\n if (codec.startsWith('opus') || codec.startsWith('Opus')) {\n return generateSilenceOpus(channels)\n }\n return generateSilenceAAC(sampleRate, channels)\n}\n\n/** Minimal silent AAC-LC access unit (raw, no ADTS). */\nfunction generateSilenceAAC(sampleRate: number, channels: number): Uint8Array {\n if (channels >= 2) {\n // CPE (channel pair element) + END\n return new Uint8Array([\n 0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80,\n ])\n }\n // SCE (single channel element) + END\n return new Uint8Array([\n 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,\n ])\n}\n\n/** Minimal silent Opus frame.\n * RFC 6716 \u00A73.1: a 1-byte frame with code 0 encodes silence for SILK/CELT. */\nfunction generateSilenceOpus(channels: number): Uint8Array {\n // Opus TOC byte: config=0 (SILK NB 10ms), s=0 (mono/stereo from channel mapping), c=0 (1 frame)\n // Frame data: single zero byte \u2192 silence\n // For stereo, channel mapping in fMP4 init handles routing; the Opus frame itself is the same.\n return new Uint8Array([0xF8, 0xFF, 0xFE])\n}\n\nexport function normalizeAacSampleForCmaf(data: Uint8Array): Uint8Array {\n if (data.length < 7 || data[0] !== 0xff || (data[1]! & 0xf6) !== 0xf0) {\n return data\n }\n const headerLength = (data[1]! & 0x01) ? 7 : 9\n if (data.length <= headerLength) return data\n const frameLength = ((data[3]! & 0x03) << 11) | (data[4]! << 3) | ((data[5]! & 0xe0) >>> 5)\n if (frameLength !== data.length || frameLength <= headerLength) return data\n return data.subarray(headerLength)\n}\n\n/**\n * Wrap a single raw codec sample in a moof+mdat fMP4 segment.\n *\n * @param data - Raw sample bytes (AVCC H.264 or raw AAC)\n * @param timestamp - Decode time in timescale units\n * @param duration - Sample duration in timescale units\n * @param keyframe - true for IDR/sync sample\n * @param sequence - moof sequence number (monotonically incrementing)\n * @param trackId - ISO track ID (default 1)\n * @returns moof+mdat bytes ready for SourceBuffer.appendBuffer()\n */\nexport function encodeDataSegment(\n data: Uint8Array,\n timestamp: number,\n duration: number,\n keyframe: boolean,\n sequence: number,\n trackId = 1,\n compositionTimeOffset?: number,\n): Uint8Array {\n assertTrackId(trackId, 'trackId')\n assertCompositionTimeOffsets([{ compositionTimeOffset }])\n if (compositionTimeOffset !== undefined) {\n return encodeMultiSampleSegment(\n [{ data, duration, keyframe, compositionTimeOffset }],\n timestamp,\n sequence,\n trackId,\n )\n }\n const sampleFlags = keyframe ? KEYFRAME_FLAGS : DELTA_FLAGS\n\n const mfhd = fullBox('mfhd', 0, 0, u32(sequence))\n const tfhd = fullBox('tfhd', 0, 0x020000, u32(trackId))\n\n // tfdt version=1 for 64-bit baseMediaDecodeTime\n const tfdtBody = new Uint8Array(8)\n const tfdtView = new DataView(tfdtBody.buffer)\n tfdtView.setUint32(0, Math.floor(timestamp / 0x100000000))\n tfdtView.setUint32(4, timestamp >>> 0)\n const tfdt = fullBox('tfdt', 1, 0, tfdtBody)\n\n // trun: flags=0x000701 (data-offset + duration + size + flags)\n const trunBody = new Uint8Array(20)\n const trunView = new DataView(trunBody.buffer)\n trunView.setUint32(0, 1) // sample_count\n trunView.setUint32(4, 0) // dataOffset placeholder\n trunView.setUint32(8, duration >>> 0)\n trunView.setUint32(12, data.length)\n trunView.setUint32(16, sampleFlags)\n const trun = fullBox('trun', 0, 0x000701, trunBody)\n\n const traf = box('traf', tfhd, tfdt, trun)\n const moof = box('moof', mfhd, traf)\n const mdat = box('mdat', data)\n\n // Fix trun.dataOffset: moof size + 8 (mdat box header)\n const dataOffsetPos = 8 + mfhd.length + 8 + tfhd.length + tfdt.length + 12 + 4\n new DataView(moof.buffer).setUint32(dataOffsetPos, moof.length + 8)\n\n const result = new Uint8Array(moof.length + mdat.length)\n result.set(moof, 0)\n result.set(mdat, moof.length)\n return result\n}\n\n/**\n * Build an ftyp+moov init segment for H.264 video MSE from an avcC box.\n *\n * @param avcC - Raw avcC box payload (SPS/PPS configuration)\n * @param width - Video width in pixels\n * @param height - Video height in pixels\n * @param timescale - Timescale (default 1_000_000 = microseconds)\n * @param trackId - Track ID (default 1)\n */\nexport function buildVideoInitSegment(\n avcC: Uint8Array,\n width: number,\n height: number,\n timescale = 1_000_000,\n trackId = 1,\n): Uint8Array {\n // Validated here as well as in setVideoTrackParams: this builder is exported\n // from the package index, so a direct caller reaches the same uint32 tkhd /\n // trex / mdhd / mvhd fields without passing through the class.\n assertTrackId(trackId, 'video trackId')\n assertTimescale(timescale, 'video timescale')\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x6d, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x6d,\n 0x69, 0x73, 0x6f, 0x36,\n 0x6d, 0x70, 0x34, 0x31,\n ]))\n\n const avcCBox = box('avcC', avcC)\n const avc1Body = new Uint8Array(78 + avcCBox.length)\n const avc1View = new DataView(avc1Body.buffer)\n avc1View.setUint16(6, 1)\n avc1View.setUint16(24, width)\n avc1View.setUint16(26, height)\n avc1View.setUint32(28, 0x00480000)\n avc1View.setUint32(32, 0x00480000)\n avc1View.setUint16(40, 1)\n avc1View.setUint16(74, 0x0018)\n avc1View.setInt16(76, -1)\n avc1Body.set(avcCBox, 78)\n const avc1 = box('avc1', avc1Body)\n\n const stsd = fullBox('stsd', 0, 0, u32(1), avc1)\n const stbl = box('stbl', stsd,\n fullBox('stts', 0, 0, u32(0)),\n fullBox('stsc', 0, 0, u32(0)),\n fullBox('stsz', 0, 0, u32(0), u32(0)),\n fullBox('stco', 0, 0, u32(0)),\n )\n const dinf = box('dinf', fullBox('dref', 0, 0, u32(1), fullBox('url ', 0, 1)))\n const minf = box('minf', fullBox('vmhd', 0, 1), dinf, stbl)\n const hdlr = fullBox('hdlr', 0, 0, new Uint8Array([\n 0, 0, 0, 0, 0x76, 0x69, 0x64, 0x65,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x56, 0x69, 0x64, 0x65, 0x6f, 0,\n ]))\n const mdhdBody = new Uint8Array(20)\n new DataView(mdhdBody.buffer).setUint32(8, timescale)\n const mdhd = fullBox('mdhd', 0, 0, mdhdBody)\n const mdia = box('mdia', mdhd, hdlr, minf)\n\n const tkhdBody = new Uint8Array(80)\n const tkhdView = new DataView(tkhdBody.buffer)\n tkhdView.setUint32(8, trackId)\n tkhdView.setUint32(36, 0x00010000)\n tkhdView.setUint32(52, 0x00010000)\n tkhdView.setUint32(64, 0x40000000)\n tkhdView.setUint32(72, width << 16)\n tkhdView.setUint32(76, height << 16)\n const tkhd = fullBox('tkhd', 0, 3, tkhdBody)\n const trak = box('trak', tkhd, mdia)\n\n const mvhdBody = new Uint8Array(96)\n const mvhdView = new DataView(mvhdBody.buffer)\n mvhdView.setUint32(8, timescale)\n mvhdView.setUint32(16, 0x00010000)\n mvhdView.setUint16(20, 0x0100)\n mvhdView.setUint32(32, 0x00010000)\n mvhdView.setUint32(48, 0x00010000)\n mvhdView.setUint32(60, 0x40000000)\n mvhdView.setUint32(92, trackId + 1)\n const mvhd = fullBox('mvhd', 0, 0, mvhdBody)\n\n const trexBody = new Uint8Array(20)\n new DataView(trexBody.buffer).setUint32(0, trackId)\n new DataView(trexBody.buffer).setUint32(4, 1)\n const mvex = box('mvex', fullBox('trex', 0, 0, trexBody))\n\n const moov = box('moov', mvhd, trak, mvex)\n const result = new Uint8Array(ftyp.length + moov.length)\n result.set(ftyp, 0)\n result.set(moov, ftyp.length)\n return result\n}\n\n/**\n * Build ftyp+moov init segment for AAC audio MSE.\n */\nexport function buildAudioInitSegment(\n sampleRate: number,\n channels: number,\n asc?: Uint8Array,\n timescale?: number,\n trackId = 1,\n): Uint8Array {\n // trackId only: this reaches the same uint32 tkhd/trex/mvhd fields as the\n // video builder. The audio *timescale* is deliberately left unchecked here \u2014\n // wrapAudioSample branches on its exact value, so constraining it belongs\n // with that path rather than in this range fix.\n assertTrackId(trackId, 'audio trackId')\n const ts = timescale ?? sampleRate\n\n if (!asc) {\n const freqTable = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]\n const fi = freqTable.indexOf(sampleRate)\n const freqIdx = fi >= 0 ? fi : 0x0f\n if (freqIdx <= 0x0e) {\n const v = (2 << 11) | (freqIdx << 7) | (channels << 3)\n asc = new Uint8Array([(v >> 8) & 0xff, v & 0xff])\n } else {\n asc = new Uint8Array([\n (2 << 3) | 0x07,\n (0x08 | ((sampleRate >> 20) & 0x07)) & 0xff,\n (sampleRate >> 12) & 0xff,\n (sampleRate >> 4) & 0xff,\n (((sampleRate & 0x0f) << 4) | (channels << 0)) & 0xff,\n ])\n }\n }\n\n // esds: ES_Descriptor \u2192 DecoderConfigDescriptor \u2192 AudioSpecificConfig\n const dsi = new Uint8Array(2 + asc.length)\n dsi[0] = 0x05; dsi[1] = asc.length; dsi.set(asc, 2)\n const dcdBody = new Uint8Array(13 + dsi.length)\n dcdBody[0] = 0x40; dcdBody[1] = 0x15; dcdBody.set(dsi, 13)\n const dcd = new Uint8Array(2 + dcdBody.length)\n dcd[0] = 0x04; dcd[1] = dcdBody.length; dcd.set(dcdBody, 2)\n const esBody = new Uint8Array(3 + dcd.length)\n esBody[0] = 0; esBody[1] = 0x01; esBody[2] = 0; esBody.set(dcd, 3)\n const es = new Uint8Array(2 + esBody.length)\n es[0] = 0x03; es[1] = esBody.length; es.set(esBody, 2)\n const esdsBox = fullBox('esds', 0, 0, es)\n\n const mp4aBody = new Uint8Array(28 + esdsBox.length)\n const mp4aView = new DataView(mp4aBody.buffer)\n mp4aView.setUint16(6, 1)\n mp4aView.setUint16(16, channels)\n mp4aView.setUint16(18, 16)\n mp4aView.setUint32(24, sampleRate << 16)\n mp4aBody.set(esdsBox, 28)\n const mp4a = box('mp4a', mp4aBody)\n\n const stsd = fullBox('stsd', 0, 0, u32(1), mp4a)\n const stbl = box('stbl', stsd,\n fullBox('stts', 0, 0, u32(0)),\n fullBox('stsc', 0, 0, u32(0)),\n fullBox('stsz', 0, 0, u32(0), u32(0)),\n fullBox('stco', 0, 0, u32(0)),\n )\n const dinf = box('dinf', fullBox('dref', 0, 0, u32(1), fullBox('url ', 0, 1)))\n const minf = box('minf', fullBox('smhd', 0, 0, new Uint8Array(4)), dinf, stbl)\n const hdlr = fullBox('hdlr', 0, 0, new Uint8Array([\n 0, 0, 0, 0, 0x73, 0x6f, 0x75, 0x6e,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x53, 0x6f, 0x75, 0x6e, 0x64, 0,\n ]))\n const mdhdBody = new Uint8Array(20)\n new DataView(mdhdBody.buffer).setUint32(8, ts)\n const mdhd = fullBox('mdhd', 0, 0, mdhdBody)\n const mdia = box('mdia', mdhd, hdlr, minf)\n\n const tkhdBody = new Uint8Array(80)\n const tkhdView = new DataView(tkhdBody.buffer)\n tkhdView.setUint32(8, trackId)\n tkhdView.setUint32(36, 0x00010000)\n tkhdView.setUint32(52, 0x00010000)\n tkhdView.setUint32(64, 0x40000000)\n const tkhd = fullBox('tkhd', 0, 3, tkhdBody)\n const trak = box('trak', tkhd, mdia)\n\n const mvhdBody = new Uint8Array(96)\n const mvhdView = new DataView(mvhdBody.buffer)\n mvhdView.setUint32(8, ts)\n mvhdView.setUint32(16, 0x00010000)\n mvhdView.setUint16(20, 0x0100)\n mvhdView.setUint32(32, 0x00010000)\n mvhdView.setUint32(48, 0x00010000)\n mvhdView.setUint32(60, 0x40000000)\n mvhdView.setUint32(92, trackId + 1)\n const mvhd = fullBox('mvhd', 0, 0, mvhdBody)\n\n const trexBody = new Uint8Array(20)\n new DataView(trexBody.buffer).setUint32(0, trackId)\n new DataView(trexBody.buffer).setUint32(4, 1)\n const mvex = box('mvex', fullBox('trex', 0, 0, trexBody))\n\n const moov = box('moov', mvhd, trak, mvex)\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x6d, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x6d,\n 0x69, 0x73, 0x6f, 0x36,\n 0x6d, 0x70, 0x34, 0x31,\n ]))\n const result = new Uint8Array(ftyp.length + moov.length)\n result.set(ftyp, 0)\n result.set(moov, ftyp.length)\n return result\n}\n\n/**\n * MMTP \u2192 CMAF converter.\n *\n * Accepts reassembled MFU frames (raw codec samples) from MmtpDecoder\n * and produces fMP4 segments for MSE SourceBuffer.\n *\n * Per draft-ramadan-moq-mmt \u00A75.3:\n * MPU metadata (ftyp+moov) \u2192 init segment\n * MFU sample bytes \u2192 moof+mdat data segment\n *\n * Timescale is microseconds (1_000_000) matching MMTP NTP short timestamps\n * converted via mmtpTimestampToMicros().\n */\nexport class MmtpToCmaf {\n #videoSeq = 1\n #audioSeq = 1\n #videoInitSegment: Uint8Array | null = null\n // Known only for locally-built init segments. Wire-supplied MPU metadata is\n // intentionally opaque here, so setVideoTrackParams remains the API that\n // lets a caller declare its track geometry before wrapping samples.\n #videoInitTrackId: number | null = null\n #audioInitSegment: Uint8Array | null = null\n #lastVideoTimestamp = 0\n // Sticky sample duration in video timescale units, updated from caller-\n // supplied durations or adjacent-timestamp deltas. null means \"nothing\n // observed yet\", in which case #videoFrameDuration derives ~30fps from the\n // configured timescale (33333 at the 1_000_000 default, i.e. unchanged).\n #frameDuration: number | null = null\n // Per-track rebase: each track anchors on its OWN first sample so\n // baseMediaDecodeTime is never negative. A shared base was wrong \u2014 if the\n // first sample of one track arrives later than the other's first sample,\n // the earlier track computes `timestamp - sharedBase` as a negative number,\n // which serializes into tfdt as a huge unsigned uint64 (~2^64 - 46) and\n // Chromium rejects the segment with CHUNK_DEMUXER_ERROR_APPEND_FAILED,\n // closing the MediaSource and detaching all SourceBuffers.\n // For A/V alignment, choose a COMMON anchor: set when the first sample of\n // EITHER track arrives, but only if that sample's timestamp is <= any\n // subsequent track's first sample. Implementation: each track rebases to\n // the minimum timestamp seen across tracks on their respective first sample.\n #videoBaseTs = -1\n #audioBaseTs = -1\n\n // Video track geometry. These pair with the video init segment's tkhd\n // track_ID and mdhd/mvhd timescale: every moof this converter emits must\n // reference the same track at the same rate or the browser either drops the\n // fragment (unknown track) or plays it at the wrong rate. They are\n // configuration rather than stream state, so \u2014 unlike the sequence numbers\n // and time bases above \u2014 reset() deliberately preserves them, matching the\n // fact that reset() also preserves #videoInitSegment.\n #videoTrackId = 1\n #videoTimescale = 1_000_000\n\n /**\n * Point the single-sample video wrappers at a specific track and rate.\n *\n * Call this when the init segment came off the wire (setInitSegmentFromMpu)\n * rather than from buildVideoInit, so the wrappers match the publisher's\n * tkhd/mdhd instead of assuming trackId=1 at microsecond rate. Consumers\n * that build their init through buildVideoInit can pass the same values\n * there instead and skip this call.\n *\n * The rate is settable only until the first single-sample wrap \u2014 see the\n * throw below for why.\n */\n setVideoTrackParams(trackId: number, timescale: number) {\n assertTrackId(trackId, 'video trackId')\n assertTimescale(timescale, 'video timescale')\n // #frameDuration, #lastVideoTimestamp and #videoBaseTs are all denominated\n // in #videoTimescale, so moving the rate out from under them reinterprets\n // every one at the new rate. Both consequences are silent:\n // - a duration latched as 33333 (1 MHz ~30fps) re-emits as 33333 ticks of\n // 90 kHz, a 370 ms frame;\n // - a base captured on the old scale rebases new-scale timestamps to a\n // negative relTs, which tfdt serializes as a ~2^64 uint64 and Chromium\n // rejects with CHUNK_DEMUXER_ERROR_APPEND_FAILED, closing the\n // MediaSource (same failure the #videoBaseTs comment above describes).\n // Rescaling instead of refusing would be a guess: the class cannot tell\n // whether the caller's next timestamps continue this timeline in new units\n // or open a fresh epoch. reset() is the exact mechanism for that\n // discontinuity \u2014 it clears all three fields while preserving geometry \u2014\n // so require it rather than infer. Re-asserting the same rate is a no-op.\n // A cached init also fixes the track ID in tkhd/trex; changing only the\n // wrapper setting would make later tfhd IDs disagree with that init.\n if (trackId !== this.#videoTrackId && this.#videoInitTrackId !== null) {\n throw new Error(\n `video track ID cannot change from ${this.#videoTrackId} to ${trackId} ` +\n 'after a video init has been cached; replace the init atomically',\n )\n }\n if (timescale !== this.#videoTimescale && this.#videoBaseTs >= 0) {\n throw new Error(\n `video timescale cannot change from ${this.#videoTimescale} to ${timescale} ` +\n `after video samples have been wrapped; call reset() first`,\n )\n }\n this.#videoTrackId = trackId\n this.#videoTimescale = timescale\n }\n\n /** Set init segment from MPU metadata packet (fragment_type=0).\n * These are complete ftyp+moov bytes from FFmpeg \u2014 use directly. */\n setInitSegmentFromMpu(data: Uint8Array, isAudio: boolean) {\n if (isAudio) {\n this.#audioInitSegment = data\n } else {\n this.#videoInitSegment = data\n this.#videoInitTrackId = null\n }\n }\n\n /** Build init segment from codec config (catalog path \u2014 no MPU metadata available).\n * Passing timescale/trackId also configures the wrappers via\n * setVideoTrackParams, so init and media segments cannot disagree. */\n buildVideoInit(avcC: Uint8Array, width: number, height: number, timescale?: number, trackId?: number) {\n const nextTimescale = timescale ?? this.#videoTimescale\n const nextTrackId = trackId ?? this.#videoTrackId\n assertTrackId(nextTrackId, 'video trackId')\n assertTimescale(nextTimescale, 'video timescale')\n if (nextTimescale !== this.#videoTimescale && this.#videoBaseTs >= 0) {\n throw new Error(\n `video timescale cannot change from ${this.#videoTimescale} to ${nextTimescale} ` +\n 'after video samples have been wrapped; call reset() first',\n )\n }\n // Build first, then publish both geometry and init together. This is the\n // sanctioned path for replacing a cached init with a new track ID.\n const init = buildVideoInitSegment(\n avcC,\n width,\n height,\n nextTimescale,\n nextTrackId,\n )\n this.#videoTimescale = nextTimescale\n this.#videoTrackId = nextTrackId\n this.#videoInitSegment = init\n this.#videoInitTrackId = nextTrackId\n }\n\n buildAudioInit(sampleRate: number, channels: number, asc?: Uint8Array, timescale?: number) {\n const ts = timescale ?? sampleRate\n this.#audioTimescale = ts\n this.#audioInitSegment = buildAudioInitSegment(sampleRate, channels, asc, ts)\n }\n\n get videoInitSegment(): Uint8Array | null { return this.#videoInitSegment }\n get audioInitSegment(): Uint8Array | null { return this.#audioInitSegment }\n\n /** Convert a raw video sample to an fMP4 moof+mdat segment. */\n wrapVideoSample(data: Uint8Array, timestamp: number, keyframe: boolean, duration?: number): Uint8Array {\n return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration).segment\n }\n\n /**\n * Convert a raw video sample and return the exact browser media interval\n * encoded into tfdt/trun. Consumers that correlate SourceBuffer appends with\n * requestVideoFrameCallback must use this rebased timestamp, not the wire or\n * caller-owned timestamp passed above.\n */\n wrapVideoSampleWithTiming(\n data: Uint8Array,\n timestamp: number,\n keyframe: boolean,\n duration?: number,\n ): Readonly<{ segment: Uint8Array; mediaTimestamp: number; duration: number }> {\n // Prefer a caller-provided media duration when the browser append timeline\n // is intentionally decoupled from sparse MMTP wire timestamps. Fall back to\n // estimating from adjacent timestamps for legacy/direct callers. A delta of\n // a full second or more is not a frame interval, so it is rejected as a\n // discontinuity rather than latched.\n if (duration !== undefined && Number.isFinite(duration) && duration > 0) {\n this.#frameDuration = Math.round(duration)\n } else if (this.#lastVideoTimestamp > 0 && timestamp > this.#lastVideoTimestamp) {\n const delta = timestamp - this.#lastVideoTimestamp\n if (delta > 0 && delta < this.#videoTimescale) this.#frameDuration = delta\n }\n this.#lastVideoTimestamp = timestamp\n if (this.#videoBaseTs < 0) this.#videoBaseTs = timestamp\n const relTs = timestamp - this.#videoBaseTs\n const frameDuration = this.#videoFrameDuration\n return Object.freeze({\n segment: encodeDataSegment(\n data,\n relTs,\n frameDuration,\n keyframe,\n this.#videoSeq++,\n this.#videoTrackId,\n ),\n mediaTimestamp: relTs,\n duration: frameDuration,\n })\n }\n\n /** Sticky duration if one has been observed, else ~30fps at the current rate. */\n get #videoFrameDuration(): number {\n return this.#frameDuration ?? Math.max(1, Math.round(this.#videoTimescale / 30))\n }\n\n /** Convert an append-safe video batch using the caller-owned timeline.\n * Durations, baseDecodeTime, and compositionTimeOffset are in the\n * configured video timescale. compositionTimeOffset is the signed PTS-DTS\n * delta; its presence selects a version-1 trun for the whole batch.\n * An explicit trackId is range-checked before #videoSeq++ for the same\n * reason as wrapAudioSamples: the encoder's own check fires too late to\n * keep the sequence ungapped. */\n wrapVideoSamples(\n samples: Array<{\n data: Uint8Array\n duration: number\n keyframe: boolean\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n trackId = this.#videoTrackId,\n ): Uint8Array {\n assertTrackId(trackId, 'video trackId')\n assertCompositionTimeOffsets(samples)\n return encodeMultiSampleSegment(samples, baseDecodeTime, this.#videoSeq++, trackId)\n }\n\n // Audio timescale from init segment (default 1M \u00B5s; real FFmpeg init uses sampleRate).\n // Set by buildAudioInit or setAudioTimescale.\n #audioTimescale = 1_000_000\n\n /** Set audio timescale to match the init segment's mdhd timescale.\n * Call after appending the real encoder init (FT=0 ftyp+moov). */\n setAudioTimescale(timescale: number) { this.#audioTimescale = timescale }\n\n // Audio sample counter for drift-free baseMediaDecodeTime.\n // AAC frames are exactly 1024 samples at sampleRate. Using sequential\n // counter \u00D7 1024 avoids floating-point rounding drift from timestamp conversion.\n #audioSampleCount = 0\n\n /** AAC access-unit length in samples. ISO/IEC 14496-3: an AAC-LC frame is\n * exactly 1024 samples at every sample rate \u2014 it is not rate-dependent. */\n readonly #aacFrameSamples = 1024\n\n /** Convert a raw audio sample to an fMP4 moof+mdat segment. */\n wrapAudioSample(\n data: Uint8Array,\n timestamp: number,\n sampleDuration = 21333,\n compositionTimeOffset?: number,\n ): Uint8Array {\n assertCompositionTimeOffsets([{ compositionTimeOffset }])\n const sampleData = normalizeAacSampleForCmaf(data)\n if (this.#audioBaseTs < 0) this.#audioBaseTs = timestamp\n\n // When timescale matches sampleRate (e.g. 48000), use integer sample counting\n // for exact baseMediaDecodeTime alignment. This eliminates cumulative rounding\n // drift from Math.round(\u00B5s * sampleRate / 1_000_000) that causes frequency\n // wandering in FFT analysis (42% consistency \u2192 99%+ with exact counting).\n //\n // samplesPerFrame is the AAC access-unit length, NOT a rescaled duration.\n // Deriving it as Math.round(sampleDuration * timescale / 1e6) only lands on\n // 1024 when the rate happens to be 48 kHz (21333 * 48000 / 1e6 = 1023.98),\n // which made the default silently correct at 48 kHz and wrong everywhere\n // else: at 44.1 kHz it yields 941, so every moof declared ~8% short frames\n // and Chrome rejected the first packet with PIPELINE_ERROR_DECODE\n // (\"Failed to send audio packet for decoding\", duration=21337\u00B5s = 941/44100).\n const samplesPerFrame = this.#audioTimescale !== 1_000_000\n ? this.#aacFrameSamples\n : sampleDuration\n const scaledTs = this.#audioTimescale !== 1_000_000\n ? this.#audioSampleCount * samplesPerFrame\n : (timestamp - this.#audioBaseTs)\n this.#audioSampleCount++\n\n return encodeDataSegment(\n sampleData,\n scaledTs,\n samplesPerFrame,\n true,\n this.#audioSeq++,\n 1,\n compositionTimeOffset,\n )\n }\n\n /** Convert an ordered audio batch using the caller-owned timeline. */\n wrapAudioSamples(\n samples: Array<{\n data: Uint8Array\n duration: number\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n trackId = 1,\n ): Uint8Array {\n // Checked before #audioSeq++ below: the encoder validates too, but its\n // throw would land after the counter had already advanced, leaving the\n // sequence gapped by a call that produced no segment.\n assertTrackId(trackId, 'audio trackId')\n assertCompositionTimeOffsets(samples)\n return encodeMultiSampleSegment(\n samples.map(sample => ({\n data: normalizeAacSampleForCmaf(sample.data),\n duration: sample.duration,\n keyframe: true,\n compositionTimeOffset: sample.compositionTimeOffset,\n })),\n baseDecodeTime,\n this.#audioSeq++,\n trackId,\n )\n }\n\n /** Clear per-stream sequencing and time bases.\n * Cached init segments and the video track geometry survive, so a converter\n * reset mid-subscription keeps emitting moofs the existing init can resolve.\n * Clearing the timescale-denominated timing state also re-opens the video\n * rate for change \u2014 this is the sanctioned way to retarget mid-subscription. */\n reset() {\n this.#videoSeq = 1\n this.#audioSeq = 1\n this.#audioSampleCount = 0\n this.#lastVideoTimestamp = 0\n this.#frameDuration = null\n this.#videoBaseTs = -1\n this.#audioBaseTs = -1\n this.#audioTimescale = 1_000_000\n }\n}\n", "/**\n * H.264/AVC codec utilities for MMTP container format conversion.\n *\n * Shared between moq-lib (hang-mmt-fec) and moqtail players.\n * Handles AVCC\u2194Annex-B conversion, SPS/PPS extraction, fallback avcC generation,\n * and MMTP timestamp conversion.\n *\n * @packageDocumentation\n */\n\n// \u2500\u2500\u2500 Public Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Result of extracting a video codec configuration record from an fMP4 init segment. */\nexport interface AvcCInfo {\n codec: string\n description: Uint8Array\n}\n\n/** Result of extracting AAC AudioSpecificConfig from an fMP4 init segment. */\nexport interface AacAscInfo {\n /** Codec string like \"mp4a.40.2\" (AAC-LC). Derived from AOT in ASC[0] >> 3. */\n codec: string\n /** AudioSpecificConfig bytes \u2014 what AudioDecoder.configure({description}) needs for raw AAC. */\n description: Uint8Array\n}\n\n/** SPS and PPS NAL units extracted from an avcC record. */\nexport interface SpsPps {\n sps: Uint8Array\n pps: Uint8Array\n}\n\n/** Options for fallback avcC generation. */\nexport interface FallbackAvcCOptions {\n /** Codec string like \"avc1.640033\". Profile/constraint/level parsed from hex triplet. */\n codec?: string\n /** Coded width in pixels. Used in SPS pic_width_in_mbs. */\n width?: number\n /** Coded height in pixels. Used in SPS pic_height_in_map_units. */\n height?: number\n}\n\n// \u2500\u2500\u2500 Public Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Extract the codec configuration record (avcC/hvcC/av1C/vpcC) from\n * an fMP4 init segment (moov box).\n * MMTP FT=0 packets contain a complete fMP4: moov > trak > mdia > minf > stbl > stsd > sample entry > codec config.\n *\n * Walks every trak and returns the first supported video sample entry. This\n * handles both per-track CMSF init segments and multiplexed ftyp+moov blobs\n * where the audio trak may appear before video.\n */\nexport function extractAvcCFromInitSegment(data: Uint8Array): AvcCInfo | undefined {\n if (!hasIsoBmffMagic(data)) return undefined\n\n for (const stsd of findTrackStsdBoxes(data)) {\n const info = extractVideoConfigFromStsd(data, stsd)\n if (info) return info\n }\n\n return undefined\n}\n\nfunction extractVideoConfigFromStsd(data: Uint8Array, stsd: { o: number; sz: number }): AvcCInfo | undefined {\n let s = stsd.o + 16\n const e = stsd.o + stsd.sz\n\n // H.264: avc1 VisualSampleEntry \u2192 avcC.\n const avc1 = findBox(data, s, e, 'avc1')\n if (avc1 && avc1.sz >= 86) {\n const avcC = findBox(data, avc1.o + 86, avc1.o + avc1.sz, 'avcC')\n if (avcC && avcC.sz >= 12) {\n const d = data.subarray(avcC.o + 8, avcC.o + avcC.sz)\n const codec = `avc1.${hex2(d[1])}${hex2(d[2])}${hex2(d[3])}`\n return { codec, description: d }\n }\n }\n // HEVC: hvc1/hev1 VisualSampleEntry \u2192 hvcC. Same +86 child-box offset as\n // avc1 (identical VisualSampleEntry layout). Without this branch, HEVC\n // ftyp+moov inits yield no descriptor, so the WebCodecs path configures the\n // VideoDecoder with no `description` and the first length-prefixed hvc1\n // keyframe decode() throws DataError (\"must fill out the description field\"),\n // which the player's MoQ pump catch swallows \u2192 video track silently 0-fps\n // (BLO-8054).\n const hvc1 = findBox(data, s, e, 'hvc1') ?? findBox(data, s, e, 'hev1')\n if (hvc1 && hvc1.sz >= 86) {\n const hvcC = findBox(data, hvc1.o + 86, hvc1.o + hvc1.sz, 'hvcC')\n // HEVCDecoderConfigurationRecord is \u226523 bytes (+8 box header).\n if (hvcC && hvcC.sz >= 8 + 23) {\n const d = data.subarray(hvcC.o + 8, hvcC.o + hvcC.sz)\n return { codec: hevcCodecStringFromHvcC(d), description: d }\n }\n }\n // AV1: av01 VisualSampleEntry -> av1C. Real FFmpeg MMTP inits can carry an\n // empty av1C box (size=8) while still providing the authoritative sample\n // entry/codec signal. Return an empty description for that shape so callers\n // can open their FT=0 gate without passing a zero-byte WebCodecs description.\n const av01 = findBox(data, s, e, 'av01')\n if (av01 && av01.sz >= 86) {\n const av1C = findBox(data, av01.o + 86, av01.o + av01.sz, 'av1C')\n if (av1C && av1C.sz >= 8) {\n const d = data.subarray(av1C.o + 8, av1C.o + av1C.sz)\n return { codec: codecStringFromAv1C(d), description: d }\n }\n }\n // VP9: vp09 VisualSampleEntry -> vpcC. Some encoders omit the VP codec record\n // payload; use the sample entry as readiness evidence and fall back to a\n // conservative vp09 codec string in that case.\n const vp09 = findBox(data, s, e, 'vp09')\n if (vp09 && vp09.sz >= 86) {\n const vpcC = findBox(data, vp09.o + 86, vp09.o + vp09.sz, 'vpcC')\n if (vpcC && vpcC.sz >= 8) {\n const d = data.subarray(vpcC.o + 8, vpcC.o + vpcC.sz)\n return { codec: codecStringFromVpcC(d), description: d }\n }\n }\n return undefined\n}\n\n/**\n * Generate a minimal avcC (AVCDecoderConfigurationRecord) from codec parameters.\n * Parses \"avc1.XXYYZZ\" \u2192 profile_idc=0xXX, constraint_flags=0xYY, level_idc=0xZZ.\n * Width/height are encoded in the SPS; if not provided, they're inferred from the\n * H.264 level's max frame size (e.g. level 4.2 \u2192 2048x1088).\n * Used when late MoQ subscribers miss the FT=0 init segment (moov/avcC).\n */\nexport function generateFallbackAvcC(options?: FallbackAvcCOptions | string): Uint8Array {\n const opts: FallbackAvcCOptions = typeof options === 'string' ? { codec: options } : (options ?? {})\n\n let profile = 0x64\n let constraint = 0x00\n let level = 0x2a\n\n if (opts.codec) {\n const match = opts.codec.match(/^avc[13]\\.([0-9a-fA-F]{6})$/)\n if (match) {\n profile = Number.parseInt(match[1].substring(0, 2), 16)\n constraint = Number.parseInt(match[1].substring(2, 4), 16)\n level = Number.parseInt(match[1].substring(4, 6), 16)\n }\n }\n\n const { width, height } = resolveResolution(opts.width, opts.height, level)\n const sps = buildMinimalSps(profile, constraint, level, width, height)\n const pps = buildMinimalPps(profile)\n\n const avcC = new Uint8Array(5 + 1 + 2 + sps.length + 1 + 2 + pps.length)\n let w = 0\n avcC[w++] = 0x01\n avcC[w++] = profile\n avcC[w++] = constraint\n avcC[w++] = level\n avcC[w++] = 0xff\n avcC[w++] = 0xe1\n avcC[w++] = (sps.length >> 8) & 0xff\n avcC[w++] = sps.length & 0xff\n avcC.set(sps, w)\n w += sps.length\n avcC[w++] = 0x01\n avcC[w++] = (pps.length >> 8) & 0xff\n avcC[w++] = pps.length & 0xff\n avcC.set(pps, w)\n return avcC\n}\n\n/**\n * Extract raw SPS and PPS NAL unit bytes from an avcC (AVCDecoderConfigurationRecord).\n * Returns the first SPS and first PPS found.\n */\nexport function extractSpsPpsFromAvcC(avcC: Uint8Array): SpsPps | undefined {\n if (avcC.length < 8) return undefined\n const numSPS = avcC[5] & 0x1f\n let offset = 6\n let sps: Uint8Array | undefined\n for (let i = 0; i < numSPS && offset + 2 <= avcC.length; i++) {\n const spsLen = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n if (offset + spsLen <= avcC.length) {\n if (!sps) sps = avcC.subarray(offset, offset + spsLen)\n offset += spsLen\n }\n }\n let pps: Uint8Array | undefined\n if (offset < avcC.length) {\n const numPPS = avcC[offset] & 0x1f\n offset++\n for (let i = 0; i < numPPS && offset + 2 <= avcC.length; i++) {\n const ppsLen = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n if (offset + ppsLen <= avcC.length) {\n if (!pps) pps = avcC.subarray(offset, offset + ppsLen)\n offset += ppsLen\n }\n }\n }\n return sps && pps ? { sps, pps } : undefined\n}\n\n/**\n * Convert AVCC (4-byte NAL length prefixed) to Annex-B (start code prefixed).\n * Prepends SPS/PPS NALs before keyframes.\n */\nexport function avccToAnnexB(avccData: Uint8Array, isKeyframe: boolean, spsPps: SpsPps): Uint8Array {\n let offset = 0\n let totalNalSize = 0\n let nalCount = 0\n while (offset + 4 <= avccData.length) {\n const nalLen =\n (avccData[offset] << 24) |\n (avccData[offset + 1] << 16) |\n (avccData[offset + 2] << 8) |\n avccData[offset + 3]\n offset += 4\n if (nalLen <= 0 || offset + nalLen > avccData.length) break\n totalNalSize += nalLen\n nalCount++\n offset += nalLen\n }\n if (nalCount === 0) return avccData\n\n let outSize = nalCount * 4 + totalNalSize\n if (isKeyframe) {\n outSize += 4 + spsPps.sps.length + 4 + spsPps.pps.length\n }\n const out = new Uint8Array(outSize)\n let w = 0\n\n if (isKeyframe) {\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(spsPps.sps, w); w += spsPps.sps.length\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(spsPps.pps, w); w += spsPps.pps.length\n }\n\n offset = 0\n while (offset + 4 <= avccData.length) {\n const nalLen =\n (avccData[offset] << 24) |\n (avccData[offset + 1] << 16) |\n (avccData[offset + 2] << 8) |\n avccData[offset + 3]\n offset += 4\n if (nalLen <= 0 || offset + nalLen > avccData.length) break\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(avccData.subarray(offset, offset + nalLen), w)\n w += nalLen\n offset += nalLen\n }\n return out\n}\n\n/**\n * Build an avcC record by parsing Annex-B data to extract SPS (NAL type 7) and PPS (NAL type 8).\n * Returns the avcC record, or null if SPS/PPS not found.\n */\nexport function extractCodecDescriptionFromAnnexB(data: Uint8Array): Uint8Array | null {\n const nalUnits: Array<{ type: number; data: Uint8Array }> = []\n let i = 0\n while (i < data.length - 4) {\n if (data[i] === 0 && data[i + 1] === 0) {\n let nalStart = 0\n if (data[i + 2] === 1) {\n nalStart = i + 3\n } else if (data[i + 2] === 0 && data[i + 3] === 1) {\n nalStart = i + 4\n }\n if (nalStart > 0 && nalStart < data.length) {\n let nalEnd = data.length\n for (let j = nalStart; j < data.length - 3; j++) {\n if (data[j] === 0 && data[j + 1] === 0 &&\n (data[j + 2] === 1 || (data[j + 2] === 0 && data[j + 3] === 1))) {\n nalEnd = j\n break\n }\n }\n const nalType = data[nalStart] & 0x1f\n nalUnits.push({ type: nalType, data: data.slice(nalStart, nalEnd) })\n i = nalEnd\n continue\n }\n }\n i++\n }\n\n const sps = nalUnits.find(n => n.type === 7)\n const pps = nalUnits.find(n => n.type === 8)\n if (!sps || !pps) return null\n\n const avcCLength = 6 + 2 + sps.data.length + 1 + 2 + pps.data.length\n const avcC = new Uint8Array(avcCLength)\n let offset = 0\n avcC[offset++] = 1\n avcC[offset++] = sps.data[1]\n avcC[offset++] = sps.data[2]\n avcC[offset++] = sps.data[3]\n avcC[offset++] = 0xff\n avcC[offset++] = 0xe1\n avcC[offset++] = (sps.data.length >> 8) & 0xff\n avcC[offset++] = sps.data.length & 0xff\n avcC.set(sps.data, offset); offset += sps.data.length\n avcC[offset++] = 1\n avcC[offset++] = (pps.data.length >> 8) & 0xff\n avcC[offset++] = pps.data.length & 0xff\n avcC.set(pps.data, offset)\n return avcC\n}\n\n/**\n * Derive codec string from avcC record (e.g. \"avc1.640033\").\n */\nexport function codecStringFromAvcC(avcC: Uint8Array): string {\n if (avcC.length < 4) return 'avc1.640033'\n return `avc1.${hex2(avcC[1])}${hex2(avcC[2])}${hex2(avcC[3])}`\n}\n\n/** VPS/SPS/PPS NAL units extracted from an HEVC keyframe (raw NAL bytes, no start code/length prefix). */\nexport interface HevcParameterSets {\n vps?: Uint8Array\n sps?: Uint8Array\n pps?: Uint8Array\n}\n\n/** True for HEVC/H.265 codec strings (hev1.* / hvc1.*). */\nexport function isHevcCodec(codec: string): boolean {\n return codec.startsWith('hev1') || codec.startsWith('hvc1')\n}\n\n/** HEVC NAL unit type from the first NAL header byte: (byte >> 1) & 0x3f. */\nfunction hevcNalType(nal: Uint8Array): number {\n return (nal[0] >> 1) & 0x3f\n}\n\n/**\n * Remove H.26x emulation-prevention bytes (0x03 after 0x00 0x00) from an RBSP so\n * fixed-position fields (e.g. HEVC profile_tier_level) can be read by byte offset.\n */\nexport function removeEmulationPrevention(rbsp: Uint8Array): Uint8Array {\n const out: number[] = []\n let zeros = 0\n for (let i = 0; i < rbsp.length; i++) {\n const b = rbsp[i]\n if (zeros >= 2 && b === 0x03 && i + 1 < rbsp.length && rbsp[i + 1] <= 0x03) {\n zeros = 0\n continue\n }\n out.push(b)\n zeros = b === 0 ? zeros + 1 : 0\n }\n return Uint8Array.from(out)\n}\n\n/**\n * Split an AVCC/hvcC bitstream (length-prefixed NAL units) into raw NAL byte slices.\n * `lengthSize` is the NAL length prefix width (4 for FFmpeg LOC / fMP4 sample data).\n */\nexport function splitAvccNalUnits(data: Uint8Array, lengthSize = 4): Uint8Array[] {\n const nals: Uint8Array[] = []\n let i = 0\n while (i + lengthSize <= data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i + len > data.length) break\n nals.push(data.subarray(i, i + len))\n i += len\n }\n return nals\n}\n\n/**\n * True when `data` is exactly one or more length-prefixed NAL units.\n *\n * This is intentionally stricter than \"starts with a plausible length\": a\n * H.264 AVCC access unit may begin with bytes `00 00 00 01` when the first\n * NAL is a one-byte AUD. That byte pattern is also an Annex-B start code, so\n * callers must prove the whole buffer is complete AVCC before falling back to\n * Annex-B detection/conversion.\n */\nexport function isCompleteAvccSample(data: Uint8Array, lengthSize = 4): boolean {\n let i = 0\n let count = 0\n while (i + lengthSize <= data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i + len > data.length) return false\n i += len\n count++\n }\n return count > 0 && i === data.length\n}\n\nexport type H264SampleFormat = 'avcc' | 'annexb' | 'raw-nal' | 'unknown'\nexport type H264NalUnitFormat = H264SampleFormat | 'partial-avcc'\n\nexport interface H264AvccSample {\n data: Uint8Array\n format: H264SampleFormat\n}\n\nexport interface H264NalUnitSample {\n nals: Uint8Array[]\n format: H264NalUnitFormat\n}\n\n/**\n * Normalize a H.264 access unit/sample to length-prefixed AVCC for fMP4 mdat\n * payloads. Already-AVCC samples are returned as-is. Annex-B and single raw\n * NAL samples are converted one-way to AVCC at the MSE/fMP4 boundary.\n */\nexport function normalizeH264SampleToAvcc(data: Uint8Array): H264AvccSample {\n if (isCompleteAvccSample(data)) return { data, format: 'avcc' }\n if (isAnnexB(data)) return { data: annexBToAvcc(data), format: 'annexb' }\n if (isLikelyRawH264NalUnit(data)) return { data: rawH264NalToAvcc(data), format: 'raw-nal' }\n return { data, format: 'unknown' }\n}\n\n/**\n * Split a H.264 access unit/sample into NAL units without changing its framing.\n * Use this for routing, keyframe gates, and diagnostics. Conversion to AVCC is\n * reserved for `normalizeH264SampleToAvcc` at the fMP4/MSE boundary.\n */\nexport function splitH264SampleNalUnits(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): H264NalUnitSample {\n if (isCompleteAvccSample(data)) return { nals: splitAvccNalUnits(data), format: 'avcc' }\n if (isAnnexB(data)) return { nals: splitAnnexBNalUnits(data), format: 'annexb' }\n if (options.allowPartialAvcc === true) {\n const partial = splitPartialAvccNalUnits(data)\n if (partial.length > 0) return { nals: partial, format: 'partial-avcc' }\n }\n if (isLikelyRawH264NalUnit(data)) return { nals: [data], format: 'raw-nal' }\n const nals = splitAvccNalUnits(data)\n return { nals, format: nals.length > 0 ? 'avcc' : 'unknown' }\n}\n\n/**\n * Extract HEVC VPS (type 32) / SPS (33) / PPS (34) NAL units from a keyframe access\n * unit. Accepts either Annex-B (start-code delimited) or AVCC/hvcC (length-prefixed)\n * framing \u2014 FFmpeg LOC delivers the latter.\n */\nexport function extractHevcParameterSets(keyframe: Uint8Array): HevcParameterSets {\n const nals = isAnnexB(keyframe) ? splitAnnexBNalUnits(keyframe) : splitAvccNalUnits(keyframe)\n const out: HevcParameterSets = {}\n for (const nal of nals) {\n if (nal.length === 0) continue\n const t = hevcNalType(nal)\n if (t === 32 && !out.vps) out.vps = nal\n else if (t === 33 && !out.sps) out.sps = nal\n else if (t === 34 && !out.pps) out.pps = nal\n }\n return out\n}\n\n/**\n * Build a minimal hvcC (HEVCDecoderConfigurationRecord, ISO 14496-15 \u00A78.3.3.1) from\n * VPS/SPS/PPS NAL units. The general profile_tier_level (12 bytes) is copied from the\n * SPS (de-emulated); remaining fields use the common 4:2:0 / 8-bit / 4-byte-NAL-length\n * defaults. Suitable as the `description` for a WebCodecs hvc1 VideoDecoderConfig.\n *\n * WebCodecs REQUIRES a description for length-prefixed HEVC \u2014 unlike H.264, Chrome will\n * not self-configure HEVC from the bitstream (BLO-7764).\n */\nexport function generateHvcCFromParameterSets(sets: HevcParameterSets): Uint8Array | null {\n const { vps, sps, pps } = sets\n if (!sps || !pps) return null\n const spsRbsp = removeEmulationPrevention(sps)\n // general profile_tier_level is 12 bytes at RBSP offset 3:\n // 2-byte NAL header + 1 byte (sps_video_parameter_set_id u(4), sps_max_sub_layers_minus1\n // u(3), sps_temporal_id_nesting_flag u(1)), then general_profile_space..general_level_idc.\n const ptl = spsRbsp.subarray(3, 15)\n const arrays = [\n { type: 32, nal: vps },\n { type: 33, nal: sps },\n { type: 34, nal: pps },\n ].filter((a): a is { type: number; nal: Uint8Array } => a.nal !== undefined)\n\n let size = 23\n for (const a of arrays) size += 5 + a.nal.length\n const h = new Uint8Array(size)\n let o = 0\n h[o++] = 1 // configurationVersion\n for (let i = 0; i < 12; i++) h[o++] = ptl[i] ?? 0 // general profile_tier_level\n h[o++] = 0xf0; h[o++] = 0x00 // reserved(1111) + min_spatial_segmentation_idc(0)\n h[o++] = 0xfc // reserved(111111) + parallelismType(0)\n h[o++] = 0xfd // reserved(111111) + chromaFormat(1 = 4:2:0)\n h[o++] = 0xf8 // reserved(11111) + bitDepthLumaMinus8(0)\n h[o++] = 0xf8 // reserved(11111) + bitDepthChromaMinus8(0)\n h[o++] = 0x00; h[o++] = 0x00 // avgFrameRate(0 = unspecified)\n h[o++] = 0x0b // CFR(0) numTempLayers(1) nested(0) lengthSizeMinusOne(3)\n h[o++] = arrays.length // numOfArrays\n for (const a of arrays) {\n h[o++] = a.type & 0x3f // array_completeness(0) + NAL_unit_type\n h[o++] = 0; h[o++] = 1 // numNalus = 1\n h[o++] = (a.nal.length >> 8) & 0xff\n h[o++] = a.nal.length & 0xff\n h.set(a.nal, o); o += a.nal.length\n }\n return h.subarray(0, o)\n}\n\n/**\n * Build an hvcC `description` for a WebCodecs HEVC VideoDecoderConfig directly from a\n * keyframe access unit (Annex-B or length-prefixed). Returns null if VPS/SPS/PPS aren't\n * present in-band. HEVC analogue of {@link extractCodecDescriptionFromAnnexB}.\n */\nexport function extractHevcCodecDescription(keyframe: Uint8Array): Uint8Array | null {\n return generateHvcCFromParameterSets(extractHevcParameterSets(keyframe))\n}\n\n/**\n * Strip non-VCL NAL units (VPS/SPS/PPS/SEI/AUD, type >= 32) from an HEVC access unit,\n * returning only the VCL NAL units (type <= 31) as a 4-byte length-prefixed buffer.\n *\n * Required when decoding `hvc1` with an explicit hvcC `description`: WebCodecs rejects a\n * sample whose data still carries in-band parameter sets (\"Unable to determine size of\n * bitstream buffer\"). Accepts Annex-B or length-prefixed input. Returns the input\n * unchanged if it already contains only VCL NALs (cheap no-op for delta frames).\n */\nexport function hevcVclOnly(data: Uint8Array): Uint8Array {\n const nals = isAnnexB(data) ? splitAnnexBNalUnits(data) : splitAvccNalUnits(data)\n const vcl = nals.filter((n) => n.length > 0 && hevcNalType(n) <= 31)\n if (vcl.length === nals.length && !isAnnexB(data)) return data\n let size = 0\n for (const n of vcl) size += 4 + n.length\n const out = new Uint8Array(size)\n let o = 0\n for (const n of vcl) {\n out[o++] = (n.length >> 24) & 0xff\n out[o++] = (n.length >> 16) & 0xff\n out[o++] = (n.length >> 8) & 0xff\n out[o++] = n.length & 0xff\n out.set(n, o); o += n.length\n }\n return out\n}\n\n/**\n * Check if data starts with an Annex-B start code (00 00 01 or 00 00 00 01).\n */\nexport function isAnnexB(data: Uint8Array): boolean {\n if (data.length >= 4 && data[0] === 0 && data[1] === 0 &&\n (data[2] === 1 || (data[2] === 0 && data[3] === 1))) {\n return true\n }\n return false\n}\n\n/**\n * Find the byte offset of the first Annex-B start code in data.\n * Returns -1 if no start code found.\n */\nexport function findAnnexBStartCode(data: Uint8Array): number {\n for (let i = 0; i < data.length - 3; i++) {\n if (data[i] === 0 && data[i + 1] === 0) {\n if (data[i + 2] === 1) return i\n if (data[i + 2] === 0 && data[i + 3] === 1) return i\n }\n }\n return -1\n}\n\n/**\n * Split Annex-B bitstream into NAL units.\n * Returns array of NAL unit byte slices (without start codes).\n */\nexport function splitAnnexBNalUnits(data: Uint8Array): Uint8Array[] {\n const nalUnits: Uint8Array[] = []\n let i = 0\n while (i < data.length - 3) {\n if (data[i] === 0 && data[i + 1] === 0) {\n let scLen = 0\n if (data[i + 2] === 1) scLen = 3\n else if (data[i + 2] === 0 && i + 3 < data.length && data[i + 3] === 1) scLen = 4\n if (scLen > 0) {\n const nalStart = i + scLen\n let nalEnd = data.length\n for (let j = nalStart + 1; j < data.length - 2; j++) {\n if (data[j] === 0 && data[j + 1] === 0 &&\n (data[j + 2] === 1 || (data[j + 2] === 0 && j + 3 < data.length && data[j + 3] === 1))) {\n nalEnd = j\n break\n }\n }\n if (nalEnd > nalStart) nalUnits.push(data.subarray(nalStart, nalEnd))\n i = nalEnd\n continue\n }\n }\n i++\n }\n return nalUnits\n}\n\n/**\n * Convert Annex-B (start-code delimited) to AVCC (4-byte length prefixed).\n * Optionally prepends SPS/PPS NALs for keyframes.\n */\nexport function annexBToAvcc(data: Uint8Array, spsPps?: SpsPps): Uint8Array {\n const nalUnits = splitAnnexBNalUnits(data)\n if (nalUnits.length === 0) return data\n\n let extraSize = 0\n if (spsPps) {\n extraSize = 4 + spsPps.sps.length + 4 + spsPps.pps.length\n }\n const frameSize = nalUnits.reduce((sum, nal) => sum + 4 + nal.length, 0)\n const output = new Uint8Array(extraSize + frameSize)\n let w = 0\n\n if (spsPps) {\n w = writeNalLength(output, w, spsPps.sps.length)\n output.set(spsPps.sps, w); w += spsPps.sps.length\n w = writeNalLength(output, w, spsPps.pps.length)\n output.set(spsPps.pps, w); w += spsPps.pps.length\n }\n\n for (const nal of nalUnits) {\n w = writeNalLength(output, w, nal.length)\n output.set(nal, w); w += nal.length\n }\n return output\n}\n\nexport interface H264KeyframeDetectionOptions {\n /**\n * Allow classifying a length-prefixed NAL when the declared NAL length runs\n * beyond this buffer. MMTP routing can see only the first packet fragment of\n * a sample, where the NAL header is present but the full NAL is not.\n */\n allowPartialAvcc?: boolean\n}\n\n/**\n * Classify H.264 keyframe status by scanning NAL units. Returns undefined when\n * the payload is not H.264-classifiable. Handles Annex-B and AVCC formats.\n */\nexport function classifyH264Keyframe(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): boolean | undefined {\n const nals = h264NalUnitsForKeyframeDetection(data, options)\n if (nals.length === 0) return undefined\n let sawIntraSlice = false\n let sawNonIntraVcl = false\n let sawNal = false\n for (const nal of nals) {\n sawNal = true\n const nalType = nal[0] !== undefined ? nal[0] & 0x1f : -1\n if (nalType === 5 || nalType === 7) return true\n if (nalType === 1) {\n if (isH264IntraSlice(nal)) sawIntraSlice = true\n else sawNonIntraVcl = true\n }\n }\n if (sawIntraSlice && !sawNonIntraVcl) return true\n return sawNal ? false : undefined\n}\n\n/**\n * Detect H.264 keyframe by scanning for IDR/SPS or intra non-IDR slices.\n * Handles both Annex-B and AVCC formats.\n */\nexport function detectH264Keyframe(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): boolean {\n return classifyH264Keyframe(data, options) === true\n}\n\n/**\n * Convert MMTP timestamp (NTP short format) to monotonic microseconds.\n * Per ISO 23008-1 \u00A79.2.2 / RFC 5905: upper 16 bits = seconds (lower 16\n * of NTP seconds), lower 16 bits = fractional seconds.\n * Returns a monotonically increasing \u00B5s value within an ~18-hour window.\n */\nexport function mmtpTimestampToMicros(rawTs: bigint | number): number {\n const ts = Number(rawTs) >>> 0 // ensure unsigned 32-bit\n if (ts === 0) return 0\n const seconds = ts >>> 16\n const frac = ts & 0xFFFF\n return seconds * 1_000_000 + Math.floor(frac * 1_000_000 / 65536)\n}\n\n/** Validate the CMSF/MMTP catalog initData contract: complete top-level ftyp+moov. */\nexport function isFmp4InitSegment(data: Uint8Array): boolean {\n let offset = 0\n let sawFtyp = false\n let sawMoov = false\n\n while (offset + 8 <= data.byteLength) {\n const view = new DataView(data.buffer, data.byteOffset + offset, data.byteLength - offset)\n let size = view.getUint32(0, false)\n const type = String.fromCharCode(data[offset + 4]!, data[offset + 5]!, data[offset + 6]!, data[offset + 7]!)\n let headerSize = 8\n\n if (size === 1) {\n if (offset + 16 > data.byteLength) return false\n const largeSize = view.getBigUint64(8, false)\n if (largeSize > BigInt(Number.MAX_SAFE_INTEGER)) return false\n size = Number(largeSize)\n headerSize = 16\n } else if (size === 0) {\n size = data.byteLength - offset\n }\n\n if (size < headerSize || offset + size > data.byteLength) return false\n if (type === 'ftyp') sawFtyp = true\n if (type === 'moov') {\n if (!sawFtyp) return false\n sawMoov = true\n }\n offset += size\n }\n\n return offset === data.byteLength && sawFtyp && sawMoov\n}\n\n// \u2500\u2500\u2500 Internal Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasIsoBmffMagic(data: Uint8Array): boolean {\n for (let i = 0; i + 8 <= data.length && i < 32; i += 4) {\n const tag = String.fromCharCode(data[i + 4], data[i + 5], data[i + 6], data[i + 7])\n if (tag === 'ftyp' || tag === 'moov') return true\n }\n return false\n}\n\nfunction findTrackStsdBoxes(data: Uint8Array): Array<{ o: number; sz: number }> {\n const moov = findBox(data, 0, data.length, 'moov')\n if (!moov) return []\n\n const out: Array<{ o: number; sz: number }> = []\n for (const trak of findBoxes(data, moov.o + 8, moov.o + moov.sz, 'trak')) {\n const stsd = findNestedBox(data, trak.o + 8, trak.o + trak.sz, ['mdia', 'minf', 'stbl', 'stsd'])\n if (stsd) out.push(stsd)\n }\n return out\n}\n\nfunction findNestedBox(\n buf: Uint8Array,\n start: number,\n end: number,\n path: string[],\n): { o: number; sz: number } | undefined {\n let s = start\n let e = end\n let current: { o: number; sz: number } | undefined\n for (const type of path) {\n current = findBox(buf, s, e, type)\n if (!current) return undefined\n s = current.o + 8\n e = current.o + current.sz\n }\n return current\n}\n\nfunction findBox(buf: Uint8Array, start: number, end: number, type: string): { o: number; sz: number } | undefined {\n return findBoxes(buf, start, end, type)[0]\n}\n\nfunction findBoxes(buf: Uint8Array, start: number, end: number, type: string): Array<{ o: number; sz: number }> {\n const boxes: Array<{ o: number; sz: number }> = []\n let o = start\n while (o + 8 <= end) {\n let sz = (buf[o] << 24) | (buf[o + 1] << 16) | (buf[o + 2] << 8) | buf[o + 3]\n const t = String.fromCharCode(buf[o + 4], buf[o + 5], buf[o + 6], buf[o + 7])\n if (sz === 0) sz = end - o\n if (sz < 8 || o + sz > end) break\n if (t === type) boxes.push({ o, sz })\n o += sz\n }\n return boxes\n}\n\nfunction writeNalLength(buf: Uint8Array, offset: number, len: number): number {\n buf[offset] = (len >> 24) & 0xff\n buf[offset + 1] = (len >> 16) & 0xff\n buf[offset + 2] = (len >> 8) & 0xff\n buf[offset + 3] = len & 0xff\n return offset + 4\n}\n\nfunction h264NalUnitsForKeyframeDetection(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions,\n): Uint8Array[] {\n return splitH264SampleNalUnits(data, options).nals\n}\n\nfunction splitPartialAvccNalUnits(data: Uint8Array, lengthSize = 4): Uint8Array[] {\n const nals: Uint8Array[] = []\n let i = 0\n while (i + lengthSize < data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i >= data.length) break\n const end = Math.min(i + len, data.length)\n nals.push(data.subarray(i, end))\n if (end < i + len) break\n i = end\n }\n return nals\n}\n\nfunction isLikelyRawH264NalUnit(data: Uint8Array): boolean {\n if (data.length === 0) return false\n const header = data[0]!\n if ((header & 0x80) !== 0) return false\n const nalType = header & 0x1f\n return nalType > 0 && nalType < 24\n}\n\nfunction rawH264NalToAvcc(data: Uint8Array): Uint8Array {\n const out = new Uint8Array(4 + data.length)\n new DataView(out.buffer, out.byteOffset, out.byteLength).setUint32(0, data.length)\n out.set(data, 4)\n return out\n}\n\nfunction isH264IntraSlice(nal: Uint8Array): boolean {\n const sliceType = readH264SliceType(nal)\n return sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9\n}\n\nfunction readH264SliceType(nal: Uint8Array): number | null {\n if (nal.length < 2 || (nal[0]! & 0x1f) !== 1) return null\n const rbsp = removeEmulationPrevention(nal.subarray(1))\n const state = { bitOffset: 0 }\n if (readUnsignedExpGolomb(rbsp, state) === null) return null\n return readUnsignedExpGolomb(rbsp, state)\n}\n\nfunction readUnsignedExpGolomb(data: Uint8Array, state: { bitOffset: number }): number | null {\n let leadingZeroBits = 0\n while (true) {\n const bit = readBit(data, state)\n if (bit === null) return null\n if (bit === 1) break\n leadingZeroBits++\n if (leadingZeroBits > 30) return null\n }\n\n let suffix = 0\n for (let i = 0; i < leadingZeroBits; i++) {\n const bit = readBit(data, state)\n if (bit === null) return null\n suffix = (suffix << 1) | bit\n }\n return (1 << leadingZeroBits) - 1 + suffix\n}\n\nfunction readBit(data: Uint8Array, state: { bitOffset: number }): 0 | 1 | null {\n if (state.bitOffset >= data.length * 8) return null\n const byte = data[state.bitOffset >> 3]!\n const bit = (byte >> (7 - (state.bitOffset & 7))) & 1\n state.bitOffset++\n return bit as 0 | 1\n}\n\nfunction hex2(n: number): string {\n return n.toString(16).padStart(2, '0')\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, '0')\n}\n\nfunction codecStringFromAv1C(av1C: Uint8Array): string {\n if (av1C.length < 4) return 'av01.0.01M.08'\n const profile = (av1C[1]! >>> 5) & 0x07\n const level = av1C[1]! & 0x1f\n const tier = (av1C[2]! & 0x80) !== 0 ? 'H' : 'M'\n let bitDepth = 8\n if ((av1C[2]! & 0x40) !== 0) {\n bitDepth = (av1C[2]! & 0x20) !== 0 ? 12 : 10\n }\n return `av01.${profile}.${pad2(level)}${tier}.${pad2(bitDepth)}`\n}\n\nfunction codecStringFromVpcC(vpcC: Uint8Array): string {\n if (vpcC.length < 3) return 'vp09.00.10.08'\n // ISO/IEC 14496-15 defines vpcC as a FullBox. Some tooling hands callers\n // the VPCodecConfigurationRecord after the 4-byte FullBox header; tolerate\n // both shapes because WebCodecs callers only need a stable RFC 6381 fallback.\n const offset = vpcC.length >= 7 && vpcC[0] <= 1 ? 4 : 0\n if (offset + 2 >= vpcC.length) return 'vp09.00.10.08'\n const profile = vpcC[offset]!\n const level = vpcC[offset + 1]!\n const bitDepth = (vpcC[offset + 2]! >>> 4) || 8\n return `vp09.${pad2(profile)}.${pad2(level)}.${pad2(bitDepth)}`\n}\n\n/**\n * Derive an RFC 6381 HEVC codec string (e.g. \"hvc1.1.6.L93.90\") from the\n * payload of an hvcC box (the HEVCDecoderConfigurationRecord, ISO 14496-15 \u00A78.3.3.1).\n * Only the general_* fields in the fixed 23-byte header are needed:\n * byte 1: general_profile_space(2) | general_tier_flag(1) | general_profile_idc(5)\n * bytes 2-5: general_profile_compatibility_flags (32 bits)\n * bytes 6-11: general_constraint_indicator_flags (48 bits)\n * byte 12: general_level_idc\n */\nfunction hevcCodecStringFromHvcC(c: Uint8Array): string {\n const profileSpace = (c[1] >> 6) & 0x3\n const tierFlag = (c[1] >> 5) & 0x1\n const profileIdc = c[1] & 0x1f\n // Compatibility flags are emitted reversed bit-order as hex, leading zeros trimmed.\n const compat = ((c[2] << 24) | (c[3] << 16) | (c[4] << 8) | c[5]) >>> 0\n let rev = 0\n let v = compat\n for (let i = 0; i < 32; i++) {\n rev = ((rev << 1) | (v & 1)) >>> 0\n v >>>= 1\n }\n const compatStr = rev.toString(16)\n // Constraint flags: dot-separated hex bytes, trailing zero bytes trimmed.\n const constraint = c.subarray(6, 12)\n let lastNonZero = -1\n for (let i = 0; i < constraint.length; i++) if (constraint[i] !== 0) lastNonZero = i\n const constraintParts: string[] = []\n for (let i = 0; i <= lastNonZero; i++) constraintParts.push(constraint[i].toString(16))\n const space = profileSpace === 0 ? '' : String.fromCharCode(64 + profileSpace) // 1\u2192'A', 2\u2192'B', 3\u2192'C'\n const tier = tierFlag === 0 ? 'L' : 'H'\n let s = `hvc1.${space}${profileIdc}.${compatStr}.${tier}${c[12]}`\n if (constraintParts.length > 0) s += '.' + constraintParts.join('.')\n return s\n}\n\n/** Exp-Golomb bitstream writer for SPS/PPS generation. */\nclass BitWriter {\n buf: number[] = []\n byte = 0\n bit = 7\n\n u(val: number, bits: number) {\n for (let i = bits - 1; i >= 0; i--) {\n this.byte |= ((val >> i) & 1) << this.bit\n if (--this.bit < 0) {\n this.buf.push(this.byte)\n this.byte = 0\n this.bit = 7\n }\n }\n }\n\n ue(val: number) {\n const v = val + 1\n const bits = Math.floor(Math.log2(v)) + 1\n this.u(0, bits - 1)\n this.u(v, bits)\n }\n\n se(val: number) {\n this.ue(val <= 0 ? -val * 2 : val * 2 - 1)\n }\n\n finish(): Uint8Array {\n if (this.bit < 7) {\n this.byte |= 1 << this.bit\n this.buf.push(this.byte)\n }\n return new Uint8Array(this.buf)\n }\n}\n\nfunction resolveResolution(\n explicitW: number | undefined,\n explicitH: number | undefined,\n level: number,\n): { width: number; height: number } {\n if (explicitW && explicitH) return { width: explicitW, height: explicitH }\n\n const levelResolutions: Record<number, [number, number]> = {\n 10: [176, 144], 11: [352, 288], 12: [352, 288], 13: [352, 288],\n 20: [352, 288], 21: [720, 576], 22: [720, 576],\n 30: [1280, 720], 31: [1280, 720], 32: [1280, 1024],\n 40: [1920, 1088], 41: [1920, 1088], 42: [2048, 1088],\n 50: [4096, 2160], 51: [4096, 2160], 52: [4096, 2160],\n }\n\n const [w, h] = levelResolutions[level] ?? [1920, 1088]\n return { width: explicitW ?? w, height: explicitH ?? h }\n}\n\nfunction buildMinimalSps(\n profile: number, constraint: number, level: number,\n width: number, height: number,\n): Uint8Array {\n const widthInMbs = Math.ceil(width / 16)\n const heightInMapUnits = Math.ceil(height / 16)\n\n const w = new BitWriter()\n w.u(0, 1); w.u(3, 2); w.u(7, 5) // NAL header: SPS\n w.u(profile, 8); w.u(constraint, 8); w.u(level, 8)\n w.ue(0) // seq_parameter_set_id\n\n if (profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44) {\n w.ue(1); w.ue(0); w.ue(0) // chroma + bit depth\n w.u(0, 1); w.u(0, 1) // transform bypass + scaling matrix\n }\n\n w.ue(0) // log2_max_frame_num_minus4\n w.ue(2) // pic_order_cnt_type=2\n w.ue(1) // max_num_ref_frames\n w.u(0, 1) // gaps_in_frame_num\n w.ue(widthInMbs - 1)\n w.ue(heightInMapUnits - 1)\n w.u(1, 1) // frame_mbs_only\n w.u(1, 1) // direct_8x8_inference\n\n const cropRight = widthInMbs * 16 - width\n const cropBottom = heightInMapUnits * 16 - height\n if (cropRight > 0 || cropBottom > 0) {\n w.u(1, 1)\n w.ue(0); w.ue(cropRight / 2); w.ue(0); w.ue(cropBottom / 2)\n } else {\n w.u(0, 1)\n }\n\n w.u(0, 1) // vui_parameters_present\n return w.finish()\n}\n\nfunction buildMinimalPps(profile: number): Uint8Array {\n const isHighProfile = profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44\n const w = new BitWriter()\n w.u(0, 1); w.u(3, 2); w.u(8, 5) // NAL header: PPS\n\n w.ue(0); w.ue(0) // pps_id, sps_id\n w.u(isHighProfile ? 1 : 0, 1) // entropy_coding_mode\n w.u(0, 1) // bottom_field_pic_order\n w.ue(0); w.ue(0); w.ue(0) // slice groups, ref_idx defaults\n w.u(0, 1); w.u(0, 2) // weighted_pred\n w.se(0); w.se(0); w.se(0) // qp offsets\n w.u(1, 1); w.u(0, 1); w.u(0, 1) // deblock, constrained_intra, redundant_pic_cnt\n\n if (isHighProfile) {\n w.u(1, 1); w.u(0, 1); w.se(0) // transform_8x8, scaling_matrix, chroma_qp_offset\n }\n\n return w.finish()\n}\n\n// \u2500\u2500\u2500 AAC / ADTS Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** ISO 14496-3 sampling frequency index lookup. */\nconst ADTS_SAMPLE_RATES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350] as const\n\n/**\n * Prepend a 7-byte ADTS header to a raw AAC access unit.\n *\n * WebCodecs AudioDecoder configured WITHOUT an AudioSpecificConfig `description`\n * expects ADTS-framed AAC. MMTP carries raw AAC (no ADTS sync), so this wrapper\n * must be applied before calling `AudioDecoder.decode()`.\n */\nexport function wrapAdtsFrame(raw: Uint8Array, sampleRate: number, channels: number): Uint8Array {\n const sri = ADTS_SAMPLE_RATES.indexOf(sampleRate as typeof ADTS_SAMPLE_RATES[number])\n const idx = sri >= 0 ? sri : 3 // default 48 kHz\n const len = 7 + raw.length\n const out = new Uint8Array(len)\n out[0] = 0xFF\n out[1] = 0xF1 // MPEG-4, Layer 0, no CRC\n out[2] = (1 << 6) | (idx << 2) | (channels >> 2) // profile=AAC-LC(1), freq, ch high\n out[3] = ((channels & 3) << 6) | ((len >> 11) & 3)\n out[4] = (len >> 3) & 0xFF\n out[5] = ((len & 7) << 5) | 0x1F\n out[6] = 0xFC\n out.set(raw, 7)\n return out\n}\n\n/**\n * Extract AAC AudioSpecificConfig (ASC) from an fMP4 init segment.\n *\n * Walks moov > trak > mdia > minf > stbl > stsd > mp4a > esds, then descends\n * the MPEG-4 descriptor chain (ES_Descriptor 0x03 > DecoderConfigDescriptor\n * 0x04 > DecoderSpecificInfo 0x05) to return the ASC payload.\n *\n * Sibling of extractAvcCFromInitSegment, used by the same BLO-4830 / CMSF \u00A73.1\n * path: when the catalog initData is the full ftyp+moov, WebCodecs' AudioDecoder\n * needs the raw ASC (~2 bytes for AAC-LC) as `description`, NOT the whole\n * segment. Without this extraction the configure() succeeds but every decode()\n * silently produces zero output (no error fires), exactly the symptom that\n * shows up as \"Audio continuity FAILED: energy unstable CV=1.00\" in the\n * 7-point E2E test (CV=1.00 is the meanEnergy=0 sentinel from audio-fft.mjs).\n *\n * Returns undefined when:\n * - data has no ftyp/moov magic in the first 32 bytes\n * - no mp4a sample entry exists in any trak's stbl\n * - the esds descriptor chain doesn't yield a DecoderSpecificInfo\n * - the ASC payload is shorter than 2 bytes (AOT + sampling-freq nibble)\n *\n * Walks every trak and returns the first AAC sample entry. This mirrors\n * extractAvcCFromInitSegment so multiplexed ftyp+moov init blobs work\n * regardless of track order.\n */\nexport function extractAacAscFromInitSegment(data: Uint8Array): AacAscInfo | undefined {\n if (!hasIsoBmffMagic(data)) return undefined\n\n for (const stsd of findTrackStsdBoxes(data)) {\n const info = extractAacAscFromStsd(data, stsd)\n if (info) return info\n }\n\n return undefined\n}\n\nfunction extractAacAscFromStsd(data: Uint8Array, stsd: { o: number; sz: number }): AacAscInfo | undefined {\n // stsd: 8 box header + 4 version+flags + 4 entry_count = 16 bytes before entries.\n const s = stsd.o + 16\n const e = stsd.o + stsd.sz\n // mp4a AudioSampleEntry minimum length: 8 box header + 28 fixed fields = 36 bytes\n // before any child boxes (esds lives here).\n const mp4a = findBox(data, s, e, 'mp4a')\n if (!mp4a || mp4a.sz < 36) return undefined\n const esds = findBox(data, mp4a.o + 36, mp4a.o + mp4a.sz, 'esds')\n // esds = 8 box header + 4 full-box version+flags = 12 bytes minimum before descriptors.\n if (!esds || esds.sz < 12) return undefined\n const esdsPayload = data.subarray(esds.o + 8, esds.o + esds.sz)\n const asc = extractAudioSpecificConfig(esdsPayload)\n if (!asc || asc.length < 2) return undefined\n // AudioObjectType = top 5 bits of ASC[0]. AAC-LC = 2, HE-AAC = 5, etc.\n const aot = asc[0] >> 3\n return { codec: `mp4a.40.${aot}`, description: asc }\n}\n\n/**\n * Walk an esds descriptor chain to find DecoderSpecificInfo (tag 0x05).\n * Step over fixed-size headers of container descriptors (0x03, 0x04) so the\n * scan continues into their children rather than skipping their full payload.\n *\n * Assumes the ES_Descriptor flags byte is zero (no streamDependence, URL, OCR\n * ES_ID fields). FFmpeg's mov/mp4 muxer emits exactly that for all standard\n * AAC tracks; the assumption is the same one extractAvcCFromInitSegment makes\n * about the avc1 sample entry's reserved fields.\n *\n * Input is the esds box payload AFTER the 8-byte box header; the first 4 bytes\n * (full-box version+flags) are skipped here.\n */\nfunction extractAudioSpecificConfig(esds: Uint8Array): Uint8Array | undefined {\n let offset = 4 // skip esds version+flags\n while (offset < esds.length) {\n const tag = esds[offset++]\n let size = 0\n for (let i = 0; i < 4 && offset < esds.length; i++) {\n const b = esds[offset++]\n size = (size << 7) | (b & 0x7f)\n if ((b & 0x80) === 0) break\n }\n if (tag === 0x05) {\n if (offset + size > esds.length) return undefined\n return esds.subarray(offset, offset + size)\n }\n if (tag === 0x03) {\n offset += 3 // ES_ID (2) + flags (1)\n } else if (tag === 0x04) {\n offset += 13 // OTI (1) + streamType (1) + bufferSizeDB (3) + maxBitrate (4) + avgBitrate (4)\n } else {\n offset += size\n }\n }\n return undefined\n}\n\n// =============================================================================\n// Inline Tests (vitest)\n// =============================================================================\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest\n\n describe('codec-utils', () => {\n describe('isAnnexB', () => {\n test('4-byte start code', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(true)\n })\n test('3-byte start code', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 1, 0x65]))).toBe(true)\n })\n test('rejects AVCC', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 0, 10, 0x65]))).toBe(false)\n })\n })\n\n describe('findAnnexBStartCode', () => {\n test('at offset 0', () => {\n expect(findAnnexBStartCode(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(0)\n })\n test('at offset 5', () => {\n expect(findAnnexBStartCode(new Uint8Array([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0, 0, 1, 0x65]))).toBe(5)\n })\n test('returns -1 when none', () => {\n expect(findAnnexBStartCode(new Uint8Array([0xAA, 0xBB, 0xCC]))).toBe(-1)\n })\n })\n\n describe('splitAnnexBNalUnits', () => {\n test('splits two NALs', () => {\n const data = new Uint8Array([0, 0, 0, 1, 0x65, 0xAA, 0xBB, 0, 0, 0, 1, 0x41, 0xCC])\n const nals = splitAnnexBNalUnits(data)\n expect(nals.length).toBe(2)\n expect(nals[0]).toEqual(new Uint8Array([0x65, 0xAA, 0xBB]))\n expect(nals[1]).toEqual(new Uint8Array([0x41, 0xCC]))\n })\n test('handles 3-byte start codes', () => {\n const nals = splitAnnexBNalUnits(new Uint8Array([0, 0, 1, 0x67, 0x42, 0, 0, 1, 0x68, 0x01]))\n expect(nals.length).toBe(2)\n })\n })\n\n describe('annexBToAvcc', () => {\n test('converts single NAL', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x41, 0xAA, 0xBB])\n const avcc = annexBToAvcc(annexB)\n expect(avcc[3]).toBe(3) // NAL length\n expect(avcc[4]).toBe(0x41)\n })\n test('prepends SPS/PPS', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x65, 0x01])\n const avcc = annexBToAvcc(annexB, { sps: new Uint8Array([0x67, 0x42]), pps: new Uint8Array([0x68, 0x01]) })\n expect(avcc[3]).toBe(2) // SPS length\n expect(avcc[4]).toBe(0x67)\n })\n })\n\n describe('detectH264Keyframe', () => {\n test('IDR in Annex-B', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(true)\n })\n test('SPS in Annex-B', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x67]))).toBe(true)\n })\n test('IDR in AVCC', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 5, 0x65, 1, 2, 3, 4]))).toBe(true)\n })\n test('IDR after AVCC AUD', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 1, 0x09,\n 0, 0, 0, 2, 0x65, 0xaa,\n ]))).toBe(true)\n })\n test('non-IDR AVC I-slice in AVCC', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 2, 0x41, 0x88,\n ]))).toBe(true)\n })\n test('raw H.264 IDR NAL', () => {\n expect(detectH264Keyframe(new Uint8Array([0x65, 0x88, 0x84]))).toBe(true)\n })\n test('raw H.264 non-IDR I-slice NAL', () => {\n expect(detectH264Keyframe(new Uint8Array([0x41, 0x88]))).toBe(true)\n })\n test('classifies partial length-prefixed IDR only when requested', () => {\n const partial = new Uint8Array([0, 0, 0x20, 0, 0x65])\n expect(classifyH264Keyframe(partial)).toBeUndefined()\n expect(classifyH264Keyframe(partial, { allowPartialAvcc: true })).toBe(true)\n })\n test('rejects P-frame', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x41]))).toBe(false)\n })\n test('rejects AVCC sample with only non-IDR slices', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 2, 0x41, 0xc0,\n 0, 0, 0, 2, 0x41, 0xc0,\n ]))).toBe(false)\n })\n })\n\n describe('avccToAnnexB', () => {\n test('converts with SPS/PPS on keyframe', () => {\n const avcc = new Uint8Array([0, 0, 0, 3, 0x65, 0xAA, 0xBB])\n const spsPps: SpsPps = { sps: new Uint8Array([0x67, 0x42]), pps: new Uint8Array([0x68, 0x01]) }\n const annexB = avccToAnnexB(avcc, true, spsPps)\n expect(annexB[3]).toBe(1) // start code\n expect(annexB[4]).toBe(0x67) // SPS\n })\n })\n\n describe('codecStringFromAvcC', () => {\n test('derives avc1.64002a', () => {\n expect(codecStringFromAvcC(new Uint8Array([1, 100, 0, 42]))).toBe('avc1.64002a')\n })\n })\n\n describe('extractAacAscFromInitSegment', () => {\n // Build a minimal valid ftyp+moov containing one mp4a sample entry whose\n // esds carries the supplied AudioSpecificConfig. The walker only needs\n // the box hierarchy moov > trak > mdia > minf > stbl > stsd > mp4a > esds;\n // mvhd/tkhd/mdhd/hdlr/smhd/dinf/stts/stsc/stsz/stco are spec-required for\n // a truly valid init but the extractor never reads them, so we omit them\n // to keep the fixture tight (~150 bytes vs ~500). FFmpeg's real output\n // includes them; the production path passes through `findBox` exactly\n // the same way.\n function buildMinimalAacInit(asc: Uint8Array): Uint8Array {\n const box = (type: string, payload: Uint8Array): Uint8Array => {\n const sz = 8 + payload.length\n const out = new Uint8Array(sz)\n out[0] = (sz >>> 24) & 0xff\n out[1] = (sz >>> 16) & 0xff\n out[2] = (sz >>> 8) & 0xff\n out[3] = sz & 0xff\n out[4] = type.charCodeAt(0); out[5] = type.charCodeAt(1)\n out[6] = type.charCodeAt(2); out[7] = type.charCodeAt(3)\n out.set(payload, 8)\n return out\n }\n const concat = (...arrs: Uint8Array[]): Uint8Array => {\n const total = arrs.reduce((n, a) => n + a.length, 0)\n const out = new Uint8Array(total)\n let off = 0\n for (const a of arrs) { out.set(a, off); off += a.length }\n return out\n }\n // ftyp: major_brand=iso5, minor=0x200, compat=iso5,iso6\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x35, // 'iso5'\n 0x00, 0x00, 0x02, 0x00, // minor 0x200\n 0x69, 0x73, 0x6f, 0x35, // 'iso5'\n 0x69, 0x73, 0x6f, 0x36, // 'iso6'\n ]))\n\n // ESDescriptor (0x03) > DecoderConfigDescriptor (0x04) > DecoderSpecificInfo (0x05) > ASC.\n // Use 1-byte BER sizes (all payloads < 128).\n const dsi = new Uint8Array(2 + asc.length)\n dsi[0] = 0x05; dsi[1] = asc.length\n dsi.set(asc, 2)\n // DCD = 13 fixed bytes + DSI: OTI=0x40 (AAC), streamType=0x05<<2|0x01 (audio, upStream=0)\n const dcd = new Uint8Array(2 + 13 + dsi.length)\n dcd[0] = 0x04; dcd[1] = 13 + dsi.length\n dcd[2] = 0x40 // objectTypeIndication: Audio ISO/IEC 14496-3\n dcd[3] = (0x05 << 2) | 1 // streamType=AudioStream(5), upStream=0, reserved=1\n // bufferSizeDB(3) + maxBitrate(4) + avgBitrate(4) all zero is fine for the walker.\n dcd.set(dsi, 15)\n // ESDescriptor: ES_ID=0, flags=0, then DCD\n const esd = new Uint8Array(2 + 3 + dcd.length)\n esd[0] = 0x03; esd[1] = 3 + dcd.length\n // ES_ID(2) + flags(1) all zero\n esd.set(dcd, 5)\n // esds box = full-box (4-byte version+flags) + ES_Descriptor chain\n const esdsPayload = new Uint8Array(4 + esd.length)\n esdsPayload.set(esd, 4)\n const esds = box('esds', esdsPayload)\n\n // mp4a sample entry: 6 reserved + 2 dref_idx + 8 reserved + 2 channels + 2 samplesize +\n // 2 pre_defined + 2 reserved + 4 samplerate(48000<<16) = 28 bytes,\n // then esds child.\n const mp4aFixed = new Uint8Array(28)\n mp4aFixed[7] = 0x01 // data_reference_index = 1\n mp4aFixed[16] = 0x00; mp4aFixed[17] = 0x01 // channelcount = 1\n mp4aFixed[18] = 0x00; mp4aFixed[19] = 0x10 // samplesize = 16\n // samplerate at offset 24-27 (top 16 bits = sampleRate). 48000 = 0xBB80.\n mp4aFixed[24] = 0xBB; mp4aFixed[25] = 0x80\n const mp4a = box('mp4a', concat(mp4aFixed, esds))\n\n // stsd: 4 ver+flags + 4 entry_count(=1) + entries\n const stsdPayload = new Uint8Array(8 + mp4a.length)\n stsdPayload[7] = 0x01 // entry_count = 1\n stsdPayload.set(mp4a, 8)\n const stsd = box('stsd', stsdPayload)\n\n const stbl = box('stbl', stsd)\n const minf = box('minf', stbl)\n const mdia = box('mdia', minf)\n const trak = box('trak', mdia)\n const moov = box('moov', trak)\n\n return concat(ftyp, moov)\n }\n\n test('extracts AAC-LC mono 48k ASC and derives codec', () => {\n // AOT=2 (00010), samplingFrequencyIndex=3 (0011, 48000Hz), channelConfig=1 (0001),\n // GA: frameLengthFlag=0, dependsOnCoreCoder=0, extensionFlag=0 \u2192 0x11 0x88.\n const asc = new Uint8Array([0x11, 0x88])\n const init = buildMinimalAacInit(asc)\n const result = extractAacAscFromInitSegment(init)\n expect(result).toBeDefined()\n expect(result!.codec).toBe('mp4a.40.2')\n expect(Array.from(result!.description)).toEqual([0x11, 0x88])\n })\n\n test('derives AOT 5 (HE-AAC) from ASC[0] >> 3', () => {\n // AOT=5 (00101), rest don't matter for codec derivation.\n const asc = new Uint8Array([0x29, 0x88]) // 00101 001 1000 1000\n const init = buildMinimalAacInit(asc)\n expect(extractAacAscFromInitSegment(init)?.codec).toBe('mp4a.40.5')\n })\n\n test('rejects data without ftyp/moov magic', () => {\n expect(extractAacAscFromInitSegment(new Uint8Array(64))).toBeUndefined()\n })\n\n test('rejects ftyp+moov with no audio (no mp4a sample entry)', () => {\n // ftyp + moov with empty trak chain \u2014 no stsd, let alone mp4a.\n const ftyp = new Uint8Array([\n 0, 0, 0, 24, 0x66, 0x74, 0x79, 0x70,\n 0x69, 0x73, 0x6f, 0x35, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x35, 0x69, 0x73, 0x6f, 0x36,\n ])\n const moov = new Uint8Array([0, 0, 0, 8, 0x6d, 0x6f, 0x6f, 0x76]) // empty moov\n const cat = new Uint8Array(ftyp.length + moov.length)\n cat.set(ftyp); cat.set(moov, ftyp.length)\n expect(extractAacAscFromInitSegment(cat)).toBeUndefined()\n })\n })\n\n describe('hevc', () => {\n // Minimal HEVC NAL units: header byte0 = (type << 1). VPS=32(0x40), SPS=33(0x42), PPS=34(0x44).\n const vps = new Uint8Array([0x40, 0x01, 0x0c, 0x01, 0xff, 0xff])\n const sps = new Uint8Array([0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa0, 0x05, 0x02])\n const pps = new Uint8Array([0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62])\n const idr = new Uint8Array([0x26, 0x01, 0xaf, 0x06]) // type 19 (IDR_W_RADL)\n const lp = (...nals: Uint8Array[]) => {\n const parts: number[] = []\n for (const n of nals) { parts.push((n.length >> 24) & 0xff, (n.length >> 16) & 0xff, (n.length >> 8) & 0xff, n.length & 0xff, ...n) }\n return Uint8Array.from(parts)\n }\n\n test('isHevcCodec', () => {\n expect(isHevcCodec('hev1.1.6.L93.B0')).toBe(true)\n expect(isHevcCodec('hvc1.1.6.L93.B0')).toBe(true)\n expect(isHevcCodec('avc1.640033')).toBe(false)\n })\n\n test('removeEmulationPrevention strips 0x03', () => {\n expect(Array.from(removeEmulationPrevention(new Uint8Array([0, 0, 0x03, 1])))).toEqual([0, 0, 1])\n expect(Array.from(removeEmulationPrevention(new Uint8Array([0xaa, 0xbb])))).toEqual([0xaa, 0xbb])\n })\n\n test('splitAvccNalUnits splits length-prefixed NALs', () => {\n const nals = splitAvccNalUnits(lp(vps, sps))\n expect(nals.length).toBe(2)\n expect(nals[0]).toEqual(vps)\n expect(nals[1]).toEqual(sps)\n })\n\n test('isCompleteAvccSample accepts complete length-prefixed NAL samples', () => {\n expect(isCompleteAvccSample(lp(new Uint8Array([0x09]), idr))).toBe(true)\n })\n\n test('isCompleteAvccSample rejects Annex-B start-code samples', () => {\n expect(isCompleteAvccSample(new Uint8Array([0, 0, 0, 1, 0x65, 0xaa]))).toBe(false)\n })\n\n test('isCompleteAvccSample rejects truncated length-prefixed samples', () => {\n expect(isCompleteAvccSample(new Uint8Array([0, 0, 0, 4, 0x65, 0xaa]))).toBe(false)\n })\n\n test('normalizeH264SampleToAvcc leaves complete AVCC samples unchanged', () => {\n const avcc = lp(new Uint8Array([0x09]), idr)\n const normalized = normalizeH264SampleToAvcc(avcc)\n expect(normalized.format).toBe('avcc')\n expect(normalized.data).toBe(avcc)\n })\n\n test('normalizeH264SampleToAvcc converts a single raw H.264 NAL to AVCC', () => {\n const raw = new Uint8Array([0x65, 0x88, 0x84])\n const normalized = normalizeH264SampleToAvcc(raw)\n expect(normalized.format).toBe('raw-nal')\n expect(normalized.data).toEqual(new Uint8Array([0, 0, 0, 3, 0x65, 0x88, 0x84]))\n })\n\n test('splitH264SampleNalUnits exposes Annex-B NALs without AVCC conversion', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x65, 0x88, 0x84])\n const sample = splitH264SampleNalUnits(annexB)\n expect(sample.format).toBe('annexb')\n expect(sample.nals).toHaveLength(1)\n expect(sample.nals[0]).toEqual(new Uint8Array([0x65, 0x88, 0x84]))\n })\n\n test('splitH264SampleNalUnits exposes single raw H.264 NALs without wrapping', () => {\n const raw = new Uint8Array([0x65, 0x88, 0x84])\n const sample = splitH264SampleNalUnits(raw)\n expect(sample.format).toBe('raw-nal')\n expect(sample.nals).toEqual([raw])\n })\n\n test('splitH264SampleNalUnits can expose partial AVCC NAL headers', () => {\n const partial = new Uint8Array([0, 0, 0, 5, 0x65, 0x88])\n const sample = splitH264SampleNalUnits(partial, { allowPartialAvcc: true })\n expect(sample.format).toBe('partial-avcc')\n expect(sample.nals).toHaveLength(1)\n expect(sample.nals[0]).toEqual(new Uint8Array([0x65, 0x88]))\n })\n\n test('extractHevcParameterSets finds VPS/SPS/PPS (length-prefixed)', () => {\n const sets = extractHevcParameterSets(lp(vps, sps, pps, idr))\n expect(sets.vps).toEqual(vps)\n expect(sets.sps).toEqual(sps)\n expect(sets.pps).toEqual(pps)\n })\n\n test('extractHevcParameterSets finds VPS/SPS/PPS (Annex-B)', () => {\n const sc = new Uint8Array([0, 0, 0, 1])\n const annexb = Uint8Array.from([...sc, ...vps, ...sc, ...sps, ...sc, ...pps, ...sc, ...idr])\n const sets = extractHevcParameterSets(annexb)\n expect(sets.vps).toEqual(vps)\n expect(sets.sps).toEqual(sps)\n expect(sets.pps).toEqual(pps)\n })\n\n test('generateHvcCFromParameterSets builds a valid hvcC', () => {\n const hvcc = generateHvcCFromParameterSets({ vps, sps, pps })!\n expect(hvcc).not.toBeNull()\n expect(hvcc[0]).toBe(1) // configurationVersion\n expect(hvcc[1]).toBe(sps[3]) // general profile_tier_level byte 0 copied from SPS[3]\n expect(hvcc[22]).toBe(3) // numOfArrays (VPS+SPS+PPS)\n // first array entry: NAL_unit_type 32 (VPS), numNalus 1\n expect(hvcc[23] & 0x3f).toBe(32)\n expect((hvcc[24] << 8) | hvcc[25]).toBe(1)\n })\n\n test('generateHvcCFromParameterSets returns null without SPS/PPS', () => {\n expect(generateHvcCFromParameterSets({ vps })).toBeNull()\n })\n\n test('extractHevcCodecDescription end-to-end from keyframe', () => {\n const desc = extractHevcCodecDescription(lp(vps, sps, pps, idr))\n expect(desc).not.toBeNull()\n expect(desc![0]).toBe(1)\n })\n\n test('hevcVclOnly strips parameter-set NALs, keeps VCL', () => {\n const stripped = hevcVclOnly(lp(vps, sps, pps, idr))\n const nals = splitAvccNalUnits(stripped)\n expect(nals.length).toBe(1) // only the IDR VCL NAL remains\n expect(nals[0]).toEqual(idr)\n })\n\n test('hevcVclOnly is a no-op for VCL-only length-prefixed input', () => {\n const vclOnly = lp(idr)\n expect(hevcVclOnly(vclOnly)).toBe(vclOnly)\n })\n })\n })\n}\n", "/**\n * Exact timing authored by an ISO-BMFF media fragment.\n *\n * `timestamp`/`duration` fields on the browser-facing APIs are converted to\n * microseconds for legacy callers. This value remains in the media track's\n * native timescale so consumers that own a CMAF/WebCodecs timeline do not\n * have to reconstruct integer ticks from rounded wall-clock values.\n */\nexport interface AuthoredTiming {\n /** Exact decode time in the media track's timescale. */\n decodeTime: bigint\n /** Exact presentation time in the media track's timescale, including CTS. */\n presentationTime: bigint\n /**\n * Exact sample duration in the media track's timescale. This remains a\n * number because ISO-BMFF stores sample_duration as an unsigned 32-bit\n * field, whose full range is exactly representable by JavaScript numbers.\n */\n durationTicks: number\n /** `mdhd` timescale for all values above. */\n mediaTimescale: number\n}\n\n/** Convert authored media ticks to an integer target timescale without first\n * narrowing the authored tick value to a wall-clock float. */\nexport function scaleAuthoredTicks(\n ticks: bigint,\n mediaTimescale: number,\n targetTimescale: number,\n): number | null {\n if (!Number.isSafeInteger(mediaTimescale) || mediaTimescale <= 0 ||\n !Number.isSafeInteger(targetTimescale) || targetTimescale <= 0) return null\n\n const negative = ticks < 0n\n const numerator = (negative ? -ticks : ticks) * BigInt(targetTimescale)\n const denominator = BigInt(mediaTimescale)\n const whole = numerator / denominator\n const remainder = numerator % denominator\n if (whole > BigInt(Number.MAX_SAFE_INTEGER)) return null\n const value = Number(whole) + Number(remainder) / mediaTimescale\n return Number.isFinite(value) ? (negative ? -value : value) : null\n}\n\n/** Convert exact authored presentation time and duration to an assembler's\n * public timestamp scale. */\nexport function scaleAuthoredTiming(\n timing: AuthoredTiming,\n targetTimescale: number,\n): { timestamp: number; duration: number } | null {\n if (!Number.isSafeInteger(timing.durationTicks) || timing.durationTicks <= 0) return null\n const timestamp = scaleAuthoredTicks(\n timing.presentationTime,\n timing.mediaTimescale,\n targetTimescale,\n )\n const duration = scaleAuthoredTicks(\n BigInt(timing.durationTicks),\n timing.mediaTimescale,\n targetTimescale,\n )\n if (timestamp === null || duration === null || duration <= 0) return null\n return { timestamp, duration }\n}\n", "/**\n * FEC-block-aware CMAF segment assembler for MSE multicast.\n *\n * Buffers reassembled frames per FEC source block (SBN). On block completion\n * (K source symbols received clean, or FEC recovery), sorts frames by ESI\n * and builds a single multi-sample moof+mdat CMAF segment. On block timeout,\n * generates fill frames (green video / silence audio) for missing ESI slots.\n *\n * One assembler instance per track (video or audio). MulticastManager owns\n * these instances and calls them directly with SBN/ESI from the FEC pipeline.\n */\n\nimport {\n encodeDataSegment,\n buildVideoInitSegment,\n buildAudioInitSegment,\n generateGreenFillNAL,\n normalizeAacSampleForCmaf,\n} from './mmtp-to-cmaf.js'\nimport {\n classifyH264Keyframe,\n detectH264Keyframe,\n splitH264SampleNalUnits,\n} from './codec-utils.js'\nimport {\n scaleAuthoredTicks,\n scaleAuthoredTiming,\n type AuthoredTiming,\n} from './authored-timing.js'\nimport type { MmtpDeliveryProvenance } from './mfu-reassembler.js'\n\nconst INT32_MIN = -0x80000000\nconst INT32_MAX = 0x7fffffff\n\ninterface BlockFrame {\n data: Uint8Array\n timestamp: number\n keyframe: boolean\n /** Exact ISO-BMFF timing retained from the parser for FEC/source ordering. */\n authoredTiming?: AuthoredTiming\n /** MMTP packet_sequence_number identifying the delivered access unit. */\n packetSequenceNumber?: number\n /** Every authoritative MMTP source-packet sequence that formed this sample. */\n packetSequenceNumbers?: number[]\n /** Subset of packetSequenceNumbers reconstructed by FEC. */\n repairedPacketSequenceNumbers?: number[]\n /** Native MMTP MPU group coordinate retained across source/FEC ordering. */\n mpuSequenceNumber?: number\n catalogTrackName?: string\n /**\n * Whole-frame delivery verdict folded across every contributing fragment.\n * Absent means no caller declared one; it is never an implied 'multicast'.\n */\n deliveryProvenance?: MmtpDeliveryProvenance\n}\n\nexport interface CmafBlockSample {\n data: Uint8Array\n timestamp: number\n duration: number\n keyframe: boolean\n /** Signed PTS-DTS offset in the configured CMAF timescale. */\n compositionTimeOffset?: number\n /** Exact ISO-BMFF timing in the media track's native timescale. */\n authoredTiming?: AuthoredTiming\n /** MMTP packet_sequence_number identifying the delivered access unit. */\n packetSequenceNumber?: number\n /** Every authoritative MMTP source-packet sequence that formed this sample. */\n packetSequenceNumbers?: number[]\n /** Subset of packetSequenceNumbers reconstructed by FEC. */\n repairedPacketSequenceNumbers?: number[]\n /** Native MMTP MPU group coordinate retained for exact replay selection. */\n mpuSequenceNumber?: number\n /** Immutable catalog identity supplied by the owning ingress subscription. */\n catalogTrackName?: string\n /**\n * Whole-frame delivery verdict, carried so MSE `onSample` consumers can see\n * the same evidence the non-MSE frame path gets. Without it the MSE branch\n * silently loses a computed 'mixed' or 'multicast' finding.\n */\n deliveryProvenance?: MmtpDeliveryProvenance\n}\n\nexport type CmafSampleOrderPolicy =\n | { mode: 'arrival' }\n | {\n /** Release samples according to media progression, without a wall clock. */\n mode: 'media-window'\n /** Delivery window in the same units as CmafBlockSample.timestamp. */\n deliveryWindow: number\n /** Optional modulo period for wrapped input timestamps, in timestamp units. */\n timestampWrapPeriod?: number\n }\n\nexport interface CmafSampleOrderStats {\n staleSamples: number\n duplicateSamples: number\n preRapDeadlineDrops: number\n noRapFlushDrops: number\n forcedReleases: number\n}\n\nexport interface BlockAssemblerConfig {\n /** Number of source symbols per FEC block */\n k: number\n /** Timescale for CMAF segments (default 1_000_000 = microseconds) */\n timescale?: number\n /** ISO track ID (default 1) */\n trackId?: number\n /** Track type \u2014 determines fill frame generation and init segment format */\n trackType: 'video' | 'audio'\n /** Video/audio codec string (e.g. 'avc1.64002a', 'mp4a.40.2'). */\n codec?: string\n // Video config (required when trackType='video')\n /** Raw avcC payload from catalog description \u2014 for init + green fill */\n avcC?: Uint8Array\n /** Video width in pixels */\n width?: number\n /** Video height in pixels */\n height?: number\n // Audio config (required when trackType='audio')\n /** Audio codec string (e.g. 'mp4a.40.2', 'opus') \u2014 for silence fill generation */\n audioCodec?: string\n /** Audio sample rate (e.g. 48000) */\n sampleRate?: number\n /** Audio channel count (e.g. 1 or 2) */\n channels?: number\n /** Raw AudioSpecificConfig from catalog */\n asc?: Uint8Array\n // Shared\n /** Frames per second \u2014 fallback for duration estimation */\n fps?: number\n /** Explicit sample ordering policy. Datagram/FEC callers use media-window. */\n sampleOrder?: CmafSampleOrderPolicy\n /**\n * Bounded sample reorder depth for callback mode.\n *\n * Default 0 preserves immediate emission. When set on video tracks with\n * onSample enabled, samples are sorted by timestamp and the oldest sample is\n * emitted only after this many newer samples are available.\n * @deprecated Use sampleOrder with an explicit policy.\n */\n sampleReorderWindow?: number\n}\n\ninterface OrderedSample extends CmafBlockSample {\n advancesHorizon: boolean\n}\n\nexport class CmafBlockAssembler {\n #config: Required<Pick<BlockAssemblerConfig, 'k' | 'timescale' | 'trackId' | 'trackType'>>\n #blocks = new Map<number, Map<number, BlockFrame>>()\n #pendingFlush = new Set<number>()\n #pendingRecovered = new Map<number, BlockFrame>()\n #sequence = 1\n #baseTs = -1\n #fillFrame: Uint8Array\n #lastDecodableAudioFrame: Uint8Array | null = null\n #frameDuration: number\n #lastEmittedTs = -1\n #lastSourceTs = -1\n #sampleReorderWindow = 0\n #sampleOrder: CmafSampleOrderPolicy = { mode: 'arrival' }\n #sampleOrderCapacity = 0\n #sampleReorderQueue: OrderedSample[] = []\n #recoveredHorizonTs = -1\n #sampleOrderStats: CmafSampleOrderStats = {\n staleSamples: 0,\n duplicateSamples: 0,\n preRapDeadlineDrops: 0,\n noRapFlushDrops: 0,\n forcedReleases: 0,\n }\n #validateH264Keyframes = false\n #keyframeRejectDumpCount = 0\n\n /** Callback: emits a complete moof+mdat CMAF segment */\n onSegment: ((segment: Uint8Array) => void) | null = null\n /** Callback: emits a gated/deduped raw sample for callers that already own the MSE timeline. */\n onSample: ((sample: CmafBlockSample) => void) | null = null\n /** Callback: emits an init segment (ftyp+moov) */\n onInitSegment: ((init: Uint8Array) => void) | null = null\n\n // Video keyframe gate (BLO-3035 layer 3): Chrome's CHUNK_DEMUXER rejects a\n // moof+mdat whose first sample is non-sync with no prior reference frames\n // (\"CHUNK_DEMUXER_ERROR_APPEND_FAILED: Failed to prepare video sample for\n // decode\") and detaches the SourceBuffer for the rest of the session.\n // Mid-stream join almost guarantees the first FEC blocks are mid-GOP \u2014 all\n // delta frames. Gate emission until the first block containing an IDR;\n // within that block, splice samples to start at the IDR index. Audio passes\n // unconditionally \u2014 valid for the codecs supported here (AAC, Opus) where\n // every frame is independently decodable. SBR-only AAC, USAC, or HE-AAC v2\n // with PCE re-entry would need a similar gate.\n #armedVideo = false\n\n // Legacy SBN emission watermark for the old block-buffered path. Direct\n // source emission is now timestamp-ordered instead; recovered frames are\n // queued by media timestamp so they can fill gaps without racing ahead of\n // source frames.\n #lastEmittedSbn = -1\n\n /** Attempt to claim emission for `sbn`. Returns true if `sbn` is past\n * the watermark (and advances it); false if this sbn has already been\n * claimed or is older (caller should drop). */\n #claimSbnEmission(sbn: number): boolean {\n if (sbn <= this.#lastEmittedSbn) return false\n this.#lastEmittedSbn = sbn\n return true\n }\n\n /** Truncate `frames` to start at the first keyframe for video tracks before\n * the first emission. Returns the (possibly spliced) frames, or null to\n * drop the block entirely. Audio + already-armed video: identity. */\n #applyVideoKeyframeGate<T extends { data: Uint8Array; keyframe: boolean }>(frames: T[]): T[] | null {\n const keyedFrames = this.#normalizeVideoKeyframes(frames)\n if (this.#config.trackType !== 'video' || this.#armedVideo) return keyedFrames\n const firstKfIdx = keyedFrames.findIndex(f => f.keyframe)\n if (firstKfIdx < 0) return null\n return firstKfIdx === 0 ? keyedFrames : keyedFrames.slice(firstKfIdx)\n }\n\n #normalizeVideoKeyframes<T extends { data: Uint8Array; keyframe: boolean }>(frames: T[]): T[] {\n if (this.#config.trackType !== 'video' || !this.#validateH264Keyframes) return frames\n return frames.map((frame) => this.#withEffectiveVideoKeyframe(frame))\n }\n\n #withEffectiveVideoKeyframe<T extends { data: Uint8Array; keyframe: boolean }>(frame: T): T {\n if (this.#config.trackType !== 'video' || !this.#validateH264Keyframes) return frame\n const keyframe = detectH264Keyframe(frame.data)\n if (!keyframe) this.#dumpRejectedVideoKeyframe(frame.data, frame.keyframe)\n return keyframe === frame.keyframe ? frame : { ...frame, keyframe }\n }\n\n #dumpRejectedVideoKeyframe(data: Uint8Array, metadataKeyframe: boolean): void {\n if (this.#keyframeRejectDumpCount >= 12) return\n this.#keyframeRejectDumpCount++\n const sample = splitH264SampleNalUnits(data)\n const nalTypes = describeH264NalTypes(sample.nals)\n const classify = classifyH264Keyframe(data)\n const hex = Array.from(data.subarray(0, Math.min(48, data.length)))\n .map(b => (b as number).toString(16).padStart(2, '0'))\n .join(' ')\n console.log(\n `[L4-KF-GATE] reject#${this.#keyframeRejectDumpCount} len=${data.length} ` +\n `metadataKf=${metadataKeyframe} classify=${classify} format=${sample.format} ` +\n `nalTypes=[${nalTypes.join(',')}] first48=[${hex}]`,\n )\n }\n\n /** Mark video as already synchronized by an external decoder path.\n * Used by MoQ\u2192multicast MSE continuity when MoQ has already appended a\n * keyframe to the same SourceBuffer timeline before multicast takeover. */\n markVideoSynced(): void {\n if (this.#config.trackType === 'video') this.#armedVideo = true\n }\n\n /** Emit each frame as its own single-sample moof+mdat segment. Matches the\n * case-20 path (`MmtpToCmaf.wrapVideoSample` \u2192 `encodeDataSegment`) byte-\n * for-byte per frame. Working hypothesis (pending Chromium-source\n * validation against `media/filters/chunk_demuxer.cc`):\n * `encodeMultiSampleSegment` blobs are accepted by ChunkDemuxer in this\n * pipeline but only the first sample renders for live, possibly because\n * the pipeline expects per-frame moof boundaries. Track in BLO-3035.\n *\n * Stale-tfdt defense-in-depth: drops any frame whose timestamp is older\n * than `#lastEmittedTs`. The SBN watermark already prevents out-of-order\n * FEC-block emissions, but `addBypassFrame` (oversized MFU / no-FEC path)\n * doesn't touch the watermark \u2014 a bypass frame at t=T followed by a FEC\n * block whose frames precede T would otherwise inject earlier tfdt and\n * detach the SourceBuffer. */\n #ordersSamples(): boolean {\n return this.#sampleOrder.mode === 'media-window' || this.#sampleReorderWindow > 0\n }\n\n #unwrapTimestamp(timestamp: number): number {\n const wrapPeriod = this.#sampleOrder.mode === 'media-window'\n ? this.#sampleOrder.timestampWrapPeriod\n : undefined\n if (!wrapPeriod) return timestamp\n const reference = this.#lastSourceTs >= 0\n ? this.#lastSourceTs\n : this.#recoveredHorizonTs >= 0\n ? this.#recoveredHorizonTs\n : this.#lastEmittedTs\n if (reference < 0) return timestamp\n return timestamp + Math.round((reference - timestamp) / wrapPeriod) * wrapPeriod\n }\n\n #emitSample(\n data: Uint8Array,\n timestamp: number,\n duration: number,\n keyframe: boolean,\n advancesHorizon: boolean,\n catalogTrackName: string | undefined,\n mpuSequenceNumber: number | undefined,\n packetSequenceNumber: number | undefined,\n packetSequenceNumbers: number[] | undefined,\n repairedPacketSequenceNumbers: number[] | undefined,\n authoredTiming: AuthoredTiming | undefined,\n // Required, not optional: an omitted optional argument is silently\n // undefined, which is exactly how this field went missing from the\n // recovered path in the first place. Callers with nothing to declare pass\n // `undefined` on purpose.\n deliveryProvenance: MmtpDeliveryProvenance | undefined,\n ): void {\n const scaledTiming = authoredTiming === undefined\n ? null\n : scaleAuthoredTiming(authoredTiming, this.#config.timescale)\n if (authoredTiming !== undefined && scaledTiming === null) return\n const authoredTimestamp = scaledTiming?.timestamp ?? timestamp\n const authoredDuration = scaledTiming?.duration ?? duration\n let compositionTimeOffset: number | undefined\n if (authoredTiming !== undefined) {\n const scaledOffset = scaleAuthoredTicks(\n authoredTiming.presentationTime - authoredTiming.decodeTime,\n authoredTiming.mediaTimescale,\n this.#config.timescale,\n )\n if (scaledOffset === null) return\n // trun stores composition offsets as integer target-timescale ticks.\n // Preserve the nearest representable tick, then enforce the signed\n // int32 serialization range on the rounded value.\n const roundedOffset = Math.round(scaledOffset)\n if (\n !Number.isSafeInteger(roundedOffset) ||\n roundedOffset < INT32_MIN ||\n roundedOffset > INT32_MAX\n ) return\n compositionTimeOffset = roundedOffset\n }\n const unwrappedTimestamp = this.#unwrapTimestamp(authoredTimestamp)\n if (unwrappedTimestamp <= this.#lastEmittedTs) {\n this.#sampleOrderStats.staleSamples++\n return\n }\n\n const sample = this.#withEffectiveVideoKeyframe({\n data,\n timestamp: unwrappedTimestamp,\n duration: authoredDuration,\n keyframe,\n ...(compositionTimeOffset === undefined ? {} : { compositionTimeOffset }),\n advancesHorizon,\n ...(authoredTiming === undefined ? {} : { authoredTiming }),\n ...(packetSequenceNumber === undefined ? {} : { packetSequenceNumber }),\n ...(packetSequenceNumbers === undefined ? {} : { packetSequenceNumbers }),\n ...(repairedPacketSequenceNumbers === undefined\n ? {}\n : { repairedPacketSequenceNumbers }),\n ...(mpuSequenceNumber === undefined ? {} : { mpuSequenceNumber }),\n ...(catalogTrackName === undefined ? {} : { catalogTrackName }),\n ...(deliveryProvenance === undefined ? {} : { deliveryProvenance }),\n })\n if (advancesHorizon && unwrappedTimestamp > this.#lastSourceTs) {\n this.#lastSourceTs = unwrappedTimestamp\n } else if (!advancesHorizon && unwrappedTimestamp > this.#recoveredHorizonTs) {\n this.#recoveredHorizonTs = unwrappedTimestamp\n }\n\n if (this.#ordersSamples()) {\n this.#queueSample(sample)\n return\n }\n this.#emitArrivalOrdered(sample)\n }\n\n #emitArrivalOrdered(sample: OrderedSample): void {\n if (this.#config.trackType === 'video' && !this.#armedVideo && !sample.keyframe) {\n this.#sampleOrderStats.preRapDeadlineDrops++\n return\n }\n this.#emitSampleNow(sample)\n }\n\n #queueSample(sample: OrderedSample): void {\n if (this.#sampleReorderQueue.some(s => s.timestamp === sample.timestamp)) {\n this.#sampleOrderStats.duplicateSamples++\n return\n }\n this.#sampleReorderQueue.push(sample)\n this.#sampleReorderQueue.sort((a, b) => a.timestamp - b.timestamp)\n this.#drainSampleReorder(false)\n this.#enforceSampleOrderCapacity()\n }\n\n #releaseHorizon(): number {\n return this.#lastSourceTs >= 0 ? this.#lastSourceTs : this.#recoveredHorizonTs\n }\n\n #sampleIsReleasable(sample: OrderedSample, flushAll: boolean): boolean {\n if (flushAll) return true\n if (this.#sampleOrder.mode === 'media-window') {\n const horizon = this.#releaseHorizon()\n return horizon >= 0 && sample.timestamp < horizon - this.#sampleOrder.deliveryWindow\n }\n return this.#sampleReorderQueue.length > this.#sampleReorderWindow\n }\n\n #dropPreRapSamples(flushAll: boolean): boolean {\n if (this.#config.trackType !== 'video' || this.#armedVideo) return false\n\n const firstRap = this.#sampleReorderQueue.findIndex(\n sample => sample.keyframe && this.#sampleIsReleasable(sample, flushAll),\n )\n if (firstRap >= 0) {\n if (firstRap > 0) {\n this.#sampleOrderStats.preRapDeadlineDrops += firstRap\n this.#sampleReorderQueue.splice(0, firstRap)\n }\n return false\n }\n\n let dropped = 0\n while (\n this.#sampleReorderQueue[0] &&\n this.#sampleIsReleasable(this.#sampleReorderQueue[0]!, flushAll)\n ) {\n this.#sampleReorderQueue.shift()\n dropped++\n }\n if (flushAll) this.#sampleOrderStats.noRapFlushDrops += dropped\n else this.#sampleOrderStats.preRapDeadlineDrops += dropped\n return dropped > 0\n }\n\n #drainSampleReorder(flushAll: boolean): void {\n while (this.#sampleReorderQueue.length > 0) {\n if (this.#dropPreRapSamples(flushAll) && this.#sampleReorderQueue.length === 0) return\n const sample = this.#sampleReorderQueue[0]\n if (!sample || !this.#sampleIsReleasable(sample, flushAll)) return\n this.#sampleReorderQueue.shift()\n this.#emitQueuedSample(sample)\n }\n }\n\n #emitQueuedSample(sample: OrderedSample): void {\n const next = this.#sampleReorderQueue.find(s => s.timestamp > sample.timestamp)\n const duration = sample.authoredTiming\n ? sample.duration\n : next ? next.timestamp - sample.timestamp : sample.duration\n this.#emitSampleNow({\n ...sample,\n duration: duration > 0\n ? duration\n : sample.authoredTiming ? sample.duration : this.#frameDuration,\n })\n }\n\n #enforceSampleOrderCapacity(): void {\n if (this.#sampleOrder.mode !== 'media-window') return\n while (this.#sampleReorderQueue.length > this.#sampleOrderCapacity) {\n const sample = this.#sampleReorderQueue.shift()\n if (!sample) return\n this.#sampleOrderStats.forcedReleases++\n console.warn(\n `[CmafBlockAssembler] ${this.#config.trackType} media-window queue exceeded ` +\n `${this.#sampleOrderCapacity} samples; force-releasing timestamp=${sample.timestamp}`,\n )\n if (this.#config.trackType === 'video' && !this.#armedVideo && !sample.keyframe) {\n this.#sampleOrderStats.preRapDeadlineDrops++\n continue\n }\n this.#emitQueuedSample(sample)\n }\n }\n\n #emitSampleNow(sample: CmafBlockSample): void {\n if (sample.timestamp <= this.#lastEmittedTs) {\n this.#sampleOrderStats.staleSamples++\n return\n }\n this.#emitAudioGapFillNowBefore(sample.timestamp)\n this.#writeSampleNow(sample, true)\n }\n\n #writeSampleNow(sample: CmafBlockSample, rememberAudio: boolean): void {\n const { timestamp, duration, keyframe } = sample\n this.#lastEmittedTs = timestamp\n if (this.#config.trackType === 'video' && keyframe) this.#armedVideo = true\n const data = this.#normalizeSampleData(sample.data)\n if (this.#config.trackType === 'audio' && rememberAudio && data.length > 0) {\n // Keep decoder-proven codec data for concealment only after the FEC\n // delivery deadline has passed without the missing audio sample.\n this.#lastDecodableAudioFrame = data.slice()\n }\n if (this.onSample) {\n this.onSample(data === sample.data ? sample : { ...sample, data })\n } else {\n const baseTime = this.#rebase(timestamp)\n const segment = encodeDataSegment(\n data,\n baseTime,\n duration,\n keyframe,\n this.#sequence++,\n this.#config.trackId,\n sample.compositionTimeOffset,\n )\n this.onSegment?.(segment)\n }\n }\n\n #emitAudioGapFillNowBefore(timestamp: number): void {\n if (\n this.#config.trackType !== 'audio' ||\n this.#lastEmittedTs < 0 ||\n this.#lastDecodableAudioFrame === null\n ) return\n\n const gap = timestamp - this.#lastEmittedTs\n if (gap <= this.#frameDuration * 1.5) return\n\n const missingFrames = Math.max(0, Math.round(gap / this.#frameDuration) - 1)\n for (let i = 0; i < missingFrames; i++) {\n const fillTs = this.#lastEmittedTs + this.#frameDuration\n this.#writeSampleNow({\n data: this.#lastDecodableAudioFrame.slice(),\n timestamp: fillTs,\n duration: this.#frameDuration,\n keyframe: true,\n }, false)\n }\n }\n\n #emitPerSample(\n frames: BlockFrame[],\n audioDurationOverride?: number,\n advancesHorizon = false,\n ): void {\n for (let i = 0; i < frames.length; i++) {\n const f = frames[i]!\n // Per-frame duration from delta to next frame, or fallback.\n let duration: number\n if (this.#config.trackType === 'audio') {\n duration = audioDurationOverride ?? this.#frameDuration\n } else if (i < frames.length - 1) {\n duration = frames[i + 1]!.timestamp - f.timestamp\n } else if (i > 0) {\n duration = f.timestamp - frames[i - 1]!.timestamp\n } else {\n duration = audioDurationOverride ?? this.#frameDuration\n }\n if (duration <= 0) duration = audioDurationOverride ?? this.#frameDuration\n this.#emitSample(\n f.data,\n f.timestamp,\n duration,\n f.keyframe,\n advancesHorizon,\n f.catalogTrackName,\n f.mpuSequenceNumber,\n f.packetSequenceNumber,\n f.packetSequenceNumbers,\n f.repairedPacketSequenceNumbers,\n f.authoredTiming,\n f.deliveryProvenance,\n )\n }\n }\n\n // [BLO-3035-LAYER4-DIAG] Byte-dump for the first 6 video emits + 1Hz\n // aggregate counters that survive the whole run. The counters tell us\n // whether \"emits=low\" (assembler emits too few segments) or\n // \"addFrame=low\" (parser delivers too few frames) \u2014 which routes the\n // root-cause hunt to assembler vs router vs publisher.\n #dumpCount = 0\n #emitCount = 0\n #sampleCount = 0\n #keyframeCount = 0\n #addFrameCount = 0\n #recoveredBlockCount = 0\n #completeBlockCount = 0\n #failBlockCount = 0\n #aggregateTimer: ReturnType<typeof setInterval> | null = null\n #startAggregateTimer(): void {\n if (this.#aggregateTimer) return\n this.#aggregateTimer = setInterval(() => {\n console.log(\n `[L4-AGG-${this.#config.trackType}] emits=${this.#emitCount} samples=${this.#sampleCount} ` +\n `kf=${this.#keyframeCount} addFrame=${this.#addFrameCount} ` +\n `recovered=${this.#recoveredBlockCount} complete=${this.#completeBlockCount} ` +\n `fail=${this.#failBlockCount} pendingBlocks=${this.#blocks.size} ` +\n `pendingFlushes=${this.#pendingFlush.size} armedVideo=${this.#armedVideo}`,\n )\n this.#emitCount = 0\n this.#sampleCount = 0\n this.#keyframeCount = 0\n this.#addFrameCount = 0\n this.#recoveredBlockCount = 0\n this.#completeBlockCount = 0\n this.#failBlockCount = 0\n }, 1000)\n }\n #dumpEmit(path: string, samples: Array<{ data: Uint8Array; keyframe: boolean; timestamp?: number }>, sbn?: number): void {\n this.#emitCount++\n this.#sampleCount += samples.length\n this.#keyframeCount += samples.filter(s => s.keyframe).length\n // Always log video keyframes (no cap) \u2014 needed to see bytes of every IDR\n // including the t=5s one that Chrome's decoder rejected (BLO-3035 L4).\n const anyKf = this.#config.trackType === 'video' && samples.some(s => s.keyframe)\n if (this.#config.trackType !== 'video' || (this.#dumpCount >= 6 && !anyKf)) return\n this.#dumpCount++\n const s0 = samples[0]\n if (!s0) return\n const d = s0.data\n const hex = Array.from(d.subarray(0, Math.min(48, d.length)))\n .map(b => (b as number).toString(16).padStart(2, '0'))\n .join(' ')\n // djb2 hash of full s0 buffer \u2014 used to compare clean vs FEC-recovered emit bytes.\n let h = 5381\n for (let i = 0; i < d.length; i++) h = (h * 33 + (d[i] as number)) | 0\n const hash = (h >>> 0).toString(16).padStart(8, '0')\n const ts0 = s0.timestamp ?? -1\n const tsN = samples[samples.length - 1]?.timestamp ?? -1\n console.log(\n `[L4-DIAG] EMIT#${this.#dumpCount} path=${path}${sbn !== undefined ? ` sbn=${sbn}` : ''} ` +\n `samples=${samples.length} s0.kf=${s0.keyframe} s0.len=${d.length} ` +\n `ts0=${ts0} tsN=${tsN} dur=${tsN - ts0} hash=${hash} first48=[${hex}]`,\n )\n }\n\n constructor(config: BlockAssemblerConfig) {\n this.#config = {\n k: config.k,\n timescale: config.timescale ?? 1_000_000,\n trackId: config.trackId ?? 1,\n trackType: config.trackType,\n }\n\n // Compute default frame duration from fps (updated from timestamp deltas at runtime)\n if (config.fps && config.fps > 0) {\n this.#frameDuration = Math.round(this.#config.timescale / config.fps)\n } else if (config.trackType === 'audio' && config.sampleRate) {\n this.#frameDuration = Math.round(this.#config.timescale * 1024 / config.sampleRate)\n } else {\n // No fps info \u2014 will be refined from actual timestamp deltas\n this.#frameDuration = 33333\n }\n\n // Build fill frame based on track type (requires codec config from catalog)\n if (config.trackType === 'video' && config.avcC && config.width && config.height) {\n this.#fillFrame = generateGreenFillNAL(config.avcC, config.width, config.height)\n } else {\n this.#fillFrame = new Uint8Array(0)\n }\n\n const sampleReorderWindow = config.sampleReorderWindow ?? 0\n if (!Number.isFinite(sampleReorderWindow) || sampleReorderWindow < 0) {\n throw new Error('[CmafBlockAssembler] sampleReorderWindow must be finite and non-negative')\n }\n if (config.sampleOrder && sampleReorderWindow > 0) {\n throw new Error('[CmafBlockAssembler] configure sampleOrder or sampleReorderWindow, not both')\n }\n this.#sampleReorderWindow = Math.floor(sampleReorderWindow)\n this.#sampleOrder = config.sampleOrder ?? { mode: 'arrival' }\n if (this.#sampleOrder.mode === 'media-window') {\n const { deliveryWindow, timestampWrapPeriod } = this.#sampleOrder\n if (!Number.isSafeInteger(deliveryWindow) || deliveryWindow <= 0) {\n throw new Error(\n '[CmafBlockAssembler] media-window deliveryWindow must be a positive safe integer',\n )\n }\n if (\n timestampWrapPeriod !== undefined &&\n (!Number.isSafeInteger(timestampWrapPeriod) || timestampWrapPeriod <= deliveryWindow * 2)\n ) {\n throw new Error(\n '[CmafBlockAssembler] timestampWrapPeriod must be a safe integer larger than two delivery windows',\n )\n }\n const samplesPerSecond = config.trackType === 'audio' && config.sampleRate\n ? config.sampleRate / 1024\n : config.fps\n if (!samplesPerSecond || !Number.isFinite(samplesPerSecond) || samplesPerSecond <= 0) {\n throw new Error(\n '[CmafBlockAssembler] media-window ordering requires catalog-derived media cadence',\n )\n }\n this.#sampleOrderCapacity =\n Math.ceil(deliveryWindow * samplesPerSecond / this.#config.timescale) + 1\n }\n this.#validateH264Keyframes =\n config.trackType === 'video' &&\n (!!config.avcC || !config.codec || isH264Codec(config.codec))\n if (config.trackType === 'video') {\n console.log(\n `[L4-KF-CONFIG] validate=${this.#validateH264Keyframes} ` +\n `codec=${config.codec ?? ''} avcC=${config.avcC?.length ?? 0}`,\n )\n }\n\n // Store config for init segment generation\n this._videoConfig = config.trackType === 'video' && config.avcC\n ? { avcC: config.avcC, width: config.width ?? 0, height: config.height ?? 0 }\n : null\n this._audioConfig = config.trackType === 'audio' && config.sampleRate && config.channels\n ? { sampleRate: config.sampleRate, channels: config.channels, asc: config.asc }\n : null\n }\n\n private _videoConfig: { avcC?: Uint8Array; width: number; height: number } | null\n private _audioConfig: { sampleRate: number; channels: number; asc?: Uint8Array } | null\n\n get sampleOrderStats(): Readonly<CmafSampleOrderStats> {\n return { ...this.#sampleOrderStats }\n }\n\n /** Emit a single frame immediately as a one-sample moof+mdat segment.\n *\n * BLO-3035 layer 4 (4b): the prior SBN-grouped buffering scheme stranded\n * frames whenever a multi-packet frame spanned FEC block boundaries \u2014\n * intermediate SBNs had packets-but-no-frames and got `completeBlock`\n * events that landed on empty `#blocks` (\u2192 `pendingFlush` leak), while\n * the SBN where the multi-packet frame finally completed received the\n * `addFrame` but its `trackBlock` count never reached K (\u2192 `pendingBlocks`\n * leak). Result: ~50% of received frames never reached MSE.\n *\n * This path now mirrors `addBypassFrame` \u2014 emit on arrival, no buffering.\n * FEC recovery (`addRecoveredBlock`) keeps its SBN-watermark dedup against\n * the same SBN being re-emitted from two paths. Out-of-order regression\n * is guarded by the per-frame `lastEmittedTs` check (also enforced in\n * `#emitPerSample`). The `sbn`/`esi` parameters are kept for the call-site\n * signature but no longer affect routing. */\n addFrame(\n sbn: number,\n esi: number,\n data: Uint8Array,\n timestamp: number,\n keyframe: boolean,\n catalogTrackName?: string,\n mpuSequenceNumber?: number,\n packetSequenceNumber?: number,\n packetSequenceNumbers?: number[],\n repairedPacketSequenceNumbers?: number[],\n authoredTiming?: AuthoredTiming,\n deliveryProvenance?: MmtpDeliveryProvenance,\n ): void {\n void sbn; void esi\n this.#addFrameCount++\n this.#startAggregateTimer()\n\n if (!this.#ordersSamples()) this.#drainRecoveredUpTo(timestamp)\n\n // Per-frame duration: default to catalog-derived `#frameDuration`. For\n // variable-rate content Chrome refines duration from the next sample's\n // DTS at append time, so a fallback here is safe.\n this.#emitSample(\n data,\n timestamp,\n this.#frameDuration,\n keyframe,\n true,\n catalogTrackName,\n mpuSequenceNumber,\n packetSequenceNumber,\n packetSequenceNumbers,\n repairedPacketSequenceNumbers,\n authoredTiming,\n deliveryProvenance,\n )\n\n // Stats \u2014 #dumpEmit increments emit/sample/keyframe counters internally.\n this.#dumpEmit('addFrame-direct', [{ data, timestamp, keyframe }])\n }\n\n /** Mark a block as complete (all K source symbols received or FEC recovery succeeded).\n * If all frames are already buffered, flushes immediately. Otherwise sets pending-flush. */\n completeBlock(sbn: number): void {\n void sbn\n this.#completeBlockCount++\n this.#startAggregateTimer()\n // Source samples are emitted directly from addFrame(). A clean FEC block\n // completion is still useful for stats, but it must not enqueue stale\n // pending flushes from the retired block-buffered path.\n }\n\n /** Handle block timeout \u2014 emit whatever frames we have + fill for missing slots. */\n failBlock(sbn: number): void {\n this.#failBlockCount++\n this.#startAggregateTimer()\n this.#pendingFlush.delete(sbn)\n const block = this.#blocks.get(sbn)\n if (!block || block.size === 0) {\n this.#blocks.delete(sbn)\n return\n }\n this.#flushBlockWithFill(sbn)\n }\n\n /** Add all frames from a FEC-recovered block at once and emit immediately. */\n addRecoveredBlock(sbn: number, frames: BlockFrame[]): void {\n void sbn\n this.#recoveredBlockCount++\n this.#startAggregateTimer()\n // Build samples directly \u2014 recovered frames are already sorted\n this.#pendingFlush.delete(sbn)\n this.#blocks.delete(sbn)\n\n if (frames.length === 0) return\n const normalized = this.#normalizeVideoKeyframes(frames)\n this.#dumpEmit('addRecoveredBlock', normalized, sbn)\n if (this.#ordersSamples()) {\n this.#emitPerSample(normalized, undefined, false)\n return\n }\n\n // Arrival mode preserves the legacy protection against future recovered\n // samples advancing past source media. Explicit media-window mode routes\n // both paths through one queue instead.\n if (this.#lastSourceTs >= 0) {\n this.#enqueueRecovered(normalized)\n this.#drainRecoveredUpTo(this.#lastSourceTs)\n } else {\n const gated = this.#applyVideoKeyframeGate(normalized)\n if (gated) this.#emitPerSample(gated, undefined, false)\n }\n }\n\n /** Emit a single frame immediately as a one-sample segment (for oversized packets bypassing FEC). */\n addBypassFrame(\n data: Uint8Array,\n timestamp: number,\n keyframe: boolean,\n catalogTrackName?: string,\n mpuSequenceNumber?: number,\n packetSequenceNumber?: number,\n packetSequenceNumbers?: number[],\n repairedPacketSequenceNumbers?: number[],\n authoredTiming?: AuthoredTiming,\n deliveryProvenance?: MmtpDeliveryProvenance,\n ): void {\n if (!this.#ordersSamples()) this.#drainRecoveredUpTo(timestamp)\n this.#emitSample(\n data,\n timestamp,\n this.#frameDuration,\n keyframe,\n true,\n catalogTrackName,\n mpuSequenceNumber,\n packetSequenceNumber,\n packetSequenceNumbers,\n repairedPacketSequenceNumbers,\n authoredTiming,\n deliveryProvenance,\n )\n }\n\n /** Build and emit init segment from catalog config. */\n emitInit(): void {\n let init: Uint8Array | null = null\n if (this._videoConfig?.avcC) {\n init = buildVideoInitSegment(\n this._videoConfig.avcC,\n this._videoConfig.width,\n this._videoConfig.height,\n this.#config.timescale,\n this.#config.trackId,\n )\n } else if (this._audioConfig) {\n init = buildAudioInitSegment(\n this._audioConfig.sampleRate,\n this._audioConfig.channels,\n this._audioConfig.asc,\n this.#config.timescale,\n this.#config.trackId,\n )\n }\n if (init) this.onInitSegment?.(init)\n }\n\n /** Drain all ordered samples at end-of-stream or before reconfiguration. */\n flush(): void {\n if (this.#ordersSamples()) {\n this.#drainSampleReorder(true)\n return\n }\n if (this.#pendingRecovered.size === 0) return\n const frames = [...this.#pendingRecovered.values()].sort((a, b) => a.timestamp - b.timestamp)\n this.#pendingRecovered.clear()\n const gated = this.#applyVideoKeyframeGate(frames)\n if (gated) this.#emitPerSample(gated, undefined, false)\n else if (this.#config.trackType === 'video') {\n this.#sampleOrderStats.noRapFlushDrops += frames.length\n }\n }\n\n /** Drop all queued state and begin a fresh timestamp epoch. */\n reset(): void {\n this.#blocks.clear()\n this.#pendingFlush.clear()\n this.#pendingRecovered.clear()\n this.#sequence = 1\n this.#baseTs = -1\n this.#lastEmittedTs = -1\n this.#lastSourceTs = -1\n this.#recoveredHorizonTs = -1\n this.#lastDecodableAudioFrame = null\n this.#armedVideo = false\n this.#lastEmittedSbn = -1\n this.#sampleReorderQueue = []\n }\n\n dispose(): void {\n this.reset()\n this.onSegment = null\n this.onSample = null\n this.onInitSegment = null\n if (this.#aggregateTimer) {\n clearInterval(this.#aggregateTimer)\n this.#aggregateTimer = null\n }\n }\n\n // \u2500\u2500 Private \u2500\u2500\n\n /** Rebase an absolute timestamp to relative media time (starting near 0). */\n #rebase(timestamp: number): number {\n if (this.#baseTs < 0) this.#baseTs = timestamp\n return timestamp - this.#baseTs\n }\n\n #normalizeSampleData(data: Uint8Array): Uint8Array {\n return this.#config.trackType === 'audio' ? normalizeAacSampleForCmaf(data) : data\n }\n\n #enqueueRecovered(frames: BlockFrame[]): void {\n for (const frame of frames) {\n if (this.#lastEmittedTs >= 0 && frame.timestamp <= this.#lastEmittedTs) {\n this.#sampleOrderStats.staleSamples++\n continue\n }\n if (this.#pendingRecovered.has(frame.timestamp)) {\n this.#sampleOrderStats.duplicateSamples++\n continue\n }\n this.#pendingRecovered.set(frame.timestamp, frame)\n }\n }\n\n #drainRecoveredUpTo(horizonTs: number): void {\n if (this.#pendingRecovered.size === 0) return\n const ready = [...this.#pendingRecovered.values()]\n .filter(frame => frame.timestamp <= horizonTs)\n .sort((a, b) => a.timestamp - b.timestamp)\n\n for (const frame of ready) {\n this.#pendingRecovered.delete(frame.timestamp)\n this.#emitSample(\n frame.data,\n frame.timestamp,\n this.#frameDuration,\n frame.keyframe,\n false,\n frame.catalogTrackName,\n frame.mpuSequenceNumber,\n frame.packetSequenceNumber,\n frame.packetSequenceNumbers,\n frame.repairedPacketSequenceNumbers,\n frame.authoredTiming,\n frame.deliveryProvenance,\n )\n this.#dumpEmit('recovered-drain', [frame])\n }\n }\n\n /** Flush a block's buffered frames as a multi-sample CMAF segment. */\n #flushBlock(sbn: number): void {\n const block = this.#blocks.get(sbn)\n if (!block || block.size === 0) {\n this.#blocks.delete(sbn)\n return\n }\n\n // Sort by ESI to restore original frame order\n const entries = [...block.entries()].sort((a, b) => a[0] - b[0])\n const sortedFrames = entries.map(([, f]) => f)\n this.#blocks.delete(sbn)\n\n if (!this.#claimSbnEmission(sbn)) return\n const frames = this.#applyVideoKeyframeGate(sortedFrames)\n if (!frames) return\n\n this.#dumpEmit('flushBlock', frames, sbn)\n this.#emitPerSample(frames)\n }\n\n /** Flush a block with fill frames for missing ESI slots (FEC timeout path). */\n #flushBlockWithFill(sbn: number): void {\n const block = this.#blocks.get(sbn)\n if (!block) return\n\n const k = this.#config.k\n const isVideo = this.#config.trackType === 'video'\n const firstAudioFrame = !isVideo\n ? [...block.values()].sort((a, b) => a.timestamp - b.timestamp)[0]?.data\n : undefined\n const audioConcealmentFrame = this.#lastDecodableAudioFrame ?? firstAudioFrame\n\n // Build full K-slot array: real frames + fill for missing\n const allFrames: BlockFrame[] = []\n let lastRealTs = -1\n let firstRealTs = -1\n\n // Find min/max timestamps from received frames to interpolate missing ones\n for (const [, f] of block) {\n if (firstRealTs < 0 || f.timestamp < firstRealTs) firstRealTs = f.timestamp\n if (f.timestamp > lastRealTs) lastRealTs = f.timestamp\n }\n const estimatedBlockDuration = block.size > 1\n ? (lastRealTs - firstRealTs) / (block.size - 1) * k\n : this.#frameDuration * k\n\n for (let esi = 0; esi < k; esi++) {\n const real = block.get(esi)\n if (real) {\n allFrames.push(real)\n } else {\n // Interpolate timestamp for missing slot\n const interpolatedTs = firstRealTs >= 0\n ? firstRealTs + Math.round(esi * estimatedBlockDuration / k)\n : (this.#lastEmittedTs >= 0\n ? this.#lastEmittedTs + this.#frameDuration * (esi + 1)\n : 0)\n allFrames.push({\n // A synthesized AAC access unit is not portable across every\n // AudioSpecificConfig. Repeat known-good encoded audio instead;\n // if this is the first block, use its earliest received sample.\n data: isVideo\n ? this.#fillFrame\n : (audioConcealmentFrame?.slice() ?? new Uint8Array(0)),\n timestamp: interpolatedTs,\n // Video: first fill is keyframe (IDR). Audio: all fill marked keyframe.\n keyframe: isVideo ? !block.has(0) && esi === 0 : true,\n })\n }\n }\n\n this.#blocks.delete(sbn)\n if (!this.#claimSbnEmission(sbn)) return\n const gatedFrames = this.#applyVideoKeyframeGate(allFrames)\n if (!gatedFrames) return\n\n this.#emitPerSample(gatedFrames)\n }\n}\n\nfunction isH264Codec(codec?: string): boolean {\n const c = codec?.toLowerCase()\n return c?.startsWith('avc1') === true || c?.startsWith('avc3') === true\n}\n\nfunction describeH264NalTypes(nals: Uint8Array[]): number[] {\n return nals.slice(0, 16).map((nal) => (\n nal[0] !== undefined ? nal[0] & 0x1f : -1\n ))\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAiBA,SAAS,IAAI,SAAiB,UAAoC;AAChE,MAAI,OAAO;AACX,aAAW,KAAK,SAAU,SAAQ,EAAE;AACpC,QAAM,MAAM,IAAI,WAAW,IAAI;AAC/B,MAAI,SAAS,IAAI,MAAM,EAAE,UAAU,GAAG,IAAI;AAC1C,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,MAAM;AACV,aAAW,KAAK,UAAU;AACxB,QAAI,IAAI,GAAG,GAAG;AACd,WAAO,EAAE;AAAA,EACX;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,MAAc,SAAiB,UAAkB,UAAoC;AACpG,MAAI,OAAO;AACX,aAAW,KAAK,SAAU,SAAQ,EAAE;AACpC,QAAM,MAAM,IAAI,WAAW,IAAI;AAC/B,QAAM,KAAK,IAAI,SAAS,IAAI,MAAM;AAClC,KAAG,UAAU,GAAG,IAAI;AACpB,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,MAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAC1B,KAAG,UAAU,GAAI,WAAW,KAAO,QAAQ,QAAS;AACpD,MAAI,MAAM;AACV,aAAW,KAAK,UAAU;AACxB,QAAI,IAAI,GAAG,GAAG;AACd,WAAO,EAAE;AAAA,EACX;AACA,SAAO;AACT;AAEA,SAAS,IAAI,GAAuB;AAClC,QAAM,IAAI,IAAI,WAAW,CAAC;AAC1B,MAAI,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC;AACrC,SAAO;AACT;AAGA,IAAM,iBAAiB;AACvB,IAAM,cAAc;AAQpB,IAAM,aAAa;AAOnB,IAAM,eAAe,aAAa;AAClC,IAAM,YAAY;AAClB,IAAM,YAAY;AAYlB,SAAS,cAAc,SAAiB,OAAqB;AAC3D,MAAI,CAAC,OAAO,UAAU,OAAO,KAAK,WAAW,KAAK,UAAU,cAAc;AACxE,UAAM,IAAI,WAAW,GAAG,KAAK,6BAA6B,YAAY,SAAS,OAAO,EAAE;AAAA,EAC1F;AACF;AAGA,SAAS,gBAAgB,WAAmB,OAAqB;AAC/D,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,aAAa,KAAK,YAAY,YAAY;AAC5E,UAAM,IAAI,WAAW,GAAG,KAAK,6BAA6B,UAAU,SAAS,SAAS,EAAE;AAAA,EAC1F;AACF;AAGA,SAAS,6BACP,SACM;AACN,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC,EAAG;AAC3B,QAAI,WAAW,WACV,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,aAAa,SAAS,YAAY;AAC3E,YAAM,IAAI;AAAA,QACR,UAAU,CAAC,gDAAgD,SAAS,KAAK,SAAS,SAAS,MAAM;AAAA,MACnG;AAAA,IACF;AAAA,EACF;AACF;AAeO,SAAS,yBACd,SAMA,gBACA,UACA,UAAU,GACE;AACZ,MAAI,QAAQ,WAAW,EAAG,QAAO,IAAI,WAAW,CAAC;AACjD,gBAAc,SAAS,SAAS;AAChC,+BAA6B,OAAO;AAEpC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,QAAQ,CAAC;AAChD,QAAM,OAAO,QAAQ,QAAQ,GAAG,QAAU,IAAI,OAAO,CAAC;AAGtD,QAAM,WAAW,IAAI,WAAW,CAAC;AACjC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,KAAK,MAAM,iBAAiB,UAAW,CAAC;AAC9D,WAAS,UAAU,GAAG,mBAAmB,CAAC;AAC1C,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAI3C,QAAM,2BAA2B,QAAQ,KAAK,YAAU,OAAO,0BAA0B,MAAS;AAClG,QAAM,cAAc,2BAA2B,IAAI;AACnD,QAAM,YAAY,QAAY,2BAA2B,OAAW;AAEpE,QAAM,cAAc,QAAQ;AAC5B,QAAM,kBAAkB,2BAA2B,KAAK;AACxD,QAAM,WAAW,IAAI,WAAW,IAAI,cAAc,eAAe;AACjE,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,WAAW;AACjC,WAAS,UAAU,GAAG,CAAC;AACvB,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAM,IAAI,QAAQ,CAAC;AACnB,UAAM,MAAM,IAAI,IAAI;AACpB,aAAS,UAAU,KAAK,EAAE,aAAa,CAAC;AACxC,aAAS,UAAU,MAAM,GAAG,EAAE,KAAK,MAAM;AACzC,aAAS,UAAU,MAAM,GAAG,EAAE,WAAW,iBAAiB,WAAW;AACrE,QAAI,0BAA0B;AAC5B,eAAS,SAAS,MAAM,IAAI,EAAE,yBAAyB,CAAC;AAAA,IAC1D;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,QAAQ,aAAa,WAAW,QAAQ;AAE7D,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AACzC,QAAM,OAAO,IAAI,QAAQ,MAAM,IAAI;AAGnC,MAAI,WAAW;AACf,aAAW,KAAK,QAAS,aAAY,EAAE,KAAK;AAC5C,QAAM,cAAc,IAAI,WAAW,QAAQ;AAC3C,MAAI,MAAM;AACV,aAAW,KAAK,SAAS;AACvB,gBAAY,IAAI,EAAE,MAAM,GAAG;AAC3B,WAAO,EAAE,KAAK;AAAA,EAChB;AACA,QAAM,OAAO,IAAI,QAAQ,WAAW;AAGpC,QAAM,gBAAgB,IAAI,KAAK,SAAS,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK;AAC7E,MAAI,SAAS,KAAK,MAAM,EAAE,UAAU,eAAe,KAAK,SAAS,CAAC;AAElE,QAAM,SAAS,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACvD,SAAO,IAAI,MAAM,CAAC;AAClB,SAAO,IAAI,MAAM,KAAK,MAAM;AAC5B,SAAO;AACT;AAeO,SAAS,qBAAqB,MAAkB,OAAe,QAA4B;AAIhG,MAAI,KAAK,SAAS,EAAG,QAAO,IAAI,WAAW,CAAC;AAE5C,QAAM,cAAc,KAAK,CAAC,IAAK,KAAQ;AACvC,MAAI,SAAS;AACb,QAAM,SAAS,KAAK,QAAQ,IAAK;AACjC,QAAM,OAAqB,CAAC;AAG5B,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,QAAI,SAAS,IAAI,KAAK,OAAQ;AAC9B,UAAM,SAAU,KAAK,MAAM,KAAM,IAAK,KAAK,SAAS,CAAC;AACrD,cAAU;AACV,QAAI,SAAS,SAAS,KAAK,OAAQ;AACnC,UAAM,MAAM,KAAK,SAAS,QAAQ,SAAS,MAAM;AAEjD,UAAM,SAAS,IAAI,WAAW,IAAI,IAAI,MAAM;AAC5C,QAAI,SAAS,OAAO,MAAM,EAAE,UAAU,GAAG,IAAI,MAAM;AACnD,WAAO,IAAI,KAAK,CAAC;AACjB,SAAK,KAAK,MAAM;AAChB,cAAU;AAAA,EACZ;AAGA,MAAI,SAAS,KAAK,QAAQ;AACxB,UAAM,SAAS,KAAK,QAAQ;AAC5B,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,UAAI,SAAS,IAAI,KAAK,OAAQ;AAC9B,YAAM,SAAU,KAAK,MAAM,KAAM,IAAK,KAAK,SAAS,CAAC;AACrD,gBAAU;AACV,UAAI,SAAS,SAAS,KAAK,OAAQ;AACnC,YAAM,MAAM,KAAK,SAAS,QAAQ,SAAS,MAAM;AACjD,YAAM,SAAS,IAAI,WAAW,IAAI,IAAI,MAAM;AAC5C,UAAI,SAAS,OAAO,MAAM,EAAE,UAAU,GAAG,IAAI,MAAM;AACnD,aAAO,IAAI,KAAK,CAAC;AACjB,WAAK,KAAK,MAAM;AAChB,gBAAU;AAAA,IACZ;AAAA,EACF;AAcA,QAAM,UAAU,KAAK,KAAK,QAAQ,EAAE;AACpC,QAAM,WAAW,KAAK,KAAK,SAAS,EAAE;AACtC,QAAM,WAAW,UAAU;AAQ3B,QAAM,WAAW,IAAI,WAAW;AAAA,IAC9B;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA;AAAA,EAEF,CAAC;AACD,QAAM,YAAY,IAAI,WAAW,IAAI,SAAS,MAAM;AACpD,MAAI,SAAS,UAAU,MAAM,EAAE,UAAU,GAAG,SAAS,MAAM;AAC3D,YAAU,IAAI,UAAU,CAAC;AACzB,OAAK,KAAK,SAAS;AAGnB,MAAI,WAAW;AACf,aAAW,KAAK,KAAM,aAAY,EAAE;AACpC,QAAM,SAAS,IAAI,WAAW,QAAQ;AACtC,MAAI,IAAI;AACR,aAAW,KAAK,MAAM;AACpB,WAAO,IAAI,GAAG,CAAC;AACf,SAAK,EAAE;AAAA,EACT;AACA,SAAO;AACT;AA0CO,SAAS,0BAA0B,MAA8B;AACtE,MAAI,KAAK,SAAS,KAAK,KAAK,CAAC,MAAM,QAAS,KAAK,CAAC,IAAK,SAAU,KAAM;AACrE,WAAO;AAAA,EACT;AACA,QAAM,eAAgB,KAAK,CAAC,IAAK,IAAQ,IAAI;AAC7C,MAAI,KAAK,UAAU,aAAc,QAAO;AACxC,QAAM,eAAgB,KAAK,CAAC,IAAK,MAAS,KAAO,KAAK,CAAC,KAAM,KAAO,KAAK,CAAC,IAAK,SAAU;AACzF,MAAI,gBAAgB,KAAK,UAAU,eAAe,aAAc,QAAO;AACvE,SAAO,KAAK,SAAS,YAAY;AACnC;AAaO,SAAS,kBACd,MACA,WACA,UACA,UACA,UACA,UAAU,GACV,uBACY;AACZ,gBAAc,SAAS,SAAS;AAChC,+BAA6B,CAAC,EAAE,sBAAsB,CAAC,CAAC;AACxD,MAAI,0BAA0B,QAAW;AACvC,WAAO;AAAA,MACL,CAAC,EAAE,MAAM,UAAU,UAAU,sBAAsB,CAAC;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,cAAc,WAAW,iBAAiB;AAEhD,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,QAAQ,CAAC;AAChD,QAAM,OAAO,QAAQ,QAAQ,GAAG,QAAU,IAAI,OAAO,CAAC;AAGtD,QAAM,WAAW,IAAI,WAAW,CAAC;AACjC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,KAAK,MAAM,YAAY,UAAW,CAAC;AACzD,WAAS,UAAU,GAAG,cAAc,CAAC;AACrC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAG3C,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,CAAC;AACvB,WAAS,UAAU,GAAG,CAAC;AACvB,WAAS,UAAU,GAAG,aAAa,CAAC;AACpC,WAAS,UAAU,IAAI,KAAK,MAAM;AAClC,WAAS,UAAU,IAAI,WAAW;AAClC,QAAM,OAAO,QAAQ,QAAQ,GAAG,MAAU,QAAQ;AAElD,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AACzC,QAAM,OAAO,IAAI,QAAQ,MAAM,IAAI;AACnC,QAAM,OAAO,IAAI,QAAQ,IAAI;AAG7B,QAAM,gBAAgB,IAAI,KAAK,SAAS,IAAI,KAAK,SAAS,KAAK,SAAS,KAAK;AAC7E,MAAI,SAAS,KAAK,MAAM,EAAE,UAAU,eAAe,KAAK,SAAS,CAAC;AAElE,QAAM,SAAS,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACvD,SAAO,IAAI,MAAM,CAAC;AAClB,SAAO,IAAI,MAAM,KAAK,MAAM;AAC5B,SAAO;AACT;AAWO,SAAS,sBACd,MACA,OACA,QACA,YAAY,KACZ,UAAU,GACE;AAIZ,gBAAc,SAAS,eAAe;AACtC,kBAAgB,WAAW,iBAAiB;AAC5C,QAAM,OAAO,IAAI,QAAQ,IAAI,WAAW;AAAA,IACtC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IACjC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAClB;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAClB;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,EACpB,CAAC,CAAC;AAEF,QAAM,UAAU,IAAI,QAAQ,IAAI;AAChC,QAAM,WAAW,IAAI,WAAW,KAAK,QAAQ,MAAM;AACnD,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,CAAC;AACvB,WAAS,UAAU,IAAI,KAAK;AAC5B,WAAS,UAAU,IAAI,MAAM;AAC7B,WAAS,UAAU,IAAI,OAAU;AACjC,WAAS,UAAU,IAAI,OAAU;AACjC,WAAS,UAAU,IAAI,CAAC;AACxB,WAAS,UAAU,IAAI,EAAM;AAC7B,WAAS,SAAS,IAAI,EAAE;AACxB,WAAS,IAAI,SAAS,EAAE;AACxB,QAAM,OAAO,IAAI,QAAQ,QAAQ;AAEjC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI;AAC/C,QAAM,OAAO;AAAA,IAAI;AAAA,IAAQ;AAAA,IACvB,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,IAC5B,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,IAC5B,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,IACpC,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,EAC9B;AACA,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAAC;AAC7E,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,CAAC,GAAG,MAAM,IAAI;AAC1D,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,WAAW;AAAA,IAChD;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAC9B;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IACjC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,EAChC,CAAC,CAAC;AACF,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,SAAS;AACpD,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAC3C,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AAEzC,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,OAAO;AAC7B,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,UAAU;AACjC,WAAS,UAAU,IAAI,SAAS,EAAE;AAClC,WAAS,UAAU,IAAI,UAAU,EAAE;AACnC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAC3C,QAAM,OAAO,IAAI,QAAQ,MAAM,IAAI;AAEnC,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,SAAS;AAC/B,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,GAAM;AAC7B,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,UAAU;AACjC,WAAS,UAAU,IAAI,UAAU,CAAC;AAClC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAE3C,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,OAAO;AAClD,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,CAAC;AAC5C,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,GAAG,QAAQ,CAAC;AAExD,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AACzC,QAAM,SAAS,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACvD,SAAO,IAAI,MAAM,CAAC;AAClB,SAAO,IAAI,MAAM,KAAK,MAAM;AAC5B,SAAO;AACT;AAKO,SAAS,sBACd,YACA,UACA,KACA,WACA,UAAU,GACE;AAKZ,gBAAc,SAAS,eAAe;AACtC,QAAM,KAAK,aAAa;AAExB,MAAI,CAAC,KAAK;AACR,UAAM,YAAY,CAAC,MAAO,OAAO,MAAO,MAAO,OAAO,MAAO,MAAO,OAAO,MAAO,MAAO,OAAO,KAAM,IAAI;AAC1G,UAAM,KAAK,UAAU,QAAQ,UAAU;AACvC,UAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,QAAI,WAAW,IAAM;AACnB,YAAM,IAAK,KAAK,KAAO,WAAW,IAAM,YAAY;AACpD,YAAM,IAAI,WAAW,CAAE,KAAK,IAAK,KAAM,IAAI,GAAI,CAAC;AAAA,IAClD,OAAO;AACL,YAAM,IAAI,WAAW;AAAA,QAClB,KAAK,IAAK;AAAA,SACV,IAAS,cAAc,KAAM,KAAS;AAAA,QACtC,cAAc,KAAM;AAAA,QACpB,cAAc,IAAK;AAAA,UACjB,aAAa,OAAS,IAAM,YAAY,KAAM;AAAA,MACnD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,MAAM,IAAI,WAAW,IAAI,IAAI,MAAM;AACzC,MAAI,CAAC,IAAI;AAAM,MAAI,CAAC,IAAI,IAAI;AAAQ,MAAI,IAAI,KAAK,CAAC;AAClD,QAAM,UAAU,IAAI,WAAW,KAAK,IAAI,MAAM;AAC9C,UAAQ,CAAC,IAAI;AAAM,UAAQ,CAAC,IAAI;AAAM,UAAQ,IAAI,KAAK,EAAE;AACzD,QAAM,MAAM,IAAI,WAAW,IAAI,QAAQ,MAAM;AAC7C,MAAI,CAAC,IAAI;AAAM,MAAI,CAAC,IAAI,QAAQ;AAAQ,MAAI,IAAI,SAAS,CAAC;AAC1D,QAAM,SAAS,IAAI,WAAW,IAAI,IAAI,MAAM;AAC5C,SAAO,CAAC,IAAI;AAAG,SAAO,CAAC,IAAI;AAAM,SAAO,CAAC,IAAI;AAAG,SAAO,IAAI,KAAK,CAAC;AACjE,QAAM,KAAK,IAAI,WAAW,IAAI,OAAO,MAAM;AAC3C,KAAG,CAAC,IAAI;AAAM,KAAG,CAAC,IAAI,OAAO;AAAQ,KAAG,IAAI,QAAQ,CAAC;AACrD,QAAM,UAAU,QAAQ,QAAQ,GAAG,GAAG,EAAE;AAExC,QAAM,WAAW,IAAI,WAAW,KAAK,QAAQ,MAAM;AACnD,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,CAAC;AACvB,WAAS,UAAU,IAAI,QAAQ;AAC/B,WAAS,UAAU,IAAI,EAAE;AACzB,WAAS,UAAU,IAAI,cAAc,EAAE;AACvC,WAAS,IAAI,SAAS,EAAE;AACxB,QAAM,OAAO,IAAI,QAAQ,QAAQ;AAEjC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI;AAC/C,QAAM,OAAO;AAAA,IAAI;AAAA,IAAQ;AAAA,IACvB,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,IAC5B,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,IAC5B,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,IACpC,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC;AAAA,EAC9B;AACA,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,GAAG,IAAI,CAAC,GAAG,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAAC;AAC7E,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,GAAG,IAAI,WAAW,CAAC,CAAC,GAAG,MAAM,IAAI;AAC7E,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,IAAI,WAAW;AAAA,IAChD;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAC9B;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IACjC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,EAChC,CAAC,CAAC;AACF,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,EAAE;AAC7C,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAC3C,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AAEzC,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,OAAO;AAC7B,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,UAAU;AACjC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAC3C,QAAM,OAAO,IAAI,QAAQ,MAAM,IAAI;AAEnC,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,QAAM,WAAW,IAAI,SAAS,SAAS,MAAM;AAC7C,WAAS,UAAU,GAAG,EAAE;AACxB,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,GAAM;AAC7B,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,KAAU;AACjC,WAAS,UAAU,IAAI,UAAU;AACjC,WAAS,UAAU,IAAI,UAAU,CAAC;AAClC,QAAM,OAAO,QAAQ,QAAQ,GAAG,GAAG,QAAQ;AAE3C,QAAM,WAAW,IAAI,WAAW,EAAE;AAClC,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,OAAO;AAClD,MAAI,SAAS,SAAS,MAAM,EAAE,UAAU,GAAG,CAAC;AAC5C,QAAM,OAAO,IAAI,QAAQ,QAAQ,QAAQ,GAAG,GAAG,QAAQ,CAAC;AAExD,QAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,IAAI;AACzC,QAAM,OAAO,IAAI,QAAQ,IAAI,WAAW;AAAA,IACtC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAAG;AAAA,IAAG;AAAA,IAAG;AAAA,IACjC;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAClB;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,IAClB;AAAA,IAAM;AAAA,IAAM;AAAA,IAAM;AAAA,EACpB,CAAC,CAAC;AACF,QAAM,SAAS,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACvD,SAAO,IAAI,MAAM,CAAC;AAClB,SAAO,IAAI,MAAM,KAAK,MAAM;AAC5B,SAAO;AACT;;;ACrSO,SAAS,0BAA0B,MAA8B;AACtE,QAAM,MAAgB,CAAC;AACvB,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,SAAS,KAAK,MAAM,KAAQ,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,CAAC,KAAK,GAAM;AAC1E,cAAQ;AACR;AAAA,IACF;AACA,QAAI,KAAK,CAAC;AACV,YAAQ,MAAM,IAAI,QAAQ,IAAI;AAAA,EAChC;AACA,SAAO,WAAW,KAAK,GAAG;AAC5B;AAMO,SAAS,kBAAkB,MAAkB,aAAa,GAAiB;AAChF,QAAM,OAAqB,CAAC;AAC5B,MAAI,IAAI;AACR,SAAO,IAAI,cAAc,KAAK,QAAQ;AACpC,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,YAAY,IAAK,OAAO,OAAO,IAAK,KAAK,IAAI,CAAC;AAClE,SAAK;AACL,QAAI,OAAO,KAAK,IAAI,MAAM,KAAK,OAAQ;AACvC,SAAK,KAAK,KAAK,SAAS,GAAG,IAAI,GAAG,CAAC;AACnC,SAAK;AAAA,EACP;AACA,SAAO;AACT;AAWO,SAAS,qBAAqB,MAAkB,aAAa,GAAY;AAC9E,MAAI,IAAI;AACR,MAAI,QAAQ;AACZ,SAAO,IAAI,cAAc,KAAK,QAAQ;AACpC,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,YAAY,IAAK,OAAO,OAAO,IAAK,KAAK,IAAI,CAAC;AAClE,SAAK;AACL,QAAI,OAAO,KAAK,IAAI,MAAM,KAAK,OAAQ,QAAO;AAC9C,SAAK;AACL;AAAA,EACF;AACA,SAAO,QAAQ,KAAK,MAAM,KAAK;AACjC;AAgCO,SAAS,wBACd,MACA,UAAwC,CAAC,GACtB;AACnB,MAAI,qBAAqB,IAAI,EAAG,QAAO,EAAE,MAAM,kBAAkB,IAAI,GAAG,QAAQ,OAAO;AACvF,MAAI,SAAS,IAAI,EAAG,QAAO,EAAE,MAAM,oBAAoB,IAAI,GAAG,QAAQ,SAAS;AAC/E,MAAI,QAAQ,qBAAqB,MAAM;AACrC,UAAM,UAAU,yBAAyB,IAAI;AAC7C,QAAI,QAAQ,SAAS,EAAG,QAAO,EAAE,MAAM,SAAS,QAAQ,eAAe;AAAA,EACzE;AACA,MAAI,uBAAuB,IAAI,EAAG,QAAO,EAAE,MAAM,CAAC,IAAI,GAAG,QAAQ,UAAU;AAC3E,QAAM,OAAO,kBAAkB,IAAI;AACnC,SAAO,EAAE,MAAM,QAAQ,KAAK,SAAS,IAAI,SAAS,UAAU;AAC9D;AA0GO,SAAS,SAAS,MAA2B;AAClD,MAAI,KAAK,UAAU,KAAK,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,MAChD,KAAK,CAAC,MAAM,KAAM,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAK;AACvD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAoBO,SAAS,oBAAoB,MAAgC;AAClE,QAAM,WAAyB,CAAC;AAChC,MAAI,IAAI;AACR,SAAO,IAAI,KAAK,SAAS,GAAG;AAC1B,QAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,MAAM,GAAG;AACtC,UAAI,QAAQ;AACZ,UAAI,KAAK,IAAI,CAAC,MAAM,EAAG,SAAQ;AAAA,eACtB,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,CAAC,MAAM,EAAG,SAAQ;AAChF,UAAI,QAAQ,GAAG;AACb,cAAM,WAAW,IAAI;AACrB,YAAI,SAAS,KAAK;AAClB,iBAAS,IAAI,WAAW,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACnD,cAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,MAAM,MAChC,KAAK,IAAI,CAAC,MAAM,KAAM,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,CAAC,MAAM,IAAK;AAC1F,qBAAS;AACT;AAAA,UACF;AAAA,QACF;AACA,YAAI,SAAS,SAAU,UAAS,KAAK,KAAK,SAAS,UAAU,MAAM,CAAC;AACpE,YAAI;AACJ;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AACA,SAAO;AACT;AA6CO,SAAS,qBACd,MACA,UAAwC,CAAC,GACpB;AACrB,QAAM,OAAO,iCAAiC,MAAM,OAAO;AAC3D,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI,gBAAgB;AACpB,MAAI,iBAAiB;AACrB,MAAI,SAAS;AACb,aAAW,OAAO,MAAM;AACtB,aAAS;AACT,UAAM,UAAU,IAAI,CAAC,MAAM,SAAY,IAAI,CAAC,IAAI,KAAO;AACvD,QAAI,YAAY,KAAK,YAAY,EAAG,QAAO;AAC3C,QAAI,YAAY,GAAG;AACjB,UAAI,iBAAiB,GAAG,EAAG,iBAAgB;AAAA,UACtC,kBAAiB;AAAA,IACxB;AAAA,EACF;AACA,MAAI,iBAAiB,CAAC,eAAgB,QAAO;AAC7C,SAAO,SAAS,QAAQ;AAC1B;AAMO,SAAS,mBACd,MACA,UAAwC,CAAC,GAChC;AACT,SAAO,qBAAqB,MAAM,OAAO,MAAM;AACjD;AAoHA,SAAS,iCACP,MACA,SACc;AACd,SAAO,wBAAwB,MAAM,OAAO,EAAE;AAChD;AAEA,SAAS,yBAAyB,MAAkB,aAAa,GAAiB;AAChF,QAAM,OAAqB,CAAC;AAC5B,MAAI,IAAI;AACR,SAAO,IAAI,aAAa,KAAK,QAAQ;AACnC,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,YAAY,IAAK,OAAO,OAAO,IAAK,KAAK,IAAI,CAAC;AAClE,SAAK;AACL,QAAI,OAAO,KAAK,KAAK,KAAK,OAAQ;AAClC,UAAM,MAAM,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM;AACzC,SAAK,KAAK,KAAK,SAAS,GAAG,GAAG,CAAC;AAC/B,QAAI,MAAM,IAAI,IAAK;AACnB,QAAI;AAAA,EACN;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,MAA2B;AACzD,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,SAAS,KAAK,CAAC;AACrB,OAAK,SAAS,SAAU,EAAG,QAAO;AAClC,QAAM,UAAU,SAAS;AACzB,SAAO,UAAU,KAAK,UAAU;AAClC;AASA,SAAS,iBAAiB,KAA0B;AAClD,QAAM,YAAY,kBAAkB,GAAG;AACvC,SAAO,cAAc,KAAK,cAAc,KAAK,cAAc,KAAK,cAAc;AAChF;AAEA,SAAS,kBAAkB,KAAgC;AACzD,MAAI,IAAI,SAAS,MAAM,IAAI,CAAC,IAAK,QAAU,EAAG,QAAO;AACrD,QAAM,OAAO,0BAA0B,IAAI,SAAS,CAAC,CAAC;AACtD,QAAM,QAAQ,EAAE,WAAW,EAAE;AAC7B,MAAI,sBAAsB,MAAM,KAAK,MAAM,KAAM,QAAO;AACxD,SAAO,sBAAsB,MAAM,KAAK;AAC1C;AAEA,SAAS,sBAAsB,MAAkB,OAA6C;AAC5F,MAAI,kBAAkB;AACtB,SAAO,MAAM;AACX,UAAM,MAAM,QAAQ,MAAM,KAAK;AAC/B,QAAI,QAAQ,KAAM,QAAO;AACzB,QAAI,QAAQ,EAAG;AACf;AACA,QAAI,kBAAkB,GAAI,QAAO;AAAA,EACnC;AAEA,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACxC,UAAM,MAAM,QAAQ,MAAM,KAAK;AAC/B,QAAI,QAAQ,KAAM,QAAO;AACzB,aAAU,UAAU,IAAK;AAAA,EAC3B;AACA,UAAQ,KAAK,mBAAmB,IAAI;AACtC;AAEA,SAAS,QAAQ,MAAkB,OAA4C;AAC7E,MAAI,MAAM,aAAa,KAAK,SAAS,EAAG,QAAO;AAC/C,QAAM,OAAO,KAAK,MAAM,aAAa,CAAC;AACtC,QAAM,MAAO,QAAS,KAAK,MAAM,YAAY,KAAO;AACpD,QAAM;AACN,SAAO;AACT;AAsTA,IAAI,QAAoB;AACtB,QAAM,EAAE,UAAU,MAAM,OAAO,IAAI;AAEnC,WAAS,eAAe,MAAM;AAC5B,aAAS,YAAY,MAAM;AACzB,WAAK,qBAAqB,MAAM;AAC9B,eAAO,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAChE,CAAC;AACD,WAAK,qBAAqB,MAAM;AAC9B,eAAO,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC7D,CAAC;AACD,WAAK,gBAAgB,MAAM;AACzB,eAAO,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,IAAI,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MAClE,CAAC;AAAA,IACH,CAAC;AAED,aAAS,uBAAuB,MAAM;AACpC,WAAK,eAAe,MAAM;AACxB,eAAO,oBAAoB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAAA,MACxE,CAAC;AACD,WAAK,eAAe,MAAM;AACxB,eAAO,oBAAoB,IAAI,WAAW,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAAA,MACnG,CAAC;AACD,WAAK,wBAAwB,MAAM;AACjC,eAAO,oBAAoB,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE;AAAA,MACzE,CAAC;AAAA,IACH,CAAC;AAED,aAAS,uBAAuB,MAAM;AACpC,WAAK,mBAAmB,MAAM;AAC5B,cAAM,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,KAAM,KAAM,GAAG,GAAG,GAAG,GAAG,IAAM,GAAI,CAAC;AAClF,cAAM,OAAO,oBAAoB,IAAI;AACrC,eAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAC1B,eAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC,CAAC;AAC1D,eAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC,CAAC;AAAA,MACtD,CAAC;AACD,WAAK,8BAA8B,MAAM;AACvC,cAAM,OAAO,oBAAoB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,KAAM,IAAM,GAAG,GAAG,GAAG,KAAM,CAAI,CAAC,CAAC;AAC3F,eAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAAA,MAC5B,CAAC;AAAA,IACH,CAAC;AAED,aAAS,gBAAgB,MAAM;AAC7B,WAAK,uBAAuB,MAAM;AAChC,cAAM,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,IAAM,KAAM,GAAI,CAAC;AAC5D,cAAM,OAAO,aAAa,MAAM;AAChC,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AACtB,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,EAAI;AAAA,MAC3B,CAAC;AACD,WAAK,oBAAoB,MAAM;AAC7B,cAAM,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,CAAI,CAAC;AACtD,cAAM,OAAO,aAAa,QAAQ,EAAE,KAAK,IAAI,WAAW,CAAC,KAAM,EAAI,CAAC,GAAG,KAAK,IAAI,WAAW,CAAC,KAAM,CAAI,CAAC,EAAE,CAAC;AAC1G,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AACtB,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,GAAI;AAAA,MAC3B,CAAC;AAAA,IACH,CAAC;AAED,aAAS,sBAAsB,MAAM;AACnC,WAAK,kBAAkB,MAAM;AAC3B,eAAO,mBAAmB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC1E,CAAC;AACD,WAAK,kBAAkB,MAAM;AAC3B,eAAO,mBAAmB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC1E,CAAC;AACD,WAAK,eAAe,MAAM;AACxB,eAAO,mBAAmB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MACtF,CAAC;AACD,WAAK,sBAAsB,MAAM;AAC/B,eAAO,mBAAmB,IAAI,WAAW;AAAA,UACvC;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UACZ;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,QACpB,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAChB,CAAC;AACD,WAAK,+BAA+B,MAAM;AACxC,eAAO,mBAAmB,IAAI,WAAW;AAAA,UACvC;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,QACpB,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAChB,CAAC;AACD,WAAK,qBAAqB,MAAM;AAC9B,eAAO,mBAAmB,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC1E,CAAC;AACD,WAAK,iCAAiC,MAAM;AAC1C,eAAO,mBAAmB,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MACpE,CAAC;AACD,WAAK,8DAA8D,MAAM;AACvE,cAAM,UAAU,IAAI,WAAW,CAAC,GAAG,GAAG,IAAM,GAAG,GAAI,CAAC;AACpD,eAAO,qBAAqB,OAAO,CAAC,EAAE,cAAc;AACpD,eAAO,qBAAqB,SAAS,EAAE,kBAAkB,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC7E,CAAC;AACD,WAAK,mBAAmB,MAAM;AAC5B,eAAO,mBAAmB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,EAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MAC3E,CAAC;AACD,WAAK,gDAAgD,MAAM;AACzD,eAAO,mBAAmB,IAAI,WAAW;AAAA,UACvC;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,UAClB;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAM;AAAA,QACpB,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAED,aAAS,gBAAgB,MAAM;AAC7B,WAAK,qCAAqC,MAAM;AAC9C,cAAM,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,KAAM,GAAI,CAAC;AAC1D,cAAM,SAAiB,EAAE,KAAK,IAAI,WAAW,CAAC,KAAM,EAAI,CAAC,GAAG,KAAK,IAAI,WAAW,CAAC,KAAM,CAAI,CAAC,EAAE;AAC9F,cAAM,SAAS,aAAa,MAAM,MAAM,MAAM;AAC9C,eAAO,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC;AACxB,eAAO,OAAO,CAAC,CAAC,EAAE,KAAK,GAAI;AAAA,MAC7B,CAAC;AAAA,IACH,CAAC;AAED,aAAS,uBAAuB,MAAM;AACpC,WAAK,uBAAuB,MAAM;AAChC,eAAO,oBAAoB,IAAI,WAAW,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa;AAAA,MACjF,CAAC;AAAA,IACH,CAAC;AAED,aAAS,gCAAgC,MAAM;AAS7C,eAAS,oBAAoB,KAA6B;AACxD,cAAMA,OAAM,CAAC,MAAc,YAAoC;AAC7D,gBAAM,KAAK,IAAI,QAAQ;AACvB,gBAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,cAAI,CAAC,IAAK,OAAO,KAAM;AACvB,cAAI,CAAC,IAAK,OAAO,KAAM;AACvB,cAAI,CAAC,IAAK,OAAO,IAAK;AACtB,cAAI,CAAC,IAAI,KAAK;AACd,cAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAAG,cAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AACvD,cAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAAG,cAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AACvD,cAAI,IAAI,SAAS,CAAC;AAClB,iBAAO;AAAA,QACT;AACA,cAAM,SAAS,IAAI,SAAmC;AACpD,gBAAM,QAAQ,KAAK,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AACnD,gBAAM,MAAM,IAAI,WAAW,KAAK;AAChC,cAAI,MAAM;AACV,qBAAW,KAAK,MAAM;AAAE,gBAAI,IAAI,GAAG,GAAG;AAAG,mBAAO,EAAE;AAAA,UAAO;AACzD,iBAAO;AAAA,QACT;AAEA,cAAM,OAAOA,KAAI,QAAQ,IAAI,WAAW;AAAA,UACtC;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA;AAAA,UAClB;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA;AAAA,UAClB;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA;AAAA,UAClB;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA;AAAA,QACpB,CAAC,CAAC;AAIF,cAAM,MAAM,IAAI,WAAW,IAAI,IAAI,MAAM;AACzC,YAAI,CAAC,IAAI;AAAM,YAAI,CAAC,IAAI,IAAI;AAC5B,YAAI,IAAI,KAAK,CAAC;AAEd,cAAM,MAAM,IAAI,WAAW,IAAI,KAAK,IAAI,MAAM;AAC9C,YAAI,CAAC,IAAI;AAAM,YAAI,CAAC,IAAI,KAAK,IAAI;AACjC,YAAI,CAAC,IAAI;AACT,YAAI,CAAC,IAAK,KAAQ,IAAK;AAEvB,YAAI,IAAI,KAAK,EAAE;AAEf,cAAM,MAAM,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM;AAC7C,YAAI,CAAC,IAAI;AAAM,YAAI,CAAC,IAAI,IAAI,IAAI;AAEhC,YAAI,IAAI,KAAK,CAAC;AAEd,cAAM,cAAc,IAAI,WAAW,IAAI,IAAI,MAAM;AACjD,oBAAY,IAAI,KAAK,CAAC;AACtB,cAAM,OAAOA,KAAI,QAAQ,WAAW;AAKpC,cAAM,YAAY,IAAI,WAAW,EAAE;AACnC,kBAAU,CAAC,IAAI;AACf,kBAAU,EAAE,IAAI;AAAM,kBAAU,EAAE,IAAI;AACtC,kBAAU,EAAE,IAAI;AAAM,kBAAU,EAAE,IAAI;AAEtC,kBAAU,EAAE,IAAI;AAAM,kBAAU,EAAE,IAAI;AACtC,cAAM,OAAOA,KAAI,QAAQ,OAAO,WAAW,IAAI,CAAC;AAGhD,cAAM,cAAc,IAAI,WAAW,IAAI,KAAK,MAAM;AAClD,oBAAY,CAAC,IAAI;AACjB,oBAAY,IAAI,MAAM,CAAC;AACvB,cAAM,OAAOA,KAAI,QAAQ,WAAW;AAEpC,cAAM,OAAOA,KAAI,QAAQ,IAAI;AAC7B,cAAM,OAAOA,KAAI,QAAQ,IAAI;AAC7B,cAAM,OAAOA,KAAI,QAAQ,IAAI;AAC7B,cAAM,OAAOA,KAAI,QAAQ,IAAI;AAC7B,cAAM,OAAOA,KAAI,QAAQ,IAAI;AAE7B,eAAO,OAAO,MAAM,IAAI;AAAA,MAC1B;AAEA,WAAK,kDAAkD,MAAM;AAG3D,cAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC;AACvC,cAAM,OAAO,oBAAoB,GAAG;AACpC,cAAM,SAAS,6BAA6B,IAAI;AAChD,eAAO,MAAM,EAAE,YAAY;AAC3B,eAAO,OAAQ,KAAK,EAAE,KAAK,WAAW;AACtC,eAAO,MAAM,KAAK,OAAQ,WAAW,CAAC,EAAE,QAAQ,CAAC,IAAM,GAAI,CAAC;AAAA,MAC9D,CAAC;AAED,WAAK,2CAA2C,MAAM;AAEpD,cAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAI,CAAC;AACvC,cAAM,OAAO,oBAAoB,GAAG;AACpC,eAAO,6BAA6B,IAAI,GAAG,KAAK,EAAE,KAAK,WAAW;AAAA,MACpE,CAAC;AAED,WAAK,wCAAwC,MAAM;AACjD,eAAO,6BAA6B,IAAI,WAAW,EAAE,CAAC,CAAC,EAAE,cAAc;AAAA,MACzE,CAAC;AAED,WAAK,0DAA0D,MAAM;AAEnE,cAAM,OAAO,IAAI,WAAW;AAAA,UAC1B;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UAAI;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAC/B;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAG;AAAA,UAAG;AAAA,UAAG;AAAA,UACjC;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,UAAM;AAAA,QAC5C,CAAC;AACD,cAAM,OAAO,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,KAAM,KAAM,GAAI,CAAC;AAChE,cAAM,MAAM,IAAI,WAAW,KAAK,SAAS,KAAK,MAAM;AACpD,YAAI,IAAI,IAAI;AAAG,YAAI,IAAI,MAAM,KAAK,MAAM;AACxC,eAAO,6BAA6B,GAAG,CAAC,EAAE,cAAc;AAAA,MAC1D,CAAC;AAAA,IACH,CAAC;AAED,aAAS,QAAQ,MAAM;AAErB,YAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAM,IAAM,GAAM,KAAM,GAAI,CAAC;AAC/D,YAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAM,GAAM,GAAM,IAAM,GAAM,GAAM,GAAM,KAAM,GAAM,GAAM,GAAM,GAAM,GAAM,IAAM,KAAM,GAAM,CAAI,CAAC;AACvI,YAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAM,KAAM,KAAM,KAAM,EAAI,CAAC;AAC/D,YAAM,MAAM,IAAI,WAAW,CAAC,IAAM,GAAM,KAAM,CAAI,CAAC;AACnD,YAAM,KAAK,IAAI,SAAuB;AACpC,cAAM,QAAkB,CAAC;AACzB,mBAAW,KAAK,MAAM;AAAE,gBAAM,KAAM,EAAE,UAAU,KAAM,KAAO,EAAE,UAAU,KAAM,KAAO,EAAE,UAAU,IAAK,KAAM,EAAE,SAAS,KAAM,GAAG,CAAC;AAAA,QAAE;AACpI,eAAO,WAAW,KAAK,KAAK;AAAA,MAC9B;AAEA,WAAK,eAAe,MAAM;AACxB,eAAO,YAAY,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAChD,eAAO,YAAY,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAChD,eAAO,YAAY,aAAa,CAAC,EAAE,KAAK,KAAK;AAAA,MAC/C,CAAC;AAED,WAAK,yCAAyC,MAAM;AAClD,eAAO,MAAM,KAAK,0BAA0B,IAAI,WAAW,CAAC,GAAG,GAAG,GAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC;AAChG,eAAO,MAAM,KAAK,0BAA0B,IAAI,WAAW,CAAC,KAAM,GAAI,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAM,GAAI,CAAC;AAAA,MAClG,CAAC;AAED,WAAK,iDAAiD,MAAM;AAC1D,cAAM,OAAO,kBAAkB,GAAG,KAAK,GAAG,CAAC;AAC3C,eAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAC1B,eAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG;AAC3B,eAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG;AAAA,MAC7B,CAAC;AAED,WAAK,qEAAqE,MAAM;AAC9E,eAAO,qBAAqB,GAAG,IAAI,WAAW,CAAC,CAAI,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MACzE,CAAC;AAED,WAAK,2DAA2D,MAAM;AACpE,eAAO,qBAAqB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MACnF,CAAC;AAED,WAAK,kEAAkE,MAAM;AAC3E,eAAO,qBAAqB,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,GAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,MACnF,CAAC;AAED,WAAK,oEAAoE,MAAM;AAC7E,cAAM,OAAO,GAAG,IAAI,WAAW,CAAC,CAAI,CAAC,GAAG,GAAG;AAC3C,cAAM,aAAa,0BAA0B,IAAI;AACjD,eAAO,WAAW,MAAM,EAAE,KAAK,MAAM;AACrC,eAAO,WAAW,IAAI,EAAE,KAAK,IAAI;AAAA,MACnC,CAAC;AAED,WAAK,qEAAqE,MAAM;AAC9E,cAAM,MAAM,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC;AAC7C,cAAM,aAAa,0BAA0B,GAAG;AAChD,eAAO,WAAW,MAAM,EAAE,KAAK,SAAS;AACxC,eAAO,WAAW,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,KAAM,GAAI,CAAC,CAAC;AAAA,MAChF,CAAC;AAED,WAAK,wEAAwE,MAAM;AACjF,cAAM,SAAS,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,KAAM,GAAI,CAAC;AAC5D,cAAM,SAAS,wBAAwB,MAAM;AAC7C,eAAO,OAAO,MAAM,EAAE,KAAK,QAAQ;AACnC,eAAO,OAAO,IAAI,EAAE,aAAa,CAAC;AAClC,eAAO,OAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC,CAAC;AAAA,MACnE,CAAC;AAED,WAAK,0EAA0E,MAAM;AACnF,cAAM,MAAM,IAAI,WAAW,CAAC,KAAM,KAAM,GAAI,CAAC;AAC7C,cAAM,SAAS,wBAAwB,GAAG;AAC1C,eAAO,OAAO,MAAM,EAAE,KAAK,SAAS;AACpC,eAAO,OAAO,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC;AAAA,MACnC,CAAC;AAED,WAAK,+DAA+D,MAAM;AACxE,cAAM,UAAU,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,KAAM,GAAI,CAAC;AACvD,cAAM,SAAS,wBAAwB,SAAS,EAAE,kBAAkB,KAAK,CAAC;AAC1E,eAAO,OAAO,MAAM,EAAE,KAAK,cAAc;AACzC,eAAO,OAAO,IAAI,EAAE,aAAa,CAAC;AAClC,eAAO,OAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,IAAI,WAAW,CAAC,KAAM,GAAI,CAAC,CAAC;AAAA,MAC7D,CAAC;AAED,WAAK,gEAAgE,MAAM;AACzE,cAAM,OAAO,yBAAyB,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC;AAC5D,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAC5B,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAC5B,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAAA,MAC9B,CAAC;AAED,WAAK,wDAAwD,MAAM;AACjE,cAAM,KAAK,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AACtC,cAAM,SAAS,WAAW,KAAK,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC;AAC3F,cAAM,OAAO,yBAAyB,MAAM;AAC5C,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAC5B,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAC5B,eAAO,KAAK,GAAG,EAAE,QAAQ,GAAG;AAAA,MAC9B,CAAC;AAED,WAAK,qDAAqD,MAAM;AAC9D,cAAM,OAAO,8BAA8B,EAAE,KAAK,KAAK,IAAI,CAAC;AAC5D,eAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;AACtB,eAAO,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;AAC3B,eAAO,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC;AAEvB,eAAO,KAAK,EAAE,IAAI,EAAI,EAAE,KAAK,EAAE;AAC/B,eAAQ,KAAK,EAAE,KAAK,IAAK,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC;AAAA,MAC3C,CAAC;AAED,WAAK,8DAA8D,MAAM;AACvE,eAAO,8BAA8B,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,MAC1D,CAAC;AAED,WAAK,wDAAwD,MAAM;AACjE,cAAM,OAAO,4BAA4B,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC;AAC/D,eAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,eAAO,KAAM,CAAC,CAAC,EAAE,KAAK,CAAC;AAAA,MACzB,CAAC;AAED,WAAK,oDAAoD,MAAM;AAC7D,cAAM,WAAW,YAAY,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC;AACnD,cAAM,OAAO,kBAAkB,QAAQ;AACvC,eAAO,KAAK,MAAM,EAAE,KAAK,CAAC;AAC1B,eAAO,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG;AAAA,MAC7B,CAAC;AAED,WAAK,6DAA6D,MAAM;AACtE,cAAM,UAAU,GAAG,GAAG;AACtB,eAAO,YAAY,OAAO,CAAC,EAAE,KAAK,OAAO;AAAA,MAC3C,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;;;ACz+CO,SAAS,mBACd,OACA,gBACA,iBACe;AACf,MAAI,CAAC,OAAO,cAAc,cAAc,KAAK,kBAAkB,KAC3D,CAAC,OAAO,cAAc,eAAe,KAAK,mBAAmB,EAAG,QAAO;AAE3E,QAAM,WAAW,QAAQ;AACzB,QAAM,aAAa,WAAW,CAAC,QAAQ,SAAS,OAAO,eAAe;AACtE,QAAM,cAAc,OAAO,cAAc;AACzC,QAAM,QAAQ,YAAY;AAC1B,QAAM,YAAY,YAAY;AAC9B,MAAI,QAAQ,OAAO,OAAO,gBAAgB,EAAG,QAAO;AACpD,QAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,SAAS,IAAI;AAClD,SAAO,OAAO,SAAS,KAAK,IAAK,WAAW,CAAC,QAAQ,QAAS;AAChE;AAIO,SAAS,oBACd,QACA,iBACgD;AAChD,MAAI,CAAC,OAAO,cAAc,OAAO,aAAa,KAAK,OAAO,iBAAiB,EAAG,QAAO;AACrF,QAAM,YAAY;AAAA,IAChB,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,EACF;AACA,QAAM,WAAW;AAAA,IACf,OAAO,OAAO,aAAa;AAAA,IAC3B,OAAO;AAAA,IACP;AAAA,EACF;AACA,MAAI,cAAc,QAAQ,aAAa,QAAQ,YAAY,EAAG,QAAO;AACrE,SAAO,EAAE,WAAW,SAAS;AAC/B;;;AC/BA,IAAMC,aAAY;AAClB,IAAMC,aAAY;AAhClB;AAqJO,IAAM,qBAAN,MAAyB;AAAA,EAyd9B,YAAY,QAA8B;AAzdrC;AACL;AACA,gCAAU,oBAAI,IAAqC;AACnD,sCAAgB,oBAAI,IAAY;AAChC,0CAAoB,oBAAI,IAAwB;AAChD,kCAAY;AACZ,gCAAU;AACV;AACA,iDAA8C;AAC9C;AACA,uCAAiB;AACjB,sCAAgB;AAChB,6CAAuB;AACvB,qCAAsC,EAAE,MAAM,UAAU;AACxD,6CAAuB;AACvB,4CAAuC,CAAC;AACxC,4CAAsB;AACtB,0CAA0C;AAAA,MACxC,cAAc;AAAA,MACd,kBAAkB;AAAA,MAClB,qBAAqB;AAAA,MACrB,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,IAClB;AACA,+CAAyB;AACzB,iDAA2B;AAG3B;AAAA,qBAAoD;AAEpD;AAAA,oBAAuD;AAEvD;AAAA,yBAAqD;AAYrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAAc;AAMd;AAAA;AAAA;AAAA;AAAA,wCAAkB;AA+WlB;AAAA;AAAA;AAAA;AAAA;AAAA,mCAAa;AACb,mCAAa;AACb,qCAAe;AACf,uCAAiB;AACjB,uCAAiB;AACjB,6CAAuB;AACvB,4CAAsB;AACtB,wCAAkB;AAClB,wCAAyD;AAiDvD,uBAAK,SAAU;AAAA,MACb,GAAG,OAAO;AAAA,MACV,WAAW,OAAO,aAAa;AAAA,MAC/B,SAAS,OAAO,WAAW;AAAA,MAC3B,WAAW,OAAO;AAAA,IACpB;AAGA,QAAI,OAAO,OAAO,OAAO,MAAM,GAAG;AAChC,yBAAK,gBAAiB,KAAK,MAAM,mBAAK,SAAQ,YAAY,OAAO,GAAG;AAAA,IACtE,WAAW,OAAO,cAAc,WAAW,OAAO,YAAY;AAC5D,yBAAK,gBAAiB,KAAK,MAAM,mBAAK,SAAQ,YAAY,OAAO,OAAO,UAAU;AAAA,IACpF,OAAO;AAEL,yBAAK,gBAAiB;AAAA,IACxB;AAGA,QAAI,OAAO,cAAc,WAAW,OAAO,QAAQ,OAAO,SAAS,OAAO,QAAQ;AAChF,yBAAK,YAAa,qBAAqB,OAAO,MAAM,OAAO,OAAO,OAAO,MAAM;AAAA,IACjF,OAAO;AACL,yBAAK,YAAa,IAAI,WAAW,CAAC;AAAA,IACpC;AAEA,UAAM,sBAAsB,OAAO,uBAAuB;AAC1D,QAAI,CAAC,OAAO,SAAS,mBAAmB,KAAK,sBAAsB,GAAG;AACpE,YAAM,IAAI,MAAM,0EAA0E;AAAA,IAC5F;AACA,QAAI,OAAO,eAAe,sBAAsB,GAAG;AACjD,YAAM,IAAI,MAAM,6EAA6E;AAAA,IAC/F;AACA,uBAAK,sBAAuB,KAAK,MAAM,mBAAmB;AAC1D,uBAAK,cAAe,OAAO,eAAe,EAAE,MAAM,UAAU;AAC5D,QAAI,mBAAK,cAAa,SAAS,gBAAgB;AAC7C,YAAM,EAAE,gBAAgB,oBAAoB,IAAI,mBAAK;AACrD,UAAI,CAAC,OAAO,cAAc,cAAc,KAAK,kBAAkB,GAAG;AAChE,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,UACE,wBAAwB,WACvB,CAAC,OAAO,cAAc,mBAAmB,KAAK,uBAAuB,iBAAiB,IACvF;AACA,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,mBAAmB,OAAO,cAAc,WAAW,OAAO,aAC5D,OAAO,aAAa,OACpB,OAAO;AACX,UAAI,CAAC,oBAAoB,CAAC,OAAO,SAAS,gBAAgB,KAAK,oBAAoB,GAAG;AACpF,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,yBAAK,sBACH,KAAK,KAAK,iBAAiB,mBAAmB,mBAAK,SAAQ,SAAS,IAAI;AAAA,IAC5E;AACA,uBAAK,wBACH,OAAO,cAAc,YACpB,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,SAAS,YAAY,OAAO,KAAK;AAC7D,QAAI,OAAO,cAAc,SAAS;AAChC,cAAQ;AAAA,QACN,2BAA2B,mBAAK,uBAAsB,UAC7C,OAAO,SAAS,EAAE,SAAS,OAAO,MAAM,UAAU,CAAC;AAAA,MAC9D;AAAA,IACF;AAGA,SAAK,eAAe,OAAO,cAAc,WAAW,OAAO,OACvD,EAAE,MAAM,OAAO,MAAM,OAAO,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,EAAE,IAC1E;AACJ,SAAK,eAAe,OAAO,cAAc,WAAW,OAAO,cAAc,OAAO,WAC5E,EAAE,YAAY,OAAO,YAAY,UAAU,OAAO,UAAU,KAAK,OAAO,IAAI,IAC5E;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EA/bA,kBAAwB;AACtB,QAAI,mBAAK,SAAQ,cAAc,QAAS,oBAAK,aAAc;AAAA,EAC7D;AAAA,EAkcA,IAAI,mBAAmD;AACrD,WAAO,EAAE,GAAG,mBAAK,mBAAkB;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,SACE,KACA,KACA,MACA,WACA,UACA,kBACA,mBACA,sBACA,uBACA,+BACA,gBACA,oBACM;AACN,SAAK;AAAK,SAAK;AACf,2BAAK,gBAAL;AACA,0BAAK,uDAAL;AAEA,QAAI,CAAC,sBAAK,iDAAL,WAAuB,uBAAK,sDAAL,WAAyB;AAKrD,0BAAK,8CAAL,WACE,MACA,WACA,mBAAK,iBACL,UACA,MACA,kBACA,mBACA,sBACA,uBACA,+BACA,gBACA;AAIF,0BAAK,4CAAL,WAAe,mBAAmB,CAAC,EAAE,MAAM,WAAW,SAAS,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA,EAIA,cAAc,KAAmB;AAC/B,SAAK;AACL,2BAAK,qBAAL;AACA,0BAAK,uDAAL;AAAA,EAIF;AAAA;AAAA,EAGA,UAAU,KAAmB;AAC3B,2BAAK,iBAAL;AACA,0BAAK,uDAAL;AACA,uBAAK,eAAc,OAAO,GAAG;AAC7B,UAAM,QAAQ,mBAAK,SAAQ,IAAI,GAAG;AAClC,QAAI,CAAC,SAAS,MAAM,SAAS,GAAG;AAC9B,yBAAK,SAAQ,OAAO,GAAG;AACvB;AAAA,IACF;AACA,0BAAK,sDAAL,WAAyB;AAAA,EAC3B;AAAA;AAAA,EAGA,kBAAkB,KAAa,QAA4B;AACzD,SAAK;AACL,2BAAK,sBAAL;AACA,0BAAK,uDAAL;AAEA,uBAAK,eAAc,OAAO,GAAG;AAC7B,uBAAK,SAAQ,OAAO,GAAG;AAEvB,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,aAAa,sBAAK,2DAAL,WAA8B;AACjD,0BAAK,4CAAL,WAAe,qBAAqB,YAAY;AAChD,QAAI,sBAAK,iDAAL,YAAuB;AACzB,4BAAK,iDAAL,WAAoB,YAAY,QAAW;AAC3C;AAAA,IACF;AAKA,QAAI,mBAAK,kBAAiB,GAAG;AAC3B,4BAAK,oDAAL,WAAuB;AACvB,4BAAK,sDAAL,WAAyB,mBAAK;AAAA,IAChC,OAAO;AACL,YAAM,QAAQ,sBAAK,0DAAL,WAA6B;AAC3C,UAAI,MAAO,uBAAK,iDAAL,WAAoB,OAAO,QAAW;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAGA,eACE,MACA,WACA,UACA,kBACA,mBACA,sBACA,uBACA,+BACA,gBACA,oBACM;AACN,QAAI,CAAC,sBAAK,iDAAL,WAAuB,uBAAK,sDAAL,WAAyB;AACrD,0BAAK,8CAAL,WACE,MACA,WACA,mBAAK,iBACL,UACA,MACA,kBACA,mBACA,sBACA,uBACA,+BACA,gBACA;AAAA,EAEJ;AAAA;AAAA,EAGA,WAAiB;AACf,QAAI,OAA0B;AAC9B,QAAI,KAAK,cAAc,MAAM;AAC3B,aAAO;AAAA,QACL,KAAK,aAAa;AAAA,QAClB,KAAK,aAAa;AAAA,QAClB,KAAK,aAAa;AAAA,QAClB,mBAAK,SAAQ;AAAA,QACb,mBAAK,SAAQ;AAAA,MACf;AAAA,IACF,WAAW,KAAK,cAAc;AAC5B,aAAO;AAAA,QACL,KAAK,aAAa;AAAA,QAClB,KAAK,aAAa;AAAA,QAClB,KAAK,aAAa;AAAA,QAClB,mBAAK,SAAQ;AAAA,QACb,mBAAK,SAAQ;AAAA,MACf;AAAA,IACF;AACA,QAAI,KAAM,MAAK,gBAAgB,IAAI;AAAA,EACrC;AAAA;AAAA,EAGA,QAAc;AACZ,QAAI,sBAAK,iDAAL,YAAuB;AACzB,4BAAK,sDAAL,WAAyB;AACzB;AAAA,IACF;AACA,QAAI,mBAAK,mBAAkB,SAAS,EAAG;AACvC,UAAM,SAAS,CAAC,GAAG,mBAAK,mBAAkB,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAC5F,uBAAK,mBAAkB,MAAM;AAC7B,UAAM,QAAQ,sBAAK,0DAAL,WAA6B;AAC3C,QAAI,MAAO,uBAAK,iDAAL,WAAoB,OAAO,QAAW;AAAA,aACxC,mBAAK,SAAQ,cAAc,SAAS;AAC3C,yBAAK,mBAAkB,mBAAmB,OAAO;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAGA,QAAc;AACZ,uBAAK,SAAQ,MAAM;AACnB,uBAAK,eAAc,MAAM;AACzB,uBAAK,mBAAkB,MAAM;AAC7B,uBAAK,WAAY;AACjB,uBAAK,SAAU;AACf,uBAAK,gBAAiB;AACtB,uBAAK,eAAgB;AACrB,uBAAK,qBAAsB;AAC3B,uBAAK,0BAA2B;AAChC,uBAAK,aAAc;AACnB,uBAAK,iBAAkB;AACvB,uBAAK,qBAAsB,CAAC;AAAA,EAC9B;AAAA,EAEA,UAAgB;AACd,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,SAAK,WAAW;AAChB,SAAK,gBAAgB;AACrB,QAAI,mBAAK,kBAAiB;AACxB,oBAAc,mBAAK,gBAAe;AAClC,yBAAK,iBAAkB;AAAA,IACzB;AAAA,EACF;AAqIF;AAh4BE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AAmBA;AAMA;AAlDK;AAAA;AAAA;AAAA;AAuDL,sBAAiB,SAAC,KAAsB;AACtC,MAAI,OAAO,mBAAK,iBAAiB,QAAO;AACxC,qBAAK,iBAAkB;AACvB,SAAO;AACT;AAAA;AAAA;AAAA;AAKA,4BAA0E,SAAC,QAAyB;AAClG,QAAM,cAAc,sBAAK,2DAAL,WAA8B;AAClD,MAAI,mBAAK,SAAQ,cAAc,WAAW,mBAAK,aAAa,QAAO;AACnE,QAAM,aAAa,YAAY,UAAU,OAAK,EAAE,QAAQ;AACxD,MAAI,aAAa,EAAG,QAAO;AAC3B,SAAO,eAAe,IAAI,cAAc,YAAY,MAAM,UAAU;AACtE;AAEA,6BAA2E,SAAC,QAAkB;AAC5F,MAAI,mBAAK,SAAQ,cAAc,WAAW,CAAC,mBAAK,wBAAwB,QAAO;AAC/E,SAAO,OAAO,IAAI,CAAC,UAAU,sBAAK,8DAAL,WAAiC,MAAM;AACtE;AAEA,gCAA8E,SAAC,OAAa;AAC1F,MAAI,mBAAK,SAAQ,cAAc,WAAW,CAAC,mBAAK,wBAAwB,QAAO;AAC/E,QAAM,WAAW,mBAAmB,MAAM,IAAI;AAC9C,MAAI,CAAC,SAAU,uBAAK,6DAAL,WAAgC,MAAM,MAAM,MAAM;AACjE,SAAO,aAAa,MAAM,WAAW,QAAQ,EAAE,GAAG,OAAO,SAAS;AACpE;AAEA,+BAA0B,SAAC,MAAkB,kBAAiC;AAC5E,MAAI,mBAAK,6BAA4B,GAAI;AACzC,yBAAK,0BAAL;AACA,QAAM,SAAS,wBAAwB,IAAI;AAC3C,QAAM,WAAW,qBAAqB,OAAO,IAAI;AACjD,QAAM,WAAW,qBAAqB,IAAI;AAC1C,QAAM,MAAM,MAAM,KAAK,KAAK,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,EAC/D,IAAI,OAAM,EAAa,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACpD,KAAK,GAAG;AACX,UAAQ;AAAA,IACN,uBAAuB,mBAAK,yBAAwB,QAAQ,KAAK,MAAM,eACzD,gBAAgB,aAAa,QAAQ,WAAW,OAAO,MAAM,cAC9D,SAAS,KAAK,GAAG,CAAC,cAAc,GAAG;AAAA,EAClD;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,mBAAc,WAAY;AACxB,SAAO,mBAAK,cAAa,SAAS,kBAAkB,mBAAK,wBAAuB;AAClF;AAEA,qBAAgB,SAAC,WAA2B;AAC1C,QAAM,aAAa,mBAAK,cAAa,SAAS,iBAC1C,mBAAK,cAAa,sBAClB;AACJ,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,YAAY,mBAAK,kBAAiB,IACpC,mBAAK,iBACL,mBAAK,wBAAuB,IAC1B,mBAAK,uBACL,mBAAK;AACX,MAAI,YAAY,EAAG,QAAO;AAC1B,SAAO,YAAY,KAAK,OAAO,YAAY,aAAa,UAAU,IAAI;AACxE;AAEA,gBAAW,SACT,MACA,WACA,UACA,UACA,iBACA,kBACA,mBACA,sBACA,uBACA,+BACA,gBAKA,oBACM;AACN,QAAM,eAAe,mBAAmB,SACpC,OACA,oBAAoB,gBAAgB,mBAAK,SAAQ,SAAS;AAC9D,MAAI,mBAAmB,UAAa,iBAAiB,KAAM;AAC3D,QAAM,oBAAoB,cAAc,aAAa;AACrD,QAAM,mBAAmB,cAAc,YAAY;AACnD,MAAI;AACJ,MAAI,mBAAmB,QAAW;AAChC,UAAM,eAAe;AAAA,MACnB,eAAe,mBAAmB,eAAe;AAAA,MACjD,eAAe;AAAA,MACf,mBAAK,SAAQ;AAAA,IACf;AACA,QAAI,iBAAiB,KAAM;AAI3B,UAAM,gBAAgB,KAAK,MAAM,YAAY;AAC7C,QACE,CAAC,OAAO,cAAc,aAAa,KACnC,gBAAgBD,cAChB,gBAAgBC,WAChB;AACF,4BAAwB;AAAA,EAC1B;AACA,QAAM,qBAAqB,sBAAK,mDAAL,WAAsB;AACjD,MAAI,sBAAsB,mBAAK,iBAAgB;AAC7C,uBAAK,mBAAkB;AACvB;AAAA,EACF;AAEA,QAAM,SAAS,sBAAK,8DAAL,WAAiC;AAAA,IAC9C;AAAA,IACA,WAAW;AAAA,IACX,UAAU;AAAA,IACV;AAAA,IACA,GAAI,0BAA0B,SAAY,CAAC,IAAI,EAAE,sBAAsB;AAAA,IACvE;AAAA,IACA,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;AAAA,IACzD,GAAI,yBAAyB,SAAY,CAAC,IAAI,EAAE,qBAAqB;AAAA,IACrE,GAAI,0BAA0B,SAAY,CAAC,IAAI,EAAE,sBAAsB;AAAA,IACvE,GAAI,kCAAkC,SAClC,CAAC,IACD,EAAE,8BAA8B;AAAA,IACpC,GAAI,sBAAsB,SAAY,CAAC,IAAI,EAAE,kBAAkB;AAAA,IAC/D,GAAI,qBAAqB,SAAY,CAAC,IAAI,EAAE,iBAAiB;AAAA,IAC7D,GAAI,uBAAuB,SAAY,CAAC,IAAI,EAAE,mBAAmB;AAAA,EACnE;AACA,MAAI,mBAAmB,qBAAqB,mBAAK,gBAAe;AAC9D,uBAAK,eAAgB;AAAA,EACvB,WAAW,CAAC,mBAAmB,qBAAqB,mBAAK,sBAAqB;AAC5E,uBAAK,qBAAsB;AAAA,EAC7B;AAEA,MAAI,sBAAK,iDAAL,YAAuB;AACzB,0BAAK,+CAAL,WAAkB;AAClB;AAAA,EACF;AACA,wBAAK,sDAAL,WAAyB;AAC3B;AAEA,wBAAmB,SAAC,QAA6B;AAC/C,MAAI,mBAAK,SAAQ,cAAc,WAAW,CAAC,mBAAK,gBAAe,CAAC,OAAO,UAAU;AAC/E,uBAAK,mBAAkB;AACvB;AAAA,EACF;AACA,wBAAK,iDAAL,WAAoB;AACtB;AAEA,iBAAY,SAAC,QAA6B;AACxC,MAAI,mBAAK,qBAAoB,KAAK,OAAK,EAAE,cAAc,OAAO,SAAS,GAAG;AACxE,uBAAK,mBAAkB;AACvB;AAAA,EACF;AACA,qBAAK,qBAAoB,KAAK,MAAM;AACpC,qBAAK,qBAAoB,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AACjE,wBAAK,sDAAL,WAAyB;AACzB,wBAAK,8DAAL;AACF;AAEA,oBAAe,WAAW;AACxB,SAAO,mBAAK,kBAAiB,IAAI,mBAAK,iBAAgB,mBAAK;AAC7D;AAEA,wBAAmB,SAAC,QAAuB,UAA4B;AACrE,MAAI,SAAU,QAAO;AACrB,MAAI,mBAAK,cAAa,SAAS,gBAAgB;AAC7C,UAAM,UAAU,sBAAK,kDAAL;AAChB,WAAO,WAAW,KAAK,OAAO,YAAY,UAAU,mBAAK,cAAa;AAAA,EACxE;AACA,SAAO,mBAAK,qBAAoB,SAAS,mBAAK;AAChD;AAEA,uBAAkB,SAAC,UAA4B;AAC7C,MAAI,mBAAK,SAAQ,cAAc,WAAW,mBAAK,aAAa,QAAO;AAEnE,QAAM,WAAW,mBAAK,qBAAoB;AAAA,IACxC,YAAU,OAAO,YAAY,sBAAK,sDAAL,WAAyB,QAAQ;AAAA,EAChE;AACA,MAAI,YAAY,GAAG;AACjB,QAAI,WAAW,GAAG;AAChB,yBAAK,mBAAkB,uBAAuB;AAC9C,yBAAK,qBAAoB,OAAO,GAAG,QAAQ;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAEA,MAAI,UAAU;AACd,SACE,mBAAK,qBAAoB,CAAC,KAC1B,sBAAK,sDAAL,WAAyB,mBAAK,qBAAoB,CAAC,GAAI,WACvD;AACA,uBAAK,qBAAoB,MAAM;AAC/B;AAAA,EACF;AACA,MAAI,SAAU,oBAAK,mBAAkB,mBAAmB;AAAA,MACnD,oBAAK,mBAAkB,uBAAuB;AACnD,SAAO,UAAU;AACnB;AAEA,wBAAmB,SAAC,UAAyB;AAC3C,SAAO,mBAAK,qBAAoB,SAAS,GAAG;AAC1C,QAAI,sBAAK,qDAAL,WAAwB,aAAa,mBAAK,qBAAoB,WAAW,EAAG;AAChF,UAAM,SAAS,mBAAK,qBAAoB,CAAC;AACzC,QAAI,CAAC,UAAU,CAAC,sBAAK,sDAAL,WAAyB,QAAQ,UAAW;AAC5D,uBAAK,qBAAoB,MAAM;AAC/B,0BAAK,oDAAL,WAAuB;AAAA,EACzB;AACF;AAEA,sBAAiB,SAAC,QAA6B;AAC7C,QAAM,OAAO,mBAAK,qBAAoB,KAAK,OAAK,EAAE,YAAY,OAAO,SAAS;AAC9E,QAAM,WAAW,OAAO,iBACpB,OAAO,WACP,OAAO,KAAK,YAAY,OAAO,YAAY,OAAO;AACtD,wBAAK,iDAAL,WAAoB;AAAA,IAClB,GAAG;AAAA,IACH,UAAU,WAAW,IACjB,WACA,OAAO,iBAAiB,OAAO,WAAW,mBAAK;AAAA,EACrD;AACF;AAEA,gCAA2B,WAAS;AAClC,MAAI,mBAAK,cAAa,SAAS,eAAgB;AAC/C,SAAO,mBAAK,qBAAoB,SAAS,mBAAK,uBAAsB;AAClE,UAAM,SAAS,mBAAK,qBAAoB,MAAM;AAC9C,QAAI,CAAC,OAAQ;AACb,uBAAK,mBAAkB;AACvB,YAAQ;AAAA,MACN,wBAAwB,mBAAK,SAAQ,SAAS,gCAC3C,mBAAK,qBAAoB,uCAAuC,OAAO,SAAS;AAAA,IACrF;AACA,QAAI,mBAAK,SAAQ,cAAc,WAAW,CAAC,mBAAK,gBAAe,CAAC,OAAO,UAAU;AAC/E,yBAAK,mBAAkB;AACvB;AAAA,IACF;AACA,0BAAK,oDAAL,WAAuB;AAAA,EACzB;AACF;AAEA,mBAAc,SAAC,QAA+B;AAC5C,MAAI,OAAO,aAAa,mBAAK,iBAAgB;AAC3C,uBAAK,mBAAkB;AACvB;AAAA,EACF;AACA,wBAAK,6DAAL,WAAgC,OAAO;AACvC,wBAAK,kDAAL,WAAqB,QAAQ;AAC/B;AAEA,oBAAe,SAAC,QAAyB,eAA8B;AACrE,QAAM,EAAE,WAAW,UAAU,SAAS,IAAI;AAC1C,qBAAK,gBAAiB;AACtB,MAAI,mBAAK,SAAQ,cAAc,WAAW,SAAU,oBAAK,aAAc;AACvE,QAAM,OAAO,sBAAK,uDAAL,WAA0B,OAAO;AAC9C,MAAI,mBAAK,SAAQ,cAAc,WAAW,iBAAiB,KAAK,SAAS,GAAG;AAG1E,uBAAK,0BAA2B,KAAK,MAAM;AAAA,EAC7C;AACA,MAAI,KAAK,UAAU;AACjB,SAAK,SAAS,SAAS,OAAO,OAAO,SAAS,EAAE,GAAG,QAAQ,KAAK,CAAC;AAAA,EACnE,OAAO;AACL,UAAM,WAAW,sBAAK,0CAAL,WAAa;AAC9B,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAK,WAAL;AAAA,MACA,mBAAK,SAAQ;AAAA,MACb,OAAO;AAAA,IACT;AACA,SAAK,YAAY,OAAO;AAAA,EAC1B;AACF;AAEA,+BAA0B,SAAC,WAAyB;AAClD,MACE,mBAAK,SAAQ,cAAc,WAC3B,mBAAK,kBAAiB,KACtB,mBAAK,8BAA6B,KAClC;AAEF,QAAM,MAAM,YAAY,mBAAK;AAC7B,MAAI,OAAO,mBAAK,kBAAiB,IAAK;AAEtC,QAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,mBAAK,eAAc,IAAI,CAAC;AAC3E,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,UAAM,SAAS,mBAAK,kBAAiB,mBAAK;AAC1C,0BAAK,kDAAL,WAAqB;AAAA,MACnB,MAAM,mBAAK,0BAAyB,MAAM;AAAA,MAC1C,WAAW;AAAA,MACX,UAAU,mBAAK;AAAA,MACf,UAAU;AAAA,IACZ,GAAG;AAAA,EACL;AACF;AAEA,mBAAc,SACZ,QACA,uBACA,kBAAkB,OACZ;AACN,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,IAAI,OAAO,CAAC;AAElB,QAAI;AACJ,QAAI,mBAAK,SAAQ,cAAc,SAAS;AACtC,iBAAW,yBAAyB,mBAAK;AAAA,IAC3C,WAAW,IAAI,OAAO,SAAS,GAAG;AAChC,iBAAW,OAAO,IAAI,CAAC,EAAG,YAAY,EAAE;AAAA,IAC1C,WAAW,IAAI,GAAG;AAChB,iBAAW,EAAE,YAAY,OAAO,IAAI,CAAC,EAAG;AAAA,IAC1C,OAAO;AACL,iBAAW,yBAAyB,mBAAK;AAAA,IAC3C;AACA,QAAI,YAAY,EAAG,YAAW,yBAAyB,mBAAK;AAC5D,0BAAK,8CAAL,WACE,EAAE,MACF,EAAE,WACF,UACA,EAAE,UACF,iBACA,EAAE,kBACF,EAAE,mBACF,EAAE,sBACF,EAAE,uBACF,EAAE,+BACF,EAAE,gBACF,EAAE;AAAA,EAEN;AACF;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAoB,WAAS;AAC3B,MAAI,mBAAK,iBAAiB;AAC1B,qBAAK,iBAAkB,YAAY,MAAM;AACvC,YAAQ;AAAA,MACN,WAAW,mBAAK,SAAQ,SAAS,WAAW,mBAAK,WAAU,YAAY,mBAAK,aAAY,OAClF,mBAAK,eAAc,aAAa,mBAAK,eAAc,cAC5C,mBAAK,qBAAoB,aAAa,mBAAK,oBAAmB,SACnE,mBAAK,gBAAe,kBAAkB,mBAAK,SAAQ,IAAI,mBAC7C,mBAAK,eAAc,IAAI,eAAe,mBAAK,YAAW;AAAA,IAC1E;AACA,uBAAK,YAAa;AAClB,uBAAK,cAAe;AACpB,uBAAK,gBAAiB;AACtB,uBAAK,gBAAiB;AACtB,uBAAK,sBAAuB;AAC5B,uBAAK,qBAAsB;AAC3B,uBAAK,iBAAkB;AAAA,EACzB,GAAG,GAAI;AACT;AACA,cAAS,SAAC,MAAc,SAA6E,KAAoB;AACvH,yBAAK,YAAL;AACA,qBAAK,cAAL,mBAAK,gBAAgB,QAAQ;AAC7B,qBAAK,gBAAL,mBAAK,kBAAkB,QAAQ,OAAO,OAAK,EAAE,QAAQ,EAAE;AAGvD,QAAM,QAAQ,mBAAK,SAAQ,cAAc,WAAW,QAAQ,KAAK,OAAK,EAAE,QAAQ;AAChF,MAAI,mBAAK,SAAQ,cAAc,WAAY,mBAAK,eAAc,KAAK,CAAC,MAAQ;AAC5E,yBAAK,YAAL;AACA,QAAM,KAAK,QAAQ,CAAC;AACpB,MAAI,CAAC,GAAI;AACT,QAAM,IAAI,GAAG;AACb,QAAM,MAAM,MAAM,KAAK,EAAE,SAAS,GAAG,KAAK,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC,EACzD,IAAI,OAAM,EAAa,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACpD,KAAK,GAAG;AAEX,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,IAAK,KAAK,IAAI,KAAM,EAAE,CAAC,IAAgB;AACrE,QAAM,QAAQ,MAAM,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACnD,QAAM,MAAM,GAAG,aAAa;AAC5B,QAAM,MAAM,QAAQ,QAAQ,SAAS,CAAC,GAAG,aAAa;AACtD,UAAQ;AAAA,IACN,kBAAkB,mBAAK,WAAU,SAAS,IAAI,GAAG,QAAQ,SAAY,QAAQ,GAAG,KAAK,EAAE,YAC5E,QAAQ,MAAM,UAAU,GAAG,QAAQ,WAAW,EAAE,MAAM,QAC1D,GAAG,QAAQ,GAAG,QAAQ,MAAM,GAAG,SAAS,IAAI,aAAa,GAAG;AAAA,EACrE;AACF;AAAA;AAAA;AA0SA,YAAO,SAAC,WAA2B;AACjC,MAAI,mBAAK,WAAU,EAAG,oBAAK,SAAU;AACrC,SAAO,YAAY,mBAAK;AAC1B;AAEA,yBAAoB,SAAC,MAA8B;AACjD,SAAO,mBAAK,SAAQ,cAAc,UAAU,0BAA0B,IAAI,IAAI;AAChF;AAEA,sBAAiB,SAAC,QAA4B;AAC5C,aAAW,SAAS,QAAQ;AAC1B,QAAI,mBAAK,mBAAkB,KAAK,MAAM,aAAa,mBAAK,iBAAgB;AACtE,yBAAK,mBAAkB;AACvB;AAAA,IACF;AACA,QAAI,mBAAK,mBAAkB,IAAI,MAAM,SAAS,GAAG;AAC/C,yBAAK,mBAAkB;AACvB;AAAA,IACF;AACA,uBAAK,mBAAkB,IAAI,MAAM,WAAW,KAAK;AAAA,EACnD;AACF;AAEA,wBAAmB,SAAC,WAAyB;AAC3C,MAAI,mBAAK,mBAAkB,SAAS,EAAG;AACvC,QAAM,QAAQ,CAAC,GAAG,mBAAK,mBAAkB,OAAO,CAAC,EAC9C,OAAO,WAAS,MAAM,aAAa,SAAS,EAC5C,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAE3C,aAAW,SAAS,OAAO;AACzB,uBAAK,mBAAkB,OAAO,MAAM,SAAS;AAC7C,0BAAK,8CAAL,WACE,MAAM,MACN,MAAM,WACN,mBAAK,iBACL,MAAM,UACN,OACA,MAAM,kBACN,MAAM,mBACN,MAAM,sBACN,MAAM,uBACN,MAAM,+BACN,MAAM,gBACN,MAAM;AAER,0BAAK,4CAAL,WAAe,mBAAmB,CAAC,KAAK;AAAA,EAC1C;AACF;AAAA;AAGA,gBAAW,SAAC,KAAmB;AAC7B,QAAM,QAAQ,mBAAK,SAAQ,IAAI,GAAG;AAClC,MAAI,CAAC,SAAS,MAAM,SAAS,GAAG;AAC9B,uBAAK,SAAQ,OAAO,GAAG;AACvB;AAAA,EACF;AAGA,QAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/D,QAAM,eAAe,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;AAC7C,qBAAK,SAAQ,OAAO,GAAG;AAEvB,MAAI,CAAC,sBAAK,oDAAL,WAAuB,KAAM;AAClC,QAAM,SAAS,sBAAK,0DAAL,WAA6B;AAC5C,MAAI,CAAC,OAAQ;AAEb,wBAAK,4CAAL,WAAe,cAAc,QAAQ;AACrC,wBAAK,iDAAL,WAAoB;AACtB;AAAA;AAGA,wBAAmB,SAAC,KAAmB;AACrC,QAAM,QAAQ,mBAAK,SAAQ,IAAI,GAAG;AAClC,MAAI,CAAC,MAAO;AAEZ,QAAM,IAAI,mBAAK,SAAQ;AACvB,QAAM,UAAU,mBAAK,SAAQ,cAAc;AAC3C,QAAM,kBAAkB,CAAC,UACrB,CAAC,GAAG,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,GAAG,OAClE;AACJ,QAAM,wBAAwB,mBAAK,6BAA4B;AAG/D,QAAM,YAA0B,CAAC;AACjC,MAAI,aAAa;AACjB,MAAI,cAAc;AAGlB,aAAW,CAAC,EAAE,CAAC,KAAK,OAAO;AACzB,QAAI,cAAc,KAAK,EAAE,YAAY,YAAa,eAAc,EAAE;AAClE,QAAI,EAAE,YAAY,WAAY,cAAa,EAAE;AAAA,EAC/C;AACA,QAAM,yBAAyB,MAAM,OAAO,KACvC,aAAa,gBAAgB,MAAM,OAAO,KAAK,IAChD,mBAAK,kBAAiB;AAE1B,WAAS,MAAM,GAAG,MAAM,GAAG,OAAO;AAChC,UAAM,OAAO,MAAM,IAAI,GAAG;AAC1B,QAAI,MAAM;AACR,gBAAU,KAAK,IAAI;AAAA,IACrB,OAAO;AAEL,YAAM,iBAAiB,eAAe,IAClC,cAAc,KAAK,MAAM,MAAM,yBAAyB,CAAC,IACxD,mBAAK,mBAAkB,IACtB,mBAAK,kBAAiB,mBAAK,mBAAkB,MAAM,KACnD;AACN,gBAAU,KAAK;AAAA;AAAA;AAAA;AAAA,QAIb,MAAM,UACF,mBAAK,cACJ,uBAAuB,MAAM,KAAK,IAAI,WAAW,CAAC;AAAA,QACvD,WAAW;AAAA;AAAA,QAEX,UAAU,UAAU,CAAC,MAAM,IAAI,CAAC,KAAK,QAAQ,IAAI;AAAA,MACnD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,qBAAK,SAAQ,OAAO,GAAG;AACvB,MAAI,CAAC,sBAAK,oDAAL,WAAuB,KAAM;AAClC,QAAM,cAAc,sBAAK,0DAAL,WAA6B;AACjD,MAAI,CAAC,YAAa;AAElB,wBAAK,iDAAL,WAAoB;AACtB;AAGF,SAAS,YAAY,OAAyB;AAC5C,QAAM,IAAI,OAAO,YAAY;AAC7B,SAAO,GAAG,WAAW,MAAM,MAAM,QAAQ,GAAG,WAAW,MAAM,MAAM;AACrE;AAEA,SAAS,qBAAqB,MAA8B;AAC1D,SAAO,KAAK,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,QAC5B,IAAI,CAAC,MAAM,SAAY,IAAI,CAAC,IAAI,KAAO,EACxC;AACH;",
6
+ "names": ["box", "INT32_MIN", "INT32_MAX"]
7
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CMAF batcher for MoQ group boundaries.
3
+ *
4
+ * Collects frames via addFrame() and emits a single multi-sample moof+mdat
5
+ * segment on flush(). Designed to be called once per MoQ group so one
6
+ * appendBuffer() call per group lands in MSE.
7
+ *
8
+ * Unlike CmafBlockAssembler (FEC-SBN keyed, for multicast), this class is
9
+ * caller-driven — no SBN/ESI, no block timeouts. Call flush() when the
10
+ * group's readFrame() loop returns done.
11
+ *
12
+ * Timestamps passed to addFrame() MUST be in the same timescale the caller
13
+ * used to build the init segment (typically microseconds). The batcher does
14
+ * not scale — it rebases per-instance (first sample → 0) and passes
15
+ * inter-frame deltas as sample durations.
16
+ */
17
+ export interface CmafGroupBatcherConfig {
18
+ trackType: 'video' | 'audio';
19
+ /** ISO track ID. Must match the trackId used when building the init segment. */
20
+ trackId: number;
21
+ /**
22
+ * Duration (in the same units as timestamp) for the last sample of a group
23
+ * with exactly one frame (no inter-frame delta to measure). Derive from
24
+ * catalog: video = 1_000_000 / fps; audio = 1_000_000 * 1024 / sampleRate.
25
+ */
26
+ fallbackFrameDuration: number;
27
+ }
28
+ export declare class CmafGroupBatcher {
29
+ #private;
30
+ readonly trackType: 'video' | 'audio';
31
+ onSegment: ((segment: Uint8Array) => void) | null;
32
+ constructor(config: CmafGroupBatcherConfig);
33
+ addFrame(data: Uint8Array, timestamp: number, keyframe: boolean): void;
34
+ flush(): void;
35
+ reset(): void;
36
+ dispose(): void;
37
+ }
38
+ //# sourceMappingURL=cmaf-group-batcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmaf-group-batcher.d.ts","sourceRoot":"","sources":["../src/cmaf-group-batcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAA;IAC5B,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,qBAAqB,EAAE,MAAM,CAAA;CAC9B;AAQD,qBAAa,gBAAgB;;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAA;IASrC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,IAAI,CAAO;gBAE5C,MAAM,EAAE,sBAAsB;IAc1C,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKtE,KAAK,IAAI,IAAI;IAwBb,KAAK,IAAI,IAAI;IAMb,OAAO,IAAI,IAAI;CAKhB"}