@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.
- package/CHANGELOG.md +42 -0
- package/LICENSE +22 -0
- package/README.md +396 -0
- package/dist/Meframe.d.ts +82 -0
- package/dist/Meframe.d.ts.map +1 -0
- package/dist/Meframe.js +290 -0
- package/dist/Meframe.js.map +1 -0
- package/dist/_virtual/mp4box.all.js +5 -0
- package/dist/_virtual/mp4box.all.js.map +1 -0
- package/dist/cache/BatchWriter.d.ts +25 -0
- package/dist/cache/BatchWriter.d.ts.map +1 -0
- package/dist/cache/CacheManager.d.ts +115 -0
- package/dist/cache/CacheManager.d.ts.map +1 -0
- package/dist/cache/CacheManager.js +388 -0
- package/dist/cache/CacheManager.js.map +1 -0
- package/dist/cache/CacheStatsDecorator.d.ts +27 -0
- package/dist/cache/CacheStatsDecorator.d.ts.map +1 -0
- package/dist/cache/L2Cache.d.ts +39 -0
- package/dist/cache/L2Cache.d.ts.map +1 -0
- package/dist/cache/L2Cache.js +282 -0
- package/dist/cache/L2Cache.js.map +1 -0
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/l1/AudioL1Cache.d.ts +30 -0
- package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -0
- package/dist/cache/l1/AudioL1Cache.js +306 -0
- package/dist/cache/l1/AudioL1Cache.js.map +1 -0
- package/dist/cache/l1/MixedAudioL1Cache.d.ts +13 -0
- package/dist/cache/l1/MixedAudioL1Cache.d.ts.map +1 -0
- package/dist/cache/l1/MixedAudioL1Cache.js +52 -0
- package/dist/cache/l1/MixedAudioL1Cache.js.map +1 -0
- package/dist/cache/l1/VideoL1Cache.d.ts +69 -0
- package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -0
- package/dist/cache/l1/VideoL1Cache.js +318 -0
- package/dist/cache/l1/VideoL1Cache.js.map +1 -0
- package/dist/cache/l1/gop-utils.d.ts +10 -0
- package/dist/cache/l1/gop-utils.d.ts.map +1 -0
- package/dist/cache/l1/gop-utils.js +78 -0
- package/dist/cache/l1/gop-utils.js.map +1 -0
- package/dist/cache/l1/index.d.ts +4 -0
- package/dist/cache/l1/index.d.ts.map +1 -0
- package/dist/cache/l1/types.d.ts +17 -0
- package/dist/cache/l1/types.d.ts.map +1 -0
- package/dist/cache/types.d.ts +93 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/config/ConfigLoader.d.ts +69 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +133 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/config/defaults.d.ts +125 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +191 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/presets.d.ts +32 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/presets.js +11 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/config/types.d.ts +199 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/validation.d.ts +19 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +232 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/controllers/PlaybackController.d.ts +55 -0
- package/dist/controllers/PlaybackController.d.ts.map +1 -0
- package/dist/controllers/PlaybackController.js +369 -0
- package/dist/controllers/PlaybackController.js.map +1 -0
- package/dist/controllers/PreRenderService.d.ts +34 -0
- package/dist/controllers/PreRenderService.d.ts.map +1 -0
- package/dist/controllers/PreRenderService.js +83 -0
- package/dist/controllers/PreRenderService.js.map +1 -0
- package/dist/controllers/PreRenderTaskQueue.d.ts +21 -0
- package/dist/controllers/PreRenderTaskQueue.d.ts.map +1 -0
- package/dist/controllers/PreviewHandle.d.ts +23 -0
- package/dist/controllers/PreviewHandle.d.ts.map +1 -0
- package/dist/controllers/PreviewHandle.js +39 -0
- package/dist/controllers/PreviewHandle.js.map +1 -0
- package/dist/controllers/index.d.ts +8 -0
- package/dist/controllers/index.d.ts.map +1 -0
- package/dist/controllers/types.d.ts +102 -0
- package/dist/controllers/types.d.ts.map +1 -0
- package/dist/event/EventBus.d.ts +42 -0
- package/dist/event/EventBus.d.ts.map +1 -0
- package/dist/event/EventBus.js +94 -0
- package/dist/event/EventBus.js.map +1 -0
- package/dist/event/events.d.ts +371 -0
- package/dist/event/events.d.ts.map +1 -0
- package/dist/event/events.js +71 -0
- package/dist/event/events.js.map +1 -0
- package/dist/event/index.d.ts +4 -0
- package/dist/event/index.d.ts.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/model/CompositionModel.d.ts +48 -0
- package/dist/model/CompositionModel.d.ts.map +1 -0
- package/dist/model/CompositionModel.js +197 -0
- package/dist/model/CompositionModel.js.map +1 -0
- package/dist/model/RcFrame.d.ts +34 -0
- package/dist/model/RcFrame.d.ts.map +1 -0
- package/dist/model/RcFrame.js +97 -0
- package/dist/model/RcFrame.js.map +1 -0
- package/dist/model/dirty-range.d.ts +5 -0
- package/dist/model/dirty-range.d.ts.map +1 -0
- package/dist/model/dirty-range.js +220 -0
- package/dist/model/dirty-range.js.map +1 -0
- package/dist/model/index.d.ts +7 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/patch.d.ts +5 -0
- package/dist/model/patch.d.ts.map +1 -0
- package/dist/model/patch.js +250 -0
- package/dist/model/patch.js.map +1 -0
- package/dist/model/types.d.ts +135 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +5 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validation.d.ts +15 -0
- package/dist/model/validation.d.ts.map +1 -0
- package/dist/model/validation.js +74 -0
- package/dist/model/validation.js.map +1 -0
- package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js +7046 -0
- package/dist/node_modules/.pnpm/mp4box@0.5.4/node_modules/mp4box/dist/mp4box.all.js.map +1 -0
- package/dist/orchestrator/ClipSessionManager.d.ts +75 -0
- package/dist/orchestrator/ClipSessionManager.d.ts.map +1 -0
- package/dist/orchestrator/ClipSessionManager.js +160 -0
- package/dist/orchestrator/ClipSessionManager.js.map +1 -0
- package/dist/orchestrator/CompositionPlanner.d.ts +55 -0
- package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -0
- package/dist/orchestrator/CompositionPlanner.js +411 -0
- package/dist/orchestrator/CompositionPlanner.js.map +1 -0
- package/dist/orchestrator/Orchestrator.d.ts +59 -0
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/Orchestrator.js +390 -0
- package/dist/orchestrator/Orchestrator.js.map +1 -0
- package/dist/orchestrator/VideoClipSession.d.ts +64 -0
- package/dist/orchestrator/VideoClipSession.d.ts.map +1 -0
- package/dist/orchestrator/VideoClipSession.js +309 -0
- package/dist/orchestrator/VideoClipSession.js.map +1 -0
- package/dist/orchestrator/index.d.ts +5 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/types.d.ts +64 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/plugins/BackpressureMonitor.d.ts +33 -0
- package/dist/plugins/BackpressureMonitor.d.ts.map +1 -0
- package/dist/plugins/BackpressureMonitor.js +62 -0
- package/dist/plugins/BackpressureMonitor.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +37 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +66 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/types.d.ts +60 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/stages/compose/AudioDucker.d.ts +59 -0
- package/dist/stages/compose/AudioDucker.d.ts.map +1 -0
- package/dist/stages/compose/AudioDucker.js +161 -0
- package/dist/stages/compose/AudioDucker.js.map +1 -0
- package/dist/stages/compose/AudioMixer.d.ts +29 -0
- package/dist/stages/compose/AudioMixer.d.ts.map +1 -0
- package/dist/stages/compose/AudioMixer.js +373 -0
- package/dist/stages/compose/AudioMixer.js.map +1 -0
- package/dist/stages/compose/FilterProcessor.d.ts +41 -0
- package/dist/stages/compose/FilterProcessor.d.ts.map +1 -0
- package/dist/stages/compose/FilterProcessor.js +226 -0
- package/dist/stages/compose/FilterProcessor.js.map +1 -0
- package/dist/stages/compose/GlobalAudioSession.d.ts +38 -0
- package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -0
- package/dist/stages/compose/GlobalAudioSession.js +122 -0
- package/dist/stages/compose/GlobalAudioSession.js.map +1 -0
- package/dist/stages/compose/LayerRenderer.d.ts +30 -0
- package/dist/stages/compose/LayerRenderer.d.ts.map +1 -0
- package/dist/stages/compose/LayerRenderer.js +215 -0
- package/dist/stages/compose/LayerRenderer.js.map +1 -0
- package/dist/stages/compose/OfflineAudioMixer.d.ts +14 -0
- package/dist/stages/compose/OfflineAudioMixer.d.ts.map +1 -0
- package/dist/stages/compose/OfflineAudioMixer.js +68 -0
- package/dist/stages/compose/OfflineAudioMixer.js.map +1 -0
- package/dist/stages/compose/TransitionProcessor.d.ts +30 -0
- package/dist/stages/compose/TransitionProcessor.d.ts.map +1 -0
- package/dist/stages/compose/TransitionProcessor.js +189 -0
- package/dist/stages/compose/TransitionProcessor.js.map +1 -0
- package/dist/stages/compose/VideoComposer.d.ts +30 -0
- package/dist/stages/compose/VideoComposer.d.ts.map +1 -0
- package/dist/stages/compose/VideoComposer.js +186 -0
- package/dist/stages/compose/VideoComposer.js.map +1 -0
- package/dist/stages/compose/audio-compose.worker.d.ts +79 -0
- package/dist/stages/compose/audio-compose.worker.d.ts.map +1 -0
- package/dist/stages/compose/audio-compose.worker.js +541 -0
- package/dist/stages/compose/audio-compose.worker.js.map +1 -0
- package/dist/stages/compose/instructions.d.ts +95 -0
- package/dist/stages/compose/instructions.d.ts.map +1 -0
- package/dist/stages/compose/types.d.ts +245 -0
- package/dist/stages/compose/types.d.ts.map +1 -0
- package/dist/stages/compose/video-compose.worker.d.ts +60 -0
- package/dist/stages/compose/video-compose.worker.d.ts.map +1 -0
- package/dist/stages/compose/video-compose.worker.js +369 -0
- package/dist/stages/compose/video-compose.worker.js.map +1 -0
- package/dist/stages/decode/AudioChunkDecoder.d.ts +41 -0
- package/dist/stages/decode/AudioChunkDecoder.d.ts.map +1 -0
- package/dist/stages/decode/AudioChunkDecoder.js +83 -0
- package/dist/stages/decode/AudioChunkDecoder.js.map +1 -0
- package/dist/stages/decode/BaseDecoder.d.ts +35 -0
- package/dist/stages/decode/BaseDecoder.d.ts.map +1 -0
- package/dist/stages/decode/BaseDecoder.js +130 -0
- package/dist/stages/decode/BaseDecoder.js.map +1 -0
- package/dist/stages/decode/VideoChunkDecoder.d.ts +54 -0
- package/dist/stages/decode/VideoChunkDecoder.d.ts.map +1 -0
- package/dist/stages/decode/VideoChunkDecoder.js +209 -0
- package/dist/stages/decode/VideoChunkDecoder.js.map +1 -0
- package/dist/stages/decode/decode.worker.d.ts +70 -0
- package/dist/stages/decode/decode.worker.d.ts.map +1 -0
- package/dist/stages/decode/decode.worker.js +436 -0
- package/dist/stages/decode/decode.worker.js.map +1 -0
- package/dist/stages/decode/index.d.ts +5 -0
- package/dist/stages/decode/index.d.ts.map +1 -0
- package/dist/stages/decode/types.d.ts +108 -0
- package/dist/stages/decode/types.d.ts.map +1 -0
- package/dist/stages/demux/MP3FrameParser.d.ts +33 -0
- package/dist/stages/demux/MP3FrameParser.d.ts.map +1 -0
- package/dist/stages/demux/MP3FrameParser.js +186 -0
- package/dist/stages/demux/MP3FrameParser.js.map +1 -0
- package/dist/stages/demux/MP4Demuxer.d.ts +45 -0
- package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -0
- package/dist/stages/demux/MP4Demuxer.js +227 -0
- package/dist/stages/demux/MP4Demuxer.js.map +1 -0
- package/dist/stages/demux/aac-esds-extractor.d.ts +7 -0
- package/dist/stages/demux/aac-esds-extractor.d.ts.map +1 -0
- package/dist/stages/demux/audio-demux.worker.d.ts +51 -0
- package/dist/stages/demux/audio-demux.worker.d.ts.map +1 -0
- package/dist/stages/demux/audio-demux.worker.js +312 -0
- package/dist/stages/demux/audio-demux.worker.js.map +1 -0
- package/dist/stages/demux/types.d.ts +77 -0
- package/dist/stages/demux/types.d.ts.map +1 -0
- package/dist/stages/demux/video-demux.worker.d.ts +48 -0
- package/dist/stages/demux/video-demux.worker.d.ts.map +1 -0
- package/dist/stages/demux/video-demux.worker.js +173 -0
- package/dist/stages/demux/video-demux.worker.js.map +1 -0
- package/dist/stages/encode/AudioChunkEncoder.d.ts +21 -0
- package/dist/stages/encode/AudioChunkEncoder.d.ts.map +1 -0
- package/dist/stages/encode/AudioChunkEncoder.js +37 -0
- package/dist/stages/encode/AudioChunkEncoder.js.map +1 -0
- package/dist/stages/encode/BaseEncoder.d.ts +44 -0
- package/dist/stages/encode/BaseEncoder.d.ts.map +1 -0
- package/dist/stages/encode/BaseEncoder.js +164 -0
- package/dist/stages/encode/BaseEncoder.js.map +1 -0
- package/dist/stages/encode/EncoderPool.d.ts +28 -0
- package/dist/stages/encode/EncoderPool.d.ts.map +1 -0
- package/dist/stages/encode/VideoChunkEncoder.d.ts +26 -0
- package/dist/stages/encode/VideoChunkEncoder.d.ts.map +1 -0
- package/dist/stages/encode/VideoChunkEncoder.js +50 -0
- package/dist/stages/encode/VideoChunkEncoder.js.map +1 -0
- package/dist/stages/encode/encode.worker.d.ts +3 -0
- package/dist/stages/encode/encode.worker.d.ts.map +1 -0
- package/dist/stages/encode/encode.worker.js +318 -0
- package/dist/stages/encode/encode.worker.js.map +1 -0
- package/dist/stages/encode/index.d.ts +6 -0
- package/dist/stages/encode/index.d.ts.map +1 -0
- package/dist/stages/encode/types.d.ts +127 -0
- package/dist/stages/encode/types.d.ts.map +1 -0
- package/dist/stages/load/EventHandlers.d.ts +35 -0
- package/dist/stages/load/EventHandlers.d.ts.map +1 -0
- package/dist/stages/load/EventHandlers.js +65 -0
- package/dist/stages/load/EventHandlers.js.map +1 -0
- package/dist/stages/load/ResourceLoader.d.ts +36 -0
- package/dist/stages/load/ResourceLoader.d.ts.map +1 -0
- package/dist/stages/load/ResourceLoader.js +184 -0
- package/dist/stages/load/ResourceLoader.js.map +1 -0
- package/dist/stages/load/StreamFactory.d.ts +42 -0
- package/dist/stages/load/StreamFactory.d.ts.map +1 -0
- package/dist/stages/load/StreamFactory.js +201 -0
- package/dist/stages/load/StreamFactory.js.map +1 -0
- package/dist/stages/load/TaskManager.d.ts +50 -0
- package/dist/stages/load/TaskManager.d.ts.map +1 -0
- package/dist/stages/load/TaskManager.js +103 -0
- package/dist/stages/load/TaskManager.js.map +1 -0
- package/dist/stages/load/WindowByteRangeResolver.d.ts +47 -0
- package/dist/stages/load/WindowByteRangeResolver.d.ts.map +1 -0
- package/dist/stages/load/WindowByteRangeResolver.js +270 -0
- package/dist/stages/load/WindowByteRangeResolver.js.map +1 -0
- package/dist/stages/load/index.d.ts +11 -0
- package/dist/stages/load/index.d.ts.map +1 -0
- package/dist/stages/load/types.d.ts +177 -0
- package/dist/stages/load/types.d.ts.map +1 -0
- package/dist/stages/mux/MP4Muxer.d.ts +44 -0
- package/dist/stages/mux/MP4Muxer.d.ts.map +1 -0
- package/dist/stages/mux/MP4Muxer.js +262 -0
- package/dist/stages/mux/MP4Muxer.js.map +1 -0
- package/dist/stages/mux/OPFSWriter.d.ts +46 -0
- package/dist/stages/mux/OPFSWriter.d.ts.map +1 -0
- package/dist/stages/mux/index.d.ts +5 -0
- package/dist/stages/mux/index.d.ts.map +1 -0
- package/dist/stages/mux/mux.worker.d.ts +65 -0
- package/dist/stages/mux/mux.worker.d.ts.map +1 -0
- package/dist/stages/mux/mux.worker.js +219 -0
- package/dist/stages/mux/mux.worker.js.map +1 -0
- package/dist/stages/mux/types.d.ts +95 -0
- package/dist/stages/mux/types.d.ts.map +1 -0
- package/dist/stages/mux/utils.d.ts +32 -0
- package/dist/stages/mux/utils.d.ts.map +1 -0
- package/dist/stages/mux/utils.js +34 -0
- package/dist/stages/mux/utils.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/BackpressureAdapter.d.ts +26 -0
- package/dist/utils/BackpressureAdapter.d.ts.map +1 -0
- package/dist/utils/binary-search.d.ts +33 -0
- package/dist/utils/binary-search.d.ts.map +1 -0
- package/dist/utils/binary-search.js +62 -0
- package/dist/utils/binary-search.js.map +1 -0
- package/dist/utils/canvas-utils.d.ts +96 -0
- package/dist/utils/canvas-utils.d.ts.map +1 -0
- package/dist/utils/canvas-utils.js +58 -0
- package/dist/utils/canvas-utils.js.map +1 -0
- package/dist/utils/object-utils.d.ts +34 -0
- package/dist/utils/object-utils.d.ts.map +1 -0
- package/dist/utils/object-utils.js +22 -0
- package/dist/utils/object-utils.js.map +1 -0
- package/dist/utils/time-utils.d.ts +10 -0
- package/dist/utils/time-utils.d.ts.map +1 -0
- package/dist/utils/time-utils.js +60 -0
- package/dist/utils/time-utils.js.map +1 -0
- package/dist/worker/BaseWorker.d.ts +44 -0
- package/dist/worker/BaseWorker.d.ts.map +1 -0
- package/dist/worker/BaseWorker.js +98 -0
- package/dist/worker/BaseWorker.js.map +1 -0
- package/dist/worker/WorkerChannel.d.ts +105 -0
- package/dist/worker/WorkerChannel.d.ts.map +1 -0
- package/dist/worker/WorkerChannel.js +355 -0
- package/dist/worker/WorkerChannel.js.map +1 -0
- package/dist/worker/WorkerPool.d.ts +52 -0
- package/dist/worker/WorkerPool.d.ts.map +1 -0
- package/dist/worker/WorkerPool.js +124 -0
- package/dist/worker/WorkerPool.js.map +1 -0
- package/dist/worker/index.d.ts +11 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/transferable-helper.d.ts +89 -0
- package/dist/worker/transferable-helper.d.ts.map +1 -0
- package/dist/worker/transferable-helper.js +44 -0
- package/dist/worker/transferable-helper.js.map +1 -0
- package/dist/worker/types.d.ts +179 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +50 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/worker-event-whitelist.d.ts +23 -0
- package/dist/worker/worker-event-whitelist.d.ts.map +1 -0
- package/dist/worker/worker-retry.d.ts +36 -0
- package/dist/worker/worker-retry.d.ts.map +1 -0
- package/dist/worker/worker-retry.js +55 -0
- package/dist/worker/worker-retry.js.map +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-demux.worker.js","sources":["../../../src/stages/demux/video-demux.worker.ts"],"sourcesContent":["import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { MP4Demuxer } from './MP4Demuxer';\nimport type { DemuxConfig } from './types';\n\ninterface LoaderStreamMetadata {\n direction?: 'upstream' | string;\n clipId?: string;\n resourceId?: string;\n byteStart?: number;\n byteEnd?: number;\n range?: { start: number; end: number };\n}\n/**\n * VideoDemuxWorker - First stage for video processing\n * Extracts video tracks from container formats (MP4, etc.)\n *\n * Pipeline: ResourceLoader (Main Thread) → VideoDemuxWorker → DecodeWorker\n *\n * Features:\n * - MP4 container demuxing with mp4box.js\n * - Stream-based processing with backpressure\n * - Direct streaming to DecodeWorker\n */\nexport class VideoDemuxWorker {\n private channel: WorkerChannel;\n private demuxer: MP4Demuxer | null = null;\n private resourceId: string | null = null;\n private clipId?: string;\n private downstreamPort: MessagePort | null = null;\n private range?: { start: number; end: number };\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self as DedicatedWorkerGlobalScope, {\n name: 'VideoDemuxWorker',\n timeout: 30000,\n });\n this.setupHandlers();\n }\n\n /* @better-ai.mdc For test visibility */\n protected setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.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 ResourceLoader (main thread)\n this.channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n\n /**\n * Handle connection from orchestrator\n */\n private async handleConnect(payload: {\n port?: MessagePort;\n streamType?: string;\n clipId?: string;\n }): Promise<{ success: boolean }> {\n const { port, clipId } = payload;\n\n if (!port) {\n return { success: false };\n }\n\n // Store connection to decoder worker\n this.downstreamPort = port;\n this.clipId = clipId;\n\n return { success: true };\n }\n\n /**\n * Configure demuxer with format settings\n * @param payload.config - Demuxer configuration\n * @param payload.initial - If true, initialize worker state; otherwise just update config\n */\n private async handleConfigure(payload: {\n config: DemuxConfig;\n initial?: boolean;\n }): Promise<{ success: boolean; tracks?: any[] }> {\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 demuxer instance\n if (this.demuxer) {\n this.demuxer.destroy();\n }\n\n this.demuxer = new MP4Demuxer({\n ...config,\n skipAudio: true, // Video only\n onReady: () => this.handleDemuxerReady(),\n });\n\n // Notify configuration complete\n this.channel.notify('configured');\n\n return { success: true };\n } else {\n // Update configuration only (e.g., backpressure settings)\n this.demuxer?.updateConfig(config);\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 * Handle input stream from ResourceLoader (main thread)\n * Strategy: Stream immediately, send codec info when ready\n */\n private async handleReceiveStream(\n stream: ReadableStream<Uint8Array | ArrayBuffer>,\n metadata?: LoaderStreamMetadata\n ): Promise<void> {\n console.log('[VideoDemuxWorker] handleReceiveStream', metadata?.clipId, metadata?.resourceId);\n\n const currentResourceId =\n metadata?.resourceId || metadata?.clipId || this.resourceId || 'default';\n const clipId = metadata?.clipId;\n\n // According to ARCHITECTURE_VNEXT, one worker should only handle one resource\n // If resource changes, it's a bug in Orchestrator\n if (this.resourceId && this.resourceId !== currentResourceId) {\n throw new Error(\n `[VideoDemuxWorker] BUG: Resource ID changed from ${this.resourceId} to ${currentResourceId}. ` +\n `Each VideoDemuxWorker instance should only handle one resource.`\n );\n }\n\n if (!this.resourceId) {\n this.resourceId = currentResourceId;\n }\n\n // Initialize demuxer on first stream (not on every stream)\n if (!this.demuxer) {\n this.demuxer = new MP4Demuxer({\n highWaterMark: 10,\n skipAudio: true, // Video only\n onReady: () => this.handleDemuxerReady(),\n });\n }\n\n if (!this.downstreamPort) {\n throw new Error('Decoder not connected');\n }\n\n if (clipId) {\n this.clipId = clipId;\n }\n\n if (metadata?.range) {\n this.range = metadata.range;\n }\n\n // Create transform stream immediately\n const videoStream = this.demuxer.createVideoStream();\n // Send stream to decoder immediately (without codec info)\n const downstreamChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoDemux-Decoder',\n timeout: 30000,\n });\n\n // Send stream first, codec info will follow when ready\n downstreamChannel.sendStream(videoStream.readable, {\n streamType: 'video',\n clipId: this.clipId,\n ...(this.range && { range: this.range }),\n // codec info will be sent separately when ready\n });\n\n await stream.pipeTo(videoStream!.writable);\n }\n\n private handleDemuxerReady(): void {\n if (!this.demuxer || !this.downstreamPort) {\n return;\n }\n\n const videoTrackInfo = this.demuxer.videoTrackInfo;\n if (!videoTrackInfo) {\n console.error('[VideoDemuxWorker] No video track found after ready');\n return;\n }\n\n const downstreamChannel = new WorkerChannel(this.downstreamPort, {\n name: 'VideoDemux-Decoder',\n timeout: 30000,\n });\n\n downstreamChannel.send('configure' as any, {\n clipId: this.clipId,\n streamType: 'video',\n codec: videoTrackInfo.codec,\n width: videoTrackInfo.width,\n height: videoTrackInfo.height,\n ...(this.range && { range: this.range }),\n description: videoTrackInfo.description,\n });\n }\n\n /**\n * Get demuxer statistics\n */\n private async handleGetStats(): Promise<{\n queueSize?: number;\n tracksInfo?: any[];\n state?: WorkerState;\n }> {\n if (!this.demuxer) {\n return { state: this.channel.state };\n }\n\n return {\n tracksInfo: Array.from(this.demuxer.tracks.values()),\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 demuxer\n this.demuxer?.destroy();\n this.demuxer = null;\n this.resourceId = null;\n\n // Close connections\n this.downstreamPort?.close();\n this.downstreamPort = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n// Initialize worker\nconst worker = new VideoDemuxWorker();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseEncoder } from './BaseEncoder';
|
|
2
|
+
import { AudioEncoderConfig } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AudioChunkEncoder - Encodes AudioData to EncodedAudioChunk
|
|
6
|
+
* Stream-based encoder with backpressure handling
|
|
7
|
+
*/
|
|
8
|
+
export declare class AudioChunkEncoder extends BaseEncoder<AudioEncoder, AudioEncoderConfig, AudioData, EncodedAudioChunk, EncodedAudioChunkMetadata> {
|
|
9
|
+
private static readonly DEFAULT_HIGH_WATER_MARK;
|
|
10
|
+
private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD;
|
|
11
|
+
protected readonly highWaterMark: number;
|
|
12
|
+
protected readonly encodeQueueThreshold: number;
|
|
13
|
+
constructor(config: AudioEncoderConfig);
|
|
14
|
+
protected isConfigSupported(config: AudioEncoderConfig): Promise<{
|
|
15
|
+
supported: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
protected createEncoder(init: AudioEncoderInit): AudioEncoder;
|
|
18
|
+
protected getEncoderType(): string;
|
|
19
|
+
encode(data: AudioData): void;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=AudioChunkEncoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioChunkEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/AudioChunkEncoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,WAAW,CAChD,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,yBAAyB,CAC1B;IACC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAK;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAM;IAE5D,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;gBAEpC,MAAM,EAAE,kBAAkB;cAUtB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAK9F,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY;IAI7D,SAAS,CAAC,cAAc,IAAI,MAAM;IAIlC,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;CAiB9B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseEncoder } from "./BaseEncoder.js";
|
|
2
|
+
class AudioChunkEncoder extends BaseEncoder {
|
|
3
|
+
static DEFAULT_HIGH_WATER_MARK = 4;
|
|
4
|
+
static DEFAULT_ENCODE_QUEUE_THRESHOLD = 16;
|
|
5
|
+
highWaterMark;
|
|
6
|
+
encodeQueueThreshold;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
super(config);
|
|
9
|
+
this.highWaterMark = config.backpressure?.highWaterMark ?? AudioChunkEncoder.DEFAULT_HIGH_WATER_MARK;
|
|
10
|
+
this.encodeQueueThreshold = config.backpressure?.encodeQueueThreshold ?? AudioChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;
|
|
11
|
+
}
|
|
12
|
+
async isConfigSupported(config) {
|
|
13
|
+
const result = await AudioEncoder.isConfigSupported(config);
|
|
14
|
+
return { supported: result.supported ?? false };
|
|
15
|
+
}
|
|
16
|
+
createEncoder(init) {
|
|
17
|
+
return new AudioEncoder(init);
|
|
18
|
+
}
|
|
19
|
+
getEncoderType() {
|
|
20
|
+
return "Audio";
|
|
21
|
+
}
|
|
22
|
+
encode(data) {
|
|
23
|
+
if (this.encoder?.state !== "configured") {
|
|
24
|
+
throw new Error("Audio encoder not configured");
|
|
25
|
+
}
|
|
26
|
+
const config = this.getConfig();
|
|
27
|
+
if (data.sampleRate !== config.sampleRate || data.numberOfChannels !== config.numberOfChannels) {
|
|
28
|
+
throw new Error("AudioData requires resampling or channel remap before encoding");
|
|
29
|
+
}
|
|
30
|
+
this.encoder.encode(data);
|
|
31
|
+
data.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
AudioChunkEncoder
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=AudioChunkEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioChunkEncoder.js","sources":["../../../src/stages/encode/AudioChunkEncoder.ts"],"sourcesContent":["import { BaseEncoder } from './BaseEncoder';\nimport type { AudioEncoderConfig } from './types';\n\n/**\n * AudioChunkEncoder - Encodes AudioData to EncodedAudioChunk\n * Stream-based encoder with backpressure handling\n */\nexport class AudioChunkEncoder extends BaseEncoder<\n AudioEncoder,\n AudioEncoderConfig,\n AudioData,\n EncodedAudioChunk,\n EncodedAudioChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 4;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 16;\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n constructor(config: AudioEncoderConfig) {\n super(config);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n config.backpressure?.highWaterMark ?? AudioChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n config.backpressure?.encodeQueueThreshold ?? AudioChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: AudioEncoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: AudioEncoderInit): AudioEncoder {\n return new AudioEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Audio';\n }\n\n encode(data: AudioData): void {\n if (this.encoder?.state !== 'configured') {\n throw new Error('Audio encoder not configured');\n }\n\n // Ensure input data matches encoder configuration\n const config = this.getConfig();\n if (\n data.sampleRate !== config.sampleRate ||\n data.numberOfChannels !== config.numberOfChannels\n ) {\n throw new Error('AudioData requires resampling or channel remap before encoding');\n }\n\n this.encoder.encode(data);\n data.close();\n }\n}\n"],"names":[],"mappings":";AAOO,MAAM,0BAA0B,YAMrC;AAAA,EACA,OAAwB,0BAA0B;AAAA,EAClD,OAAwB,iCAAiC;AAAA,EAEtC;AAAA,EACA;AAAA,EAEnB,YAAY,QAA4B;AACtC,UAAM,MAAM;AAGZ,SAAK,gBACH,OAAO,cAAc,iBAAiB,kBAAkB;AAC1D,SAAK,uBACH,OAAO,cAAc,wBAAwB,kBAAkB;AAAA,EACnE;AAAA,EAEA,MAAgB,kBAAkB,QAA6D;AAC7F,UAAM,SAAS,MAAM,aAAa,kBAAkB,MAAM;AAC1D,WAAO,EAAE,WAAW,OAAO,aAAa,MAAA;AAAA,EAC1C;AAAA,EAEU,cAAc,MAAsC;AAC5D,WAAO,IAAI,aAAa,IAAI;AAAA,EAC9B;AAAA,EAEU,iBAAyB;AACjC,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,MAAuB;AAC5B,QAAI,KAAK,SAAS,UAAU,cAAc;AACxC,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAGA,UAAM,SAAS,KAAK,UAAA;AACpB,QACE,KAAK,eAAe,OAAO,cAC3B,KAAK,qBAAqB,OAAO,kBACjC;AACA,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AAEA,SAAK,QAAQ,OAAO,IAAI;AACxB,SAAK,MAAA;AAAA,EACP;AACF;"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base encoder class for both video and audio encoding
|
|
3
|
+
* Handles common WebCodecs encoder operations
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class BaseEncoder<TEncoder extends VideoEncoder | AudioEncoder, TConfig extends VideoEncoderConfig | AudioEncoderConfig, TInput extends VideoFrame | AudioData, TChunk extends EncodedVideoChunk | EncodedAudioChunk, TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata> {
|
|
6
|
+
protected encoder?: TEncoder;
|
|
7
|
+
protected config: TConfig;
|
|
8
|
+
protected controller: TransformStreamDefaultController<TChunk> | null;
|
|
9
|
+
constructor(config: TConfig);
|
|
10
|
+
getConfig(): TConfig;
|
|
11
|
+
protected get currentConfig(): TConfig;
|
|
12
|
+
protected shouldReconfigure(partial: Partial<TConfig>): boolean;
|
|
13
|
+
protected hasConfigChanged(next: TConfig): boolean;
|
|
14
|
+
protected configsEqual(a: TConfig, b: TConfig): boolean;
|
|
15
|
+
initialize(): Promise<void>;
|
|
16
|
+
reconfigure(config: Partial<TConfig>): Promise<void>;
|
|
17
|
+
flush(): Promise<void>;
|
|
18
|
+
reset(): Promise<void>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
get isReady(): boolean;
|
|
21
|
+
get queueSize(): number;
|
|
22
|
+
protected handleOutput(chunk: TChunk, _metadata: TMetadata): void;
|
|
23
|
+
protected handleError(error: DOMException): void;
|
|
24
|
+
protected abstract isConfigSupported(config: TConfig): Promise<{
|
|
25
|
+
supported: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
protected abstract createEncoder(init: EncoderInit): TEncoder;
|
|
28
|
+
protected abstract getEncoderType(): string;
|
|
29
|
+
protected onReset(): void;
|
|
30
|
+
protected abstract readonly highWaterMark: number;
|
|
31
|
+
protected abstract readonly encodeQueueThreshold: number;
|
|
32
|
+
/**
|
|
33
|
+
* Create transform stream for encoding
|
|
34
|
+
* Implements common stream logic with backpressure handling
|
|
35
|
+
*/
|
|
36
|
+
createStream(): TransformStream<TInput, TChunk>;
|
|
37
|
+
abstract encode(input: TInput): void;
|
|
38
|
+
}
|
|
39
|
+
interface EncoderInit {
|
|
40
|
+
output: (chunk: any, metadata: any) => void;
|
|
41
|
+
error: (error: DOMException) => void;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=BaseEncoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/BaseEncoder.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,MAAM,SAAS,UAAU,GAAG,SAAS,EACrC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,EACpD,SAAS,SAAS,yBAAyB,GAAG,yBAAyB;IAEvE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,UAAU,EAAE,gCAAgC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAQ;gBAEjE,MAAM,EAAE,OAAO;IAI3B,SAAS,IAAI,OAAO;IAIpB,SAAS,KAAK,aAAa,IAAI,OAAO,CAErC;IAED,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAW/D,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBlD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IAIjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAKjE,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAMhD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACtF,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ;IAC7D,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,MAAM;IAG3C,SAAS,CAAC,OAAO,IAAI,IAAI;IAKzB,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEzD;;;OAGG;IACH,YAAY,IAAI,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC;IAiD/C,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CACrC;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5C,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CACtC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
class BaseEncoder {
|
|
2
|
+
encoder;
|
|
3
|
+
config;
|
|
4
|
+
controller = null;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
getConfig() {
|
|
9
|
+
return { ...this.config };
|
|
10
|
+
}
|
|
11
|
+
get currentConfig() {
|
|
12
|
+
return this.config;
|
|
13
|
+
}
|
|
14
|
+
shouldReconfigure(partial) {
|
|
15
|
+
const next = { ...this.config, ...partial };
|
|
16
|
+
const keys = Object.keys(partial ?? {});
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
if (partial[key] !== void 0 && next[key] !== this.config[key]) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
hasConfigChanged(next) {
|
|
25
|
+
const currentEntries = Object.entries(this.config);
|
|
26
|
+
for (const [key, value] of currentEntries) {
|
|
27
|
+
if (next[key] !== value) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const key of Object.keys(next)) {
|
|
32
|
+
if (this.config[key] !== next[key]) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
configsEqual(a, b) {
|
|
39
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
40
|
+
}
|
|
41
|
+
async initialize() {
|
|
42
|
+
if (this.encoder?.state === "configured") {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const isSupported = await this.isConfigSupported(this.config);
|
|
46
|
+
if (!isSupported.supported) {
|
|
47
|
+
throw new Error(`Codec not supported: ${this.config.codec}`);
|
|
48
|
+
}
|
|
49
|
+
this.encoder = this.createEncoder({
|
|
50
|
+
output: this.handleOutput.bind(this),
|
|
51
|
+
error: this.handleError.bind(this)
|
|
52
|
+
});
|
|
53
|
+
this.encoder.configure(this.config);
|
|
54
|
+
}
|
|
55
|
+
async reconfigure(config) {
|
|
56
|
+
if (!config || Object.keys(config).length === 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const nextConfig = { ...this.config, ...config };
|
|
60
|
+
if (this.configsEqual(this.config, nextConfig)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!this.encoder) {
|
|
64
|
+
this.config = nextConfig;
|
|
65
|
+
await this.initialize();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.encoder.state === "configured") {
|
|
69
|
+
await this.encoder.flush();
|
|
70
|
+
}
|
|
71
|
+
const isSupported = await this.isConfigSupported(nextConfig);
|
|
72
|
+
if (!isSupported.supported) {
|
|
73
|
+
throw new Error(`New configuration not supported: ${nextConfig.codec}`);
|
|
74
|
+
}
|
|
75
|
+
this.config = nextConfig;
|
|
76
|
+
this.encoder.configure(this.config);
|
|
77
|
+
}
|
|
78
|
+
async flush() {
|
|
79
|
+
if (!this.encoder) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
await this.encoder.flush();
|
|
83
|
+
}
|
|
84
|
+
async reset() {
|
|
85
|
+
if (!this.encoder) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.encoder.reset();
|
|
89
|
+
this.onReset();
|
|
90
|
+
}
|
|
91
|
+
async close() {
|
|
92
|
+
if (!this.encoder) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (this.encoder.state === "configured") {
|
|
96
|
+
await this.encoder.flush();
|
|
97
|
+
}
|
|
98
|
+
this.encoder.close();
|
|
99
|
+
this.encoder = void 0;
|
|
100
|
+
}
|
|
101
|
+
get isReady() {
|
|
102
|
+
return this.encoder?.state === "configured";
|
|
103
|
+
}
|
|
104
|
+
get queueSize() {
|
|
105
|
+
return this.encoder?.encodeQueueSize ?? 0;
|
|
106
|
+
}
|
|
107
|
+
handleOutput(chunk, _metadata) {
|
|
108
|
+
this.controller?.enqueue(chunk);
|
|
109
|
+
}
|
|
110
|
+
handleError(error) {
|
|
111
|
+
console.error(`${this.getEncoderType()} encoder error:`, error);
|
|
112
|
+
this.controller?.error(error);
|
|
113
|
+
}
|
|
114
|
+
// Hook for subclasses to handle reset
|
|
115
|
+
onReset() {
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create transform stream for encoding
|
|
119
|
+
* Implements common stream logic with backpressure handling
|
|
120
|
+
*/
|
|
121
|
+
createStream() {
|
|
122
|
+
return new TransformStream(
|
|
123
|
+
{
|
|
124
|
+
start: async (controller) => {
|
|
125
|
+
this.controller = controller;
|
|
126
|
+
if (!this.isReady) {
|
|
127
|
+
await this.initialize();
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
transform: async (input) => {
|
|
131
|
+
if (!this.encoder || this.encoder.state !== "configured") {
|
|
132
|
+
throw new Error("Encoder not configured");
|
|
133
|
+
}
|
|
134
|
+
if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
135
|
+
await new Promise((resolve) => {
|
|
136
|
+
const check = () => {
|
|
137
|
+
if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {
|
|
138
|
+
resolve();
|
|
139
|
+
} else {
|
|
140
|
+
setTimeout(check, 10);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
check();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
this.encode(input);
|
|
147
|
+
},
|
|
148
|
+
flush: async () => {
|
|
149
|
+
await this.flush();
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
// Queuing strategy with backpressure configuration
|
|
153
|
+
{
|
|
154
|
+
highWaterMark: this.highWaterMark,
|
|
155
|
+
size: () => 1
|
|
156
|
+
// Count-based
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
BaseEncoder
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=BaseEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseEncoder.js","sources":["../../../src/stages/encode/BaseEncoder.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<TChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n if (this.encoder?.state === 'configured') {\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n if (!isSupported.supported) {\n throw new Error(`Codec not supported: ${this.config.codec}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n }\n\n async close(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, _metadata: TMetadata): void {\n // Enqueue to stream controller\n this.controller?.enqueue(chunk);\n }\n\n protected handleError(error: DOMException): void {\n console.error(`${this.getEncoderType()} encoder error:`, error);\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, TChunk> {\n return new TransformStream<TInput, TChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n\n // Initialize encoder if not already initialized\n if (!this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (input) => {\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n // Check encoder queue pressure\n if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n // Wait for queue to drain\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Encode the input\n this.encode(input);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { VideoChunkEncoder } from './VideoChunkEncoder';
|
|
2
|
+
import { AudioChunkEncoder } from './AudioChunkEncoder';
|
|
3
|
+
import { VideoEncoderConfig, AudioEncoderConfig, EncoderPoolOptions } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* EncoderPool - Manages encoder instances for reuse
|
|
7
|
+
* Reduces encoder creation overhead by pooling and reusing instances
|
|
8
|
+
*/
|
|
9
|
+
export declare class EncoderPool {
|
|
10
|
+
private videoEncoders;
|
|
11
|
+
private audioEncoders;
|
|
12
|
+
private encoderHandles;
|
|
13
|
+
private options;
|
|
14
|
+
private nextId;
|
|
15
|
+
constructor(options?: EncoderPoolOptions);
|
|
16
|
+
acquireVideoEncoder(config: VideoEncoderConfig, _outputCallback?: (chunk: EncodedVideoChunk, metadata: EncodedVideoChunkMetadata) => void, _errorCallback?: (error: DOMException) => void): Promise<string>;
|
|
17
|
+
acquireAudioEncoder(config: AudioEncoderConfig, _outputCallback?: (chunk: EncodedAudioChunk, metadata: EncodedAudioChunkMetadata) => void, _errorCallback?: (error: DOMException) => void): Promise<string>;
|
|
18
|
+
getVideoEncoder(id: string): VideoChunkEncoder | undefined;
|
|
19
|
+
getAudioEncoder(id: string): AudioChunkEncoder | undefined;
|
|
20
|
+
releaseEncoder(id: string): Promise<void>;
|
|
21
|
+
markAsIdle(id: string): void;
|
|
22
|
+
closeAll(): Promise<void>;
|
|
23
|
+
private findReusableEncoder;
|
|
24
|
+
private evictLRUEncoder;
|
|
25
|
+
private isConfigEqual;
|
|
26
|
+
private generateId;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=EncoderPool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncoderPool.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/EncoderPool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAAK;gBAEP,OAAO,GAAE,kBAAuB;IAStC,mBAAmB,CACvB,MAAM,EAAE,kBAAkB,EAC1B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,yBAAyB,KAAK,IAAI,EACzF,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAC7C,OAAO,CAAC,MAAM,CAAC;IAsDZ,mBAAmB,CACvB,MAAM,EAAE,kBAAkB,EAC1B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,yBAAyB,KAAK,IAAI,EACzF,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAC7C,OAAO,CAAC,MAAM,CAAC;IAsDlB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAI1D,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIpD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BaseEncoder } from './BaseEncoder';
|
|
2
|
+
import { VideoEncoderConfig } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* VideoChunkEncoder - Encodes VideoFrame to EncodedVideoChunk
|
|
6
|
+
* Stream-based encoder with backpressure handling
|
|
7
|
+
*/
|
|
8
|
+
export declare class VideoChunkEncoder extends BaseEncoder<VideoEncoder, VideoEncoderConfig, VideoFrame, EncodedVideoChunk, EncodedVideoChunkMetadata> {
|
|
9
|
+
private static readonly DEFAULT_HIGH_WATER_MARK;
|
|
10
|
+
private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD;
|
|
11
|
+
protected readonly highWaterMark: number;
|
|
12
|
+
protected readonly encodeQueueThreshold: number;
|
|
13
|
+
private frameCount;
|
|
14
|
+
private keyFrameInterval;
|
|
15
|
+
constructor(config: VideoEncoderConfig);
|
|
16
|
+
protected isConfigSupported(config: VideoEncoderConfig): Promise<{
|
|
17
|
+
supported: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
protected createEncoder(init: VideoEncoderInit): VideoEncoder;
|
|
20
|
+
protected getEncoderType(): string;
|
|
21
|
+
protected onReset(): void;
|
|
22
|
+
encode(frame: VideoFrame): void;
|
|
23
|
+
setKeyFrameInterval(interval: number): void;
|
|
24
|
+
private shouldGenerateKeyFrame;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=VideoChunkEncoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoChunkEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/VideoChunkEncoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,WAAW,CAChD,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,yBAAyB,CAC1B;IACC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAK;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAK;IAE3D,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEhD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAAM;gBAElB,MAAM,EAAE,kBAAkB;cAUtB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAK9F,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY;IAI7D,SAAS,CAAC,cAAc,IAAI,MAAM;cAIf,OAAO,IAAI,IAAI;IAIlC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAW/B,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI3C,OAAO,CAAC,sBAAsB;CAM/B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BaseEncoder } from "./BaseEncoder.js";
|
|
2
|
+
class VideoChunkEncoder extends BaseEncoder {
|
|
3
|
+
static DEFAULT_HIGH_WATER_MARK = 2;
|
|
4
|
+
static DEFAULT_ENCODE_QUEUE_THRESHOLD = 8;
|
|
5
|
+
highWaterMark;
|
|
6
|
+
encodeQueueThreshold;
|
|
7
|
+
frameCount = 0;
|
|
8
|
+
keyFrameInterval = 60;
|
|
9
|
+
// 2 seconds at 30fps
|
|
10
|
+
constructor(config) {
|
|
11
|
+
super(config);
|
|
12
|
+
this.highWaterMark = config.backpressure?.highWaterMark ?? VideoChunkEncoder.DEFAULT_HIGH_WATER_MARK;
|
|
13
|
+
this.encodeQueueThreshold = config.backpressure?.encodeQueueThreshold ?? VideoChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;
|
|
14
|
+
}
|
|
15
|
+
async isConfigSupported(config) {
|
|
16
|
+
const result = await VideoEncoder.isConfigSupported(config);
|
|
17
|
+
return { supported: result.supported ?? false };
|
|
18
|
+
}
|
|
19
|
+
createEncoder(init) {
|
|
20
|
+
return new VideoEncoder(init);
|
|
21
|
+
}
|
|
22
|
+
getEncoderType() {
|
|
23
|
+
return "Video";
|
|
24
|
+
}
|
|
25
|
+
onReset() {
|
|
26
|
+
this.frameCount = 0;
|
|
27
|
+
}
|
|
28
|
+
encode(frame) {
|
|
29
|
+
const keyFrame = this.shouldGenerateKeyFrame();
|
|
30
|
+
const encodeOptions = {
|
|
31
|
+
keyFrame
|
|
32
|
+
};
|
|
33
|
+
this.encoder.encode(frame, encodeOptions);
|
|
34
|
+
this.frameCount++;
|
|
35
|
+
frame.close();
|
|
36
|
+
}
|
|
37
|
+
setKeyFrameInterval(interval) {
|
|
38
|
+
this.keyFrameInterval = Math.max(1, interval);
|
|
39
|
+
}
|
|
40
|
+
shouldGenerateKeyFrame() {
|
|
41
|
+
if (this.frameCount === 0) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return this.frameCount % this.keyFrameInterval === 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
VideoChunkEncoder
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=VideoChunkEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoChunkEncoder.js","sources":["../../../src/stages/encode/VideoChunkEncoder.ts"],"sourcesContent":["import { BaseEncoder } from './BaseEncoder';\nimport type { VideoEncoderConfig } from './types';\n\n/**\n * VideoChunkEncoder - Encodes VideoFrame to EncodedVideoChunk\n * Stream-based encoder with backpressure handling\n */\nexport class VideoChunkEncoder extends BaseEncoder<\n VideoEncoder,\n VideoEncoderConfig,\n VideoFrame,\n EncodedVideoChunk,\n EncodedVideoChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 2;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 8;\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n private frameCount = 0;\n private keyFrameInterval = 60; // 2 seconds at 30fps\n\n constructor(config: VideoEncoderConfig) {\n super(config);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n config.backpressure?.highWaterMark ?? VideoChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n config.backpressure?.encodeQueueThreshold ?? VideoChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: VideoEncoderConfig): Promise<{ supported: boolean }> {\n const result = await VideoEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: VideoEncoderInit): VideoEncoder {\n return new VideoEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Video';\n }\n\n protected override onReset(): void {\n this.frameCount = 0;\n }\n\n encode(frame: VideoFrame): void {\n const keyFrame = this.shouldGenerateKeyFrame();\n const encodeOptions: VideoEncoderEncodeOptions = {\n keyFrame,\n };\n\n this.encoder!.encode(frame, encodeOptions);\n this.frameCount++;\n frame.close();\n }\n\n setKeyFrameInterval(interval: number): void {\n this.keyFrameInterval = Math.max(1, interval);\n }\n\n private shouldGenerateKeyFrame(): boolean {\n if (this.frameCount === 0) {\n return true;\n }\n return this.frameCount % this.keyFrameInterval === 0;\n }\n}\n"],"names":[],"mappings":";AAOO,MAAM,0BAA0B,YAMrC;AAAA,EACA,OAAwB,0BAA0B;AAAA,EAClD,OAAwB,iCAAiC;AAAA,EAEtC;AAAA,EACA;AAAA,EAEX,aAAa;AAAA,EACb,mBAAmB;AAAA;AAAA,EAE3B,YAAY,QAA4B;AACtC,UAAM,MAAM;AAGZ,SAAK,gBACH,OAAO,cAAc,iBAAiB,kBAAkB;AAC1D,SAAK,uBACH,OAAO,cAAc,wBAAwB,kBAAkB;AAAA,EACnE;AAAA,EAEA,MAAgB,kBAAkB,QAA6D;AAC7F,UAAM,SAAS,MAAM,aAAa,kBAAkB,MAAM;AAC1D,WAAO,EAAE,WAAW,OAAO,aAAa,MAAA;AAAA,EAC1C;AAAA,EAEU,cAAc,MAAsC;AAC5D,WAAO,IAAI,aAAa,IAAI;AAAA,EAC9B;AAAA,EAEU,iBAAyB;AACjC,WAAO;AAAA,EACT;AAAA,EAEmB,UAAgB;AACjC,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,OAAO,OAAyB;AAC9B,UAAM,WAAW,KAAK,uBAAA;AACtB,UAAM,gBAA2C;AAAA,MAC/C;AAAA,IAAA;AAGF,SAAK,QAAS,OAAO,OAAO,aAAa;AACzC,SAAK;AACL,UAAM,MAAA;AAAA,EACR;AAAA,EAEA,oBAAoB,UAAwB;AAC1C,SAAK,mBAAmB,KAAK,IAAI,GAAG,QAAQ;AAAA,EAC9C;AAAA,EAEQ,yBAAkC;AACxC,QAAI,KAAK,eAAe,GAAG;AACzB,aAAO;AAAA,IACT;AACA,WAAO,KAAK,aAAa,KAAK,qBAAqB;AAAA,EACrD;AACF;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encode.worker.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/encode.worker.ts"],"names":[],"mappings":";AA0aA,wBAAoB"}
|