@meframe/core 0.0.1

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 (352) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +22 -0
  3. package/README.md +396 -0
  4. package/dist/Meframe.d.ts +82 -0
  5. package/dist/Meframe.d.ts.map +1 -0
  6. package/dist/Meframe.js +290 -0
  7. package/dist/Meframe.js.map +1 -0
  8. package/dist/_virtual/mp4box.all.js +5 -0
  9. package/dist/_virtual/mp4box.all.js.map +1 -0
  10. package/dist/cache/BatchWriter.d.ts +25 -0
  11. package/dist/cache/BatchWriter.d.ts.map +1 -0
  12. package/dist/cache/CacheManager.d.ts +115 -0
  13. package/dist/cache/CacheManager.d.ts.map +1 -0
  14. package/dist/cache/CacheManager.js +388 -0
  15. package/dist/cache/CacheManager.js.map +1 -0
  16. package/dist/cache/CacheStatsDecorator.d.ts +27 -0
  17. package/dist/cache/CacheStatsDecorator.d.ts.map +1 -0
  18. package/dist/cache/L2Cache.d.ts +39 -0
  19. package/dist/cache/L2Cache.d.ts.map +1 -0
  20. package/dist/cache/L2Cache.js +282 -0
  21. package/dist/cache/L2Cache.js.map +1 -0
  22. package/dist/cache/index.d.ts +7 -0
  23. package/dist/cache/index.d.ts.map +1 -0
  24. package/dist/cache/l1/AudioL1Cache.d.ts +30 -0
  25. package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -0
  26. package/dist/cache/l1/AudioL1Cache.js +306 -0
  27. package/dist/cache/l1/AudioL1Cache.js.map +1 -0
  28. package/dist/cache/l1/MixedAudioL1Cache.d.ts +13 -0
  29. package/dist/cache/l1/MixedAudioL1Cache.d.ts.map +1 -0
  30. package/dist/cache/l1/MixedAudioL1Cache.js +52 -0
  31. package/dist/cache/l1/MixedAudioL1Cache.js.map +1 -0
  32. package/dist/cache/l1/VideoL1Cache.d.ts +69 -0
  33. package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -0
  34. package/dist/cache/l1/VideoL1Cache.js +318 -0
  35. package/dist/cache/l1/VideoL1Cache.js.map +1 -0
  36. package/dist/cache/l1/gop-utils.d.ts +10 -0
  37. package/dist/cache/l1/gop-utils.d.ts.map +1 -0
  38. package/dist/cache/l1/gop-utils.js +78 -0
  39. package/dist/cache/l1/gop-utils.js.map +1 -0
  40. package/dist/cache/l1/index.d.ts +4 -0
  41. package/dist/cache/l1/index.d.ts.map +1 -0
  42. package/dist/cache/l1/types.d.ts +17 -0
  43. package/dist/cache/l1/types.d.ts.map +1 -0
  44. package/dist/cache/types.d.ts +93 -0
  45. package/dist/cache/types.d.ts.map +1 -0
  46. package/dist/config/ConfigLoader.d.ts +69 -0
  47. package/dist/config/ConfigLoader.d.ts.map +1 -0
  48. package/dist/config/ConfigLoader.js +133 -0
  49. package/dist/config/ConfigLoader.js.map +1 -0
  50. package/dist/config/defaults.d.ts +125 -0
  51. package/dist/config/defaults.d.ts.map +1 -0
  52. package/dist/config/defaults.js +191 -0
  53. package/dist/config/defaults.js.map +1 -0
  54. package/dist/config/index.d.ts +6 -0
  55. package/dist/config/index.d.ts.map +1 -0
  56. package/dist/config/presets.d.ts +32 -0
  57. package/dist/config/presets.d.ts.map +1 -0
  58. package/dist/config/presets.js +11 -0
  59. package/dist/config/presets.js.map +1 -0
  60. package/dist/config/types.d.ts +199 -0
  61. package/dist/config/types.d.ts.map +1 -0
  62. package/dist/config/validation.d.ts +19 -0
  63. package/dist/config/validation.d.ts.map +1 -0
  64. package/dist/config/validation.js +232 -0
  65. package/dist/config/validation.js.map +1 -0
  66. package/dist/controllers/PlaybackController.d.ts +55 -0
  67. package/dist/controllers/PlaybackController.d.ts.map +1 -0
  68. package/dist/controllers/PlaybackController.js +369 -0
  69. package/dist/controllers/PlaybackController.js.map +1 -0
  70. package/dist/controllers/PreRenderService.d.ts +34 -0
  71. package/dist/controllers/PreRenderService.d.ts.map +1 -0
  72. package/dist/controllers/PreRenderService.js +83 -0
  73. package/dist/controllers/PreRenderService.js.map +1 -0
  74. package/dist/controllers/PreRenderTaskQueue.d.ts +21 -0
  75. package/dist/controllers/PreRenderTaskQueue.d.ts.map +1 -0
  76. package/dist/controllers/PreviewHandle.d.ts +23 -0
  77. package/dist/controllers/PreviewHandle.d.ts.map +1 -0
  78. package/dist/controllers/PreviewHandle.js +39 -0
  79. package/dist/controllers/PreviewHandle.js.map +1 -0
  80. package/dist/controllers/index.d.ts +8 -0
  81. package/dist/controllers/index.d.ts.map +1 -0
  82. package/dist/controllers/types.d.ts +102 -0
  83. package/dist/controllers/types.d.ts.map +1 -0
  84. package/dist/event/EventBus.d.ts +42 -0
  85. package/dist/event/EventBus.d.ts.map +1 -0
  86. package/dist/event/EventBus.js +94 -0
  87. package/dist/event/EventBus.js.map +1 -0
  88. package/dist/event/events.d.ts +371 -0
  89. package/dist/event/events.d.ts.map +1 -0
  90. package/dist/event/events.js +71 -0
  91. package/dist/event/events.js.map +1 -0
  92. package/dist/event/index.d.ts +4 -0
  93. package/dist/event/index.d.ts.map +1 -0
  94. package/dist/index.d.ts +14 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +15 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/model/CompositionModel.d.ts +48 -0
  99. package/dist/model/CompositionModel.d.ts.map +1 -0
  100. package/dist/model/CompositionModel.js +197 -0
  101. package/dist/model/CompositionModel.js.map +1 -0
  102. package/dist/model/RcFrame.d.ts +34 -0
  103. package/dist/model/RcFrame.d.ts.map +1 -0
  104. package/dist/model/RcFrame.js +97 -0
  105. package/dist/model/RcFrame.js.map +1 -0
  106. package/dist/model/dirty-range.d.ts +5 -0
  107. package/dist/model/dirty-range.d.ts.map +1 -0
  108. package/dist/model/dirty-range.js +220 -0
  109. package/dist/model/dirty-range.js.map +1 -0
  110. package/dist/model/index.d.ts +7 -0
  111. package/dist/model/index.d.ts.map +1 -0
  112. package/dist/model/patch.d.ts +5 -0
  113. package/dist/model/patch.d.ts.map +1 -0
  114. package/dist/model/patch.js +250 -0
  115. package/dist/model/patch.js.map +1 -0
  116. package/dist/model/types.d.ts +135 -0
  117. package/dist/model/types.d.ts.map +1 -0
  118. package/dist/model/types.js +5 -0
  119. package/dist/model/types.js.map +1 -0
  120. package/dist/model/validation.d.ts +15 -0
  121. package/dist/model/validation.d.ts.map +1 -0
  122. package/dist/model/validation.js +74 -0
  123. package/dist/model/validation.js.map +1 -0
  124. package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js +7046 -0
  125. package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +1 -0
  126. package/dist/orchestrator/ClipSessionManager.d.ts +75 -0
  127. package/dist/orchestrator/ClipSessionManager.d.ts.map +1 -0
  128. package/dist/orchestrator/ClipSessionManager.js +160 -0
  129. package/dist/orchestrator/ClipSessionManager.js.map +1 -0
  130. package/dist/orchestrator/CompositionPlanner.d.ts +55 -0
  131. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -0
  132. package/dist/orchestrator/CompositionPlanner.js +411 -0
  133. package/dist/orchestrator/CompositionPlanner.js.map +1 -0
  134. package/dist/orchestrator/Orchestrator.d.ts +59 -0
  135. package/dist/orchestrator/Orchestrator.d.ts.map +1 -0
  136. package/dist/orchestrator/Orchestrator.js +390 -0
  137. package/dist/orchestrator/Orchestrator.js.map +1 -0
  138. package/dist/orchestrator/VideoClipSession.d.ts +64 -0
  139. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -0
  140. package/dist/orchestrator/VideoClipSession.js +309 -0
  141. package/dist/orchestrator/VideoClipSession.js.map +1 -0
  142. package/dist/orchestrator/index.d.ts +5 -0
  143. package/dist/orchestrator/index.d.ts.map +1 -0
  144. package/dist/orchestrator/types.d.ts +64 -0
  145. package/dist/orchestrator/types.d.ts.map +1 -0
  146. package/dist/plugins/BackpressureMonitor.d.ts +33 -0
  147. package/dist/plugins/BackpressureMonitor.d.ts.map +1 -0
  148. package/dist/plugins/BackpressureMonitor.js +62 -0
  149. package/dist/plugins/BackpressureMonitor.js.map +1 -0
  150. package/dist/plugins/PluginManager.d.ts +37 -0
  151. package/dist/plugins/PluginManager.d.ts.map +1 -0
  152. package/dist/plugins/PluginManager.js +66 -0
  153. package/dist/plugins/PluginManager.js.map +1 -0
  154. package/dist/plugins/types.d.ts +60 -0
  155. package/dist/plugins/types.d.ts.map +1 -0
  156. package/dist/stages/compose/AudioDucker.d.ts +59 -0
  157. package/dist/stages/compose/AudioDucker.d.ts.map +1 -0
  158. package/dist/stages/compose/AudioDucker.js +161 -0
  159. package/dist/stages/compose/AudioDucker.js.map +1 -0
  160. package/dist/stages/compose/AudioMixer.d.ts +29 -0
  161. package/dist/stages/compose/AudioMixer.d.ts.map +1 -0
  162. package/dist/stages/compose/AudioMixer.js +373 -0
  163. package/dist/stages/compose/AudioMixer.js.map +1 -0
  164. package/dist/stages/compose/FilterProcessor.d.ts +41 -0
  165. package/dist/stages/compose/FilterProcessor.d.ts.map +1 -0
  166. package/dist/stages/compose/FilterProcessor.js +226 -0
  167. package/dist/stages/compose/FilterProcessor.js.map +1 -0
  168. package/dist/stages/compose/GlobalAudioSession.d.ts +38 -0
  169. package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -0
  170. package/dist/stages/compose/GlobalAudioSession.js +122 -0
  171. package/dist/stages/compose/GlobalAudioSession.js.map +1 -0
  172. package/dist/stages/compose/LayerRenderer.d.ts +30 -0
  173. package/dist/stages/compose/LayerRenderer.d.ts.map +1 -0
  174. package/dist/stages/compose/LayerRenderer.js +215 -0
  175. package/dist/stages/compose/LayerRenderer.js.map +1 -0
  176. package/dist/stages/compose/OfflineAudioMixer.d.ts +14 -0
  177. package/dist/stages/compose/OfflineAudioMixer.d.ts.map +1 -0
  178. package/dist/stages/compose/OfflineAudioMixer.js +68 -0
  179. package/dist/stages/compose/OfflineAudioMixer.js.map +1 -0
  180. package/dist/stages/compose/TransitionProcessor.d.ts +30 -0
  181. package/dist/stages/compose/TransitionProcessor.d.ts.map +1 -0
  182. package/dist/stages/compose/TransitionProcessor.js +189 -0
  183. package/dist/stages/compose/TransitionProcessor.js.map +1 -0
  184. package/dist/stages/compose/VideoComposer.d.ts +30 -0
  185. package/dist/stages/compose/VideoComposer.d.ts.map +1 -0
  186. package/dist/stages/compose/VideoComposer.js +186 -0
  187. package/dist/stages/compose/VideoComposer.js.map +1 -0
  188. package/dist/stages/compose/audio-compose.worker.d.ts +79 -0
  189. package/dist/stages/compose/audio-compose.worker.d.ts.map +1 -0
  190. package/dist/stages/compose/audio-compose.worker.js +541 -0
  191. package/dist/stages/compose/audio-compose.worker.js.map +1 -0
  192. package/dist/stages/compose/instructions.d.ts +95 -0
  193. package/dist/stages/compose/instructions.d.ts.map +1 -0
  194. package/dist/stages/compose/types.d.ts +245 -0
  195. package/dist/stages/compose/types.d.ts.map +1 -0
  196. package/dist/stages/compose/video-compose.worker.d.ts +60 -0
  197. package/dist/stages/compose/video-compose.worker.d.ts.map +1 -0
  198. package/dist/stages/compose/video-compose.worker.js +369 -0
  199. package/dist/stages/compose/video-compose.worker.js.map +1 -0
  200. package/dist/stages/decode/AudioChunkDecoder.d.ts +41 -0
  201. package/dist/stages/decode/AudioChunkDecoder.d.ts.map +1 -0
  202. package/dist/stages/decode/AudioChunkDecoder.js +83 -0
  203. package/dist/stages/decode/AudioChunkDecoder.js.map +1 -0
  204. package/dist/stages/decode/BaseDecoder.d.ts +35 -0
  205. package/dist/stages/decode/BaseDecoder.d.ts.map +1 -0
  206. package/dist/stages/decode/BaseDecoder.js +130 -0
  207. package/dist/stages/decode/BaseDecoder.js.map +1 -0
  208. package/dist/stages/decode/VideoChunkDecoder.d.ts +54 -0
  209. package/dist/stages/decode/VideoChunkDecoder.d.ts.map +1 -0
  210. package/dist/stages/decode/VideoChunkDecoder.js +209 -0
  211. package/dist/stages/decode/VideoChunkDecoder.js.map +1 -0
  212. package/dist/stages/decode/decode.worker.d.ts +70 -0
  213. package/dist/stages/decode/decode.worker.d.ts.map +1 -0
  214. package/dist/stages/decode/decode.worker.js +436 -0
  215. package/dist/stages/decode/decode.worker.js.map +1 -0
  216. package/dist/stages/decode/index.d.ts +5 -0
  217. package/dist/stages/decode/index.d.ts.map +1 -0
  218. package/dist/stages/decode/types.d.ts +108 -0
  219. package/dist/stages/decode/types.d.ts.map +1 -0
  220. package/dist/stages/demux/MP3FrameParser.d.ts +33 -0
  221. package/dist/stages/demux/MP3FrameParser.d.ts.map +1 -0
  222. package/dist/stages/demux/MP3FrameParser.js +186 -0
  223. package/dist/stages/demux/MP3FrameParser.js.map +1 -0
  224. package/dist/stages/demux/MP4Demuxer.d.ts +45 -0
  225. package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -0
  226. package/dist/stages/demux/MP4Demuxer.js +227 -0
  227. package/dist/stages/demux/MP4Demuxer.js.map +1 -0
  228. package/dist/stages/demux/aac-esds-extractor.d.ts +7 -0
  229. package/dist/stages/demux/aac-esds-extractor.d.ts.map +1 -0
  230. package/dist/stages/demux/audio-demux.worker.d.ts +51 -0
  231. package/dist/stages/demux/audio-demux.worker.d.ts.map +1 -0
  232. package/dist/stages/demux/audio-demux.worker.js +312 -0
  233. package/dist/stages/demux/audio-demux.worker.js.map +1 -0
  234. package/dist/stages/demux/types.d.ts +77 -0
  235. package/dist/stages/demux/types.d.ts.map +1 -0
  236. package/dist/stages/demux/video-demux.worker.d.ts +48 -0
  237. package/dist/stages/demux/video-demux.worker.d.ts.map +1 -0
  238. package/dist/stages/demux/video-demux.worker.js +173 -0
  239. package/dist/stages/demux/video-demux.worker.js.map +1 -0
  240. package/dist/stages/encode/AudioChunkEncoder.d.ts +21 -0
  241. package/dist/stages/encode/AudioChunkEncoder.d.ts.map +1 -0
  242. package/dist/stages/encode/AudioChunkEncoder.js +37 -0
  243. package/dist/stages/encode/AudioChunkEncoder.js.map +1 -0
  244. package/dist/stages/encode/BaseEncoder.d.ts +44 -0
  245. package/dist/stages/encode/BaseEncoder.d.ts.map +1 -0
  246. package/dist/stages/encode/BaseEncoder.js +164 -0
  247. package/dist/stages/encode/BaseEncoder.js.map +1 -0
  248. package/dist/stages/encode/EncoderPool.d.ts +28 -0
  249. package/dist/stages/encode/EncoderPool.d.ts.map +1 -0
  250. package/dist/stages/encode/VideoChunkEncoder.d.ts +26 -0
  251. package/dist/stages/encode/VideoChunkEncoder.d.ts.map +1 -0
  252. package/dist/stages/encode/VideoChunkEncoder.js +50 -0
  253. package/dist/stages/encode/VideoChunkEncoder.js.map +1 -0
  254. package/dist/stages/encode/encode.worker.d.ts +3 -0
  255. package/dist/stages/encode/encode.worker.d.ts.map +1 -0
  256. package/dist/stages/encode/encode.worker.js +318 -0
  257. package/dist/stages/encode/encode.worker.js.map +1 -0
  258. package/dist/stages/encode/index.d.ts +6 -0
  259. package/dist/stages/encode/index.d.ts.map +1 -0
  260. package/dist/stages/encode/types.d.ts +127 -0
  261. package/dist/stages/encode/types.d.ts.map +1 -0
  262. package/dist/stages/load/EventHandlers.d.ts +35 -0
  263. package/dist/stages/load/EventHandlers.d.ts.map +1 -0
  264. package/dist/stages/load/EventHandlers.js +65 -0
  265. package/dist/stages/load/EventHandlers.js.map +1 -0
  266. package/dist/stages/load/ResourceLoader.d.ts +36 -0
  267. package/dist/stages/load/ResourceLoader.d.ts.map +1 -0
  268. package/dist/stages/load/ResourceLoader.js +184 -0
  269. package/dist/stages/load/ResourceLoader.js.map +1 -0
  270. package/dist/stages/load/StreamFactory.d.ts +42 -0
  271. package/dist/stages/load/StreamFactory.d.ts.map +1 -0
  272. package/dist/stages/load/StreamFactory.js +201 -0
  273. package/dist/stages/load/StreamFactory.js.map +1 -0
  274. package/dist/stages/load/TaskManager.d.ts +50 -0
  275. package/dist/stages/load/TaskManager.d.ts.map +1 -0
  276. package/dist/stages/load/TaskManager.js +103 -0
  277. package/dist/stages/load/TaskManager.js.map +1 -0
  278. package/dist/stages/load/WindowByteRangeResolver.d.ts +47 -0
  279. package/dist/stages/load/WindowByteRangeResolver.d.ts.map +1 -0
  280. package/dist/stages/load/WindowByteRangeResolver.js +270 -0
  281. package/dist/stages/load/WindowByteRangeResolver.js.map +1 -0
  282. package/dist/stages/load/index.d.ts +11 -0
  283. package/dist/stages/load/index.d.ts.map +1 -0
  284. package/dist/stages/load/types.d.ts +177 -0
  285. package/dist/stages/load/types.d.ts.map +1 -0
  286. package/dist/stages/mux/MP4Muxer.d.ts +44 -0
  287. package/dist/stages/mux/MP4Muxer.d.ts.map +1 -0
  288. package/dist/stages/mux/MP4Muxer.js +262 -0
  289. package/dist/stages/mux/MP4Muxer.js.map +1 -0
  290. package/dist/stages/mux/OPFSWriter.d.ts +46 -0
  291. package/dist/stages/mux/OPFSWriter.d.ts.map +1 -0
  292. package/dist/stages/mux/index.d.ts +5 -0
  293. package/dist/stages/mux/index.d.ts.map +1 -0
  294. package/dist/stages/mux/mux.worker.d.ts +65 -0
  295. package/dist/stages/mux/mux.worker.d.ts.map +1 -0
  296. package/dist/stages/mux/mux.worker.js +219 -0
  297. package/dist/stages/mux/mux.worker.js.map +1 -0
  298. package/dist/stages/mux/types.d.ts +95 -0
  299. package/dist/stages/mux/types.d.ts.map +1 -0
  300. package/dist/stages/mux/utils.d.ts +32 -0
  301. package/dist/stages/mux/utils.d.ts.map +1 -0
  302. package/dist/stages/mux/utils.js +34 -0
  303. package/dist/stages/mux/utils.js.map +1 -0
  304. package/dist/types.d.ts +25 -0
  305. package/dist/types.d.ts.map +1 -0
  306. package/dist/utils/BackpressureAdapter.d.ts +26 -0
  307. package/dist/utils/BackpressureAdapter.d.ts.map +1 -0
  308. package/dist/utils/binary-search.d.ts +33 -0
  309. package/dist/utils/binary-search.d.ts.map +1 -0
  310. package/dist/utils/binary-search.js +62 -0
  311. package/dist/utils/binary-search.js.map +1 -0
  312. package/dist/utils/canvas-utils.d.ts +96 -0
  313. package/dist/utils/canvas-utils.d.ts.map +1 -0
  314. package/dist/utils/canvas-utils.js +58 -0
  315. package/dist/utils/canvas-utils.js.map +1 -0
  316. package/dist/utils/object-utils.d.ts +34 -0
  317. package/dist/utils/object-utils.d.ts.map +1 -0
  318. package/dist/utils/object-utils.js +22 -0
  319. package/dist/utils/object-utils.js.map +1 -0
  320. package/dist/utils/time-utils.d.ts +10 -0
  321. package/dist/utils/time-utils.d.ts.map +1 -0
  322. package/dist/utils/time-utils.js +60 -0
  323. package/dist/utils/time-utils.js.map +1 -0
  324. package/dist/worker/BaseWorker.d.ts +44 -0
  325. package/dist/worker/BaseWorker.d.ts.map +1 -0
  326. package/dist/worker/BaseWorker.js +98 -0
  327. package/dist/worker/BaseWorker.js.map +1 -0
  328. package/dist/worker/WorkerChannel.d.ts +105 -0
  329. package/dist/worker/WorkerChannel.d.ts.map +1 -0
  330. package/dist/worker/WorkerChannel.js +355 -0
  331. package/dist/worker/WorkerChannel.js.map +1 -0
  332. package/dist/worker/WorkerPool.d.ts +52 -0
  333. package/dist/worker/WorkerPool.d.ts.map +1 -0
  334. package/dist/worker/WorkerPool.js +124 -0
  335. package/dist/worker/WorkerPool.js.map +1 -0
  336. package/dist/worker/index.d.ts +11 -0
  337. package/dist/worker/index.d.ts.map +1 -0
  338. package/dist/worker/transferable-helper.d.ts +89 -0
  339. package/dist/worker/transferable-helper.d.ts.map +1 -0
  340. package/dist/worker/transferable-helper.js +44 -0
  341. package/dist/worker/transferable-helper.js.map +1 -0
  342. package/dist/worker/types.d.ts +179 -0
  343. package/dist/worker/types.d.ts.map +1 -0
  344. package/dist/worker/types.js +50 -0
  345. package/dist/worker/types.js.map +1 -0
  346. package/dist/worker/worker-event-whitelist.d.ts +23 -0
  347. package/dist/worker/worker-event-whitelist.d.ts.map +1 -0
  348. package/dist/worker/worker-retry.d.ts +36 -0
  349. package/dist/worker/worker-retry.d.ts.map +1 -0
  350. package/dist/worker/worker-retry.js +55 -0
  351. package/dist/worker/worker-retry.js.map +1 -0
  352. package/package.json +105 -0
