@meframe/core 0.0.3 → 0.0.5
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/dist/Meframe.d.ts +16 -7
- package/dist/Meframe.d.ts.map +1 -1
- package/dist/Meframe.js +75 -90
- package/dist/Meframe.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +28 -11
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +93 -30
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/L2Cache.d.ts +31 -2
- package/dist/cache/L2Cache.d.ts.map +1 -1
- package/dist/cache/L2Cache.js +245 -44
- package/dist/cache/L2Cache.js.map +1 -1
- package/dist/cache/l1/VideoL1Cache.d.ts +3 -3
- package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -1
- package/dist/cache/l1/VideoL1Cache.js +13 -8
- package/dist/cache/l1/VideoL1Cache.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/types.d.ts +3 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/controllers/PlaybackController.d.ts +7 -8
- package/dist/controllers/PlaybackController.d.ts.map +1 -1
- package/dist/controllers/PlaybackController.js +56 -76
- package/dist/controllers/PlaybackController.js.map +1 -1
- package/dist/controllers/PreRenderService.d.ts +21 -4
- package/dist/controllers/PreRenderService.d.ts.map +1 -1
- package/dist/controllers/PreRenderService.js +67 -5
- package/dist/controllers/PreRenderService.js.map +1 -1
- package/dist/controllers/types.d.ts +2 -3
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/event/events.d.ts +1 -4
- package/dist/event/events.d.ts.map +1 -1
- package/dist/event/events.js.map +1 -1
- package/dist/model/CompositionModel.d.ts +2 -1
- package/dist/model/CompositionModel.d.ts.map +1 -1
- package/dist/model/CompositionModel.js +3 -1
- package/dist/model/CompositionModel.js.map +1 -1
- package/dist/model/patch.d.ts +6 -2
- package/dist/model/patch.d.ts.map +1 -1
- package/dist/model/patch.js +76 -2
- package/dist/model/patch.js.map +1 -1
- package/dist/model/types.d.ts +1 -0
- package/dist/model/types.d.ts.map +1 -1
- package/dist/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js +1858 -0
- package/dist/node_modules/.pnpm/mp4-muxer@5.2.2/node_modules/mp4-muxer/build/mp4-muxer.js.map +1 -0
- package/dist/orchestrator/ClipSessionManager.d.ts +1 -2
- package/dist/orchestrator/ClipSessionManager.d.ts.map +1 -1
- package/dist/orchestrator/ClipSessionManager.js +1 -0
- package/dist/orchestrator/ClipSessionManager.js.map +1 -1
- package/dist/orchestrator/CompositionPlanner.d.ts +8 -7
- package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
- package/dist/orchestrator/CompositionPlanner.js +33 -56
- package/dist/orchestrator/CompositionPlanner.js.map +1 -1
- package/dist/orchestrator/Orchestrator.d.ts +9 -2
- package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/Orchestrator.js +100 -50
- package/dist/orchestrator/Orchestrator.js.map +1 -1
- package/dist/orchestrator/VideoClipSession.d.ts +14 -9
- package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
- package/dist/orchestrator/VideoClipSession.js +108 -85
- package/dist/orchestrator/VideoClipSession.js.map +1 -1
- package/dist/orchestrator/types.d.ts +1 -0
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/stages/compose/GlobalAudioSession.d.ts +34 -1
- package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -1
- package/dist/stages/compose/GlobalAudioSession.js +149 -5
- package/dist/stages/compose/GlobalAudioSession.js.map +1 -1
- package/dist/stages/compose/VideoComposer.d.ts +1 -0
- package/dist/stages/compose/VideoComposer.d.ts.map +1 -1
- package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
- package/dist/stages/encode/AudioChunkEncoder.d.ts +2 -1
- package/dist/stages/encode/AudioChunkEncoder.d.ts.map +1 -1
- package/dist/stages/encode/AudioChunkEncoder.js +41 -0
- package/dist/stages/encode/AudioChunkEncoder.js.map +1 -0
- package/dist/stages/encode/BaseEncoder.d.ts +7 -3
- package/dist/stages/encode/BaseEncoder.d.ts.map +1 -1
- package/dist/stages/encode/BaseEncoder.js +173 -0
- package/dist/stages/encode/BaseEncoder.js.map +1 -0
- package/dist/stages/encode/ClipEncoderManager.d.ts +64 -0
- package/dist/stages/encode/ClipEncoderManager.d.ts.map +1 -0
- package/dist/stages/encode/index.d.ts +1 -1
- package/dist/stages/encode/index.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.d.ts +22 -1
- package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
- package/dist/stages/load/ResourceLoader.js +80 -29
- package/dist/stages/load/ResourceLoader.js.map +1 -1
- package/dist/stages/load/TaskManager.d.ts +1 -1
- package/dist/stages/load/TaskManager.d.ts.map +1 -1
- package/dist/stages/load/TaskManager.js +3 -2
- package/dist/stages/load/TaskManager.js.map +1 -1
- package/dist/stages/load/types.d.ts +4 -2
- package/dist/stages/load/types.d.ts.map +1 -1
- package/dist/stages/mux/MP4Muxer.d.ts +19 -38
- package/dist/stages/mux/MP4Muxer.d.ts.map +1 -1
- package/dist/stages/mux/MP4Muxer.js +60 -0
- package/dist/stages/mux/MP4Muxer.js.map +1 -0
- package/dist/stages/mux/MuxManager.d.ts +27 -0
- package/dist/stages/mux/MuxManager.d.ts.map +1 -0
- package/dist/stages/mux/MuxManager.js +148 -0
- package/dist/stages/mux/MuxManager.js.map +1 -0
- package/dist/stages/mux/index.d.ts +1 -0
- package/dist/stages/mux/index.d.ts.map +1 -1
- package/dist/stages/mux/types.d.ts +1 -0
- package/dist/stages/mux/types.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/worker/WorkerPool.d.ts +2 -0
- package/dist/worker/WorkerPool.d.ts.map +1 -1
- package/dist/worker/WorkerPool.js +6 -5
- package/dist/worker/WorkerPool.js.map +1 -1
- package/dist/worker/types.d.ts +1 -4
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/types.js +0 -3
- package/dist/worker/types.js.map +1 -1
- package/dist/worker/worker-event-whitelist.d.ts.map +1 -1
- package/dist/workers/MP4Demuxer.js +7049 -6
- package/dist/workers/MP4Demuxer.js.map +1 -1
- package/dist/workers/WorkerChannel.js +0 -3
- package/dist/workers/WorkerChannel.js.map +1 -1
- package/dist/workers/stages/compose/video-compose.worker.js +126 -83
- package/dist/workers/stages/compose/video-compose.worker.js.map +1 -1
- package/dist/workers/stages/decode/decode.worker.js +25 -16
- package/dist/workers/stages/decode/decode.worker.js.map +1 -1
- package/dist/workers/stages/demux/audio-demux.worker.js +4 -4
- package/dist/workers/stages/demux/audio-demux.worker.js.map +1 -1
- package/dist/workers/stages/demux/video-demux.worker.js +9 -7
- package/dist/workers/stages/demux/video-demux.worker.js.map +1 -1
- package/dist/workers/stages/encode/encode.worker.js +191 -195
- package/dist/workers/stages/encode/encode.worker.js.map +1 -1
- package/package.json +2 -1
- package/dist/controllers/PreviewHandle.d.ts +0 -25
- package/dist/controllers/PreviewHandle.d.ts.map +0 -1
- package/dist/controllers/PreviewHandle.js +0 -45
- package/dist/controllers/PreviewHandle.js.map +0 -1
- package/dist/model/dirty-range.js +0 -220
- package/dist/model/dirty-range.js.map +0 -1
- package/dist/stages/encode/EncoderPool.d.ts +0 -28
- package/dist/stages/encode/EncoderPool.d.ts.map +0 -1
- package/dist/workers/mp4box.all.js +0 -7049
- package/dist/workers/mp4box.all.js.map +0 -1
- package/dist/workers/stages/mux/mux.worker.js +0 -501
- package/dist/workers/stages/mux/mux.worker.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encode.worker.js","sources":["../../../../src/stages/encode/BaseEncoder.ts","../../../../src/stages/encode/VideoChunkEncoder.ts","../../../../src/stages/encode/AudioChunkEncoder.ts","../../../../src/stages/encode/encode.worker.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<TChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n if (this.encoder?.state === 'configured') {\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n if (!isSupported.supported) {\n throw new Error(`Codec not supported: ${this.config.codec}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n }\n\n async close(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, _metadata: TMetadata): void {\n // Enqueue to stream controller\n this.controller?.enqueue(chunk);\n }\n\n protected handleError(error: DOMException): void {\n console.error(`${this.getEncoderType()} encoder error:`, error);\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, TChunk> {\n return new TransformStream<TInput, TChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n\n // Initialize encoder if not already initialized\n if (!this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (input) => {\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n // Check encoder queue pressure\n if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n // Wait for queue to drain\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Encode the input\n this.encode(input);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n","import { BaseEncoder } from './BaseEncoder';\nimport type { VideoEncoderConfig } from './types';\n\n/**\n * VideoChunkEncoder - Encodes VideoFrame to EncodedVideoChunk\n * Stream-based encoder with backpressure handling\n */\nexport class VideoChunkEncoder extends BaseEncoder<\n VideoEncoder,\n VideoEncoderConfig,\n VideoFrame,\n EncodedVideoChunk,\n EncodedVideoChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 2;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 8;\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n private frameCount = 0;\n private keyFrameInterval = 60; // 2 seconds at 30fps\n\n constructor(config: VideoEncoderConfig) {\n super(config);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n config.backpressure?.highWaterMark ?? VideoChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n config.backpressure?.encodeQueueThreshold ?? VideoChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: VideoEncoderConfig): Promise<{ supported: boolean }> {\n const result = await VideoEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: VideoEncoderInit): VideoEncoder {\n return new VideoEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Video';\n }\n\n protected override onReset(): void {\n this.frameCount = 0;\n }\n\n encode(frame: VideoFrame): void {\n const keyFrame = this.shouldGenerateKeyFrame();\n const encodeOptions: VideoEncoderEncodeOptions = {\n keyFrame,\n };\n\n this.encoder!.encode(frame, encodeOptions);\n this.frameCount++;\n frame.close();\n }\n\n setKeyFrameInterval(interval: number): void {\n this.keyFrameInterval = Math.max(1, interval);\n }\n\n private shouldGenerateKeyFrame(): boolean {\n if (this.frameCount === 0) {\n return true;\n }\n return this.frameCount % this.keyFrameInterval === 0;\n }\n}\n","import { BaseEncoder } from './BaseEncoder';\nimport type { AudioEncoderConfig } from './types';\n\n/**\n * AudioChunkEncoder - Encodes AudioData to EncodedAudioChunk\n * Stream-based encoder with backpressure handling\n */\nexport class AudioChunkEncoder extends BaseEncoder<\n AudioEncoder,\n AudioEncoderConfig,\n AudioData,\n EncodedAudioChunk,\n EncodedAudioChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 4;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 16;\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n constructor(config: AudioEncoderConfig) {\n super(config);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n config.backpressure?.highWaterMark ?? AudioChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n config.backpressure?.encodeQueueThreshold ?? AudioChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: AudioEncoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: AudioEncoderInit): AudioEncoder {\n return new AudioEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Audio';\n }\n\n encode(data: AudioData): void {\n if (this.encoder?.state !== 'configured') {\n throw new Error('Audio encoder not configured');\n }\n\n // Ensure input data matches encoder configuration\n const config = this.getConfig();\n if (\n data.sampleRate !== config.sampleRate ||\n data.numberOfChannels !== config.numberOfChannels\n ) {\n throw new Error('AudioData requires resampling or channel remap before encoding');\n }\n\n this.encoder.encode(data);\n data.close();\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoChunkEncoder } from './VideoChunkEncoder';\nimport { AudioChunkEncoder } from './AudioChunkEncoder';\nimport { VideoEncoderConfig, AudioEncoderConfig } from './types';\n\n/**\n * EncodeWorker - Seventh stage in the pipeline\n * Receives composed frames from ComposeWorkers and outputs encoded chunks to CacheManager/MuxWorker\n *\n * Pipeline: VideoComposeWorker/AudioComposeWorker → EncodeWorker → CacheManager/MuxWorker\n *\n * Features:\n * - Hardware-accelerated encoding via WebCodecs\n * - Configurable bitrate and quality settings\n * - Batch flush for efficient I/O (0.5s batches)\n * - Direct streaming to cache/mux workers\n */\nclass EncodeWorker {\n private channel: WorkerChannel;\n private videoEncoder: VideoChunkEncoder | null = null;\n private audioEncoder: AudioChunkEncoder | null = null;\n\n // Connections to other workers\n private cachePort: MessagePort | null = null;\n private muxPort: MessagePort | null = null;\n private composePorts = new Map<string, MessagePort>(); // Connections from compose workers\n\n constructor() {\n // Initialize WorkerChannel with MessagePort\n this.channel = new WorkerChannel(self as any, {\n name: 'EncodeWorker',\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', this.handleConnect.bind(this));\n this.channel.registerHandler('configure_video', this.handleConfigureVideo.bind(this));\n this.channel.registerHandler('configure_audio', this.handleConfigureAudio.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';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n }): Promise<{ success: boolean }> {\n const { port, streamType } = payload;\n if (streamType === 'video') return this.handleConnectComposer({ composeType: 'video', port });\n if (streamType === 'audio') return this.handleConnectComposer({ composeType: 'audio', port });\n if (streamType === 'chunk') return this.handleConnectMux({ port });\n return { success: true };\n }\n\n /**\n * Handle configuration message from orchestrator\n * @param payload.initial - If true, initialize worker and recreate encoder instances; otherwise just update config\n */\n private async handleConfigure(payload: {\n config: {\n video?: Partial<VideoEncoderConfig> & { stream?: ReadableStream<VideoFrame> };\n audio?: Partial<AudioEncoderConfig> & { stream?: ReadableStream<AudioData> };\n };\n initial?: boolean;\n }): Promise<{ success: boolean }> {\n const { config, initial = false } = payload;\n\n // Set worker state to ready on initial configuration\n if (initial) {\n this.channel.state = WorkerState.Ready;\n }\n\n // Handle video encoder configuration\n if (config.video) {\n if (initial || !this.videoEncoder) {\n if (this.videoEncoder) {\n await this.videoEncoder.close();\n }\n this.videoEncoder = new VideoChunkEncoder(config.video as VideoEncoderConfig);\n await this.videoEncoder.initialize();\n\n const videoStream = config.video.stream?.pipeThrough(this.videoEncoder.createStream());\n if (videoStream && this.cachePort) {\n const cacheChannel = new WorkerChannel(this.cachePort, {\n name: 'Encode-Cache-Video',\n timeout: 30000,\n });\n await cacheChannel.sendStream(videoStream, {\n type: 'video',\n width: config.video.width,\n height: config.video.height,\n framerate: config.video.framerate,\n });\n }\n } else {\n await this.videoEncoder.reconfigure(config.video);\n }\n }\n\n if (config.audio) {\n if (initial || !this.audioEncoder) {\n if (this.audioEncoder) {\n await this.audioEncoder.close();\n }\n this.audioEncoder = new AudioChunkEncoder(config.audio as AudioEncoderConfig);\n await this.audioEncoder.initialize();\n\n const audioStream = config.audio.stream?.pipeThrough(this.audioEncoder.createStream());\n if (audioStream && this.cachePort) {\n const cacheChannel = new WorkerChannel(this.cachePort, {\n name: 'Encode-Cache-Audio',\n timeout: 30000,\n });\n await cacheChannel.sendStream(audioStream, {\n type: 'audio',\n sampleRate: config.audio.sampleRate,\n numberOfChannels: config.audio.numberOfChannels,\n });\n }\n } else {\n await this.audioEncoder.reconfigure(config.audio);\n }\n }\n\n return { success: true };\n }\n\n /**\n * Connect to a compose worker to receive frames/audio data\n */\n private async handleConnectComposer(payload: {\n composeType: 'video' | 'audio';\n port: MessagePort;\n }): Promise<{ success: boolean }> {\n const { composeType, port } = payload;\n\n // Store the port\n this.composePorts.set(composeType, port);\n\n // Setup channel for receiving streams\n const composeChannel = new WorkerChannel(port, {\n name: `Encode-${composeType}Compose`,\n timeout: 30000,\n });\n\n // Receive stream from composer\n composeChannel.receiveStream(async (stream, metadata) => {\n if (metadata?.streamType === 'video' && this.videoEncoder) {\n // Process video frames\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n // value might be wrapped object {frame, metadata} or plain VideoFrame\n const wrappedValue = value as any;\n const videoFrame = wrappedValue.frame || wrappedValue;\n\n try {\n const frame = (videoFrame as VideoFrame).clone();\n this.videoEncoder.encode(frame);\n } finally {\n // Close the original frame after cloning and encoding\n (videoFrame as VideoFrame).close();\n }\n }\n } finally {\n reader.releaseLock();\n }\n } else if (metadata?.streamType === 'audio' && this.audioEncoder) {\n const composedConfig = {\n sampleRate: metadata.sampleRate,\n numberOfChannels: metadata.numberOfChannels,\n };\n\n const currentConfig = this.audioEncoder.getConfig();\n\n if (\n typeof composedConfig.sampleRate === 'number' &&\n composedConfig.sampleRate > 0 &&\n composedConfig.sampleRate !== currentConfig.sampleRate\n ) {\n await this.audioEncoder.reconfigure({ sampleRate: composedConfig.sampleRate });\n }\n\n if (\n typeof composedConfig.numberOfChannels === 'number' &&\n composedConfig.numberOfChannels > 0 &&\n composedConfig.numberOfChannels !== currentConfig.numberOfChannels\n ) {\n await this.audioEncoder.reconfigure({\n numberOfChannels: composedConfig.numberOfChannels,\n });\n }\n\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.audioEncoder.encode(value as unknown as AudioData);\n }\n } finally {\n reader.releaseLock();\n }\n }\n });\n\n return { success: true };\n }\n\n /**\n * Connect to cache manager for output streaming\n */\n // private async handleConnectCache(payload: { port: MessagePort }): Promise<{ success: boolean }> {\n // this.cachePort = payload.port;\n // return { success: true };\n // }\n\n /**\n * Connect to mux worker for output streaming\n */\n private async handleConnectMux(payload: { port: MessagePort }): Promise<{ success: boolean }> {\n this.muxPort = payload.port;\n return { success: true };\n }\n\n /**\n * Configure video encoder with specific settings\n */\n private async handleConfigureVideo(config: VideoEncoderConfig): Promise<{ success: boolean }> {\n try {\n // Create encoder if not exists (shouldn't happen if configure was called)\n if (!this.videoEncoder) {\n this.videoEncoder = new VideoChunkEncoder(config);\n await this.videoEncoder.initialize();\n } else {\n await this.videoEncoder.reconfigure(config);\n }\n\n // Notify configuration complete\n this.channel.notify('video_configured', {\n codec: config.codec,\n width: config.width,\n height: config.height,\n bitrate: config.bitrate,\n });\n\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'VIDEO_CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Configure audio encoder with specific settings\n */\n private async handleConfigureAudio(config: AudioEncoderConfig): Promise<{ success: boolean }> {\n try {\n // Create encoder if not exists (shouldn't happen if configure was called)\n if (!this.audioEncoder) {\n this.audioEncoder = new AudioChunkEncoder(config);\n await this.audioEncoder.initialize();\n } else {\n await this.audioEncoder.reconfigure(config);\n }\n\n // Notify configuration complete\n this.channel.notify('audio_configured', {\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n bitrate: config.bitrate,\n });\n\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'AUDIO_CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Flush encoders and get buffered chunks\n */\n private async handleFlush(payload?: { type?: 'video' | 'audio' }): Promise<{\n videoChunks?: any[];\n audioChunks?: any[];\n }> {\n try {\n const result: any = {};\n\n if (!payload?.type || payload.type === 'video') {\n const chunks = await this.videoEncoder?.flush();\n if (chunks) {\n result.videoChunks = chunks;\n }\n }\n\n if (!payload?.type || payload.type === 'audio') {\n const chunks = await this.audioEncoder?.flush();\n if (chunks) {\n result.audioChunks = chunks;\n }\n }\n\n return result;\n } catch (error: any) {\n throw {\n code: 'FLUSH_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Reset encoders\n */\n private async handleReset(payload?: { type?: 'video' | 'audio' }): Promise<{ success: boolean }> {\n try {\n if (!payload?.type || payload.type === 'video') {\n await this.videoEncoder?.reset();\n }\n if (!payload?.type || payload.type === 'audio') {\n await this.audioEncoder?.reset();\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 encoder statistics\n */\n private async handleGetStats(): Promise<{\n video?: any;\n audio?: any;\n }> {\n const stats: any = {};\n\n if (this.videoEncoder) {\n stats.video = {\n configured: this.videoEncoder.isReady,\n queueSize: this.videoEncoder.queueSize,\n };\n }\n\n if (this.audioEncoder) {\n stats.audio = {\n configured: this.audioEncoder.isReady,\n queueSize: this.audioEncoder.queueSize,\n };\n }\n\n return stats;\n }\n\n // Output and error handling is done via streams in the encoder itself\n // These placeholder methods can be implemented when needed for direct callback handling\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n // Close encoders\n await this.videoEncoder?.close();\n await this.audioEncoder?.close();\n\n this.videoEncoder = null;\n this.audioEncoder = null;\n\n // Close connections\n this.cachePort?.close();\n this.cachePort = null;\n\n this.muxPort?.close();\n this.muxPort = null;\n\n for (const port of this.composePorts.values()) {\n port.close();\n }\n this.composePorts.clear();\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\n// Initialize worker\nconst worker = new EncodeWorker();\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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"}
|
|
1
|
+
{"version":3,"file":"encode.worker.js","sources":["../../../../src/stages/encode/BaseEncoder.ts","../../../../src/stages/encode/VideoChunkEncoder.ts","../../../../src/stages/encode/AudioChunkEncoder.ts","../../../../src/stages/encode/ClipEncoderManager.ts","../../../../src/stages/encode/encode.worker.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\n\nexport interface EncoderChunk {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n}\n\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<EncoderChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n if (this.encoder?.state === 'configured') {\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n if (!isSupported.supported) {\n throw new Error(`Codec not supported: ${this.config.codec}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n }\n\n async close(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, metadata: TMetadata): void {\n // Only enqueue if controller exists and stream is not closed\n if (this.controller) {\n try {\n this.controller.enqueue({ chunk, metadata });\n } catch (error) {\n // Stream may be closed during flush, ignore enqueue errors\n if (!(error instanceof TypeError && error.message.includes('closed'))) {\n throw error;\n }\n }\n }\n }\n\n protected handleError(error: DOMException): void {\n console.error(`${this.getEncoderType()} encoder error:`, error);\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, EncoderChunk> {\n return new TransformStream<TInput, EncoderChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n\n // Initialize encoder if not already initialized\n if (!this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (input) => {\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n // Check encoder queue pressure\n if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n // Wait for queue to drain\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Encode the input\n const frame = (input as any).frame || input;\n this.encode(frame);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n","import { BaseEncoder } from './BaseEncoder';\nimport type { VideoEncoderConfig } from './types';\n\n/**\n * VideoChunkEncoder - Encodes VideoFrame to EncodedVideoChunk\n * Stream-based encoder with backpressure handling\n */\nexport class VideoChunkEncoder extends BaseEncoder<\n VideoEncoder,\n VideoEncoderConfig,\n VideoFrame,\n EncodedVideoChunk,\n EncodedVideoChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 2;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 8;\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n private frameCount = 0;\n private keyFrameInterval = 60; // 2 seconds at 30fps\n\n constructor(config: VideoEncoderConfig) {\n super(config);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n config.backpressure?.highWaterMark ?? VideoChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n config.backpressure?.encodeQueueThreshold ?? VideoChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: VideoEncoderConfig): Promise<{ supported: boolean }> {\n const result = await VideoEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: VideoEncoderInit): VideoEncoder {\n return new VideoEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Video';\n }\n\n protected override onReset(): void {\n this.frameCount = 0;\n }\n\n encode(frame: VideoFrame): void {\n const keyFrame = this.shouldGenerateKeyFrame();\n const encodeOptions: VideoEncoderEncodeOptions = {\n keyFrame,\n };\n\n this.encoder!.encode(frame, encodeOptions);\n this.frameCount++;\n frame.close();\n }\n\n setKeyFrameInterval(interval: number): void {\n this.keyFrameInterval = Math.max(1, interval);\n }\n\n private shouldGenerateKeyFrame(): boolean {\n if (this.frameCount === 0) {\n return true;\n }\n return this.frameCount % this.keyFrameInterval === 0;\n }\n}\n","import { BaseEncoder } from './BaseEncoder';\nimport type { AudioEncoderConfig } from './types';\n\n/**\n * AudioChunkEncoder - Encodes AudioData to EncodedAudioChunk\n * Stream-based encoder with backpressure handling\n */\nexport class AudioChunkEncoder extends BaseEncoder<\n AudioEncoder,\n AudioEncoderConfig,\n AudioData,\n EncodedAudioChunk,\n EncodedAudioChunkMetadata\n> {\n private static readonly DEFAULT_HIGH_WATER_MARK = 4;\n private static readonly DEFAULT_ENCODE_QUEUE_THRESHOLD = 16;\n\n static readonly DEFAULT_CONFIG: AudioEncoderConfig = {\n codec: 'mp4a.40.2', // AAC-LC\n sampleRate: 48000,\n numberOfChannels: 2,\n bitrate: 128000,\n };\n\n protected readonly highWaterMark: number;\n protected readonly encodeQueueThreshold: number;\n\n constructor(config?: Partial<AudioEncoderConfig>) {\n const fullConfig = { ...AudioChunkEncoder.DEFAULT_CONFIG, ...config };\n super(fullConfig);\n\n // Initialize backpressure settings from config or use defaults\n this.highWaterMark =\n fullConfig.backpressure?.highWaterMark ?? AudioChunkEncoder.DEFAULT_HIGH_WATER_MARK;\n this.encodeQueueThreshold =\n fullConfig.backpressure?.encodeQueueThreshold ??\n AudioChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;\n }\n\n protected async isConfigSupported(config: AudioEncoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioEncoder.isConfigSupported(config);\n return { supported: result.supported ?? false };\n }\n\n protected createEncoder(init: AudioEncoderInit): AudioEncoder {\n return new AudioEncoder(init);\n }\n\n protected getEncoderType(): string {\n return 'Audio';\n }\n\n encode(data: AudioData): void {\n if (this.encoder?.state !== 'configured') {\n throw new Error('Audio encoder not configured');\n }\n\n this.encoder.encode(data);\n data.close();\n }\n}\n","import { VideoChunkEncoder } from './VideoChunkEncoder';\nimport { AudioChunkEncoder } from './AudioChunkEncoder';\nimport type { VideoEncoderConfig, AudioEncoderConfig } from './types';\n\n/**\n * ClipEncoderManager - Per-Clip Encoder Instance Manager\n *\n * Responsibilities:\n * - Maintain separate encoder instances per clip (avoid frameCount pollution)\n * - Limit concurrent encoder instances (maxEncoders = 6)\n * - FIFO eviction strategy\n *\n * Note: This is NOT a traditional object pool, as it does not support\n * cross-clip instance reuse. Each sessionId gets its own dedicated encoder\n * that is destroyed (not recycled) when released.\n */\nexport class ClipEncoderManager {\n private videoEncoders = new Map<string, VideoChunkEncoder>();\n private audioEncoders = new Map<string, AudioChunkEncoder>();\n private videoCreationOrder: string[] = [];\n private audioCreationOrder: string[] = [];\n private readonly maxEncoders: number;\n\n constructor(maxEncoders = 6) {\n this.maxEncoders = maxEncoders;\n }\n\n /**\n * Acquire a video encoder for the given sessionId\n * Creates new encoder if not exists; returns existing one if already created\n */\n async acquireVideo(sessionId: string, config: VideoEncoderConfig): Promise<VideoChunkEncoder> {\n let encoder = this.videoEncoders.get(sessionId);\n\n if (!encoder) {\n // Check limit - throw error instead of auto-evicting\n // Auto-eviction is dangerous because encoder might still be in use by active streams\n if (this.videoEncoders.size >= this.maxEncoders) {\n throw new Error(\n `[ClipEncoderManager] Video encoder limit reached (${this.maxEncoders}). ` +\n `Active clips: ${Array.from(this.videoEncoders.keys()).join(', ')}. ` +\n `Please release unused encoders before acquiring new ones.`\n );\n }\n\n // Create new encoder\n encoder = new VideoChunkEncoder(config);\n await encoder.initialize();\n\n this.videoEncoders.set(sessionId, encoder);\n this.videoCreationOrder.push(sessionId);\n }\n\n return encoder;\n }\n\n /**\n * Acquire an audio encoder for the given sessionId\n */\n async acquireAudio(sessionId: string, config: AudioEncoderConfig): Promise<AudioChunkEncoder> {\n let encoder = this.audioEncoders.get(sessionId);\n\n if (!encoder) {\n // Check limit - throw error instead of auto-evicting\n if (this.audioEncoders.size >= this.maxEncoders) {\n throw new Error(\n `[ClipEncoderManager] Audio encoder limit reached (${this.maxEncoders}). ` +\n `Active clips: ${Array.from(this.audioEncoders.keys()).join(', ')}. ` +\n `Please release unused encoders before acquiring new ones.`\n );\n }\n\n // Create new encoder\n encoder = new AudioChunkEncoder(config);\n await encoder.initialize();\n\n this.audioEncoders.set(sessionId, encoder);\n this.audioCreationOrder.push(sessionId);\n }\n\n return encoder;\n }\n\n /**\n * Release video encoder for the given sessionId\n */\n async releaseVideo(sessionId: string): Promise<void> {\n const encoder = this.videoEncoders.get(sessionId);\n if (encoder) {\n await encoder.close();\n this.videoEncoders.delete(sessionId);\n\n // Remove from creation order\n const index = this.videoCreationOrder.indexOf(sessionId);\n if (index !== -1) {\n this.videoCreationOrder.splice(index, 1);\n }\n }\n }\n\n /**\n * Release audio encoder for the given sessionId\n */\n async releaseAudio(sessionId: string): Promise<void> {\n const encoder = this.audioEncoders.get(sessionId);\n if (encoder) {\n await encoder.close();\n this.audioEncoders.delete(sessionId);\n\n // Remove from creation order\n const index = this.audioCreationOrder.indexOf(sessionId);\n if (index !== -1) {\n this.audioCreationOrder.splice(index, 1);\n }\n }\n }\n\n /**\n * Release both video and audio encoders for the given sessionId\n */\n async releaseClip(sessionId: string): Promise<void> {\n await Promise.all([this.releaseVideo(sessionId), this.releaseAudio(sessionId)]);\n }\n\n /**\n * Close all encoders and clear state\n */\n async closeAll(): Promise<void> {\n const promises = [\n ...Array.from(this.videoEncoders.values()).map((e) => e.close()),\n ...Array.from(this.audioEncoders.values()).map((e) => e.close()),\n ];\n\n await Promise.all(promises);\n\n this.videoEncoders.clear();\n this.audioEncoders.clear();\n this.videoCreationOrder = [];\n this.audioCreationOrder = [];\n }\n\n /**\n * Check if encoders exist for the given sessionId\n */\n has(sessionId: string): boolean {\n return this.videoEncoders.has(sessionId) || this.audioEncoders.has(sessionId);\n }\n\n /**\n * Get statistics about current encoder state\n */\n getStats() {\n return {\n videoEncoders: this.videoEncoders.size,\n audioEncoders: this.audioEncoders.size,\n maxEncoders: this.maxEncoders,\n videoCreationOrder: [...this.videoCreationOrder],\n audioCreationOrder: [...this.audioCreationOrder],\n };\n }\n}\n","import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoChunkEncoder } from './VideoChunkEncoder';\nimport { AudioChunkEncoder } from './AudioChunkEncoder';\nimport { VideoEncoderConfig, AudioEncoderConfig } from './types';\nimport { ClipEncoderManager } from './ClipEncoderManager';\n\n/**\n * EncodeWorker - Seventh stage in the pipeline\n * Receives composed frames from ComposeWorkers and outputs encoded chunks to CacheManager/MuxWorker\n *\n * Pipeline: VideoComposeWorker/AudioComposeWorker → EncodeWorker → CacheManager/MuxWorker\n *\n * Features:\n * - Hardware-accelerated encoding via WebCodecs\n * - Configurable bitrate and quality settings\n * - Batch flush for efficient I/O (0.5s batches)\n * - Direct streaming to cache/mux workers\n */\nclass EncodeWorker {\n private channel: WorkerChannel;\n private encoderManager = new ClipEncoderManager(12); // Increased to prevent eviction during active streams\n\n // Default encoder configs\n private defaultVideoConfig: VideoEncoderConfig | null = null;\n private defaultAudioConfig: AudioEncoderConfig | null = null;\n\n // Connections to other workers\n private muxPort: MessagePort | null = null;\n private composePorts = new Map<string, MessagePort>(); // Connections from compose workers\n\n constructor() {\n // Initialize WorkerChannel with MessagePort\n this.channel = new WorkerChannel(self as any, {\n name: 'EncodeWorker',\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', this.handleConnect.bind(this));\n this.channel.registerHandler('configure_video', this.handleConfigureVideo.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('release_clip_encoder', this.handleReleaseClipEncoder.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' | 'frame' | 'chunk';\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { port, streamType, sessionId } = payload;\n\n if (streamType === 'video') {\n return this.handleConnectComposer({ composeType: 'video', port, sessionId });\n }\n if (streamType === 'audio') {\n return this.handleConnectComposer({ composeType: 'audio', port, sessionId });\n }\n if (streamType === 'chunk') return this.handleConnectMux({ port });\n return { success: true };\n }\n\n /**\n * Handle configuration message from orchestrator\n * @param payload.initial - If true, initialize worker; saves default encoder configs\n */\n private async handleConfigure(payload: {\n config: {\n video?: Partial<VideoEncoderConfig> & { stream?: ReadableStream<VideoFrame> };\n audio?: Partial<AudioEncoderConfig> & { stream?: ReadableStream<AudioData> };\n };\n initial?: boolean;\n }): Promise<{ success: boolean }> {\n const { config, initial = false } = payload;\n\n // Set worker state to ready on initial configuration\n if (initial) {\n this.channel.state = WorkerState.Ready;\n }\n\n // Save default encoder configs (used when creating per-clip encoders)\n if (config.video) {\n this.defaultVideoConfig = config.video as VideoEncoderConfig;\n }\n\n if (config.audio) {\n this.defaultAudioConfig = config.audio as AudioEncoderConfig;\n }\n\n return { success: true };\n }\n\n /**\n * Connect to a compose worker to receive frames/audio data\n */\n private async handleConnectComposer(payload: {\n composeType: 'video' | 'audio';\n port: MessagePort;\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { composeType, port, sessionId } = payload;\n\n // Store the port\n this.composePorts.set(composeType, port);\n\n // Setup channel for receiving streams\n const composeChannel = new WorkerChannel(port, {\n name: `Encode-${composeType}Compose`,\n timeout: 30000,\n });\n // Receive stream from composer\n composeChannel.receiveStream(async (stream, metadata) => {\n // Extract sessionId from metadata or use the one from connection\n const streamSessionId = (metadata as any)?.sessionId || sessionId || 'unknown';\n\n if (metadata?.streamType === 'video' && this.defaultVideoConfig) {\n // Acquire session-specific video encoder\n const encoder = await this.encoderManager.acquireVideo(\n streamSessionId,\n this.defaultVideoConfig\n );\n\n // Create encoding stream pipeline - pipeThrough returns the readable side\n const encodingTransform = encoder.createStream();\n const encodedStream = (stream as unknown as ReadableStream<VideoFrame>).pipeThrough(\n encodingTransform\n );\n\n // Send encoded chunks back to main thread\n this.channel.sendStream(encodedStream, {\n streamType: 'video',\n track: 'video',\n sessionId: streamSessionId,\n });\n }\n });\n\n return { success: true };\n }\n\n /**\n * Connect to cache manager for output streaming\n */\n // private async handleConnectCache(payload: { port: MessagePort }): Promise<{ success: boolean }> {\n // this.cachePort = payload.port;\n // return { success: true };\n // }\n\n /**\n * Connect to mux worker for output streaming\n */\n private async handleConnectMux(payload: { port: MessagePort }): Promise<{ success: boolean }> {\n this.muxPort = payload.port;\n return { success: true };\n }\n\n /**\n * Configure video encoder with specific settings\n */\n private async handleConfigureVideo(config: VideoEncoderConfig): Promise<{ success: boolean }> {\n try {\n // Update default video config\n this.defaultVideoConfig = config;\n\n // Notify configuration complete\n this.channel.notify('video_configured', {\n codec: config.codec,\n width: config.width,\n height: config.height,\n bitrate: config.bitrate,\n });\n\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'VIDEO_CONFIG_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Flush encoders (deprecated with per-clip encoder architecture)\n */\n private async handleFlush(_payload?: { type?: 'video' | 'audio' }): Promise<{\n videoChunks?: any[];\n audioChunks?: any[];\n }> {\n // With per-clip encoders, flushing is handled automatically by streams\n // This method is kept for backward compatibility\n console.warn('[EncodeWorker] handleFlush is deprecated with per-clip encoder architecture');\n return {};\n }\n\n /**\n * Reset encoders (deprecated with per-clip encoder architecture)\n */\n private async handleReset(payload?: { type?: 'video' | 'audio' }): Promise<{ success: boolean }> {\n // With per-clip encoders, reset is handled by releasing and recreating clip encoders\n // This method is kept for backward compatibility\n console.warn('[EncodeWorker] handleReset is deprecated with per-clip encoder architecture');\n\n // Notify reset complete for compatibility\n this.channel.notify('reset_complete', {\n type: payload?.type || 'all',\n });\n\n return { success: true };\n }\n\n /**\n * Release encoder for a specific clip\n */\n private async handleReleaseClipEncoder(payload: {\n sessionId: string;\n }): Promise<{ success: boolean }> {\n const { sessionId } = payload;\n\n await this.encoderManager.releaseClip(sessionId);\n\n return { success: true };\n }\n\n /**\n * Get encoder statistics\n */\n private async handleGetStats(): Promise<{\n encoders?: any;\n video?: any;\n audio?: any;\n }> {\n const stats: any = {\n encoders: this.encoderManager.getStats(),\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 encoders in the manager\n await this.encoderManager.closeAll();\n\n // Clear default configs\n this.defaultVideoConfig = null;\n this.defaultAudioConfig = null;\n\n // Close connections\n this.muxPort?.close();\n this.muxPort = null;\n\n for (const port of this.composePorts.values()) {\n port.close();\n }\n this.composePorts.clear();\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\n// Initialize worker\nconst worker = new EncodeWorker();\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meframe/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Next generation media processing framework based on WebCodecs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"CHANGELOG.md"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"mp4-muxer": "^5.2.2",
|
|
42
43
|
"mp4box": "^0.5.2"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { PreviewHandle, TimeUs } from './types';
|
|
2
|
-
import { PlaybackController } from './PlaybackController';
|
|
3
|
-
import { EventBus } from '../event/EventBus';
|
|
4
|
-
import { EventPayloadMap } from '../event/events';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* PreviewHandle implementation for playback control
|
|
8
|
-
*/
|
|
9
|
-
export declare class PreviewHandleImpl implements PreviewHandle {
|
|
10
|
-
private controller;
|
|
11
|
-
private eventBus;
|
|
12
|
-
constructor(controller: PlaybackController, eventBus: EventBus<EventPayloadMap>);
|
|
13
|
-
play(): void;
|
|
14
|
-
seek(timeUs: TimeUs): void;
|
|
15
|
-
setRate(rate: number): void;
|
|
16
|
-
pause(): void;
|
|
17
|
-
resume(): void;
|
|
18
|
-
stop(): void;
|
|
19
|
-
setVolume(volume: number): void;
|
|
20
|
-
get currentTimeUs(): TimeUs;
|
|
21
|
-
get isPlaying(): boolean;
|
|
22
|
-
on(event: string, handler: Function): void;
|
|
23
|
-
off(event: string, handler: Function): void;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=PreviewHandle.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewHandle.d.ts","sourceRoot":"","sources":["../../src/controllers/PreviewHandle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,UAAU,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC;IAK/E,IAAI,IAAI,IAAI;IAIZ,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,IAAI;IAId,IAAI,IAAI,IAAI;IAIZ,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;IAI1C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;CAG5C"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
class PreviewHandleImpl {
|
|
2
|
-
controller;
|
|
3
|
-
eventBus;
|
|
4
|
-
constructor(controller, eventBus) {
|
|
5
|
-
this.controller = controller;
|
|
6
|
-
this.eventBus = eventBus;
|
|
7
|
-
}
|
|
8
|
-
play() {
|
|
9
|
-
this.controller.play();
|
|
10
|
-
}
|
|
11
|
-
seek(timeUs) {
|
|
12
|
-
this.controller.seek(timeUs);
|
|
13
|
-
}
|
|
14
|
-
setRate(rate) {
|
|
15
|
-
this.controller.setRate(rate);
|
|
16
|
-
}
|
|
17
|
-
pause() {
|
|
18
|
-
this.controller.pause();
|
|
19
|
-
}
|
|
20
|
-
resume() {
|
|
21
|
-
this.controller.resume();
|
|
22
|
-
}
|
|
23
|
-
stop() {
|
|
24
|
-
this.controller.stop();
|
|
25
|
-
}
|
|
26
|
-
setVolume(volume) {
|
|
27
|
-
this.controller.setVolume(volume);
|
|
28
|
-
}
|
|
29
|
-
get currentTimeUs() {
|
|
30
|
-
return this.controller.currentTime;
|
|
31
|
-
}
|
|
32
|
-
get isPlaying() {
|
|
33
|
-
return this.controller.playing;
|
|
34
|
-
}
|
|
35
|
-
on(event, handler) {
|
|
36
|
-
this.eventBus.on(event, handler);
|
|
37
|
-
}
|
|
38
|
-
off(event, handler) {
|
|
39
|
-
this.eventBus.off(event, handler);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export {
|
|
43
|
-
PreviewHandleImpl
|
|
44
|
-
};
|
|
45
|
-
//# sourceMappingURL=PreviewHandle.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewHandle.js","sources":["../../src/controllers/PreviewHandle.ts"],"sourcesContent":["/**\n * PreviewHandle: Implementation of preview playback control handle\n */\n\nimport type { PreviewHandle, TimeUs } from './types';\nimport type { PlaybackController } from './PlaybackController';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\n\n/**\n * PreviewHandle implementation for playback control\n */\nexport class PreviewHandleImpl implements PreviewHandle {\n private controller: PlaybackController;\n private eventBus: EventBus<EventPayloadMap>;\n\n constructor(controller: PlaybackController, eventBus: EventBus<EventPayloadMap>) {\n this.controller = controller;\n this.eventBus = eventBus;\n }\n\n play(): void {\n this.controller.play();\n }\n\n seek(timeUs: TimeUs): void {\n this.controller.seek(timeUs);\n }\n\n setRate(rate: number): void {\n this.controller.setRate(rate);\n }\n\n pause(): void {\n this.controller.pause();\n }\n\n resume(): void {\n this.controller.resume();\n }\n\n stop(): void {\n this.controller.stop();\n }\n\n setVolume(volume: number): void {\n this.controller.setVolume(volume);\n }\n\n get currentTimeUs(): TimeUs {\n return this.controller.currentTime;\n }\n\n get isPlaying(): boolean {\n return this.controller.playing;\n }\n\n on(event: string, handler: Function): void {\n this.eventBus.on(event as any, handler as any);\n }\n\n off(event: string, handler: Function): void {\n this.eventBus.off(event as any, handler as any);\n }\n}\n"],"names":[],"mappings":"AAYO,MAAM,kBAA2C;AAAA,EAC9C;AAAA,EACA;AAAA,EAER,YAAY,YAAgC,UAAqC;AAC/E,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,OAAa;AACX,SAAK,WAAW,KAAA;AAAA,EAClB;AAAA,EAEA,KAAK,QAAsB;AACzB,SAAK,WAAW,KAAK,MAAM;AAAA,EAC7B;AAAA,EAEA,QAAQ,MAAoB;AAC1B,SAAK,WAAW,QAAQ,IAAI;AAAA,EAC9B;AAAA,EAEA,QAAc;AACZ,SAAK,WAAW,MAAA;AAAA,EAClB;AAAA,EAEA,SAAe;AACb,SAAK,WAAW,OAAA;AAAA,EAClB;AAAA,EAEA,OAAa;AACX,SAAK,WAAW,KAAA;AAAA,EAClB;AAAA,EAEA,UAAU,QAAsB;AAC9B,SAAK,WAAW,UAAU,MAAM;AAAA,EAClC;AAAA,EAEA,IAAI,gBAAwB;AAC1B,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA,EAEA,GAAG,OAAe,SAAyB;AACzC,SAAK,SAAS,GAAG,OAAc,OAAc;AAAA,EAC/C;AAAA,EAEA,IAAI,OAAe,SAAyB;AAC1C,SAAK,SAAS,IAAI,OAAc,OAAc;AAAA,EAChD;AACF;"}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
function resolveDirtyRanges(patch, model) {
|
|
2
|
-
const affectedClips = /* @__PURE__ */ new Set();
|
|
3
|
-
const affectedTracks = /* @__PURE__ */ new Set();
|
|
4
|
-
const affectedResources = /* @__PURE__ */ new Set();
|
|
5
|
-
for (const op of patch.operations) {
|
|
6
|
-
collectAffectedElements(op, model, affectedClips, affectedTracks, affectedResources);
|
|
7
|
-
}
|
|
8
|
-
return calculateTimeRanges(affectedClips, affectedTracks, affectedResources, model);
|
|
9
|
-
}
|
|
10
|
-
function collectAffectedElements(op, model, affectedClips, affectedTracks, affectedResources) {
|
|
11
|
-
switch (op.type) {
|
|
12
|
-
case "addTrack":
|
|
13
|
-
case "removeTrack":
|
|
14
|
-
case "updateTrack": {
|
|
15
|
-
const trackOp = op;
|
|
16
|
-
if (trackOp.trackId) {
|
|
17
|
-
affectedTracks.add(trackOp.trackId);
|
|
18
|
-
const track = model.findTrack(trackOp.trackId);
|
|
19
|
-
if (track) {
|
|
20
|
-
track.clips.forEach((clip) => affectedClips.add(clip.id));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
case "addClip":
|
|
26
|
-
case "removeClip":
|
|
27
|
-
case "updateClip":
|
|
28
|
-
case "moveClip": {
|
|
29
|
-
const clipOp = op;
|
|
30
|
-
if (clipOp.clipId) {
|
|
31
|
-
affectedClips.add(clipOp.clipId);
|
|
32
|
-
}
|
|
33
|
-
if (clipOp.trackId) {
|
|
34
|
-
affectedTracks.add(clipOp.trackId);
|
|
35
|
-
}
|
|
36
|
-
if (clipOp.targetTrackId) {
|
|
37
|
-
affectedTracks.add(clipOp.targetTrackId);
|
|
38
|
-
}
|
|
39
|
-
if (clipOp.clip) {
|
|
40
|
-
collectOverlappingClips(
|
|
41
|
-
model,
|
|
42
|
-
clipOp.trackId,
|
|
43
|
-
clipOp.clip.startUs || 0,
|
|
44
|
-
(clipOp.clip.startUs || 0) + (clipOp.clip.durationUs || 0),
|
|
45
|
-
affectedClips
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
case "addResource":
|
|
51
|
-
case "updateResource":
|
|
52
|
-
case "removeResource": {
|
|
53
|
-
const resourceOp = op;
|
|
54
|
-
affectedResources.add(resourceOp.resourceId);
|
|
55
|
-
for (const track of model.tracks) {
|
|
56
|
-
for (const clip of track.clips) {
|
|
57
|
-
if (clip.resourceId === resourceOp.resourceId) {
|
|
58
|
-
affectedClips.add(clip.id);
|
|
59
|
-
affectedTracks.add(track.id);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
case "addAttachment":
|
|
66
|
-
case "updateAttachment":
|
|
67
|
-
case "removeAttachment": {
|
|
68
|
-
const attachmentOp = op;
|
|
69
|
-
if (attachmentOp.clipId) {
|
|
70
|
-
affectedClips.add(attachmentOp.clipId);
|
|
71
|
-
}
|
|
72
|
-
if (attachmentOp.trackId) {
|
|
73
|
-
affectedTracks.add(attachmentOp.trackId);
|
|
74
|
-
}
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
case "addTransition":
|
|
78
|
-
case "updateTransition":
|
|
79
|
-
case "removeTransition": {
|
|
80
|
-
const transitionOp = op;
|
|
81
|
-
if (transitionOp.clipId) {
|
|
82
|
-
affectedClips.add(transitionOp.clipId);
|
|
83
|
-
collectAdjacentClips(model, transitionOp.trackId, transitionOp.clipId, affectedClips);
|
|
84
|
-
}
|
|
85
|
-
if (transitionOp.trackId) {
|
|
86
|
-
affectedTracks.add(transitionOp.trackId);
|
|
87
|
-
}
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
case "addEffect":
|
|
91
|
-
case "updateEffect":
|
|
92
|
-
case "removeEffect": {
|
|
93
|
-
const effectOp = op;
|
|
94
|
-
if (effectOp.targetType === "track") {
|
|
95
|
-
affectedTracks.add(effectOp.targetId);
|
|
96
|
-
const track = model.findTrack(effectOp.targetId);
|
|
97
|
-
if (track) {
|
|
98
|
-
track.clips.forEach((clip) => affectedClips.add(clip.id));
|
|
99
|
-
}
|
|
100
|
-
} else if (effectOp.targetType === "clip") {
|
|
101
|
-
affectedClips.add(effectOp.targetId);
|
|
102
|
-
}
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
function collectOverlappingClips(model, trackId, startUs, endUs, affectedClips) {
|
|
108
|
-
const track = model.findTrack(trackId);
|
|
109
|
-
if (!track) return;
|
|
110
|
-
const overlapping = model.getActiveClips(startUs, endUs);
|
|
111
|
-
overlapping.forEach((clip) => affectedClips.add(clip.id));
|
|
112
|
-
}
|
|
113
|
-
function collectAdjacentClips(model, trackId, clipId, affectedClips) {
|
|
114
|
-
const track = model.findTrack(trackId);
|
|
115
|
-
if (!track) return;
|
|
116
|
-
const clipIndex = track.clips.findIndex((c) => c.id === clipId);
|
|
117
|
-
if (clipIndex === -1) return;
|
|
118
|
-
const prevClip = track.clips[clipIndex - 1];
|
|
119
|
-
if (clipIndex > 0 && prevClip) {
|
|
120
|
-
affectedClips.add(prevClip.id);
|
|
121
|
-
}
|
|
122
|
-
const nextClip = track.clips[clipIndex + 1];
|
|
123
|
-
if (clipIndex < track.clips.length - 1 && nextClip) {
|
|
124
|
-
affectedClips.add(nextClip.id);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function calculateTimeRanges(affectedClips, affectedTracks, _affectedResources, model) {
|
|
128
|
-
const ranges = [];
|
|
129
|
-
const processedTracks = /* @__PURE__ */ new Set();
|
|
130
|
-
for (const clipId of affectedClips) {
|
|
131
|
-
const clip = model.findClip(clipId);
|
|
132
|
-
if (!clip) continue;
|
|
133
|
-
for (const track of model.tracks) {
|
|
134
|
-
if (track.clips.some((c) => c.id === clipId)) {
|
|
135
|
-
if (!processedTracks.has(track.id)) {
|
|
136
|
-
const range = calculateTrackDirtyRange(track.id, affectedClips, model);
|
|
137
|
-
if (range) {
|
|
138
|
-
ranges.push(range);
|
|
139
|
-
processedTracks.add(track.id);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
for (const trackId of affectedTracks) {
|
|
147
|
-
if (!processedTracks.has(trackId)) {
|
|
148
|
-
const track = model.findTrack(trackId);
|
|
149
|
-
if (track) {
|
|
150
|
-
ranges.push({
|
|
151
|
-
trackId,
|
|
152
|
-
startUs: 0,
|
|
153
|
-
endUs: model.getTrackDuration(trackId),
|
|
154
|
-
reason: "track_operation"
|
|
155
|
-
});
|
|
156
|
-
processedTracks.add(trackId);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return mergeRanges(ranges);
|
|
161
|
-
}
|
|
162
|
-
function calculateTrackDirtyRange(trackId, affectedClips, model) {
|
|
163
|
-
const track = model.findTrack(trackId);
|
|
164
|
-
if (!track) return null;
|
|
165
|
-
let minStartUs = Infinity;
|
|
166
|
-
let maxEndUs = 0;
|
|
167
|
-
let hasAffectedClips = false;
|
|
168
|
-
for (const clip of track.clips) {
|
|
169
|
-
if (affectedClips.has(clip.id)) {
|
|
170
|
-
hasAffectedClips = true;
|
|
171
|
-
minStartUs = Math.min(minStartUs, clip.startUs);
|
|
172
|
-
maxEndUs = Math.max(maxEndUs, clip.startUs + clip.durationUs);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (!hasAffectedClips) return null;
|
|
176
|
-
return {
|
|
177
|
-
trackId,
|
|
178
|
-
startUs: minStartUs,
|
|
179
|
-
endUs: maxEndUs,
|
|
180
|
-
reason: "clips_affected"
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
function mergeRanges(ranges) {
|
|
184
|
-
if (ranges.length <= 1) return ranges;
|
|
185
|
-
const trackGroups = /* @__PURE__ */ new Map();
|
|
186
|
-
for (const range of ranges) {
|
|
187
|
-
const group = trackGroups.get(range.trackId) || [];
|
|
188
|
-
group.push(range);
|
|
189
|
-
trackGroups.set(range.trackId, group);
|
|
190
|
-
}
|
|
191
|
-
const merged = [];
|
|
192
|
-
for (const [trackId, trackRanges] of trackGroups) {
|
|
193
|
-
trackRanges.sort((a, b) => a.startUs - b.startUs);
|
|
194
|
-
let current = trackRanges[0];
|
|
195
|
-
for (let i = 1; i < trackRanges.length; i++) {
|
|
196
|
-
const next = trackRanges[i];
|
|
197
|
-
if (next && current && next.startUs <= current.endUs + 1e3) {
|
|
198
|
-
current = {
|
|
199
|
-
trackId,
|
|
200
|
-
startUs: current.startUs,
|
|
201
|
-
endUs: Math.max(current.endUs, next.endUs),
|
|
202
|
-
reason: `${current.reason},${next.reason}`
|
|
203
|
-
};
|
|
204
|
-
} else {
|
|
205
|
-
if (current) {
|
|
206
|
-
merged.push(current);
|
|
207
|
-
}
|
|
208
|
-
current = next;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (current) {
|
|
212
|
-
merged.push(current);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return merged;
|
|
216
|
-
}
|
|
217
|
-
export {
|
|
218
|
-
resolveDirtyRanges
|
|
219
|
-
};
|
|
220
|
-
//# sourceMappingURL=dirty-range.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dirty-range.js","sources":["../../src/model/dirty-range.ts"],"sourcesContent":["import { CompositionModel } from './CompositionModel';\nimport { CompositionPatch, PatchOperation, DirtyRange, TimeUs } from './types';\n\nexport function resolveDirtyRanges(patch: CompositionPatch, model: CompositionModel): DirtyRange[] {\n const affectedClips = new Set<string>();\n const affectedTracks = new Set<string>();\n const affectedResources = new Set<string>();\n\n // Collect affected elements\n for (const op of patch.operations) {\n collectAffectedElements(op, model, affectedClips, affectedTracks, affectedResources);\n }\n\n // Calculate time ranges per track\n return calculateTimeRanges(affectedClips, affectedTracks, affectedResources, model);\n}\n\nfunction collectAffectedElements(\n op: PatchOperation,\n model: CompositionModel,\n affectedClips: Set<string>,\n affectedTracks: Set<string>,\n affectedResources: Set<string>\n): void {\n switch (op.type) {\n // Track-level operations affect all clips in the track\n case 'addTrack':\n case 'removeTrack':\n case 'updateTrack': {\n const trackOp = op as any;\n if (trackOp.trackId) {\n affectedTracks.add(trackOp.trackId);\n // Collect all clips in this track\n const track = model.findTrack(trackOp.trackId);\n if (track) {\n track.clips.forEach((clip) => affectedClips.add(clip.id));\n }\n }\n break;\n }\n\n // Clip-level operations\n case 'addClip':\n case 'removeClip':\n case 'updateClip':\n case 'moveClip': {\n const clipOp = op as any;\n if (clipOp.clipId) {\n affectedClips.add(clipOp.clipId);\n }\n if (clipOp.trackId) {\n affectedTracks.add(clipOp.trackId);\n }\n if (clipOp.targetTrackId) {\n affectedTracks.add(clipOp.targetTrackId);\n }\n // Check for overlapping clips\n if (clipOp.clip) {\n collectOverlappingClips(\n model,\n clipOp.trackId,\n clipOp.clip.startUs || 0,\n (clipOp.clip.startUs || 0) + (clipOp.clip.durationUs || 0),\n affectedClips\n );\n }\n break;\n }\n\n // Resource changes affect all clips using that resource\n case 'addResource':\n case 'updateResource':\n case 'removeResource': {\n const resourceOp = op as any;\n affectedResources.add(resourceOp.resourceId);\n // Find all clips using this resource\n for (const track of model.tracks) {\n for (const clip of track.clips) {\n if (clip.resourceId === resourceOp.resourceId) {\n affectedClips.add(clip.id);\n affectedTracks.add(track.id);\n }\n }\n }\n break;\n }\n\n // Attachment operations\n case 'addAttachment':\n case 'updateAttachment':\n case 'removeAttachment': {\n const attachmentOp = op as any;\n if (attachmentOp.clipId) {\n affectedClips.add(attachmentOp.clipId);\n }\n if (attachmentOp.trackId) {\n affectedTracks.add(attachmentOp.trackId);\n }\n break;\n }\n\n // Transition operations\n case 'addTransition':\n case 'updateTransition':\n case 'removeTransition': {\n const transitionOp = op as any;\n if (transitionOp.clipId) {\n affectedClips.add(transitionOp.clipId);\n // Transitions might affect adjacent clips\n collectAdjacentClips(model, transitionOp.trackId, transitionOp.clipId, affectedClips);\n }\n if (transitionOp.trackId) {\n affectedTracks.add(transitionOp.trackId);\n }\n break;\n }\n\n // Effect operations\n case 'addEffect':\n case 'updateEffect':\n case 'removeEffect': {\n const effectOp = op as any;\n if (effectOp.targetType === 'track') {\n affectedTracks.add(effectOp.targetId);\n // Track effects affect all clips in the track\n const track = model.findTrack(effectOp.targetId);\n if (track) {\n track.clips.forEach((clip) => affectedClips.add(clip.id));\n }\n } else if (effectOp.targetType === 'clip') {\n affectedClips.add(effectOp.targetId);\n }\n break;\n }\n }\n}\n\nfunction collectOverlappingClips(\n model: CompositionModel,\n trackId: string,\n startUs: TimeUs,\n endUs: TimeUs,\n affectedClips: Set<string>\n): void {\n const track = model.findTrack(trackId);\n if (!track) return;\n\n // Use binary search to find overlapping clips efficiently\n const overlapping = model.getActiveClips(startUs, endUs);\n overlapping.forEach((clip) => affectedClips.add(clip.id));\n}\n\nfunction collectAdjacentClips(\n model: CompositionModel,\n trackId: string,\n clipId: string,\n affectedClips: Set<string>\n): void {\n const track = model.findTrack(trackId);\n if (!track) return;\n\n const clipIndex = track.clips.findIndex((c) => c.id === clipId);\n if (clipIndex === -1) return;\n\n // Add previous clip if exists\n const prevClip = track.clips[clipIndex - 1];\n if (clipIndex > 0 && prevClip) {\n affectedClips.add(prevClip.id);\n }\n\n // Add next clip if exists\n const nextClip = track.clips[clipIndex + 1];\n if (clipIndex < track.clips.length - 1 && nextClip) {\n affectedClips.add(nextClip.id);\n }\n}\n\nfunction calculateTimeRanges(\n affectedClips: Set<string>,\n affectedTracks: Set<string>,\n _affectedResources: Set<string>,\n model: CompositionModel\n): DirtyRange[] {\n const ranges: DirtyRange[] = [];\n const processedTracks = new Set<string>();\n\n // Process affected clips\n for (const clipId of affectedClips) {\n const clip = model.findClip(clipId);\n if (!clip) continue;\n\n // Find the track containing this clip\n for (const track of model.tracks) {\n if (track.clips.some((c) => c.id === clipId)) {\n if (!processedTracks.has(track.id)) {\n const range = calculateTrackDirtyRange(track.id, affectedClips, model);\n if (range) {\n ranges.push(range);\n processedTracks.add(track.id);\n }\n }\n break;\n }\n }\n }\n\n // Process tracks that were directly affected but haven't been processed yet\n for (const trackId of affectedTracks) {\n if (!processedTracks.has(trackId)) {\n const track = model.findTrack(trackId);\n if (track) {\n ranges.push({\n trackId,\n startUs: 0,\n endUs: model.getTrackDuration(trackId),\n reason: 'track_operation',\n });\n processedTracks.add(trackId);\n }\n }\n }\n\n return mergeRanges(ranges);\n}\n\nfunction calculateTrackDirtyRange(\n trackId: string,\n affectedClips: Set<string>,\n model: CompositionModel\n): DirtyRange | null {\n const track = model.findTrack(trackId);\n if (!track) return null;\n\n let minStartUs = Infinity;\n let maxEndUs = 0;\n let hasAffectedClips = false;\n\n for (const clip of track.clips) {\n if (affectedClips.has(clip.id)) {\n hasAffectedClips = true;\n minStartUs = Math.min(minStartUs, clip.startUs);\n maxEndUs = Math.max(maxEndUs, clip.startUs + clip.durationUs);\n }\n }\n\n if (!hasAffectedClips) return null;\n\n return {\n trackId,\n startUs: minStartUs,\n endUs: maxEndUs,\n reason: 'clips_affected',\n };\n}\n\nfunction mergeRanges(ranges: DirtyRange[]): DirtyRange[] {\n if (ranges.length <= 1) return ranges;\n\n // Group by trackId\n const trackGroups = new Map<string, DirtyRange[]>();\n for (const range of ranges) {\n const group = trackGroups.get(range.trackId) || [];\n group.push(range);\n trackGroups.set(range.trackId, group);\n }\n\n // Merge overlapping ranges within each track\n const merged: DirtyRange[] = [];\n for (const [trackId, trackRanges] of trackGroups) {\n trackRanges.sort((a, b) => a.startUs - b.startUs);\n\n let current = trackRanges[0];\n for (let i = 1; i < trackRanges.length; i++) {\n const next = trackRanges[i];\n // Merge if overlapping or adjacent (within 1ms)\n if (next && current && next.startUs <= current.endUs + 1000) {\n current = {\n trackId,\n startUs: current.startUs,\n endUs: Math.max(current.endUs, next.endUs),\n reason: `${current.reason},${next.reason}`,\n };\n } else {\n if (current) {\n merged.push(current);\n }\n current = next;\n }\n }\n if (current) {\n merged.push(current);\n }\n }\n\n return merged;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { VideoChunkEncoder } from './VideoChunkEncoder';
|
|
2
|
-
import { AudioChunkEncoder } from './AudioChunkEncoder';
|
|
3
|
-
import { VideoEncoderConfig, AudioEncoderConfig, EncoderPoolOptions } from './types';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* EncoderPool - Manages encoder instances for reuse
|
|
7
|
-
* Reduces encoder creation overhead by pooling and reusing instances
|
|
8
|
-
*/
|
|
9
|
-
export declare class EncoderPool {
|
|
10
|
-
private videoEncoders;
|
|
11
|
-
private audioEncoders;
|
|
12
|
-
private encoderHandles;
|
|
13
|
-
private options;
|
|
14
|
-
private nextId;
|
|
15
|
-
constructor(options?: EncoderPoolOptions);
|
|
16
|
-
acquireVideoEncoder(config: VideoEncoderConfig, _outputCallback?: (chunk: EncodedVideoChunk, metadata: EncodedVideoChunkMetadata) => void, _errorCallback?: (error: DOMException) => void): Promise<string>;
|
|
17
|
-
acquireAudioEncoder(config: AudioEncoderConfig, _outputCallback?: (chunk: EncodedAudioChunk, metadata: EncodedAudioChunkMetadata) => void, _errorCallback?: (error: DOMException) => void): Promise<string>;
|
|
18
|
-
getVideoEncoder(id: string): VideoChunkEncoder | undefined;
|
|
19
|
-
getAudioEncoder(id: string): AudioChunkEncoder | undefined;
|
|
20
|
-
releaseEncoder(id: string): Promise<void>;
|
|
21
|
-
markAsIdle(id: string): void;
|
|
22
|
-
closeAll(): Promise<void>;
|
|
23
|
-
private findReusableEncoder;
|
|
24
|
-
private evictLRUEncoder;
|
|
25
|
-
private isConfigEqual;
|
|
26
|
-
private generateId;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=EncoderPool.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EncoderPool.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/EncoderPool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAAK;gBAEP,OAAO,GAAE,kBAAuB;IAStC,mBAAmB,CACvB,MAAM,EAAE,kBAAkB,EAC1B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,yBAAyB,KAAK,IAAI,EACzF,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAC7C,OAAO,CAAC,MAAM,CAAC;IAsDZ,mBAAmB,CACvB,MAAM,EAAE,kBAAkB,EAC1B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,yBAAyB,KAAK,IAAI,EACzF,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAC7C,OAAO,CAAC,MAAM,CAAC;IAsDlB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAI1D,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIpD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB/C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,UAAU;CAGnB"}
|