@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,312 @@
|
|
|
1
|
+
import { WorkerChannel } from "../../worker/WorkerChannel.js";
|
|
2
|
+
import { WorkerMessageType, WorkerState } from "../../worker/types.js";
|
|
3
|
+
import { MP4Demuxer } from "./MP4Demuxer.js";
|
|
4
|
+
import { MP3FrameParser } from "./MP3FrameParser.js";
|
|
5
|
+
class AudioDemuxWorker {
|
|
6
|
+
channel;
|
|
7
|
+
demuxer = null;
|
|
8
|
+
audioStream = null;
|
|
9
|
+
mp3Parser = null;
|
|
10
|
+
currentFormat = null;
|
|
11
|
+
// Connection to decoder worker
|
|
12
|
+
decoderPort = null;
|
|
13
|
+
constructor() {
|
|
14
|
+
this.channel = new WorkerChannel(self, {
|
|
15
|
+
name: "AudioDemuxWorker",
|
|
16
|
+
timeout: 3e4
|
|
17
|
+
});
|
|
18
|
+
this.setupHandlers();
|
|
19
|
+
}
|
|
20
|
+
setupHandlers() {
|
|
21
|
+
this.channel.registerHandler("configure", this.handleConfigure.bind(this));
|
|
22
|
+
this.channel.registerHandler("connect", this.handleConnect.bind(this));
|
|
23
|
+
this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
|
|
24
|
+
this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
|
|
25
|
+
this.channel.receiveStream(this.handleInputStream.bind(this));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Unified connect handler used by stream pipeline
|
|
29
|
+
*/
|
|
30
|
+
async handleConnect(payload) {
|
|
31
|
+
this.decoderPort = payload.port;
|
|
32
|
+
return { success: true };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Configure demuxer with format settings
|
|
36
|
+
* @param payload.config - Demuxer configuration
|
|
37
|
+
* @param payload.initial - If true, initialize worker state; otherwise just update config
|
|
38
|
+
*/
|
|
39
|
+
async handleConfigure(payload) {
|
|
40
|
+
const { config, initial = false } = payload;
|
|
41
|
+
try {
|
|
42
|
+
if (initial) {
|
|
43
|
+
this.channel.state = WorkerState.Ready;
|
|
44
|
+
const format = config.container || this.detectFormat(config);
|
|
45
|
+
if (format === "mp3") {
|
|
46
|
+
this.mp3Parser = new MP3FrameParser();
|
|
47
|
+
this.demuxer?.destroy();
|
|
48
|
+
this.demuxer = null;
|
|
49
|
+
this.audioStream = null;
|
|
50
|
+
this.currentFormat = "mp3";
|
|
51
|
+
const mp3Track = { id: 1, type: "audio", codec: "mp3" };
|
|
52
|
+
this.channel.notify("configured", {
|
|
53
|
+
tracks: [mp3Track],
|
|
54
|
+
format,
|
|
55
|
+
codec: "mp3"
|
|
56
|
+
});
|
|
57
|
+
return { success: true, tracks: [mp3Track] };
|
|
58
|
+
} else if (format === "mp4" || format === "m4a") {
|
|
59
|
+
if (this.demuxer) {
|
|
60
|
+
this.demuxer.destroy();
|
|
61
|
+
}
|
|
62
|
+
this.demuxer = new MP4Demuxer({
|
|
63
|
+
...config,
|
|
64
|
+
skipVideo: true
|
|
65
|
+
// Audio only
|
|
66
|
+
});
|
|
67
|
+
this.audioStream = this.demuxer.createAudioStream();
|
|
68
|
+
this.mp3Parser = null;
|
|
69
|
+
this.currentFormat = "mp4";
|
|
70
|
+
} else {
|
|
71
|
+
throw {
|
|
72
|
+
code: "UNSUPPORTED_FORMAT",
|
|
73
|
+
message: `Unsupported audio format: ${format}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!this.audioStream) {
|
|
77
|
+
throw {
|
|
78
|
+
code: "NO_AUDIO_TRACK",
|
|
79
|
+
message: "No audio track found in container"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const tracks = Array.from(this.demuxer.tracks.values());
|
|
83
|
+
this.channel.notify("configured", {
|
|
84
|
+
tracks,
|
|
85
|
+
format,
|
|
86
|
+
codec: tracks[0]?.codec
|
|
87
|
+
});
|
|
88
|
+
return { success: true, tracks };
|
|
89
|
+
} else {
|
|
90
|
+
if (!this.demuxer) {
|
|
91
|
+
throw {
|
|
92
|
+
code: "NOT_INITIALIZED",
|
|
93
|
+
message: "Demuxer not initialized. Call configure with initial=true first"
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return { success: true };
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw {
|
|
100
|
+
code: error.code || "CONFIG_ERROR",
|
|
101
|
+
message: error.message
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Detect audio format from configuration
|
|
107
|
+
*/
|
|
108
|
+
detectFormat(config) {
|
|
109
|
+
if (config.codec?.includes("mp3")) return "mp3";
|
|
110
|
+
if (config.codec?.includes("aac")) return "mp4";
|
|
111
|
+
if (config.codec?.includes("opus")) return "webm";
|
|
112
|
+
return "mp3";
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Handle input stream from ResourceLoader (main thread)
|
|
116
|
+
*/
|
|
117
|
+
async handleInputStream(stream, metadata) {
|
|
118
|
+
if (this.currentFormat === "mp3" && !this.mp3Parser) {
|
|
119
|
+
this.mp3Parser = new MP3FrameParser();
|
|
120
|
+
}
|
|
121
|
+
if (this.currentFormat === "mp4" && (!this.demuxer || !this.audioStream)) {
|
|
122
|
+
await this.handleConfigure({
|
|
123
|
+
config: { container: "mp4", highWaterMark: 10 },
|
|
124
|
+
initial: true
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (!this.decoderPort) {
|
|
128
|
+
throw new Error("Decoder not connected");
|
|
129
|
+
}
|
|
130
|
+
const decoderChannel = new WorkerChannel(this.decoderPort, {
|
|
131
|
+
name: "AudioDemux-Decoder",
|
|
132
|
+
timeout: 3e4
|
|
133
|
+
});
|
|
134
|
+
if (this.currentFormat === "mp3") {
|
|
135
|
+
await this.pipeMp3Stream(stream, decoderChannel, metadata);
|
|
136
|
+
} else if (this.demuxer && this.audioStream) {
|
|
137
|
+
const transformed = stream.pipeThrough(this.audioStream);
|
|
138
|
+
const trackInfo = Array.from(this.demuxer.tracks.values())[0];
|
|
139
|
+
await decoderChannel.sendStream(transformed, {
|
|
140
|
+
streamType: "audio",
|
|
141
|
+
clipId: metadata?.clipId ?? "default",
|
|
142
|
+
trackId: metadata?.trackId ?? "main",
|
|
143
|
+
codec: trackInfo?.codec ?? "mp4a.40.2",
|
|
144
|
+
sampleRate: trackInfo?.sampleRate ?? 44100,
|
|
145
|
+
numberOfChannels: trackInfo?.numberOfChannels ?? 2,
|
|
146
|
+
description: trackInfo?.description
|
|
147
|
+
});
|
|
148
|
+
this.channel.notify("demux_complete", {
|
|
149
|
+
tracksProcessed: this.demuxer?.tracks.size || 0
|
|
150
|
+
});
|
|
151
|
+
} else {
|
|
152
|
+
throw new Error("Audio demuxer not initialized");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async pipeMp3Stream(stream, decoderChannel, metadata) {
|
|
156
|
+
if (!this.mp3Parser) {
|
|
157
|
+
this.mp3Parser = new MP3FrameParser();
|
|
158
|
+
}
|
|
159
|
+
const reader = stream.getReader();
|
|
160
|
+
let currentConfig = null;
|
|
161
|
+
let configured = false;
|
|
162
|
+
const bufferedFrames = [];
|
|
163
|
+
let writer = null;
|
|
164
|
+
const ensureWriter = async () => {
|
|
165
|
+
if (!writer) {
|
|
166
|
+
const cfg = currentConfig;
|
|
167
|
+
if (!cfg) {
|
|
168
|
+
throw new Error("MP3 config missing while creating writer");
|
|
169
|
+
}
|
|
170
|
+
const transform = new TransformStream();
|
|
171
|
+
writer = transform.writable.getWriter();
|
|
172
|
+
await decoderChannel.sendStream(transform.readable, {
|
|
173
|
+
streamType: "audio",
|
|
174
|
+
clipId: metadata?.clipId ?? "default",
|
|
175
|
+
trackId: metadata?.trackId ?? "main",
|
|
176
|
+
codec: "mp3",
|
|
177
|
+
sampleRate: cfg.sampleRate,
|
|
178
|
+
numberOfChannels: cfg.channels,
|
|
179
|
+
description: void 0
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return writer;
|
|
183
|
+
};
|
|
184
|
+
try {
|
|
185
|
+
while (true) {
|
|
186
|
+
const { done, value } = await reader.read();
|
|
187
|
+
if (done) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
if (!value) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const { frames, config } = this.mp3Parser.push(value);
|
|
194
|
+
if (config) {
|
|
195
|
+
currentConfig = config;
|
|
196
|
+
}
|
|
197
|
+
if (config && !configured) {
|
|
198
|
+
await decoderChannel.send("configure", {
|
|
199
|
+
streamType: "audio",
|
|
200
|
+
clipId: metadata?.clipId ?? "default",
|
|
201
|
+
codec: "mp3",
|
|
202
|
+
sampleRate: config.sampleRate,
|
|
203
|
+
numberOfChannels: config.channels,
|
|
204
|
+
description: void 0
|
|
205
|
+
});
|
|
206
|
+
this.channel.notify("demux_configured", {
|
|
207
|
+
clipId: metadata?.clipId ?? "default",
|
|
208
|
+
codec: "mp3",
|
|
209
|
+
sampleRate: config.sampleRate,
|
|
210
|
+
numberOfChannels: config.channels
|
|
211
|
+
});
|
|
212
|
+
configured = true;
|
|
213
|
+
}
|
|
214
|
+
if (config) {
|
|
215
|
+
this.currentFormat = "mp3";
|
|
216
|
+
}
|
|
217
|
+
if (!configured) {
|
|
218
|
+
bufferedFrames.push(...frames);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const targetWriter = await ensureWriter();
|
|
222
|
+
const readyFrames = bufferedFrames.splice(0, bufferedFrames.length);
|
|
223
|
+
readyFrames.push(...frames);
|
|
224
|
+
for (const frame of readyFrames) {
|
|
225
|
+
const chunk = new EncodedAudioChunk({
|
|
226
|
+
type: "key",
|
|
227
|
+
timestamp: frame.timestampUs,
|
|
228
|
+
duration: frame.durationUs,
|
|
229
|
+
data: frame.data.buffer.slice(
|
|
230
|
+
frame.data.byteOffset,
|
|
231
|
+
frame.data.byteOffset + frame.data.byteLength
|
|
232
|
+
)
|
|
233
|
+
});
|
|
234
|
+
await targetWriter.write(chunk);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const remaining = this.mp3Parser.flush();
|
|
238
|
+
if (remaining.length) {
|
|
239
|
+
if (!configured) {
|
|
240
|
+
throw new Error("MP3 stream ended before configuration");
|
|
241
|
+
}
|
|
242
|
+
const targetWriter = await ensureWriter();
|
|
243
|
+
for (const frame of remaining) {
|
|
244
|
+
const chunk = new EncodedAudioChunk({
|
|
245
|
+
type: "key",
|
|
246
|
+
timestamp: frame.timestampUs,
|
|
247
|
+
duration: frame.durationUs,
|
|
248
|
+
data: frame.data.buffer.slice(
|
|
249
|
+
frame.data.byteOffset,
|
|
250
|
+
frame.data.byteOffset + frame.data.byteLength
|
|
251
|
+
)
|
|
252
|
+
});
|
|
253
|
+
await targetWriter.write(chunk);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (writer) {
|
|
257
|
+
await writer.close();
|
|
258
|
+
}
|
|
259
|
+
this.channel.notify("demux_complete", {
|
|
260
|
+
tracksProcessed: 1
|
|
261
|
+
});
|
|
262
|
+
} finally {
|
|
263
|
+
reader.releaseLock();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get demuxer statistics
|
|
268
|
+
*/
|
|
269
|
+
async handleGetStats() {
|
|
270
|
+
if (this.currentFormat === "mp3") {
|
|
271
|
+
return {
|
|
272
|
+
tracksInfo: this.mp3Parser ? [{ id: 1, type: "audio", codec: "mp3" }] : [],
|
|
273
|
+
format: "mp3",
|
|
274
|
+
state: this.channel.state
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
if (this.demuxer) {
|
|
278
|
+
return {
|
|
279
|
+
tracksInfo: Array.from(this.demuxer.tracks.values()),
|
|
280
|
+
format: "mp4",
|
|
281
|
+
state: this.channel.state
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return { state: this.channel.state };
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Dispose worker and cleanup resources
|
|
288
|
+
*/
|
|
289
|
+
async handleDispose() {
|
|
290
|
+
if (this.demuxer) {
|
|
291
|
+
this.demuxer.destroy();
|
|
292
|
+
}
|
|
293
|
+
this.demuxer = null;
|
|
294
|
+
this.audioStream = null;
|
|
295
|
+
this.mp3Parser = null;
|
|
296
|
+
this.currentFormat = null;
|
|
297
|
+
this.decoderPort?.close();
|
|
298
|
+
this.decoderPort = null;
|
|
299
|
+
this.channel.state = WorkerState.Disposed;
|
|
300
|
+
return { success: true };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const worker = new AudioDemuxWorker();
|
|
304
|
+
self.addEventListener("beforeunload", () => {
|
|
305
|
+
worker["handleDispose"]();
|
|
306
|
+
});
|
|
307
|
+
const audioDemux_worker = null;
|
|
308
|
+
export {
|
|
309
|
+
AudioDemuxWorker,
|
|
310
|
+
audioDemux_worker as default
|
|
311
|
+
};
|
|
312
|
+
//# sourceMappingURL=audio-demux.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-demux.worker.js","sources":["../../../src/stages/demux/audio-demux.worker.ts"],"sourcesContent":["import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { MP4Demuxer } from './MP4Demuxer';\nimport { MP3FrameParser, type MP3Config, type MP3Frame } from './MP3FrameParser';\nimport type { DemuxConfig } from './types';\n\n/**\n * AudioDemuxWorker - First stage for audio processing\n * Extracts audio tracks from various container formats (MP3, MP4/M4A, etc.)\n *\n * Pipeline: ResourceLoader (Main Thread) → AudioDemuxWorker → DecodeWorker\n *\n * Features:\n * - Multi-format support (MP3, AAC in MP4/M4A)\n * - Stream-based processing with backpressure\n * - Direct streaming to DecodeWorker\n */\nexport class AudioDemuxWorker {\n private channel: WorkerChannel;\n private demuxer: MP4Demuxer | null = null;\n private audioStream: TransformStream<Uint8Array, EncodedAudioChunk> | null = null;\n private mp3Parser: MP3FrameParser | null = null;\n private currentFormat: 'mp3' | 'mp4' | null = null;\n\n // Connection to decoder worker\n private decoderPort: MessagePort | null = null;\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self as any, {\n name: 'AudioDemuxWorker',\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 // Unified stream connect (feature-flagged)\n this.channel.registerHandler('connect' as any, this.handleConnect.bind(this));\n // Unified stream connect only\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.handleInputStream.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleConnect(payload: {\n direction: 'upstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n }): Promise<{ success: boolean }> {\n this.decoderPort = payload.port;\n // Demux connects upstream to decoder\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 // Detect format and create appropriate demuxer\n const format = config.container || this.detectFormat(config);\n\n if (format === 'mp3') {\n this.mp3Parser = new MP3FrameParser();\n this.demuxer?.destroy();\n this.demuxer = null;\n this.audioStream = null;\n this.currentFormat = 'mp3';\n\n const mp3Track = { id: 1, type: 'audio', codec: 'mp3' };\n this.channel.notify('configured', {\n tracks: [mp3Track],\n format,\n codec: 'mp3',\n });\n\n return { success: true, tracks: [mp3Track] };\n } else if (format === 'mp4' || format === 'm4a') {\n if (this.demuxer) {\n this.demuxer.destroy();\n }\n\n this.demuxer = new MP4Demuxer({\n ...config,\n skipVideo: true, // Audio only\n });\n this.audioStream = this.demuxer.createAudioStream();\n this.mp3Parser = null;\n this.currentFormat = 'mp4';\n } else {\n throw {\n code: 'UNSUPPORTED_FORMAT',\n message: `Unsupported audio format: ${format}`,\n };\n }\n\n if (!this.audioStream) {\n throw {\n code: 'NO_AUDIO_TRACK',\n message: 'No audio track found in container',\n };\n }\n\n const tracks = Array.from(this.demuxer.tracks.values());\n\n // Notify configuration complete\n this.channel.notify('configured', {\n tracks,\n format,\n codec: tracks[0]?.codec,\n });\n\n return { success: true, tracks };\n } else {\n // Update configuration only (e.g., backpressure settings)\n if (!this.demuxer) {\n throw {\n code: 'NOT_INITIALIZED',\n message: 'Demuxer not initialized. Call configure with initial=true first',\n };\n }\n\n // Demuxers don't support runtime config updates\n // Would need initial=true for changes\n\n return { success: true };\n }\n } catch (error: any) {\n throw {\n code: error.code || 'CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Detect audio format from configuration\n */\n private detectFormat(config: DemuxConfig): string {\n // Simple format detection based on codec or file extension\n if (config.codec?.includes('mp3')) return 'mp3';\n if (config.codec?.includes('aac')) return 'mp4';\n if (config.codec?.includes('opus')) return 'webm';\n\n return 'mp3';\n }\n\n /**\n * Handle input stream from ResourceLoader (main thread)\n */\n private async handleInputStream(\n stream: ReadableStream<Uint8Array>,\n metadata?: Record<string, any>\n ): Promise<void> {\n // Initialize demuxer if not configured\n if (this.currentFormat === 'mp3' && !this.mp3Parser) {\n this.mp3Parser = new MP3FrameParser();\n }\n\n if (this.currentFormat === 'mp4' && (!this.demuxer || !this.audioStream)) {\n await this.handleConfigure({\n config: { container: 'mp4', highWaterMark: 10 },\n initial: true,\n });\n }\n\n if (!this.decoderPort) {\n throw new Error('Decoder not connected');\n }\n\n // Setup channel to decoder\n const decoderChannel = new WorkerChannel(this.decoderPort, {\n name: 'AudioDemux-Decoder',\n timeout: 30000,\n });\n\n if (this.currentFormat === 'mp3') {\n await this.pipeMp3Stream(stream, decoderChannel, metadata);\n } else if (this.demuxer && this.audioStream) {\n const transformed = stream.pipeThrough(this.audioStream);\n const trackInfo = Array.from(this.demuxer.tracks.values())[0];\n\n await decoderChannel.sendStream(transformed, {\n streamType: 'audio',\n clipId: metadata?.clipId ?? 'default',\n trackId: metadata?.trackId ?? 'main',\n codec: trackInfo?.codec ?? 'mp4a.40.2',\n sampleRate: trackInfo?.sampleRate ?? 44_100,\n numberOfChannels: trackInfo?.numberOfChannels ?? 2,\n description: trackInfo?.description,\n });\n\n this.channel.notify('demux_complete', {\n tracksProcessed: this.demuxer?.tracks.size || 0,\n });\n } else {\n throw new Error('Audio demuxer not initialized');\n }\n }\n\n private async pipeMp3Stream(\n stream: ReadableStream<Uint8Array>,\n decoderChannel: WorkerChannel,\n metadata?: Record<string, any>\n ): Promise<void> {\n if (!this.mp3Parser) {\n this.mp3Parser = new MP3FrameParser();\n }\n\n const reader = stream.getReader();\n let currentConfig: MP3Config | null = null;\n let configured = false;\n const bufferedFrames: MP3Frame[] = [];\n let writer: WritableStreamDefaultWriter<EncodedAudioChunk> | null = null;\n\n const ensureWriter = async (): Promise<WritableStreamDefaultWriter<EncodedAudioChunk>> => {\n if (!writer) {\n const cfg = currentConfig;\n if (!cfg) {\n throw new Error('MP3 config missing while creating writer');\n }\n const transform = new TransformStream<EncodedAudioChunk, EncodedAudioChunk>();\n writer = transform.writable.getWriter();\n await decoderChannel.sendStream(transform.readable, {\n streamType: 'audio',\n clipId: metadata?.clipId ?? 'default',\n trackId: metadata?.trackId ?? 'main',\n codec: 'mp3',\n sampleRate: cfg.sampleRate,\n numberOfChannels: cfg.channels,\n description: undefined,\n });\n }\n return writer!;\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n if (!value) {\n continue;\n }\n\n const { frames, config } = this.mp3Parser.push(value);\n\n if (config) {\n currentConfig = config;\n }\n\n if (config && !configured) {\n await decoderChannel.send('configure' as any, {\n streamType: 'audio',\n clipId: metadata?.clipId ?? 'default',\n codec: 'mp3',\n sampleRate: config.sampleRate,\n numberOfChannels: config.channels,\n description: undefined,\n });\n this.channel.notify('demux_configured', {\n clipId: metadata?.clipId ?? 'default',\n codec: 'mp3',\n sampleRate: config.sampleRate,\n numberOfChannels: config.channels,\n });\n configured = true;\n }\n\n if (config) {\n this.currentFormat = 'mp3';\n }\n\n if (!configured) {\n bufferedFrames.push(...frames);\n continue;\n }\n\n const targetWriter = await ensureWriter();\n const readyFrames = bufferedFrames.splice(0, bufferedFrames.length);\n readyFrames.push(...frames);\n for (const frame of readyFrames) {\n const chunk = new EncodedAudioChunk({\n type: 'key',\n timestamp: frame.timestampUs,\n duration: frame.durationUs,\n data: frame.data.buffer.slice(\n frame.data.byteOffset,\n frame.data.byteOffset + frame.data.byteLength\n ),\n });\n await targetWriter.write(chunk);\n }\n }\n\n const remaining = this.mp3Parser.flush();\n if (remaining.length) {\n if (!configured) {\n throw new Error('MP3 stream ended before configuration');\n }\n const targetWriter = await ensureWriter();\n for (const frame of remaining) {\n const chunk = new EncodedAudioChunk({\n type: 'key',\n timestamp: frame.timestampUs,\n duration: frame.durationUs,\n data: frame.data.buffer.slice(\n frame.data.byteOffset,\n frame.data.byteOffset + frame.data.byteLength\n ),\n });\n await targetWriter.write(chunk);\n }\n }\n\n if (writer) {\n await (writer as WritableStreamDefaultWriter<EncodedAudioChunk>).close();\n }\n\n this.channel.notify('demux_complete', {\n tracksProcessed: 1,\n });\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Get demuxer statistics\n */\n private async handleGetStats(): Promise<{\n queueSize?: number;\n tracksInfo?: any[];\n format?: string;\n state?: WorkerState;\n }> {\n if (this.currentFormat === 'mp3') {\n return {\n tracksInfo: this.mp3Parser ? [{ id: 1, type: 'audio', codec: 'mp3' }] : [],\n format: 'mp3',\n state: this.channel.state,\n };\n }\n\n if (this.demuxer) {\n return {\n tracksInfo: Array.from(this.demuxer.tracks.values()),\n format: 'mp4',\n state: this.channel.state,\n };\n }\n\n return { state: this.channel.state };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.demuxer) {\n this.demuxer.destroy();\n }\n this.demuxer = null;\n this.audioStream = null;\n this.mp3Parser = null;\n this.currentFormat = null;\n\n this.decoderPort?.close();\n this.decoderPort = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\n// Initialize worker\nconst worker = new AudioDemuxWorker();\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,77 @@
|
|
|
1
|
+
export interface DemuxConfig {
|
|
2
|
+
codec?: string;
|
|
3
|
+
trackId?: string;
|
|
4
|
+
container?: 'mp4' | 'webm';
|
|
5
|
+
highWaterMark?: number;
|
|
6
|
+
streaming?: {
|
|
7
|
+
batchSize?: number;
|
|
8
|
+
highWaterMark?: number;
|
|
9
|
+
sizeStrategy?: 'count' | 'bytes';
|
|
10
|
+
progressive?: boolean;
|
|
11
|
+
minBufferSize?: number;
|
|
12
|
+
};
|
|
13
|
+
performance?: {
|
|
14
|
+
immediateRelease?: boolean;
|
|
15
|
+
maxMemory?: number;
|
|
16
|
+
hardwareAcceleration?: boolean;
|
|
17
|
+
};
|
|
18
|
+
tracks?: {
|
|
19
|
+
videoTracks?: number[];
|
|
20
|
+
audioTracks?: number[];
|
|
21
|
+
};
|
|
22
|
+
skipVideo?: boolean;
|
|
23
|
+
skipAudio?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface DemuxSample {
|
|
26
|
+
timestamp: number;
|
|
27
|
+
duration: number;
|
|
28
|
+
data: ArrayBuffer;
|
|
29
|
+
isKeyFrame: boolean;
|
|
30
|
+
trackId: string;
|
|
31
|
+
}
|
|
32
|
+
export interface TrackInfo {
|
|
33
|
+
id: number;
|
|
34
|
+
type: 'video' | 'audio';
|
|
35
|
+
codec: string;
|
|
36
|
+
width?: number;
|
|
37
|
+
height?: number;
|
|
38
|
+
sampleRate?: number;
|
|
39
|
+
numberOfChannels?: number;
|
|
40
|
+
bitrate?: number;
|
|
41
|
+
duration?: number;
|
|
42
|
+
timescale?: number;
|
|
43
|
+
description?: ArrayBuffer;
|
|
44
|
+
}
|
|
45
|
+
export interface DemuxerEvents {
|
|
46
|
+
onReady: (info: {
|
|
47
|
+
tracks: TrackInfo[];
|
|
48
|
+
}) => void;
|
|
49
|
+
onSamples: (samples: DemuxSample[]) => void;
|
|
50
|
+
onError: (error: Error) => void;
|
|
51
|
+
onComplete: () => void;
|
|
52
|
+
}
|
|
53
|
+
export interface BaseDemuxer {
|
|
54
|
+
configure(config: DemuxConfig): Promise<void>;
|
|
55
|
+
appendBuffer(buffer: ArrayBuffer): void;
|
|
56
|
+
flush(): void;
|
|
57
|
+
reset(): void;
|
|
58
|
+
destroy(): void;
|
|
59
|
+
}
|
|
60
|
+
export interface MP4DemuxInfo {
|
|
61
|
+
duration: number;
|
|
62
|
+
timescale: number;
|
|
63
|
+
isFragmented: boolean;
|
|
64
|
+
isProgressive: boolean;
|
|
65
|
+
hasIOD: boolean;
|
|
66
|
+
brands: string[];
|
|
67
|
+
created: Date;
|
|
68
|
+
modified: Date;
|
|
69
|
+
tracks: TrackInfo[];
|
|
70
|
+
}
|
|
71
|
+
export interface AudioDemuxConfig extends DemuxConfig {
|
|
72
|
+
codec: 'aac' | 'opus';
|
|
73
|
+
}
|
|
74
|
+
export interface VideoDemuxConfig extends DemuxConfig {
|
|
75
|
+
codec: 'h264' | 'h265' | 'vp9' | 'av1';
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/stages/demux/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VideoDemuxWorker - First stage for video processing
|
|
3
|
+
* Extracts video tracks from container formats (MP4, etc.)
|
|
4
|
+
*
|
|
5
|
+
* Pipeline: ResourceLoader (Main Thread) → VideoDemuxWorker → DecodeWorker
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - MP4 container demuxing with mp4box.js
|
|
9
|
+
* - Stream-based processing with backpressure
|
|
10
|
+
* - Direct streaming to DecodeWorker
|
|
11
|
+
*/
|
|
12
|
+
export declare class VideoDemuxWorker {
|
|
13
|
+
private channel;
|
|
14
|
+
private demuxer;
|
|
15
|
+
private resourceId;
|
|
16
|
+
private clipId?;
|
|
17
|
+
private downstreamPort;
|
|
18
|
+
private range?;
|
|
19
|
+
constructor();
|
|
20
|
+
protected setupHandlers(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Handle connection from orchestrator
|
|
23
|
+
*/
|
|
24
|
+
private handleConnect;
|
|
25
|
+
/**
|
|
26
|
+
* Configure demuxer with format settings
|
|
27
|
+
* @param payload.config - Demuxer configuration
|
|
28
|
+
* @param payload.initial - If true, initialize worker state; otherwise just update config
|
|
29
|
+
*/
|
|
30
|
+
private handleConfigure;
|
|
31
|
+
/**
|
|
32
|
+
* Handle input stream from ResourceLoader (main thread)
|
|
33
|
+
* Strategy: Stream immediately, send codec info when ready
|
|
34
|
+
*/
|
|
35
|
+
private handleReceiveStream;
|
|
36
|
+
private handleDemuxerReady;
|
|
37
|
+
/**
|
|
38
|
+
* Get demuxer statistics
|
|
39
|
+
*/
|
|
40
|
+
private handleGetStats;
|
|
41
|
+
/**
|
|
42
|
+
* Dispose worker and cleanup resources
|
|
43
|
+
*/
|
|
44
|
+
private handleDispose;
|
|
45
|
+
}
|
|
46
|
+
declare const _default: null;
|
|
47
|
+
export default _default;
|
|
48
|
+
//# sourceMappingURL=video-demux.worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-demux.worker.d.ts","sourceRoot":"","sources":["../../../src/stages/demux/video-demux.worker.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,KAAK,CAAC,CAAiC;;IAY/C,SAAS,CAAC,aAAa,IAAI,IAAI;IAW/B;;OAEG;YACW,aAAa;IAkB3B;;;;OAIG;YACW,eAAe;IAuC7B;;;OAGG;YACW,mBAAmB;IA+DjC,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;YACW,cAAc;IAe5B;;OAEG;YACW,aAAa;CAc5B;;AASD,wBAAoB"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { WorkerChannel } from "../../worker/WorkerChannel.js";
|
|
2
|
+
import { WorkerMessageType, WorkerState } from "../../worker/types.js";
|
|
3
|
+
import { MP4Demuxer } from "./MP4Demuxer.js";
|
|
4
|
+
class VideoDemuxWorker {
|
|
5
|
+
channel;
|
|
6
|
+
demuxer = null;
|
|
7
|
+
resourceId = null;
|
|
8
|
+
clipId;
|
|
9
|
+
downstreamPort = null;
|
|
10
|
+
range;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.channel = new WorkerChannel(self, {
|
|
13
|
+
name: "VideoDemuxWorker",
|
|
14
|
+
timeout: 3e4
|
|
15
|
+
});
|
|
16
|
+
this.setupHandlers();
|
|
17
|
+
}
|
|
18
|
+
/* @better-ai.mdc For test visibility */
|
|
19
|
+
setupHandlers() {
|
|
20
|
+
this.channel.registerHandler("configure", this.handleConfigure.bind(this));
|
|
21
|
+
this.channel.registerHandler("connect", this.handleConnect.bind(this));
|
|
22
|
+
this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
|
|
23
|
+
this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
|
|
24
|
+
this.channel.receiveStream(this.handleReceiveStream.bind(this));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Handle connection from orchestrator
|
|
28
|
+
*/
|
|
29
|
+
async handleConnect(payload) {
|
|
30
|
+
const { port, clipId } = payload;
|
|
31
|
+
if (!port) {
|
|
32
|
+
return { success: false };
|
|
33
|
+
}
|
|
34
|
+
this.downstreamPort = port;
|
|
35
|
+
this.clipId = clipId;
|
|
36
|
+
return { success: true };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Configure demuxer with format settings
|
|
40
|
+
* @param payload.config - Demuxer configuration
|
|
41
|
+
* @param payload.initial - If true, initialize worker state; otherwise just update config
|
|
42
|
+
*/
|
|
43
|
+
async handleConfigure(payload) {
|
|
44
|
+
const { config, initial = false } = payload;
|
|
45
|
+
try {
|
|
46
|
+
if (initial) {
|
|
47
|
+
this.channel.state = WorkerState.Ready;
|
|
48
|
+
if (this.demuxer) {
|
|
49
|
+
this.demuxer.destroy();
|
|
50
|
+
}
|
|
51
|
+
this.demuxer = new MP4Demuxer({
|
|
52
|
+
...config,
|
|
53
|
+
skipAudio: true,
|
|
54
|
+
// Video only
|
|
55
|
+
onReady: () => this.handleDemuxerReady()
|
|
56
|
+
});
|
|
57
|
+
this.channel.notify("configured");
|
|
58
|
+
return { success: true };
|
|
59
|
+
} else {
|
|
60
|
+
this.demuxer?.updateConfig(config);
|
|
61
|
+
return { success: true };
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
throw {
|
|
65
|
+
code: error.code || "CONFIG_ERROR",
|
|
66
|
+
message: error.message
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Handle input stream from ResourceLoader (main thread)
|
|
72
|
+
* Strategy: Stream immediately, send codec info when ready
|
|
73
|
+
*/
|
|
74
|
+
async handleReceiveStream(stream, metadata) {
|
|
75
|
+
console.log("[VideoDemuxWorker] handleReceiveStream", metadata?.clipId, metadata?.resourceId);
|
|
76
|
+
const currentResourceId = metadata?.resourceId || metadata?.clipId || this.resourceId || "default";
|
|
77
|
+
const clipId = metadata?.clipId;
|
|
78
|
+
if (this.resourceId && this.resourceId !== currentResourceId) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`[VideoDemuxWorker] BUG: Resource ID changed from ${this.resourceId} to ${currentResourceId}. Each VideoDemuxWorker instance should only handle one resource.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (!this.resourceId) {
|
|
84
|
+
this.resourceId = currentResourceId;
|
|
85
|
+
}
|
|
86
|
+
if (!this.demuxer) {
|
|
87
|
+
this.demuxer = new MP4Demuxer({
|
|
88
|
+
highWaterMark: 10,
|
|
89
|
+
skipAudio: true,
|
|
90
|
+
// Video only
|
|
91
|
+
onReady: () => this.handleDemuxerReady()
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (!this.downstreamPort) {
|
|
95
|
+
throw new Error("Decoder not connected");
|
|
96
|
+
}
|
|
97
|
+
if (clipId) {
|
|
98
|
+
this.clipId = clipId;
|
|
99
|
+
}
|
|
100
|
+
if (metadata?.range) {
|
|
101
|
+
this.range = metadata.range;
|
|
102
|
+
}
|
|
103
|
+
const videoStream = this.demuxer.createVideoStream();
|
|
104
|
+
const downstreamChannel = new WorkerChannel(this.downstreamPort, {
|
|
105
|
+
name: "VideoDemux-Decoder",
|
|
106
|
+
timeout: 3e4
|
|
107
|
+
});
|
|
108
|
+
downstreamChannel.sendStream(videoStream.readable, {
|
|
109
|
+
streamType: "video",
|
|
110
|
+
clipId: this.clipId,
|
|
111
|
+
...this.range && { range: this.range }
|
|
112
|
+
// codec info will be sent separately when ready
|
|
113
|
+
});
|
|
114
|
+
await stream.pipeTo(videoStream.writable);
|
|
115
|
+
}
|
|
116
|
+
handleDemuxerReady() {
|
|
117
|
+
if (!this.demuxer || !this.downstreamPort) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const videoTrackInfo = this.demuxer.videoTrackInfo;
|
|
121
|
+
if (!videoTrackInfo) {
|
|
122
|
+
console.error("[VideoDemuxWorker] No video track found after ready");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const downstreamChannel = new WorkerChannel(this.downstreamPort, {
|
|
126
|
+
name: "VideoDemux-Decoder",
|
|
127
|
+
timeout: 3e4
|
|
128
|
+
});
|
|
129
|
+
downstreamChannel.send("configure", {
|
|
130
|
+
clipId: this.clipId,
|
|
131
|
+
streamType: "video",
|
|
132
|
+
codec: videoTrackInfo.codec,
|
|
133
|
+
width: videoTrackInfo.width,
|
|
134
|
+
height: videoTrackInfo.height,
|
|
135
|
+
...this.range && { range: this.range },
|
|
136
|
+
description: videoTrackInfo.description
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get demuxer statistics
|
|
141
|
+
*/
|
|
142
|
+
async handleGetStats() {
|
|
143
|
+
if (!this.demuxer) {
|
|
144
|
+
return { state: this.channel.state };
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
tracksInfo: Array.from(this.demuxer.tracks.values()),
|
|
148
|
+
state: this.channel.state
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Dispose worker and cleanup resources
|
|
153
|
+
*/
|
|
154
|
+
async handleDispose() {
|
|
155
|
+
this.demuxer?.destroy();
|
|
156
|
+
this.demuxer = null;
|
|
157
|
+
this.resourceId = null;
|
|
158
|
+
this.downstreamPort?.close();
|
|
159
|
+
this.downstreamPort = null;
|
|
160
|
+
this.channel.state = WorkerState.Disposed;
|
|
161
|
+
return { success: true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const worker = new VideoDemuxWorker();
|
|
165
|
+
self.addEventListener("beforeunload", () => {
|
|
166
|
+
worker["handleDispose"]();
|
|
167
|
+
});
|
|
168
|
+
const videoDemux_worker = null;
|
|
169
|
+
export {
|
|
170
|
+
VideoDemuxWorker,
|
|
171
|
+
videoDemux_worker as default
|
|
172
|
+
};
|
|
173
|
+
//# sourceMappingURL=video-demux.worker.js.map
|