@@ -0,0 +1,262 @@
1
+ import "../../node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js";
2
+ import { calculateTimescale, parseCodecString, usToTimescale } from "./utils.js";
3
+ import { __exports as mp4box_all } from "../../_virtual/mp4box.all.js";
4
+ class MP4Muxer {
5
+ mp4boxFile;
6
+ tracks = /* @__PURE__ */ new Map();
7
+ mp4Tracks = /* @__PURE__ */ new Map();
8
+ // muxTrackId -> mp4boxTrackId
9
+ // Expose output chunks directly instead of getter
10
+ outputChunks = [];
11
+ // Expose total bytes written as computed property
12
+ get totalBytesWritten() {
13
+ return this.outputChunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
14
+ }
15
+ // Expose finalized state
16
+ isFinalized = false;
17
+ config;
18
+ constructor(config = { container: "mp4" }) {
19
+ this.config = config;
20
+ this.mp4boxFile = mp4box_all.createFile();
21
+ this.setupHandlers();
22
+ this.initializeTracks();
23
+ }
24
+ setupHandlers() {
25
+ this.mp4boxFile.onError = (error) => {
26
+ console.error("MP4Box error:", error);
27
+ };
28
+ this.mp4boxFile.onSegment = (_id, _user, buffer, _sampleNumber, _last) => {
29
+ const chunk = new Uint8Array(buffer);
30
+ this.outputChunks.push(chunk);
31
+ };
32
+ if (this.config.mp4?.fragmented) {
33
+ this.mp4boxFile.onInitSegment = (_tracks) => {
34
+ const initSegment = this.mp4boxFile.getInitializationSegment();
35
+ if (initSegment) {
36
+ const chunk = new Uint8Array(initSegment);
37
+ this.outputChunks.push(chunk);
38
+ }
39
+ };
40
+ }
41
+ }
42
+ initializeTracks() {
43
+ if (this.config.video) {
44
+ const videoTrack = {
45
+ id: 1,
46
+ // Default video track ID
47
+ type: "video",
48
+ codec: this.config.video.codec,
49
+ width: this.config.video.width,
50
+ height: this.config.video.height,
51
+ frameRate: this.config.video.frameRate,
52
+ timescale: calculateTimescale(this.config.video.frameRate),
53
+ codecConfig: this.config.video.description
54
+ };
55
+ this.addTrack(videoTrack);
56
+ }
57
+ if (this.config.audio) {
58
+ const audioTrack = {
59
+ id: 2,
60
+ // Default audio track ID
61
+ type: "audio",
62
+ codec: this.config.audio.codec,
63
+ sampleRate: this.config.audio.sampleRate,
64
+ channelCount: this.config.audio.channelCount,
65
+ timescale: this.config.audio.sampleRate,
66
+ codecConfig: this.config.audio.description
67
+ };
68
+ this.addTrack(audioTrack);
69
+ }
70
+ }
71
+ addTrack(track) {
72
+ if (!this.mp4boxFile) {
73
+ throw new Error("Muxer destroyed");
74
+ }
75
+ this.tracks.set(track.id, track);
76
+ const trackOptions = track.type === "video" ? this.createVideoTrackOptions(track) : this.createAudioTrackOptions(track);
77
+ const mp4TrackId = this.mp4boxFile.addTrack(trackOptions);
78
+ this.mp4Tracks.set(track.id, mp4TrackId);
79
+ if (this.config.mp4?.fragmented) {
80
+ this.configureFragmentedTrack(mp4TrackId, track);
81
+ }
82
+ return track.id;
83
+ }
84
+ configureFragmentedTrack(mp4TrackId, track) {
85
+ const fragmentDuration = this.config.mp4?.fragmentDuration || 1e6;
86
+ let nbSamples;
87
+ if (track.type === "video") {
88
+ const frameRate = track.frameRate || 30;
89
+ const fragmentDurationInSeconds = fragmentDuration / 1e6;
90
+ nbSamples = Math.ceil(fragmentDurationInSeconds * frameRate);
91
+ } else {
92
+ const sampleRate = track.sampleRate || 48e3;
93
+ const fragmentDurationInSeconds = fragmentDuration / 1e6;
94
+ const framesPerSecond = sampleRate / 1024;
95
+ nbSamples = Math.ceil(fragmentDurationInSeconds * framesPerSecond);
96
+ }
97
+ this.mp4boxFile.setSegmentOptions(mp4TrackId, null, {
98
+ nbSamples,
99
+ rapAlignement: true
100
+ // Align segments to keyframes for proper seeking
101
+ });
102
+ }
103
+ createVideoTrackOptions(track) {
104
+ const options = {
105
+ timescale: track.timescale || calculateTimescale(track.frameRate),
106
+ type: "video",
107
+ nb_samples: 0,
108
+ width: track.width,
109
+ height: track.height
110
+ };
111
+ const codecInfo = parseCodecString(track.codec);
112
+ switch (codecInfo.codec) {
113
+ case "avc1":
114
+ options.codec = "avc1";
115
+ options.avcDecoderConfigRecord = track.codecConfig;
116
+ break;
117
+ case "hev1":
118
+ case "hvc1":
119
+ options.codec = "hvc1";
120
+ options.hvcDecoderConfigRecord = track.codecConfig;
121
+ break;
122
+ case "av01":
123
+ options.codec = "av01";
124
+ options.av1DecoderConfigRecord = track.codecConfig;
125
+ break;
126
+ case "vp09":
127
+ options.codec = "vp09";
128
+ break;
129
+ default:
130
+ throw new Error(`Unsupported video codec: ${track.codec}`);
131
+ }
132
+ return options;
133
+ }
134
+ createAudioTrackOptions(track) {
135
+ const options = {
136
+ timescale: track.timescale || track.sampleRate || 48e3,
137
+ type: "audio",
138
+ nb_samples: 0,
139
+ channel_count: track.channelCount,
140
+ samplerate: track.sampleRate,
141
+ hdlr: "soun",
142
+ name: "SoundHandler"
143
+ };
144
+ const codecInfo = parseCodecString(track.codec);
145
+ switch (codecInfo.codec) {
146
+ case "mp4a":
147
+ options.codec = "mp4a.40.2";
148
+ options.audioDecoderConfig = track.codecConfig;
149
+ break;
150
+ case "opus":
151
+ options.codec = "Opus";
152
+ options.opusDecoderConfig = track.codecConfig;
153
+ break;
154
+ case "mp3":
155
+ options.codec = "mp3";
156
+ break;
157
+ case "ac-3":
158
+ options.codec = "ac-3";
159
+ break;
160
+ case "ec-3":
161
+ options.codec = "ec-3";
162
+ break;
163
+ default:
164
+ throw new Error(`Unsupported audio codec: ${track.codec}`);
165
+ }
166
+ return options;
167
+ }
168
+ /**
169
+ * Write video chunk to muxer
170
+ */
171
+ writeVideoChunk(chunk, trackId = 1) {
172
+ const mp4TrackId = this.mp4Tracks.get(trackId);
173
+ if (!mp4TrackId) {
174
+ throw new Error(`Track ${trackId} not found`);
175
+ }
176
+ const track = this.tracks.get(trackId);
177
+ if (!track) {
178
+ throw new Error(`Track info for ${trackId} not found`);
179
+ }
180
+ const data = new Uint8Array(chunk.byteLength);
181
+ chunk.copyTo(data);
182
+ const pts = usToTimescale(chunk.timestamp, track.timescale);
183
+ const dts = chunk.timestamp !== void 0 ? usToTimescale(chunk.timestamp, track.timescale) : pts;
184
+ const duration = usToTimescale(chunk.duration || 0, track.timescale);
185
+ const mp4Sample = {
186
+ data,
187
+ pts,
188
+ dts,
189
+ duration,
190
+ is_sync: chunk.type === "key"
191
+ };
192
+ this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);
193
+ }
194
+ /**
195
+ * Write audio chunk to muxer
196
+ */
197
+ writeAudioChunk(chunk, trackId = 2) {
198
+ const mp4TrackId = this.mp4Tracks.get(trackId);
199
+ if (!mp4TrackId) {
200
+ throw new Error(`Track ${trackId} not found`);
201
+ }
202
+ const track = this.tracks.get(trackId);
203
+ if (!track) {
204
+ throw new Error(`Track info for ${trackId} not found`);
205
+ }
206
+ const data = new Uint8Array(chunk.byteLength);
207
+ chunk.copyTo(data);
208
+ const pts = usToTimescale(chunk.timestamp, track.timescale);
209
+ const duration = usToTimescale(chunk.duration || 0, track.timescale);
210
+ const mp4Sample = {
211
+ data,
212
+ pts,
213
+ dts: pts,
214
+ duration,
215
+ is_sync: true
216
+ // Audio chunks are always sync samples
217
+ };
218
+ this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);
219
+ }
220
+ /**
221
+ * Flush pending samples
222
+ */
223
+ flush() {
224
+ if (this.mp4boxFile) {
225
+ this.mp4boxFile.flush();
226
+ }
227
+ }
228
+ /**
229
+ * Finalize and get the output
230
+ */
231
+ finalize() {
232
+ if (this.isFinalized) {
233
+ throw new Error("Muxer already finalized");
234
+ }
235
+ if (!this.mp4boxFile) {
236
+ throw new Error("Muxer destroyed");
237
+ }
238
+ this.flush();
239
+ if (!this.config.mp4?.fragmented) {
240
+ this.mp4boxFile.close();
241
+ }
242
+ this.isFinalized = true;
243
+ return new Blob(this.outputChunks, { type: "video/mp4" });
244
+ }
245
+ /**
246
+ * Clear output chunks (after they've been consumed)
247
+ */
248
+ clearOutputChunks() {
249
+ this.outputChunks = [];
250
+ }
251
+ destroy() {
252
+ this.mp4boxFile?.stop?.();
253
+ this.mp4boxFile = null;
254
+ this.tracks.clear();
255
+ this.mp4Tracks.clear();
256
+ this.outputChunks = [];
257
+ }
258
+ }
259
+ export {
260
+ MP4Muxer
261
+ };
262
+ //# sourceMappingURL=MP4Muxer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MP4Muxer.js","sources":["../../../src/stages/mux/MP4Muxer.ts"],"sourcesContent":["// @ts-ignore - mp4box doesn't have proper TypeScript definitions\nimport * as MP4Box from 'mp4box';\nimport type { MuxConfig, MuxTrack } from './types';\nimport { usToTimescale, calculateTimescale, parseCodecString } from './utils';\n\ninterface MP4TrackOptions {\n timescale: number;\n type: string;\n nb_samples: number;\n width?: number;\n height?: number;\n channel_count?: number;\n samplerate?: number;\n hdlr?: string;\n name?: string;\n codec?: string;\n avcDecoderConfigRecord?: Uint8Array;\n hvcDecoderConfigRecord?: Uint8Array;\n av1DecoderConfigRecord?: Uint8Array;\n audioDecoderConfig?: Uint8Array;\n opusDecoderConfig?: Uint8Array;\n}\n\n/**\n * MP4 Muxer - Multiplex encoded chunks into MP4 container\n * Terminal stage that consumes encoded chunks and produces MP4 file\n */\nexport class MP4Muxer {\n private mp4boxFile: any;\n tracks = new Map<number, MuxTrack>();\n private mp4Tracks = new Map<number, number>(); // muxTrackId -> mp4boxTrackId\n\n // Expose output chunks directly instead of getter\n outputChunks: Uint8Array[] = [];\n\n // Expose total bytes written as computed property\n get totalBytesWritten(): number {\n return this.outputChunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n }\n\n // Expose finalized state\n isFinalized = false;\n\n private config: MuxConfig;\n\n constructor(config: MuxConfig = { container: 'mp4' }) {\n this.config = config;\n this.mp4boxFile = MP4Box.createFile();\n this.setupHandlers();\n this.initializeTracks();\n }\n\n private setupHandlers(): void {\n this.mp4boxFile.onError = (error: string) => {\n console.error('MP4Box error:', error);\n };\n\n // Called when MP4Box has data to write\n this.mp4boxFile.onSegment = (\n _id: number,\n _user: any,\n buffer: ArrayBuffer,\n _sampleNumber: number,\n _last: boolean\n ) => {\n const chunk = new Uint8Array(buffer);\n this.outputChunks.push(chunk);\n };\n\n // Handle initialization segment for fragmented MP4\n if (this.config.mp4?.fragmented) {\n this.mp4boxFile.onInitSegment = (_tracks: any[]) => {\n const initSegment = this.mp4boxFile.getInitializationSegment();\n if (initSegment) {\n const chunk = new Uint8Array(initSegment);\n this.outputChunks.push(chunk);\n }\n };\n }\n }\n\n private initializeTracks(): void {\n // Add video track if configured\n if (this.config.video) {\n const videoTrack: MuxTrack = {\n id: 1, // Default video track ID\n type: 'video',\n codec: this.config.video.codec,\n width: this.config.video.width,\n height: this.config.video.height,\n frameRate: this.config.video.frameRate,\n timescale: calculateTimescale(this.config.video.frameRate),\n codecConfig: this.config.video.description,\n };\n this.addTrack(videoTrack);\n }\n\n // Add audio track if configured\n if (this.config.audio) {\n const audioTrack: MuxTrack = {\n id: 2, // Default audio track ID\n type: 'audio',\n codec: this.config.audio.codec,\n sampleRate: this.config.audio.sampleRate,\n channelCount: this.config.audio.channelCount,\n timescale: this.config.audio.sampleRate,\n codecConfig: this.config.audio.description,\n };\n this.addTrack(audioTrack);\n }\n }\n\n private addTrack(track: MuxTrack): number {\n if (!this.mp4boxFile) {\n throw new Error('Muxer destroyed');\n }\n\n // Store track info\n this.tracks.set(track.id, track);\n\n // Create track options based on type\n const trackOptions =\n track.type === 'video'\n ? this.createVideoTrackOptions(track)\n : this.createAudioTrackOptions(track);\n\n // Add track to MP4Box\n const mp4TrackId = this.mp4boxFile.addTrack(trackOptions);\n this.mp4Tracks.set(track.id, mp4TrackId);\n\n // Configure track for fragmented mode if enabled\n if (this.config.mp4?.fragmented) {\n this.configureFragmentedTrack(mp4TrackId, track);\n }\n\n return track.id;\n }\n\n private configureFragmentedTrack(mp4TrackId: number, track: MuxTrack): void {\n const fragmentDuration = this.config.mp4?.fragmentDuration || 1_000_000; // 1 second default in microseconds\n\n let nbSamples: number;\n\n if (track.type === 'video') {\n // For video: calculate number of frames per fragment based on frame rate\n // nbSamples = fragment_duration_in_seconds * frame_rate\n const frameRate = track.frameRate || 30;\n const fragmentDurationInSeconds = fragmentDuration / 1_000_000;\n nbSamples = Math.ceil(fragmentDurationInSeconds * frameRate);\n } else {\n // For audio: calculate number of samples per fragment\n // Audio typically has many more samples (e.g., 48000 Hz sample rate)\n // A reasonable fragment might contain ~1 second of audio samples\n const sampleRate = track.sampleRate || 48000;\n const fragmentDurationInSeconds = fragmentDuration / 1_000_000;\n // For compressed audio (AAC, Opus), each \"sample\" is actually a frame containing multiple PCM samples\n // AAC frame typically contains 1024 PCM samples, so at 48kHz: 48000/1024 ≈ 47 frames per second\n const framesPerSecond = sampleRate / 1024; // Assuming AAC-like frame size\n nbSamples = Math.ceil(fragmentDurationInSeconds * framesPerSecond);\n }\n\n /**\n * setSegmentOptions parameters:\n * @param trackId - The track ID to configure\n * @param user - User data (passed to callbacks, we don't use it)\n * @param options - Segmentation options:\n * - nbSamples: Number of samples per segment/fragment\n * - rapAlignement: Random Access Point alignment - ensures segments start with keyframes\n * This is critical for seeking and adaptive streaming (HLS/DASH)\n */\n this.mp4boxFile.setSegmentOptions(mp4TrackId, null, {\n nbSamples,\n rapAlignement: true, // Align segments to keyframes for proper seeking\n });\n }\n\n private createVideoTrackOptions(track: MuxTrack): MP4TrackOptions {\n const options: MP4TrackOptions = {\n timescale: track.timescale || calculateTimescale(track.frameRate),\n type: 'video',\n nb_samples: 0,\n width: track.width,\n height: track.height,\n };\n\n // Configure codec-specific options\n const codecInfo = parseCodecString(track.codec);\n\n switch (codecInfo.codec) {\n case 'avc1':\n options.codec = 'avc1';\n options.avcDecoderConfigRecord = track.codecConfig;\n break;\n case 'hev1':\n case 'hvc1':\n options.codec = 'hvc1';\n options.hvcDecoderConfigRecord = track.codecConfig;\n break;\n case 'av01':\n options.codec = 'av01';\n options.av1DecoderConfigRecord = track.codecConfig;\n break;\n case 'vp09':\n options.codec = 'vp09';\n // VP9 specific configuration\n break;\n default:\n throw new Error(`Unsupported video codec: ${track.codec}`);\n }\n\n return options;\n }\n\n private createAudioTrackOptions(track: MuxTrack): MP4TrackOptions {\n const options: MP4TrackOptions = {\n timescale: track.timescale || track.sampleRate || 48000,\n type: 'audio',\n nb_samples: 0,\n channel_count: track.channelCount,\n samplerate: track.sampleRate,\n hdlr: 'soun',\n name: 'SoundHandler',\n };\n\n // Configure codec-specific options\n const codecInfo = parseCodecString(track.codec);\n\n switch (codecInfo.codec) {\n case 'mp4a':\n options.codec = 'mp4a.40.2'; // AAC-LC\n options.audioDecoderConfig = track.codecConfig;\n break;\n case 'opus':\n options.codec = 'Opus';\n options.opusDecoderConfig = track.codecConfig;\n break;\n case 'mp3':\n options.codec = 'mp3';\n break;\n case 'ac-3':\n options.codec = 'ac-3';\n break;\n case 'ec-3':\n options.codec = 'ec-3';\n break;\n default:\n throw new Error(`Unsupported audio codec: ${track.codec}`);\n }\n\n return options;\n }\n\n /**\n * Write video chunk to muxer\n */\n writeVideoChunk(chunk: EncodedVideoChunk, trackId: number = 1): void {\n const mp4TrackId = this.mp4Tracks.get(trackId);\n if (!mp4TrackId) {\n throw new Error(`Track ${trackId} not found`);\n }\n\n const track = this.tracks.get(trackId);\n if (!track) {\n throw new Error(`Track info for ${trackId} not found`);\n }\n\n // Create buffer for chunk data\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n\n // Convert timestamps to timescale units\n const pts = usToTimescale(chunk.timestamp, track.timescale);\n const dts =\n chunk.timestamp !== undefined ? usToTimescale(chunk.timestamp, track.timescale) : pts;\n const duration = usToTimescale(chunk.duration || 0, track.timescale);\n\n // Create MP4Box sample\n const mp4Sample: any = {\n data: data,\n pts: pts,\n dts: dts,\n duration: duration,\n is_sync: chunk.type === 'key',\n };\n\n // Add sample to track\n this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);\n }\n\n /**\n * Write audio chunk to muxer\n */\n writeAudioChunk(chunk: EncodedAudioChunk, trackId: number = 2): void {\n const mp4TrackId = this.mp4Tracks.get(trackId);\n if (!mp4TrackId) {\n throw new Error(`Track ${trackId} not found`);\n }\n\n const track = this.tracks.get(trackId);\n if (!track) {\n throw new Error(`Track info for ${trackId} not found`);\n }\n\n // Create buffer for chunk data\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n\n // Convert timestamps to timescale units\n const pts = usToTimescale(chunk.timestamp, track.timescale);\n const duration = usToTimescale(chunk.duration || 0, track.timescale);\n\n // Create MP4Box sample\n const mp4Sample: any = {\n data: data,\n pts: pts,\n dts: pts,\n duration: duration,\n is_sync: true, // Audio chunks are always sync samples\n };\n\n // Add sample to track\n this.mp4boxFile.addSample(mp4TrackId, data, mp4Sample);\n }\n\n /**\n * Flush pending samples\n */\n flush(): void {\n if (this.mp4boxFile) {\n this.mp4boxFile.flush();\n }\n }\n\n /**\n * Finalize and get the output\n */\n finalize(): Blob {\n if (this.isFinalized) {\n throw new Error('Muxer already finalized');\n }\n\n if (!this.mp4boxFile) {\n throw new Error('Muxer destroyed');\n }\n\n // Flush any remaining samples\n this.flush();\n\n // For non-fragmented mode, close to write moov box\n if (!this.config.mp4?.fragmented) {\n this.mp4boxFile.close();\n }\n\n this.isFinalized = true;\n\n // Return the muxed MP4 as a Blob\n return new Blob(this.outputChunks as BlobPart[], { type: 'video/mp4' });\n }\n\n /**\n * Clear output chunks (after they've been consumed)\n */\n clearOutputChunks(): void {\n this.outputChunks = [];\n }\n\n destroy(): void {\n this.mp4boxFile?.stop?.();\n this.mp4boxFile = null;\n this.tracks.clear();\n this.mp4Tracks.clear();\n this.outputChunks = [];\n }\n}\n"],"names":["MP4Box.createFile"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * OPFS (Origin Private File System) Writer
3
+ * Provides streaming file writing capabilities for large media files
4
+ */
5
+ export declare class OPFSWriter {
6
+ private fileHandle;
7
+ private writable;
8
+ private bytesWritten;
9
+ /**
10
+ * Open or create a file in OPFS
11
+ * @param filePath - Path relative to OPFS root (e.g., "exports/video.mp4")
12
+ */
13
+ open(filePath: string): Promise<void>;
14
+ /**
15
+ * Write data to the file
16
+ */
17
+ write(data: Uint8Array): Promise<void>;
18
+ /**
19
+ * Write multiple chunks efficiently
20
+ */
21
+ writeChunks(chunks: Uint8Array[]): Promise<void>;
22
+ /**
23
+ * Close the file and finalize writing
24
+ */
25
+ close(): Promise<FileSystemFileHandle>;
26
+ /**
27
+ * Get current file size
28
+ */
29
+ get totalBytesWritten(): number;
30
+ /**
31
+ * Check if OPFS is supported
32
+ */
33
+ static isSupported(): boolean;
34
+ /**
35
+ * Get available storage quota
36
+ */
37
+ static getQuota(): Promise<{
38
+ usage: number;
39
+ quota: number;
40
+ }>;
41
+ /**
42
+ * Clean up old files in a directory
43
+ */
44
+ static cleanupDirectory(dirPath: string, keepCount?: number): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=OPFSWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OPFSWriter.d.ts","sourceRoot":"","sources":["../../../src/stages/mux/OPFSWriter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAqC;IACvD,OAAO,CAAC,QAAQ,CAA6C;IAC7D,OAAO,CAAC,YAAY,CAAK;IAEzB;;;OAGG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B3C;;OAEG;IACG,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5C;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAc5C;;OAEG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,OAAO;IAI7B;;OAEG;WACU,QAAQ,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAWlE;;OAEG;WACU,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAqCrF"}
@@ -0,0 +1,5 @@
1
+ export { MP4Muxer } from './MP4Muxer';
2
+ export { OPFSWriter } from './OPFSWriter';
3
+ export * from './types';
4
+ export * from './utils';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/stages/mux/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * MuxWorker - Final stage for video/audio multiplexing
3
+ * Combines encoded video and audio tracks into container format (MP4)
4
+ *
5
+ * Pipeline: CacheManager → MuxWorker → Export (Blob/OPFS)
6
+ *
7
+ * Features:
8
+ * - MP4 container muxing with mp4box.js
9
+ * - Stream-based processing from L2 cache
10
+ * - Support for fragmented MP4 (fMP4) for streaming
11
+ * - Direct blob output for download
12
+ */
13
+ export declare class MuxWorkerImpl {
14
+ private channel;
15
+ private muxer;
16
+ private config;
17
+ constructor();
18
+ private setupHandlers;
19
+ /**
20
+ * Unified connect handler used by stream pipeline
21
+ */
22
+ private handleUnifiedConnect;
23
+ /**
24
+ * Connect to encoder worker to receive encoded chunks
25
+ */
26
+ /**
27
+ * Configure muxer with container settings
28
+ * @param payload.config - Muxer configuration including tracks and output format
29
+ * @param payload.initial - If true, initialize worker state; otherwise just update config
30
+ */
31
+ private handleConfigure;
32
+ /**
33
+ * Write single video chunk
34
+ */
35
+ private handleWriteVideoChunk;
36
+ /**
37
+ * Write single audio chunk
38
+ */
39
+ private handleWriteAudioChunk;
40
+ /**
41
+ * Handle input stream from CacheManager (L2 encoded chunks)
42
+ * This is the main export path where CacheManager sends encoded chunks
43
+ */
44
+ private handleInputStream;
45
+ /**
46
+ * Flush pending samples
47
+ */
48
+ private handleFlush;
49
+ /**
50
+ * Finalize muxing and get output
51
+ * This completes the export process
52
+ */
53
+ private handleFinalize;
54
+ /**
55
+ * Get muxer statistics
56
+ */
57
+ private handleGetStats;
58
+ /**
59
+ * Dispose worker and cleanup resources
60
+ */
61
+ private handleDispose;
62
+ }
63
+ declare const _default: null;
64
+ export default _default;
65
+ //# sourceMappingURL=mux.worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mux.worker.d.ts","sourceRoot":"","sources":["../../../src/stages/mux/mux.worker.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,MAAM,CAA0B;;IAYxC,OAAO,CAAC,aAAa;IAiBrB;;OAEG;YACW,oBAAoB;IASlC;;OAEG;IAUH;;;;OAIG;YACW,eAAe;IAsD7B;;OAEG;YACW,qBAAqB;IAgBnC;;OAEG;YACW,qBAAqB;IAgBnC;;;OAGG;YACW,iBAAiB;IAwD/B;;OAEG;YACW,WAAW;IAYzB;;;OAGG;YACW,cAAc;IA2B5B;;OAEG;YACW,cAAc;IAkB5B;;OAEG;YACW,aAAa;CAU5B;;AAUD,wBAAoB"}
@@ -0,0 +1,219 @@
1
+ import { WorkerChannel } from "../../worker/WorkerChannel.js";
2
+ import { WorkerMessageType, WorkerState } from "../../worker/types.js";
3
+ import { MP4Muxer } from "./MP4Muxer.js";
4
+ class MuxWorkerImpl {
5
+ channel;
6
+ muxer = null;
7
+ config = null;
8
+ constructor() {
9
+ this.channel = new WorkerChannel(self, {
10
+ name: "MuxWorker",
11
+ timeout: 6e4
12
+ // 60s for export operations
13
+ });
14
+ this.setupHandlers();
15
+ }
16
+ setupHandlers() {
17
+ this.channel.registerHandler("configure", this.handleConfigure.bind(this));
18
+ this.channel.registerHandler("connect", this.handleUnifiedConnect.bind(this));
19
+ this.channel.registerHandler("write_video_chunk", this.handleWriteVideoChunk.bind(this));
20
+ this.channel.registerHandler("write_audio_chunk", this.handleWriteAudioChunk.bind(this));
21
+ this.channel.registerHandler("flush", this.handleFlush.bind(this));
22
+ this.channel.registerHandler("finalize", this.handleFinalize.bind(this));
23
+ this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
24
+ this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
25
+ this.channel.receiveStream(this.handleInputStream.bind(this));
26
+ }
27
+ /**
28
+ * Unified connect handler used by stream pipeline
29
+ */
30
+ async handleUnifiedConnect(_payload) {
31
+ return { success: true };
32
+ }
33
+ /**
34
+ * Connect to encoder worker to receive encoded chunks
35
+ */
36
+ // private async handleConnectEncoder(_payload: {
37
+ // port: MessagePort;
38
+ // }): Promise<{ success: boolean }> {
39
+ // // Store the port for receiving encoded chunks
40
+ // // The actual stream handling is done via receiveStream in handleInputStream
41
+ // // This connection allows direct communication with the encoder worker
42
+ // return { success: true };
43
+ // }
44
+ /**
45
+ * Configure muxer with container settings
46
+ * @param payload.config - Muxer configuration including tracks and output format
47
+ * @param payload.initial - If true, initialize worker state; otherwise just update config
48
+ */
49
+ async handleConfigure(payload) {
50
+ const { config, initial = false } = payload;
51
+ try {
52
+ if (initial) {
53
+ this.channel.state = WorkerState.Ready;
54
+ if (this.muxer) {
55
+ this.muxer.destroy();
56
+ }
57
+ this.config = config;
58
+ this.muxer = new MP4Muxer(config);
59
+ const trackCount = (config.video ? 1 : 0) + (config.audio ? 1 : 0);
60
+ this.channel.notify("configured", {
61
+ container: config.container,
62
+ hasVideo: !!config.video,
63
+ hasAudio: !!config.audio,
64
+ fragmented: !!config.mp4?.fragmented,
65
+ trackCount
66
+ });
67
+ return { success: true, tracks: trackCount };
68
+ } else {
69
+ if (!this.muxer) {
70
+ throw {
71
+ code: "NOT_INITIALIZED",
72
+ message: "Muxer not initialized. Call configure with initial=true first"
73
+ };
74
+ }
75
+ this.config = { ...this.config, ...config };
76
+ return { success: true };
77
+ }
78
+ } catch (error) {
79
+ throw {
80
+ code: error.code || "CONFIG_ERROR",
81
+ message: error.message
82
+ };
83
+ }
84
+ }
85
+ /**
86
+ * Write single video chunk
87
+ */
88
+ async handleWriteVideoChunk(payload) {
89
+ if (!this.muxer) {
90
+ throw {
91
+ code: "NOT_INITIALIZED",
92
+ message: "Muxer not initialized"
93
+ };
94
+ }
95
+ this.muxer.writeVideoChunk(payload.chunk, payload.trackId);
96
+ return { bytesWritten: this.muxer.totalBytesWritten };
97
+ }
98
+ /**
99
+ * Write single audio chunk
100
+ */
101
+ async handleWriteAudioChunk(payload) {
102
+ if (!this.muxer) {
103
+ throw {
104
+ code: "NOT_INITIALIZED",
105
+ message: "Muxer not initialized"
106
+ };
107
+ }
108
+ this.muxer.writeAudioChunk(payload.chunk, payload.trackId);
109
+ return { bytesWritten: this.muxer.totalBytesWritten };
110
+ }
111
+ /**
112
+ * Handle input stream from CacheManager (L2 encoded chunks)
113
+ * This is the main export path where CacheManager sends encoded chunks
114
+ */
115
+ async handleInputStream(stream, metadata) {
116
+ if (!this.muxer) {
117
+ throw new Error("Muxer not configured");
118
+ }
119
+ const reader = stream.getReader();
120
+ let chunksProcessed = 0;
121
+ try {
122
+ this.channel.state = WorkerState.Processing;
123
+ while (true) {
124
+ const { done, value } = await reader.read();
125
+ if (done) break;
126
+ const isVideoChunk = metadata?.type === "video" || value.type === "key" || value.type === "delta";
127
+ if (isVideoChunk) {
128
+ this.muxer.writeVideoChunk(value, metadata?.trackId || 1);
129
+ } else {
130
+ this.muxer.writeAudioChunk(value, metadata?.trackId || 2);
131
+ }
132
+ chunksProcessed++;
133
+ if (chunksProcessed % 100 === 0) {
134
+ this.channel.notify("mux_progress", {
135
+ chunksProcessed,
136
+ bytesWritten: this.muxer.totalBytesWritten
137
+ });
138
+ }
139
+ }
140
+ this.muxer.flush();
141
+ this.channel.state = WorkerState.Ready;
142
+ this.channel.notify("mux_complete", {
143
+ chunksProcessed,
144
+ bytesWritten: this.muxer.totalBytesWritten
145
+ });
146
+ } finally {
147
+ reader.releaseLock();
148
+ }
149
+ }
150
+ /**
151
+ * Flush pending samples
152
+ */
153
+ async handleFlush() {
154
+ if (!this.muxer) {
155
+ throw {
156
+ code: "NOT_INITIALIZED",
157
+ message: "Muxer not initialized"
158
+ };
159
+ }
160
+ this.muxer.flush();
161
+ return { success: true };
162
+ }
163
+ /**
164
+ * Finalize muxing and get output
165
+ * This completes the export process
166
+ */
167
+ async handleFinalize() {
168
+ if (!this.muxer) {
169
+ throw {
170
+ code: "NOT_INITIALIZED",
171
+ message: "Muxer not initialized"
172
+ };
173
+ }
174
+ const blob = this.muxer.finalize();
175
+ this.channel.notify("export_done", {
176
+ blob,
177
+ totalBytes: blob.size
178
+ });
179
+ return {
180
+ success: true,
181
+ blob,
182
+ totalBytes: blob.size
183
+ };
184
+ }
185
+ /**
186
+ * Get muxer statistics
187
+ */
188
+ async handleGetStats() {
189
+ if (!this.muxer) {
190
+ return { state: this.channel.state };
191
+ }
192
+ return {
193
+ bytesWritten: this.muxer.totalBytesWritten,
194
+ chunksCount: this.muxer.outputChunks.length,
195
+ isFinalized: this.muxer.isFinalized,
196
+ state: this.channel.state
197
+ };
198
+ }
199
+ /**
200
+ * Dispose worker and cleanup resources
201
+ */
202
+ async handleDispose() {
203
+ this.muxer?.destroy();
204
+ this.muxer = null;
205
+ this.config = null;
206
+ this.channel.state = WorkerState.Disposed;
207
+ return { success: true };
208
+ }
209
+ }
210
+ const worker = new MuxWorkerImpl();
211
+ self.addEventListener("beforeunload", () => {
212
+ worker["handleDispose"]();
213
+ });
214
+ const mux_worker = null;
215
+ export {
216
+ MuxWorkerImpl,
217
+ mux_worker as default
218
+ };
219
+ //# sourceMappingURL=mux.worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mux.worker.js","sources":["../../../src/stages/mux/mux.worker.ts"],"sourcesContent":["import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { MP4Muxer } from './MP4Muxer';\nimport type { MuxConfig } from './types';\n\n/**\n * MuxWorker - Final stage for video/audio multiplexing\n * Combines encoded video and audio tracks into container format (MP4)\n *\n * Pipeline: CacheManager → MuxWorker → Export (Blob/OPFS)\n *\n * Features:\n * - MP4 container muxing with mp4box.js\n * - Stream-based processing from L2 cache\n * - Support for fragmented MP4 (fMP4) for streaming\n * - Direct blob output for download\n */\nexport class MuxWorkerImpl {\n private channel: WorkerChannel;\n private muxer: MP4Muxer | null = null;\n private config: MuxConfig | null = null;\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self as any, {\n name: 'MuxWorker',\n timeout: 60000, // 60s for export operations\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n // Unified stream connect (feature-flagged)\n this.channel.registerHandler('connect' as any, this.handleUnifiedConnect.bind(this));\n // Unified stream connect only\n this.channel.registerHandler('write_video_chunk', this.handleWriteVideoChunk.bind(this));\n this.channel.registerHandler('write_audio_chunk', this.handleWriteAudioChunk.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('finalize', this.handleFinalize.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n\n // Setup stream receiver from CacheManager (L2 encoded chunks)\n this.channel.receiveStream(this.handleInputStream.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleUnifiedConnect(_payload: {\n direction: 'upstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n }): Promise<{ success: boolean }> {\n // Mux receives encoded chunks via receiveStream already\n return { success: true };\n }\n\n /**\n * Connect to encoder worker to receive encoded chunks\n */\n // private async handleConnectEncoder(_payload: {\n // port: MessagePort;\n // }): Promise<{ success: boolean }> {\n // // Store the port for receiving encoded chunks\n // // The actual stream handling is done via receiveStream in handleInputStream\n // // This connection allows direct communication with the encoder worker\n // return { success: true };\n // }\n\n /**\n * Configure muxer with container settings\n * @param payload.config - Muxer configuration including tracks and output format\n * @param payload.initial - If true, initialize worker state; otherwise just update config\n */\n private async handleConfigure(payload: {\n config: MuxConfig;\n initial?: boolean;\n }): Promise<{ success: boolean; tracks?: number }> {\n const { config, initial = false } = payload;\n\n try {\n if (initial) {\n // Initial setup - set worker state to ready\n this.channel.state = WorkerState.Ready;\n\n // Create new muxer instance\n if (this.muxer) {\n this.muxer.destroy();\n }\n\n this.config = config;\n this.muxer = new MP4Muxer(config);\n\n const trackCount = (config.video ? 1 : 0) + (config.audio ? 1 : 0);\n\n // Notify configuration complete\n this.channel.notify('configured', {\n container: config.container,\n hasVideo: !!config.video,\n hasAudio: !!config.audio,\n fragmented: !!config.mp4?.fragmented,\n trackCount,\n });\n\n return { success: true, tracks: trackCount };\n } else {\n // Update configuration only\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized. Call configure with initial=true first',\n };\n }\n\n // MP4Muxer doesn't support runtime config updates\n // Would need to recreate for changes\n this.config = { ...this.config, ...config };\n\n return { success: true };\n }\n } catch (error: any) {\n throw {\n code: error.code || 'CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Write single video chunk\n */\n private async handleWriteVideoChunk(payload: {\n chunk: EncodedVideoChunk;\n trackId?: number;\n }): Promise<{ bytesWritten: number }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.writeVideoChunk(payload.chunk, payload.trackId);\n\n return { bytesWritten: this.muxer.totalBytesWritten };\n }\n\n /**\n * Write single audio chunk\n */\n private async handleWriteAudioChunk(payload: {\n chunk: EncodedAudioChunk;\n trackId?: number;\n }): Promise<{ bytesWritten: number }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.writeAudioChunk(payload.chunk, payload.trackId);\n\n return { bytesWritten: this.muxer.totalBytesWritten };\n }\n\n /**\n * Handle input stream from CacheManager (L2 encoded chunks)\n * This is the main export path where CacheManager sends encoded chunks\n */\n private async handleInputStream(\n stream: ReadableStream<EncodedVideoChunk | EncodedAudioChunk>,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.muxer) {\n throw new Error('Muxer not configured');\n }\n\n const reader = stream.getReader();\n let chunksProcessed = 0;\n\n try {\n this.channel.state = WorkerState.Processing;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n // Determine chunk type and write accordingly\n const isVideoChunk =\n metadata?.type === 'video' ||\n (value as any).type === 'key' ||\n (value as any).type === 'delta';\n\n if (isVideoChunk) {\n this.muxer.writeVideoChunk(value as EncodedVideoChunk, metadata?.trackId || 1);\n } else {\n this.muxer.writeAudioChunk(value as EncodedAudioChunk, metadata?.trackId || 2);\n }\n\n chunksProcessed++;\n\n // Report progress periodically\n if (chunksProcessed % 100 === 0) {\n this.channel.notify('mux_progress', {\n chunksProcessed,\n bytesWritten: this.muxer.totalBytesWritten,\n });\n }\n }\n\n // Flush after stream processing\n this.muxer.flush();\n\n this.channel.state = WorkerState.Ready;\n\n // Notify muxing complete\n this.channel.notify('mux_complete', {\n chunksProcessed,\n bytesWritten: this.muxer.totalBytesWritten,\n });\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Flush pending samples\n */\n private async handleFlush(): Promise<{ success: boolean }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n this.muxer.flush();\n return { success: true };\n }\n\n /**\n * Finalize muxing and get output\n * This completes the export process\n */\n private async handleFinalize(): Promise<{\n success: boolean;\n blob: Blob;\n totalBytes: number;\n }> {\n if (!this.muxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Muxer not initialized',\n };\n }\n\n const blob = this.muxer.finalize();\n\n // Notify export completion as per architecture doc\n this.channel.notify('export_done', {\n blob,\n totalBytes: blob.size,\n });\n\n return {\n success: true,\n blob,\n totalBytes: blob.size,\n };\n }\n\n /**\n * Get muxer statistics\n */\n private async handleGetStats(): Promise<{\n bytesWritten?: number;\n chunksCount?: number;\n isFinalized?: boolean;\n state?: WorkerState;\n }> {\n if (!this.muxer) {\n return { state: this.channel.state };\n }\n\n return {\n bytesWritten: this.muxer.totalBytesWritten,\n chunksCount: this.muxer.outputChunks.length,\n isFinalized: this.muxer.isFinalized,\n state: this.channel.state,\n };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n // Destroy muxer\n this.muxer?.destroy();\n this.muxer = null;\n this.config = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\n// Initialize worker\nconst worker = new MuxWorkerImpl();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":[],"mappings":";;;AAiBO,MAAM,cAAc;AAAA,EACjB;AAAA,EACA,QAAyB;AAAA,EACzB,SAA2B;AAAA,EAEnC,cAAc;AAEZ,SAAK,UAAU,IAAI,cAAc,MAAa;AAAA,MAC5C,MAAM;AAAA,MACN,SAAS;AAAA;AAAA,IAAA,CACV;AAED,SAAK,cAAA;AAAA,EACP;AAAA,EAEQ,gBAAsB;AAE5B,SAAK,QAAQ,gBAAgB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAEzE,SAAK,QAAQ,gBAAgB,WAAkB,KAAK,qBAAqB,KAAK,IAAI,CAAC;AAEnF,SAAK,QAAQ,gBAAgB,qBAAqB,KAAK,sBAAsB,KAAK,IAAI,CAAC;AACvF,SAAK,QAAQ,gBAAgB,qBAAqB,KAAK,sBAAsB,KAAK,IAAI,CAAC;AACvF,SAAK,QAAQ,gBAAgB,SAAS,KAAK,YAAY,KAAK,IAAI,CAAC;AACjE,SAAK,QAAQ,gBAAgB,YAAY,KAAK,eAAe,KAAK,IAAI,CAAC;AACvE,SAAK,QAAQ,gBAAgB,aAAa,KAAK,eAAe,KAAK,IAAI,CAAC;AACxE,SAAK,QAAQ,gBAAgB,kBAAkB,SAAS,KAAK,cAAc,KAAK,IAAI,CAAC;AAGrF,SAAK,QAAQ,cAAc,KAAK,kBAAkB,KAAK,IAAI,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAqB,UAID;AAEhC,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAc,gBAAgB,SAGqB;AACjD,UAAM,EAAE,QAAQ,UAAU,MAAA,IAAU;AAEpC,QAAI;AACF,UAAI,SAAS;AAEX,aAAK,QAAQ,QAAQ,YAAY;AAGjC,YAAI,KAAK,OAAO;AACd,eAAK,MAAM,QAAA;AAAA,QACb;AAEA,aAAK,SAAS;AACd,aAAK,QAAQ,IAAI,SAAS,MAAM;AAEhC,cAAM,cAAc,OAAO,QAAQ,IAAI,MAAM,OAAO,QAAQ,IAAI;AAGhE,aAAK,QAAQ,OAAO,cAAc;AAAA,UAChC,WAAW,OAAO;AAAA,UAClB,UAAU,CAAC,CAAC,OAAO;AAAA,UACnB,UAAU,CAAC,CAAC,OAAO;AAAA,UACnB,YAAY,CAAC,CAAC,OAAO,KAAK;AAAA,UAC1B;AAAA,QAAA,CACD;AAED,eAAO,EAAE,SAAS,MAAM,QAAQ,WAAA;AAAA,MAClC,OAAO;AAEL,YAAI,CAAC,KAAK,OAAO;AACf,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN,SAAS;AAAA,UAAA;AAAA,QAEb;AAIA,aAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAA;AAEnC,eAAO,EAAE,SAAS,KAAA;AAAA,MACpB;AAAA,IACF,SAAS,OAAY;AACnB,YAAM;AAAA,QACJ,MAAM,MAAM,QAAQ;AAAA,QACpB,SAAS,MAAM;AAAA,MAAA;AAAA,IAEnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,SAGE;AACpC,QAAI,CAAC,KAAK,OAAO;AACf,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,MAAA;AAAA,IAEb;AAEA,SAAK,MAAM,gBAAgB,QAAQ,OAAO,QAAQ,OAAO;AAEzD,WAAO,EAAE,cAAc,KAAK,MAAM,kBAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,SAGE;AACpC,QAAI,CAAC,KAAK,OAAO;AACf,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,MAAA;AAAA,IAEb;AAEA,SAAK,MAAM,gBAAgB,QAAQ,OAAO,QAAQ,OAAO;AAEzD,WAAO,EAAE,cAAc,KAAK,MAAM,kBAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBACZ,QACA,UACe;AACf,QAAI,CAAC,KAAK,OAAO;AACf,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,UAAM,SAAS,OAAO,UAAA;AACtB,QAAI,kBAAkB;AAEtB,QAAI;AACF,WAAK,QAAQ,QAAQ,YAAY;AAEjC,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AACrC,YAAI,KAAM;AAGV,cAAM,eACJ,UAAU,SAAS,WAClB,MAAc,SAAS,SACvB,MAAc,SAAS;AAE1B,YAAI,cAAc;AAChB,eAAK,MAAM,gBAAgB,OAA4B,UAAU,WAAW,CAAC;AAAA,QAC/E,OAAO;AACL,eAAK,MAAM,gBAAgB,OAA4B,UAAU,WAAW,CAAC;AAAA,QAC/E;AAEA;AAGA,YAAI,kBAAkB,QAAQ,GAAG;AAC/B,eAAK,QAAQ,OAAO,gBAAgB;AAAA,YAClC;AAAA,YACA,cAAc,KAAK,MAAM;AAAA,UAAA,CAC1B;AAAA,QACH;AAAA,MACF;AAGA,WAAK,MAAM,MAAA;AAEX,WAAK,QAAQ,QAAQ,YAAY;AAGjC,WAAK,QAAQ,OAAO,gBAAgB;AAAA,QAClC;AAAA,QACA,cAAc,KAAK,MAAM;AAAA,MAAA,CAC1B;AAAA,IACH,UAAA;AACE,aAAO,YAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAA6C;AACzD,QAAI,CAAC,KAAK,OAAO;AACf,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,MAAA;AAAA,IAEb;AAEA,SAAK,MAAM,MAAA;AACX,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAIX;AACD,QAAI,CAAC,KAAK,OAAO;AACf,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,SAAS;AAAA,MAAA;AAAA,IAEb;AAEA,UAAM,OAAO,KAAK,MAAM,SAAA;AAGxB,SAAK,QAAQ,OAAO,eAAe;AAAA,MACjC;AAAA,MACA,YAAY,KAAK;AAAA,IAAA,CAClB;AAED,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,YAAY,KAAK;AAAA,IAAA;AAAA,EAErB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAKX;AACD,QAAI,CAAC,KAAK,OAAO;AACf,aAAO,EAAE,OAAO,KAAK,QAAQ,MAAA;AAAA,IAC/B;AAEA,WAAO;AAAA,MACL,cAAc,KAAK,MAAM;AAAA,MACzB,aAAa,KAAK,MAAM,aAAa;AAAA,MACrC,aAAa,KAAK,MAAM;AAAA,MACxB,OAAO,KAAK,QAAQ;AAAA,IAAA;AAAA,EAExB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,gBAA+C;AAE3D,SAAK,OAAO,QAAA;AACZ,SAAK,QAAQ;AACb,SAAK,SAAS;AAEd,SAAK,QAAQ,QAAQ,YAAY;AAEjC,WAAO,EAAE,SAAS,KAAA;AAAA,EACpB;AACF;AAGA,MAAM,SAAS,IAAI,cAAA;AAGnB,KAAK,iBAAiB,gBAAgB,MAAM;AAC1C,SAAO,eAAe,EAAA;AACxB,CAAC;AAED,MAAA,aAAe;"}