@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,436 @@
|
|
|
1
|
+
import { WorkerChannel } from "../../worker/WorkerChannel.js";
|
|
2
|
+
import { WorkerMessageType, WorkerState } from "../../worker/types.js";
|
|
3
|
+
import { VideoChunkDecoder } from "./VideoChunkDecoder.js";
|
|
4
|
+
import { AudioChunkDecoder } from "./AudioChunkDecoder.js";
|
|
5
|
+
const normalizeDescription = (desc) => {
|
|
6
|
+
if (!desc) return void 0;
|
|
7
|
+
if (desc instanceof ArrayBuffer) return desc;
|
|
8
|
+
const view = desc;
|
|
9
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
10
|
+
};
|
|
11
|
+
class DecodeWorker {
|
|
12
|
+
channel;
|
|
13
|
+
// Map of clipId -> decoder instance
|
|
14
|
+
videoDecoders = /* @__PURE__ */ new Map();
|
|
15
|
+
audioDecoders = /* @__PURE__ */ new Map();
|
|
16
|
+
registeredAudioTracks = /* @__PURE__ */ new Set();
|
|
17
|
+
deliveredAudioTracks = /* @__PURE__ */ new Set();
|
|
18
|
+
audioTrackMetadata = /* @__PURE__ */ new Map();
|
|
19
|
+
/** Maximum number of active decoder pairs allowed at the same time */
|
|
20
|
+
static MAX_ACTIVE_DECODERS = 8;
|
|
21
|
+
// Cached default configs merged from orchestrator
|
|
22
|
+
defaultVideoConfig = {};
|
|
23
|
+
defaultAudioConfig = {};
|
|
24
|
+
// Connections to other workers
|
|
25
|
+
composePorts = /* @__PURE__ */ new Map();
|
|
26
|
+
audioDownstreamPort = null;
|
|
27
|
+
demuxPorts = /* @__PURE__ */ new Map();
|
|
28
|
+
// Connections from demux workers
|
|
29
|
+
constructor() {
|
|
30
|
+
this.channel = new WorkerChannel(self, {
|
|
31
|
+
name: "DecodeWorker",
|
|
32
|
+
timeout: 3e4
|
|
33
|
+
});
|
|
34
|
+
this.setupHandlers();
|
|
35
|
+
}
|
|
36
|
+
setupHandlers() {
|
|
37
|
+
this.channel.registerHandler("configure", this.handleConfigure.bind(this));
|
|
38
|
+
this.channel.registerHandler("connect", this.handleConnect.bind(this));
|
|
39
|
+
this.channel.registerHandler("flush", this.handleFlush.bind(this));
|
|
40
|
+
this.channel.registerHandler("reset", this.handleReset.bind(this));
|
|
41
|
+
this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
|
|
42
|
+
this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Connect handler used by stream pipeline
|
|
46
|
+
*/
|
|
47
|
+
async handleConnect(payload) {
|
|
48
|
+
const { port, direction, clipId } = payload;
|
|
49
|
+
if (direction === "upstream") {
|
|
50
|
+
this.demuxPorts.set(clipId || "default", port);
|
|
51
|
+
const channel = new WorkerChannel(port, {
|
|
52
|
+
name: "Demux-Decode",
|
|
53
|
+
timeout: 3e4
|
|
54
|
+
});
|
|
55
|
+
channel.receiveStream((stream, metadata) => {
|
|
56
|
+
this.handleReceiveStream(stream, {
|
|
57
|
+
...metadata,
|
|
58
|
+
clipStartUs: payload.clipStartUs,
|
|
59
|
+
clipDurationUs: payload.clipDurationUs
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
channel.registerHandler("configure", this.handleConfigure.bind(this));
|
|
63
|
+
}
|
|
64
|
+
if (direction === "downstream") {
|
|
65
|
+
if (payload.streamType === "audio") {
|
|
66
|
+
this.audioDownstreamPort?.close();
|
|
67
|
+
this.audioDownstreamPort = port;
|
|
68
|
+
} else {
|
|
69
|
+
this.composePorts.set(clipId || "default", port);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { success: true };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Handle configuration message from orchestrator
|
|
76
|
+
* @param payload.initial - If true, initialize worker and recreate decoder instances; otherwise just update config
|
|
77
|
+
*/
|
|
78
|
+
async handleConfigure(payload) {
|
|
79
|
+
const {
|
|
80
|
+
clipId,
|
|
81
|
+
streamType,
|
|
82
|
+
codec,
|
|
83
|
+
width,
|
|
84
|
+
height,
|
|
85
|
+
sampleRate,
|
|
86
|
+
numberOfChannels,
|
|
87
|
+
description,
|
|
88
|
+
range
|
|
89
|
+
} = payload;
|
|
90
|
+
if (clipId && streamType) {
|
|
91
|
+
try {
|
|
92
|
+
if (streamType === "video") {
|
|
93
|
+
const decoder = this.videoDecoders.get(clipId);
|
|
94
|
+
if (decoder) {
|
|
95
|
+
await decoder.updateConfig({
|
|
96
|
+
codec,
|
|
97
|
+
width,
|
|
98
|
+
height,
|
|
99
|
+
description: normalizeDescription(description),
|
|
100
|
+
...range && { range }
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
} else if (streamType === "audio") {
|
|
104
|
+
const decoder = this.audioDecoders.get(clipId);
|
|
105
|
+
if (decoder) {
|
|
106
|
+
await decoder.updateConfig({
|
|
107
|
+
codec,
|
|
108
|
+
sampleRate,
|
|
109
|
+
numberOfChannels,
|
|
110
|
+
description: normalizeDescription(description)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error("[DecodeWorker] Failed to configure decoder:", error);
|
|
116
|
+
throw {
|
|
117
|
+
code: "CODEC_CONFIG_ERROR",
|
|
118
|
+
message: error.message
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return { success: true };
|
|
122
|
+
}
|
|
123
|
+
const { config } = payload;
|
|
124
|
+
if (!config) {
|
|
125
|
+
return { success: true };
|
|
126
|
+
}
|
|
127
|
+
this.channel.state = WorkerState.Ready;
|
|
128
|
+
if (config.video) {
|
|
129
|
+
Object.assign(this.defaultVideoConfig, config.video);
|
|
130
|
+
}
|
|
131
|
+
if (config.audio) {
|
|
132
|
+
Object.assign(this.defaultAudioConfig, config.audio);
|
|
133
|
+
}
|
|
134
|
+
if (config.video) {
|
|
135
|
+
for (const dec of this.videoDecoders.values()) {
|
|
136
|
+
await dec.updateConfig(config.video);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (config.audio) {
|
|
140
|
+
for (const dec of this.audioDecoders.values()) {
|
|
141
|
+
await dec.updateConfig(config.audio);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { success: true };
|
|
145
|
+
}
|
|
146
|
+
async handleReceiveStream(stream, metadata) {
|
|
147
|
+
const clipId = metadata?.clipId || "default";
|
|
148
|
+
const streamType = metadata?.streamType;
|
|
149
|
+
console.log("[DecodeWorker] handleReceiveStream", streamType, clipId, metadata);
|
|
150
|
+
if (streamType === "video") {
|
|
151
|
+
const decoder = await this.getOrCreateDecoder("video", clipId, metadata);
|
|
152
|
+
const transform = decoder.createStream();
|
|
153
|
+
const composePort = this.composePorts.get(clipId);
|
|
154
|
+
if (composePort) {
|
|
155
|
+
const channel = new WorkerChannel(composePort, {
|
|
156
|
+
name: "Decode-Compose",
|
|
157
|
+
timeout: 3e4
|
|
158
|
+
});
|
|
159
|
+
channel.sendStream(transform.readable, {
|
|
160
|
+
streamType: "video",
|
|
161
|
+
clipId
|
|
162
|
+
});
|
|
163
|
+
stream.pipeTo(transform.writable).catch(
|
|
164
|
+
(error) => console.error("[DecodeWorker] Video stream pipe error:", clipId, error)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
} else if (streamType === "audio") {
|
|
168
|
+
const decoder = await this.getOrCreateDecoder("audio", clipId, metadata);
|
|
169
|
+
const transform = decoder.createStream();
|
|
170
|
+
stream.pipeTo(transform.writable).catch((error) => {
|
|
171
|
+
console.error("[DecodeWorker] Audio stream pipe error:", error);
|
|
172
|
+
});
|
|
173
|
+
const trackId = metadata?.trackId ?? clipId;
|
|
174
|
+
await this.registerAudioTrack(trackId, clipId, metadata);
|
|
175
|
+
this.channel.sendStream(transform.readable, {
|
|
176
|
+
streamType: "audio",
|
|
177
|
+
clipId,
|
|
178
|
+
trackId,
|
|
179
|
+
clipStartUs: metadata?.clipStartUs ?? 0,
|
|
180
|
+
clipDurationUs: metadata?.clipDurationUs ?? 0
|
|
181
|
+
});
|
|
182
|
+
this.deliveredAudioTracks.add(trackId);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Flush decoders
|
|
187
|
+
*/
|
|
188
|
+
async handleFlush(payload) {
|
|
189
|
+
try {
|
|
190
|
+
if (!payload?.type || payload.type === "video") {
|
|
191
|
+
for (const dec of this.videoDecoders.values()) {
|
|
192
|
+
await dec.flush();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!payload?.type || payload.type === "audio") {
|
|
196
|
+
for (const dec of this.audioDecoders.values()) {
|
|
197
|
+
await dec.flush();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return { success: true };
|
|
201
|
+
} catch (error) {
|
|
202
|
+
throw {
|
|
203
|
+
code: "FLUSH_ERROR",
|
|
204
|
+
message: error.message
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Reset decoders
|
|
210
|
+
*/
|
|
211
|
+
async handleReset(payload) {
|
|
212
|
+
try {
|
|
213
|
+
if (!payload?.type || payload.type === "video") {
|
|
214
|
+
for (const dec of this.videoDecoders.values()) {
|
|
215
|
+
await dec.reset();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (!payload?.type || payload.type === "audio") {
|
|
219
|
+
for (const dec of this.audioDecoders.values()) {
|
|
220
|
+
await dec.reset();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.channel.notify("reset_complete", {
|
|
224
|
+
type: payload?.type || "all"
|
|
225
|
+
});
|
|
226
|
+
return { success: true };
|
|
227
|
+
} catch (error) {
|
|
228
|
+
throw {
|
|
229
|
+
code: "RESET_ERROR",
|
|
230
|
+
message: error.message
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get decoder statistics
|
|
236
|
+
*/
|
|
237
|
+
async handleGetStats() {
|
|
238
|
+
const stats = {};
|
|
239
|
+
if (this.videoDecoders.size) {
|
|
240
|
+
stats.video = Array.from(this.videoDecoders.entries()).map(([clipId, dec]) => ({
|
|
241
|
+
clipId,
|
|
242
|
+
configured: dec.isConfigured,
|
|
243
|
+
queueSize: dec.queueSize,
|
|
244
|
+
state: dec.state
|
|
245
|
+
}));
|
|
246
|
+
}
|
|
247
|
+
if (this.audioDecoders.size) {
|
|
248
|
+
stats.audio = Array.from(this.audioDecoders.entries()).map(([clipId, dec]) => ({
|
|
249
|
+
clipId,
|
|
250
|
+
configured: dec.isConfigured,
|
|
251
|
+
queueSize: dec.queueSize,
|
|
252
|
+
state: dec.state
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
return stats;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Dispose worker and cleanup resources
|
|
259
|
+
*/
|
|
260
|
+
async handleDispose() {
|
|
261
|
+
for (const dec of this.videoDecoders.values()) {
|
|
262
|
+
await dec.close();
|
|
263
|
+
}
|
|
264
|
+
for (const dec of this.audioDecoders.values()) {
|
|
265
|
+
await dec.close();
|
|
266
|
+
}
|
|
267
|
+
this.videoDecoders.clear();
|
|
268
|
+
this.audioDecoders.clear();
|
|
269
|
+
for (const port of this.composePorts.values()) {
|
|
270
|
+
port.close();
|
|
271
|
+
}
|
|
272
|
+
this.composePorts.clear();
|
|
273
|
+
if (this.audioDownstreamPort) {
|
|
274
|
+
this.audioDownstreamPort.close();
|
|
275
|
+
this.audioDownstreamPort = null;
|
|
276
|
+
}
|
|
277
|
+
this.registeredAudioTracks.clear();
|
|
278
|
+
this.deliveredAudioTracks.clear();
|
|
279
|
+
this.audioTrackMetadata.clear();
|
|
280
|
+
for (const port of this.demuxPorts.values()) {
|
|
281
|
+
port.close();
|
|
282
|
+
}
|
|
283
|
+
this.demuxPorts.clear();
|
|
284
|
+
this.channel.state = WorkerState.Disposed;
|
|
285
|
+
return { success: true };
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get existing decoder for clip or create a new one (with LRU eviction)
|
|
289
|
+
*/
|
|
290
|
+
async getOrCreateDecoder(kind, clipId, metadata) {
|
|
291
|
+
if (kind === "video") {
|
|
292
|
+
let decoder = this.videoDecoders.get(clipId);
|
|
293
|
+
if (!decoder) {
|
|
294
|
+
decoder = new VideoChunkDecoder(
|
|
295
|
+
clipId,
|
|
296
|
+
metadata ? {
|
|
297
|
+
...this.defaultVideoConfig,
|
|
298
|
+
codec: metadata.codec,
|
|
299
|
+
width: metadata.width,
|
|
300
|
+
height: metadata.height,
|
|
301
|
+
description: normalizeDescription(metadata.description),
|
|
302
|
+
...metadata.range && { range: metadata.range }
|
|
303
|
+
} : void 0
|
|
304
|
+
);
|
|
305
|
+
this.evictIfNeeded("video");
|
|
306
|
+
this.videoDecoders.set(clipId, decoder);
|
|
307
|
+
}
|
|
308
|
+
this.videoDecoders.delete(clipId);
|
|
309
|
+
this.videoDecoders.set(clipId, decoder);
|
|
310
|
+
return decoder;
|
|
311
|
+
} else {
|
|
312
|
+
let decoder = this.audioDecoders.get(clipId);
|
|
313
|
+
if (!decoder) {
|
|
314
|
+
decoder = new AudioChunkDecoder(
|
|
315
|
+
clipId,
|
|
316
|
+
metadata ? {
|
|
317
|
+
...this.defaultAudioConfig,
|
|
318
|
+
codec: metadata.codec,
|
|
319
|
+
sampleRate: metadata.sampleRate,
|
|
320
|
+
numberOfChannels: metadata.numberOfChannels,
|
|
321
|
+
description: normalizeDescription(metadata.description)
|
|
322
|
+
} : void 0
|
|
323
|
+
);
|
|
324
|
+
this.evictIfNeeded("audio");
|
|
325
|
+
this.audioDecoders.set(clipId, decoder);
|
|
326
|
+
}
|
|
327
|
+
this.audioDecoders.delete(clipId);
|
|
328
|
+
this.audioDecoders.set(clipId, decoder);
|
|
329
|
+
return decoder;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Evict least-recently-used decoder if we exceed MAX_ACTIVE_DECODERS.
|
|
334
|
+
*/
|
|
335
|
+
evictIfNeeded(kind) {
|
|
336
|
+
const map = kind === "video" ? this.videoDecoders : this.audioDecoders;
|
|
337
|
+
if (map.size < DecodeWorker.MAX_ACTIVE_DECODERS) return;
|
|
338
|
+
const [lrucId, lruDecoder] = map.entries().next().value;
|
|
339
|
+
lruDecoder.close().catch(() => void 0);
|
|
340
|
+
map.delete(lrucId);
|
|
341
|
+
}
|
|
342
|
+
async registerAudioTrack(trackId, clipId, metadata) {
|
|
343
|
+
const record = {
|
|
344
|
+
clipId,
|
|
345
|
+
config: this.extractTrackConfig(metadata?.runtimeConfig),
|
|
346
|
+
sampleRate: metadata?.sampleRate,
|
|
347
|
+
numberOfChannels: metadata?.numberOfChannels,
|
|
348
|
+
type: metadata?.trackType ?? "other"
|
|
349
|
+
};
|
|
350
|
+
this.audioTrackMetadata.set(trackId, record);
|
|
351
|
+
if (this.registeredAudioTracks.has(trackId)) {
|
|
352
|
+
await this.sendAudioTrackUpdate(trackId, record);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.registeredAudioTracks.add(trackId);
|
|
356
|
+
await this.sendAudioTrackAdd(trackId, record);
|
|
357
|
+
}
|
|
358
|
+
// private unregisterAudioTrack(trackId: string): void {
|
|
359
|
+
// if (!this.registeredAudioTracks.delete(trackId)) {
|
|
360
|
+
// return;
|
|
361
|
+
// }
|
|
362
|
+
// const record = this.audioTrackMetadata.get(trackId);
|
|
363
|
+
// this.audioTrackMetadata.delete(trackId);
|
|
364
|
+
// if (!record) {
|
|
365
|
+
// return;
|
|
366
|
+
// }
|
|
367
|
+
// const channel = this.ensureComposeChannel();
|
|
368
|
+
// channel
|
|
369
|
+
// ?.send(WorkerMessageType.AudioTrackRemove, {
|
|
370
|
+
// clipId: record.clipId,
|
|
371
|
+
// trackId,
|
|
372
|
+
// })
|
|
373
|
+
// .catch((error) => {
|
|
374
|
+
// console.warn('[DecodeWorker] Failed to notify track removal', error);
|
|
375
|
+
// });
|
|
376
|
+
// }
|
|
377
|
+
extractTrackConfig(config) {
|
|
378
|
+
return {
|
|
379
|
+
startTimeUs: config?.startTimeUs ?? 0,
|
|
380
|
+
durationUs: config?.durationUs,
|
|
381
|
+
volume: config?.volume ?? 1,
|
|
382
|
+
fadeIn: config?.fadeIn,
|
|
383
|
+
fadeOut: config?.fadeOut,
|
|
384
|
+
effects: config?.effects ?? [],
|
|
385
|
+
duckingTag: config?.duckingTag
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
async sendAudioTrackAdd(trackId, record) {
|
|
389
|
+
const channel = this.ensureComposeChannel();
|
|
390
|
+
if (!channel) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
await channel.send(WorkerMessageType.AudioTrackAdd, {
|
|
394
|
+
clipId: record.clipId,
|
|
395
|
+
trackId,
|
|
396
|
+
config: record.config,
|
|
397
|
+
sampleRate: record.sampleRate,
|
|
398
|
+
numberOfChannels: record.numberOfChannels,
|
|
399
|
+
type: record.type
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
async sendAudioTrackUpdate(trackId, record) {
|
|
403
|
+
const channel = this.ensureComposeChannel();
|
|
404
|
+
if (!channel) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (!channel) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
await channel.send(WorkerMessageType.AudioTrackUpdate, {
|
|
411
|
+
clipId: record.clipId,
|
|
412
|
+
trackId,
|
|
413
|
+
config: record.config,
|
|
414
|
+
type: record.type
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
ensureComposeChannel() {
|
|
418
|
+
if (!this.audioDownstreamPort) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
return new WorkerChannel(this.audioDownstreamPort, {
|
|
422
|
+
name: "Decode-AudioCompose",
|
|
423
|
+
timeout: 3e4
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const worker = new DecodeWorker();
|
|
428
|
+
self.addEventListener("beforeunload", () => {
|
|
429
|
+
worker["handleDispose"]();
|
|
430
|
+
});
|
|
431
|
+
const decode_worker = null;
|
|
432
|
+
export {
|
|
433
|
+
DecodeWorker,
|
|
434
|
+
decode_worker as default
|
|
435
|
+
};
|
|
436
|
+
//# sourceMappingURL=decode.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decode.worker.js","sources":["../../../src/stages/decode/decode.worker.ts"],"sourcesContent":["import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoChunkDecoder } from './VideoChunkDecoder';\nimport { AudioChunkDecoder } from './AudioChunkDecoder';\nimport { VideoDecoderConfig, AudioDecoderConfig } from './types';\nimport type { AudioTrackConfig } from '../compose/types';\n\ninterface TrackMetadata {\n clipId: string;\n config: AudioTrackConfig;\n sampleRate?: number;\n numberOfChannels?: number;\n type: 'bgm' | 'voice' | 'sfx' | 'other';\n}\n\nconst normalizeDescription = (desc?: ArrayBuffer | ArrayBufferView): ArrayBuffer | undefined => {\n if (!desc) return undefined;\n\n if (desc instanceof ArrayBuffer) return desc;\n\n // Handle ArrayBufferView (Uint8Array, etc.)\n const view = desc as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength) as ArrayBuffer;\n};\n\n/**\n * DecodeWorker - Third stage in the pipeline\n * Receives encoded chunks from DemuxWorkers and outputs decoded frames to ComposeWorker\n *\n * Pipeline: VideoDemuxWorker/AudioDemuxWorker → DecodeWorker → ComposeWorker\n *\n * Features:\n * - GOP-based caching for video (≤4 GOPs in memory)\n * - Stream-based processing with backpressure\n * - Direct streaming to ComposeWorker\n */\nexport class DecodeWorker {\n private channel: WorkerChannel;\n // Map of clipId -> decoder instance\n private videoDecoders = new Map<string, VideoChunkDecoder>();\n private audioDecoders = new Map<string, AudioChunkDecoder>();\n private registeredAudioTracks = new Set<string>();\n private deliveredAudioTracks = new Set<string>();\n private audioTrackMetadata = new Map<string, TrackMetadata>();\n\n /** Maximum number of active decoder pairs allowed at the same time */\n private static readonly MAX_ACTIVE_DECODERS = 8;\n\n // Cached default configs merged from orchestrator\n private defaultVideoConfig: Partial<VideoDecoderConfig> = {};\n private defaultAudioConfig: Partial<AudioDecoderConfig> = {};\n\n // Connections to other workers\n private composePorts = new Map<string, MessagePort>();\n private audioDownstreamPort: MessagePort | null = null;\n private demuxPorts = new Map<string, MessagePort>(); // Connections from demux workers\n\n constructor() {\n // Initialize WorkerChannel with MessagePort\n this.channel = new WorkerChannel(self as any, {\n name: 'DecodeWorker',\n timeout: 30000,\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 this.channel.registerHandler('connect' as any, this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n /**\n * Connect handler used by stream pipeline\n */\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType: 'video' | 'audio';\n clipId?: string;\n clipStartUs?: number;\n clipDurationUs?: number;\n }): Promise<{ success: boolean }> {\n const { port, direction, clipId } = payload;\n if (direction === 'upstream') {\n this.demuxPorts.set(clipId || 'default', port);\n const channel = new WorkerChannel(port, {\n name: 'Demux-Decode',\n timeout: 30000,\n });\n channel.receiveStream((stream, metadata) => {\n this.handleReceiveStream(stream, {\n ...metadata,\n clipStartUs: payload.clipStartUs,\n clipDurationUs: payload.clipDurationUs,\n });\n });\n // Also register configure handler on upstream channel for codec info from demuxer\n channel.registerHandler('configure' as any, this.handleConfigure.bind(this));\n }\n if (direction === 'downstream') {\n if (payload.streamType === 'audio') {\n this.audioDownstreamPort?.close();\n this.audioDownstreamPort = port;\n } else {\n this.composePorts.set(clipId || 'default', port);\n }\n }\n return { success: true };\n }\n\n /**\n * Handle configuration message from orchestrator\n * @param payload.initial - If true, initialize worker and recreate decoder instances; otherwise just update config\n */\n private async handleConfigure(payload: {\n config?: { video?: Partial<VideoDecoderConfig>; audio?: Partial<AudioDecoderConfig> };\n // Support direct codec info from demuxer\n clipId?: string;\n streamType?: 'video' | 'audio';\n codec?: string;\n width?: number;\n height?: number;\n sampleRate?: number;\n numberOfChannels?: number;\n description?: ArrayBuffer | Uint8Array;\n range?: { start: number; end: number };\n }): Promise<{ success: boolean }> {\n // If this is codec info from demuxer (has clipId and streamType)\n const {\n clipId,\n streamType,\n codec,\n width,\n height,\n sampleRate,\n numberOfChannels,\n description,\n range,\n } = payload;\n if (clipId && streamType) {\n try {\n if (streamType === 'video') {\n const decoder = this.videoDecoders.get(clipId);\n if (decoder) {\n await decoder.updateConfig({\n codec,\n width,\n height,\n description: normalizeDescription(description),\n ...(range && { range }),\n });\n }\n } else if (streamType === 'audio') {\n const decoder = this.audioDecoders.get(clipId);\n if (decoder) {\n await decoder.updateConfig({\n codec,\n sampleRate,\n numberOfChannels,\n description: normalizeDescription(description),\n });\n }\n }\n } catch (error: any) {\n console.error('[DecodeWorker] Failed to configure decoder:', error);\n throw {\n code: 'CODEC_CONFIG_ERROR',\n message: error.message,\n };\n }\n return { success: true };\n }\n\n // Otherwise, this is a global config from orchestrator\n const { config } = payload;\n if (!config) {\n return { success: true };\n }\n\n // Ensure worker becomes ready once configured at least once\n this.channel.state = WorkerState.Ready;\n\n // Merge and cache default configs\n if (config.video) {\n Object.assign(this.defaultVideoConfig, config.video);\n }\n if (config.audio) {\n Object.assign(this.defaultAudioConfig, config.audio);\n }\n\n // Propagate updated config to existing decoders\n if (config.video) {\n for (const dec of this.videoDecoders.values()) {\n await dec.updateConfig(config.video);\n }\n }\n if (config.audio) {\n for (const dec of this.audioDecoders.values()) {\n await dec.updateConfig(config.audio);\n }\n }\n\n return { success: true };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n const clipId: string = metadata?.clipId || 'default';\n const streamType = metadata?.streamType;\n\n console.log('[DecodeWorker] handleReceiveStream', streamType, clipId, metadata);\n\n if (streamType === 'video') {\n // For video, create decoder that will buffer chunks until configured\n const decoder = await this.getOrCreateDecoder('video', clipId, metadata);\n const transform = decoder.createStream();\n\n // Forward decoded frames downstream if port exists\n const composePort = this.composePorts.get(clipId);\n if (composePort) {\n const channel = new WorkerChannel(composePort, {\n name: 'Decode-Compose',\n timeout: 30000,\n });\n channel.sendStream(transform.readable as ReadableStream, {\n streamType: 'video',\n clipId,\n });\n\n // Pipe encoded chunks into decoder (will buffer if not configured)\n stream\n .pipeTo(transform.writable)\n .catch((error) =>\n console.error('[DecodeWorker] Video stream pipe error:', clipId, error)\n );\n }\n } else if (streamType === 'audio') {\n const decoder = await this.getOrCreateDecoder('audio', clipId, metadata);\n const transform = decoder.createStream();\n stream.pipeTo(transform.writable).catch((error) => {\n console.error('[DecodeWorker] Audio stream pipe error:', error);\n });\n\n const trackId = metadata?.trackId ?? clipId;\n await this.registerAudioTrack(trackId, clipId, metadata);\n\n this.channel.sendStream(transform.readable as ReadableStream<AudioData>, {\n streamType: 'audio',\n clipId,\n trackId,\n clipStartUs: metadata?.clipStartUs ?? 0,\n clipDurationUs: metadata?.clipDurationUs ?? 0,\n });\n\n this.deliveredAudioTracks.add(trackId);\n }\n }\n\n /**\n * Flush decoders\n */\n private async handleFlush(payload?: { type?: 'video' | 'audio' }): Promise<{ success: boolean }> {\n try {\n if (!payload?.type || payload.type === 'video') {\n for (const dec of this.videoDecoders.values()) {\n await dec.flush();\n }\n }\n if (!payload?.type || payload.type === 'audio') {\n for (const dec of this.audioDecoders.values()) {\n await dec.flush();\n }\n }\n\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'FLUSH_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Reset decoders\n */\n private async handleReset(payload?: { type?: 'video' | 'audio' }): Promise<{ success: boolean }> {\n try {\n if (!payload?.type || payload.type === 'video') {\n for (const dec of this.videoDecoders.values()) {\n await dec.reset();\n }\n }\n if (!payload?.type || payload.type === 'audio') {\n for (const dec of this.audioDecoders.values()) {\n await dec.reset();\n }\n }\n\n // Notify reset complete\n this.channel.notify('reset_complete', {\n type: payload?.type || 'all',\n });\n\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'RESET_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Get decoder statistics\n */\n private async handleGetStats(): Promise<{\n video?: any;\n audio?: any;\n }> {\n const stats: any = {};\n\n if (this.videoDecoders.size) {\n stats.video = Array.from(this.videoDecoders.entries()).map(([clipId, dec]) => ({\n clipId,\n configured: dec.isConfigured,\n queueSize: dec.queueSize,\n state: dec.state,\n }));\n }\n\n if (this.audioDecoders.size) {\n stats.audio = Array.from(this.audioDecoders.entries()).map(([clipId, dec]) => ({\n clipId,\n configured: dec.isConfigured,\n queueSize: dec.queueSize,\n state: dec.state,\n }));\n }\n\n return stats;\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n // Close all decoders\n for (const dec of this.videoDecoders.values()) {\n await dec.close();\n }\n for (const dec of this.audioDecoders.values()) {\n await dec.close();\n }\n\n this.videoDecoders.clear();\n this.audioDecoders.clear();\n\n // Close connections\n for (const port of this.composePorts.values()) {\n port.close();\n }\n this.composePorts.clear();\n\n if (this.audioDownstreamPort) {\n this.audioDownstreamPort.close();\n this.audioDownstreamPort = null;\n }\n\n this.registeredAudioTracks.clear();\n this.deliveredAudioTracks.clear();\n this.audioTrackMetadata.clear();\n\n for (const port of this.demuxPorts.values()) {\n port.close();\n }\n this.demuxPorts.clear();\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n\n /**\n * Get existing decoder for clip or create a new one (with LRU eviction)\n */\n private async getOrCreateDecoder(\n kind: 'video' | 'audio',\n clipId: string,\n metadata?: Record<string, any> | null\n ): Promise<VideoChunkDecoder | AudioChunkDecoder> {\n if (kind === 'video') {\n let decoder = this.videoDecoders.get(clipId);\n if (!decoder) {\n // Create decoder without configuration if metadata is null\n decoder = new VideoChunkDecoder(\n clipId,\n metadata\n ? {\n ...this.defaultVideoConfig,\n codec: metadata.codec,\n width: metadata.width,\n height: metadata.height,\n description: normalizeDescription(metadata.description),\n ...(metadata.range && { range: metadata.range }),\n }\n : undefined\n ); // Pass undefined to create unconfigured decoder\n\n this.evictIfNeeded('video');\n this.videoDecoders.set(clipId, decoder);\n }\n // refresh LRU order\n this.videoDecoders.delete(clipId);\n this.videoDecoders.set(clipId, decoder);\n return decoder;\n } else {\n let decoder = this.audioDecoders.get(clipId);\n if (!decoder) {\n decoder = new AudioChunkDecoder(\n clipId,\n metadata\n ? {\n ...this.defaultAudioConfig,\n codec: metadata.codec,\n sampleRate: metadata.sampleRate,\n numberOfChannels: metadata.numberOfChannels,\n description: normalizeDescription(metadata.description),\n }\n : undefined\n );\n\n this.evictIfNeeded('audio');\n this.audioDecoders.set(clipId, decoder);\n }\n // refresh LRU order\n this.audioDecoders.delete(clipId);\n this.audioDecoders.set(clipId, decoder);\n return decoder;\n }\n }\n\n /**\n * Evict least-recently-used decoder if we exceed MAX_ACTIVE_DECODERS.\n */\n private evictIfNeeded(kind: 'video' | 'audio'): void {\n const map = kind === 'video' ? this.videoDecoders : this.audioDecoders;\n if (map.size < DecodeWorker.MAX_ACTIVE_DECODERS) return;\n\n // Map preserves insertion order; first entry is LRU\n const [lrucId, lruDecoder] = map.entries().next().value as [string, any];\n lruDecoder.close().catch(() => undefined);\n map.delete(lrucId);\n }\n\n private async registerAudioTrack(\n trackId: string,\n clipId: string,\n metadata?: Record<string, any>\n ): Promise<void> {\n const record: TrackMetadata = {\n clipId,\n config: this.extractTrackConfig(metadata?.runtimeConfig),\n sampleRate: metadata?.sampleRate,\n numberOfChannels: metadata?.numberOfChannels,\n type: (metadata?.trackType as TrackMetadata['type']) ?? 'other',\n };\n\n this.audioTrackMetadata.set(trackId, record);\n\n if (this.registeredAudioTracks.has(trackId)) {\n await this.sendAudioTrackUpdate(trackId, record);\n return;\n }\n\n this.registeredAudioTracks.add(trackId);\n await this.sendAudioTrackAdd(trackId, record);\n }\n\n // private unregisterAudioTrack(trackId: string): void {\n // if (!this.registeredAudioTracks.delete(trackId)) {\n // return;\n // }\n\n // const record = this.audioTrackMetadata.get(trackId);\n // this.audioTrackMetadata.delete(trackId);\n\n // if (!record) {\n // return;\n // }\n\n // const channel = this.ensureComposeChannel();\n // channel\n // ?.send(WorkerMessageType.AudioTrackRemove, {\n // clipId: record.clipId,\n // trackId,\n // })\n // .catch((error) => {\n // console.warn('[DecodeWorker] Failed to notify track removal', error);\n // });\n // }\n\n private extractTrackConfig(config: any): AudioTrackConfig {\n return {\n startTimeUs: config?.startTimeUs ?? 0,\n durationUs: config?.durationUs,\n volume: config?.volume ?? 1,\n fadeIn: config?.fadeIn,\n fadeOut: config?.fadeOut,\n effects: config?.effects ?? [],\n duckingTag: config?.duckingTag,\n };\n }\n\n private async sendAudioTrackAdd(trackId: string, record: TrackMetadata): Promise<void> {\n const channel = this.ensureComposeChannel();\n if (!channel) {\n return;\n }\n\n await channel.send(WorkerMessageType.AudioTrackAdd, {\n clipId: record.clipId,\n trackId,\n config: record.config,\n sampleRate: record.sampleRate,\n numberOfChannels: record.numberOfChannels,\n type: record.type,\n });\n }\n\n private async sendAudioTrackUpdate(trackId: string, record: TrackMetadata): Promise<void> {\n const channel = this.ensureComposeChannel();\n if (!channel) {\n return;\n }\n\n if (!channel) {\n return;\n }\n\n await channel.send(WorkerMessageType.AudioTrackUpdate, {\n clipId: record.clipId,\n trackId,\n config: record.config,\n type: record.type,\n });\n }\n\n private ensureComposeChannel(): WorkerChannel | null {\n if (!this.audioDownstreamPort) {\n return null;\n }\n\n return new WorkerChannel(this.audioDownstreamPort, {\n name: 'Decode-AudioCompose',\n timeout: 30000,\n });\n }\n}\n\n// Initialize worker\nconst worker = new DecodeWorker();\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,5 @@
|
|
|
1
|
+
export { BaseDecoder } from './BaseDecoder';
|
|
2
|
+
export { VideoChunkDecoder } from './VideoChunkDecoder';
|
|
3
|
+
export { AudioChunkDecoder } from './AudioChunkDecoder';
|
|
4
|
+
export type { DecoderConfig, VideoDecoderConfig, AudioDecoderConfig, DecodeRequest, DecodeResult, SeekRequest, GOPInfo, DecoderStats, DecoderPoolConfig, DecoderState, DecoderInstance, DecoderMessage, DecoderResponse, } from './types';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/stages/decode/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,eAAe,GAChB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export interface DecoderConfig {
|
|
2
|
+
trackId: string;
|
|
3
|
+
codec: string;
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
sampleRate?: number;
|
|
7
|
+
numberOfChannels?: number;
|
|
8
|
+
hardwareAcceleration?: HardwareAcceleration;
|
|
9
|
+
optimizeForLatency?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface VideoDecoderConfig extends DecoderConfig {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
codec: string;
|
|
15
|
+
description?: ArrayBuffer;
|
|
16
|
+
displayAspectWidth?: number;
|
|
17
|
+
displayAspectHeight?: number;
|
|
18
|
+
colorSpace?: VideoColorSpaceInit;
|
|
19
|
+
backpressure?: {
|
|
20
|
+
highWaterMark?: number;
|
|
21
|
+
decodeQueueThreshold?: number;
|
|
22
|
+
};
|
|
23
|
+
maxGOPs?: number;
|
|
24
|
+
range?: {
|
|
25
|
+
start: number;
|
|
26
|
+
end: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface DecodedVideoFrame {
|
|
30
|
+
frame: VideoFrame;
|
|
31
|
+
gopSerial: number;
|
|
32
|
+
isKeyframe: boolean;
|
|
33
|
+
timestamp: number;
|
|
34
|
+
}
|
|
35
|
+
export interface AudioDecoderConfig extends DecoderConfig {
|
|
36
|
+
sampleRate: number;
|
|
37
|
+
numberOfChannels: number;
|
|
38
|
+
codec: string;
|
|
39
|
+
description?: ArrayBuffer;
|
|
40
|
+
backpressure?: {
|
|
41
|
+
highWaterMark?: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface DecodeRequest {
|
|
45
|
+
trackId: string;
|
|
46
|
+
chunk: EncodedVideoChunk | EncodedAudioChunk;
|
|
47
|
+
priority?: 'high' | 'normal' | 'low';
|
|
48
|
+
}
|
|
49
|
+
export interface DecodeResult {
|
|
50
|
+
trackId: string;
|
|
51
|
+
frame: VideoFrame | AudioData;
|
|
52
|
+
timestamp: number;
|
|
53
|
+
duration?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface SeekRequest {
|
|
56
|
+
trackId: string;
|
|
57
|
+
targetTimeUs: number;
|
|
58
|
+
mode?: 'exact' | 'closest-gop';
|
|
59
|
+
}
|
|
60
|
+
export interface GOPInfo {
|
|
61
|
+
index: number;
|
|
62
|
+
keyFrameTimeUs: number;
|
|
63
|
+
endTimeUs: number;
|
|
64
|
+
frameCount: number;
|
|
65
|
+
frames: VideoFrame[];
|
|
66
|
+
}
|
|
67
|
+
export interface DecodedFrameWithGOP {
|
|
68
|
+
frame: VideoFrame;
|
|
69
|
+
gopSerial: number;
|
|
70
|
+
isKeyframe: boolean;
|
|
71
|
+
clipId: string;
|
|
72
|
+
}
|
|
73
|
+
export interface DecoderStats {
|
|
74
|
+
trackId: string;
|
|
75
|
+
decodedFrames: number;
|
|
76
|
+
droppedFrames: number;
|
|
77
|
+
queueSize: number;
|
|
78
|
+
averageDecodeTime: number;
|
|
79
|
+
gopCacheSize: number;
|
|
80
|
+
}
|
|
81
|
+
export interface DecoderPoolConfig {
|
|
82
|
+
maxDecoders?: number;
|
|
83
|
+
maxGOPsPerDecoder?: number;
|
|
84
|
+
memoryThresholdMB?: number;
|
|
85
|
+
evictionStrategy?: 'lru' | 'lfu' | 'fifo';
|
|
86
|
+
}
|
|
87
|
+
export type DecoderState = 'idle' | 'decoding' | 'seeking' | 'error' | 'closed';
|
|
88
|
+
export interface DecoderInstance {
|
|
89
|
+
id: string;
|
|
90
|
+
trackId: string;
|
|
91
|
+
type: 'video' | 'audio';
|
|
92
|
+
state: DecoderState;
|
|
93
|
+
decoder: VideoDecoder | AudioDecoder;
|
|
94
|
+
gopCache?: Map<number, GOPInfo>;
|
|
95
|
+
stats: DecoderStats;
|
|
96
|
+
lastAccessTime: number;
|
|
97
|
+
}
|
|
98
|
+
export interface DecoderMessage {
|
|
99
|
+
type: 'configure' | 'decode' | 'seek' | 'flush' | 'reset' | 'close' | 'stats';
|
|
100
|
+
payload: any;
|
|
101
|
+
id?: string;
|
|
102
|
+
}
|
|
103
|
+
export interface DecoderResponse {
|
|
104
|
+
type: 'configured' | 'decoded' | 'seeked' | 'flushed' | 'reset' | 'closed' | 'error' | 'stats';
|
|
105
|
+
payload: any;
|
|
106
|
+
id?: string;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/stages/decode/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface MP3Config {
|
|
2
|
+
codec: 'mp3';
|
|
3
|
+
sampleRate: number;
|
|
4
|
+
channels: number;
|
|
5
|
+
bitrateKbps: number | null;
|
|
6
|
+
samplesPerFrame: number;
|
|
7
|
+
}
|
|
8
|
+
export interface MP3Frame {
|
|
9
|
+
data: Uint8Array;
|
|
10
|
+
timestampUs: number;
|
|
11
|
+
durationUs: number;
|
|
12
|
+
}
|
|
13
|
+
interface ParseResult {
|
|
14
|
+
frames: MP3Frame[];
|
|
15
|
+
config?: MP3Config;
|
|
16
|
+
}
|
|
17
|
+
export declare class MP3FrameParser {
|
|
18
|
+
private buffer;
|
|
19
|
+
private config;
|
|
20
|
+
private timestampUs;
|
|
21
|
+
push(chunk: Uint8Array): ParseResult;
|
|
22
|
+
flush(): MP3Frame[];
|
|
23
|
+
private appendToBuffer;
|
|
24
|
+
private skipId3Headers;
|
|
25
|
+
private parseHeader;
|
|
26
|
+
private getVersion;
|
|
27
|
+
private getLayer;
|
|
28
|
+
private getSamplesPerFrame;
|
|
29
|
+
private calculateFrameSize;
|
|
30
|
+
private readSynchsafeInteger;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=MP3FrameParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MP3FrameParser.d.ts","sourceRoot":"","sources":["../../../src/stages/demux/MP3FrameParser.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAAK;IAExB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW;IAkDpC,KAAK,IAAI,QAAQ,EAAE;IAUnB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,WAAW;IA0DnB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,oBAAoB;CAW7B"}
|