@meframe/core 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/orchestrator/ExportScheduler.d.ts +9 -7
  2. package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
  3. package/dist/orchestrator/ExportScheduler.js +182 -80
  4. package/dist/orchestrator/ExportScheduler.js.map +1 -1
  5. package/dist/orchestrator/Orchestrator.js +22 -22
  6. package/dist/orchestrator/Orchestrator.js.map +1 -1
  7. package/dist/orchestrator/VideoWindowDecodeSession.d.ts.map +1 -1
  8. package/dist/orchestrator/VideoWindowDecodeSession.js +15 -3
  9. package/dist/orchestrator/VideoWindowDecodeSession.js.map +1 -1
  10. package/dist/stages/compose/VideoComposer.d.ts +2 -0
  11. package/dist/stages/compose/VideoComposer.d.ts.map +1 -1
  12. package/dist/stages/compose/VideoComposer.js +41 -2
  13. package/dist/stages/compose/VideoComposer.js.map +1 -1
  14. package/dist/stages/decode/video-decoder.d.ts.map +1 -1
  15. package/dist/stages/decode/video-decoder.js +45 -2
  16. package/dist/stages/decode/video-decoder.js.map +1 -1
  17. package/dist/utils/time-utils.d.ts +15 -0
  18. package/dist/utils/time-utils.d.ts.map +1 -1
  19. package/dist/utils/time-utils.js +33 -0
  20. package/dist/utils/time-utils.js.map +1 -0
  21. package/dist/worker/WorkerChannel.d.ts.map +1 -1
  22. package/dist/worker/WorkerChannel.js +3 -15
  23. package/dist/worker/WorkerChannel.js.map +1 -1
  24. package/dist/worker/WorkerPool.d.ts.map +1 -1
  25. package/dist/worker/WorkerPool.js +4 -12
  26. package/dist/worker/WorkerPool.js.map +1 -1
  27. package/dist/worker/types.d.ts +1 -1
  28. package/dist/worker/types.d.ts.map +1 -1
  29. package/dist/worker/types.js.map +1 -1
  30. package/dist/worker/worker-event-whitelist.d.ts.map +1 -1
  31. package/dist/workers/stages/{compose/video-compose.worker.KMZjuJuY.js → export/export.worker.BYttrqTQ.js} +872 -217
  32. package/dist/workers/stages/export/export.worker.BYttrqTQ.js.map +1 -0
  33. package/dist/workers/worker-manifest.json +1 -3
  34. package/package.json +1 -1
  35. package/dist/orchestrator/VideoClipSession.d.ts +0 -80
  36. package/dist/orchestrator/VideoClipSession.d.ts.map +0 -1
  37. package/dist/orchestrator/VideoClipSession.js +0 -361
  38. package/dist/orchestrator/VideoClipSession.js.map +0 -1
  39. package/dist/workers/WorkerChannel.DQK8rAab.js +0 -528
  40. package/dist/workers/WorkerChannel.DQK8rAab.js.map +0 -1
  41. package/dist/workers/stages/compose/audio-compose.worker.B4Io5w9i.js +0 -1063
  42. package/dist/workers/stages/compose/audio-compose.worker.B4Io5w9i.js.map +0 -1
  43. package/dist/workers/stages/compose/video-compose.worker.KMZjuJuY.js.map +0 -1
  44. package/dist/workers/stages/encode/video-encode.worker.D6aB_rF9.js +0 -334
  45. package/dist/workers/stages/encode/video-encode.worker.D6aB_rF9.js.map +0 -1
@@ -1,334 +0,0 @@
1
- import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.DQK8rAab.js";
2
- class BaseEncoder {
3
- encoder;
4
- config;
5
- controller = null;
6
- constructor(config) {
7
- this.config = config;
8
- }
9
- getConfig() {
10
- return { ...this.config };
11
- }
12
- get currentConfig() {
13
- return this.config;
14
- }
15
- shouldReconfigure(partial) {
16
- const next = { ...this.config, ...partial };
17
- const keys = Object.keys(partial ?? {});
18
- for (const key of keys) {
19
- if (partial[key] !== void 0 && next[key] !== this.config[key]) {
20
- return true;
21
- }
22
- }
23
- return false;
24
- }
25
- hasConfigChanged(next) {
26
- const currentEntries = Object.entries(this.config);
27
- for (const [key, value] of currentEntries) {
28
- if (next[key] !== value) {
29
- return true;
30
- }
31
- }
32
- for (const key of Object.keys(next)) {
33
- if (this.config[key] !== next[key]) {
34
- return true;
35
- }
36
- }
37
- return false;
38
- }
39
- configsEqual(a, b) {
40
- return JSON.stringify(a) === JSON.stringify(b);
41
- }
42
- async initialize() {
43
- if (this.encoder?.state === "configured") {
44
- return;
45
- }
46
- const isSupported = await this.isConfigSupported(this.config);
47
- if (!isSupported.supported) {
48
- throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);
49
- }
50
- this.encoder = this.createEncoder({
51
- output: this.handleOutput.bind(this),
52
- error: this.handleError.bind(this)
53
- });
54
- this.encoder.configure(this.config);
55
- }
56
- async reconfigure(config) {
57
- if (!config || Object.keys(config).length === 0) {
58
- return;
59
- }
60
- const nextConfig = { ...this.config, ...config };
61
- if (this.configsEqual(this.config, nextConfig)) {
62
- return;
63
- }
64
- if (!this.encoder) {
65
- this.config = nextConfig;
66
- await this.initialize();
67
- return;
68
- }
69
- if (this.encoder.state === "configured") {
70
- await this.encoder.flush();
71
- }
72
- const isSupported = await this.isConfigSupported(nextConfig);
73
- if (!isSupported.supported) {
74
- throw new Error(`New configuration not supported: ${nextConfig.codec}`);
75
- }
76
- this.config = nextConfig;
77
- this.encoder.configure(this.config);
78
- }
79
- async flush() {
80
- if (!this.encoder) {
81
- return;
82
- }
83
- await this.encoder.flush();
84
- }
85
- async reset() {
86
- if (!this.encoder) {
87
- return;
88
- }
89
- this.encoder.reset();
90
- this.onReset();
91
- }
92
- async close() {
93
- if (!this.encoder) {
94
- return;
95
- }
96
- if (this.encoder.state === "configured") {
97
- await this.encoder.flush();
98
- }
99
- this.encoder.close();
100
- this.encoder = void 0;
101
- }
102
- get isReady() {
103
- return this.encoder?.state === "configured";
104
- }
105
- get queueSize() {
106
- return this.encoder?.encodeQueueSize ?? 0;
107
- }
108
- handleOutput(chunk, metadata) {
109
- if (this.controller) {
110
- try {
111
- this.controller.enqueue({ chunk, metadata });
112
- } catch (error) {
113
- if (!(error instanceof TypeError && error.message.includes("closed"))) {
114
- throw error;
115
- }
116
- }
117
- }
118
- }
119
- handleError(error) {
120
- console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {
121
- name: error.name,
122
- message: error.message,
123
- encoderState: this.encoder?.state,
124
- queueSize: this.queueSize,
125
- platform: typeof navigator !== "undefined" ? navigator.platform : "unknown"
126
- });
127
- this.controller?.error(error);
128
- }
129
- // Hook for subclasses to handle reset
130
- onReset() {
131
- }
132
- /**
133
- * Create transform stream for encoding
134
- * Implements common stream logic with backpressure handling
135
- */
136
- createStream() {
137
- return new TransformStream(
138
- {
139
- start: async (controller) => {
140
- this.controller = controller;
141
- if (!this.isReady) {
142
- await this.initialize();
143
- }
144
- },
145
- transform: async (input) => {
146
- if (!this.encoder || this.encoder.state !== "configured") {
147
- throw new Error("Encoder not configured");
148
- }
149
- if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
150
- await new Promise((resolve) => {
151
- const check = () => {
152
- if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {
153
- resolve();
154
- } else {
155
- setTimeout(check, 10);
156
- }
157
- };
158
- check();
159
- });
160
- }
161
- const frame = input.frame || input;
162
- this.encode(frame);
163
- },
164
- flush: async () => {
165
- await this.flush();
166
- }
167
- },
168
- // Queuing strategy with backpressure configuration
169
- {
170
- highWaterMark: this.highWaterMark,
171
- size: () => 1
172
- // Count-based
173
- }
174
- );
175
- }
176
- }
177
- class VideoChunkEncoder extends BaseEncoder {
178
- static DEFAULT_HIGH_WATER_MARK = 2;
179
- static DEFAULT_ENCODE_QUEUE_THRESHOLD = 8;
180
- highWaterMark;
181
- encodeQueueThreshold;
182
- frameCount = 0;
183
- // Default 1 second at 30fps for better social media compatibility
184
- keyFrameInterval = 30;
185
- constructor(config) {
186
- super(config);
187
- this.highWaterMark = config.backpressure?.highWaterMark ?? VideoChunkEncoder.DEFAULT_HIGH_WATER_MARK;
188
- this.encodeQueueThreshold = config.backpressure?.encodeQueueThreshold ?? VideoChunkEncoder.DEFAULT_ENCODE_QUEUE_THRESHOLD;
189
- if (config.keyFrameInterval !== void 0) {
190
- this.keyFrameInterval = Math.max(1, config.keyFrameInterval);
191
- }
192
- }
193
- async isConfigSupported(config) {
194
- const result = await VideoEncoder.isConfigSupported(config);
195
- return { supported: result.supported ?? false };
196
- }
197
- createEncoder(init) {
198
- return new VideoEncoder(init);
199
- }
200
- getEncoderType() {
201
- return "Video";
202
- }
203
- onReset() {
204
- this.frameCount = 0;
205
- }
206
- encode(frame) {
207
- const keyFrame = this.shouldGenerateKeyFrame();
208
- const encodeOptions = {
209
- keyFrame
210
- };
211
- this.encoder.encode(frame, encodeOptions);
212
- this.frameCount++;
213
- frame.close();
214
- }
215
- setKeyFrameInterval(interval) {
216
- this.keyFrameInterval = Math.max(1, interval);
217
- }
218
- shouldGenerateKeyFrame() {
219
- if (this.frameCount === 0) {
220
- return true;
221
- }
222
- return this.frameCount % this.keyFrameInterval === 0;
223
- }
224
- }
225
- class VideoEncodeWorker {
226
- channel;
227
- encoder = null;
228
- clipId = "";
229
- upstreamPort = null;
230
- constructor() {
231
- this.channel = new WorkerChannel(self, {
232
- name: "VideoEncodeWorker",
233
- timeout: 3e4
234
- });
235
- this.setupHandlers();
236
- }
237
- setupHandlers() {
238
- this.channel.registerHandler("configure", this.handleConfigure.bind(this));
239
- this.channel.registerHandler("connect", this.handleConnect.bind(this));
240
- this.channel.registerHandler("flush", this.handleFlush.bind(this));
241
- this.channel.registerHandler("reset", this.handleReset.bind(this));
242
- this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
243
- this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
244
- }
245
- async handleConnect(payload) {
246
- const { port, streamType, sessionId, direction } = payload;
247
- if (direction === "upstream" && streamType === "video") {
248
- return this.handleConnectComposer({ port, sessionId });
249
- }
250
- return { success: true };
251
- }
252
- async handleConfigure(payload) {
253
- const { config, initial = false } = payload;
254
- if (initial) {
255
- this.channel.state = WorkerState.Ready;
256
- this.encoder = new VideoChunkEncoder(config);
257
- this.encoder.initialize();
258
- }
259
- return { success: true };
260
- }
261
- async handleConnectComposer(payload) {
262
- const { port, sessionId } = payload;
263
- this.upstreamPort = port;
264
- this.clipId = sessionId || "default";
265
- const composeChannel = new WorkerChannel(port, {
266
- name: "Encode-VideoCompose",
267
- timeout: 3e4
268
- });
269
- composeChannel.receiveStream(async (stream, metadata) => {
270
- const streamSessionId = metadata?.sessionId || sessionId || "unknown";
271
- if (metadata?.streamType === "video") {
272
- if (!this.encoder) {
273
- console.error("[VideoEncoderWorker] error: no encoder");
274
- return;
275
- }
276
- const encodingTransform = this.encoder.createStream();
277
- const encodedStream = stream.pipeThrough(
278
- encodingTransform
279
- );
280
- this.channel.sendStream(encodedStream, {
281
- streamType: "video",
282
- track: "video",
283
- sessionId: streamSessionId
284
- });
285
- }
286
- });
287
- return { success: true };
288
- }
289
- async handleFlush() {
290
- if (this.encoder) {
291
- await this.encoder.flush();
292
- }
293
- return { success: true };
294
- }
295
- async handleReset() {
296
- if (this.encoder) {
297
- await this.encoder.reset();
298
- }
299
- this.channel.notify("reset_complete", {
300
- type: "video"
301
- });
302
- return { success: true };
303
- }
304
- async handleGetStats() {
305
- if (!this.encoder) {
306
- return {};
307
- }
308
- return {
309
- video: {
310
- clipId: this.clipId,
311
- configured: true
312
- }
313
- };
314
- }
315
- async handleDispose() {
316
- if (this.encoder) {
317
- await this.encoder.close();
318
- this.encoder = null;
319
- }
320
- this.upstreamPort?.close();
321
- this.upstreamPort = null;
322
- this.channel.state = WorkerState.Disposed;
323
- return { success: true };
324
- }
325
- }
326
- const worker = new VideoEncodeWorker();
327
- self.addEventListener("beforeunload", () => {
328
- worker["handleDispose"]();
329
- });
330
- const videoEncode_worker = null;
331
- export {
332
- videoEncode_worker as default
333
- };
334
- //# sourceMappingURL=video-encode.worker.D6aB_rF9.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video-encode.worker.D6aB_rF9.js","sources":["../../../../src/stages/encode/BaseEncoder.ts","../../../../src/stages/encode/VideoChunkEncoder.ts","../../../../src/stages/encode/video-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\n if (!isSupported.supported) {\n throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);\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] Encode error:`, {\n name: error.name,\n message: error.message,\n encoderState: this.encoder?.state,\n queueSize: this.queueSize,\n platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',\n });\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 // Default 1 second at 30fps for better social media compatibility\n private keyFrameInterval = 30;\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 // Allow custom keyframe interval from config\n if (config.keyFrameInterval !== undefined) {\n this.keyFrameInterval = Math.max(1, config.keyFrameInterval);\n }\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 { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoChunkEncoder } from './VideoChunkEncoder';\nimport { VideoEncoderConfig } from './types';\n\n/**\n * VideoEncodeWorker (Clip Local) - Encodes video for a single clip\n * Receives composed frames from VideoComposeWorker and outputs encoded chunks\n *\n * Pipeline: VideoComposeWorker → VideoEncodeWorker → CacheManager (L2)\n *\n * Features:\n * - Single clip, single VideoEncoder instance (no manager needed)\n * - Hardware-accelerated encoding via WebCodecs\n * - Only used in L2 channel (preview channel skips encoding)\n * - Lifecycle tied to L2 clip pipeline\n */\nclass VideoEncodeWorker {\n private channel: WorkerChannel;\n private encoder: VideoChunkEncoder | null = null;\n private clipId: string = '';\n\n private upstreamPort: MessagePort | null = null;\n\n constructor() {\n this.channel = new WorkerChannel(self as any, {\n name: 'VideoEncodeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect', this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n this.channel.registerHandler('reset', this.handleReset.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType: 'video' | 'frame';\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { port, streamType, sessionId, direction } = payload;\n\n if (direction === 'upstream' && streamType === 'video') {\n return this.handleConnectComposer({ port, sessionId });\n }\n\n return { success: true };\n }\n\n private async handleConfigure(payload: {\n config: VideoEncoderConfig;\n initial?: boolean;\n }): Promise<{ success: boolean }> {\n const { config, initial = false } = payload;\n\n if (initial) {\n this.channel.state = WorkerState.Ready;\n this.encoder = new VideoChunkEncoder(config);\n this.encoder.initialize();\n }\n\n return { success: true };\n }\n\n private async handleConnectComposer(payload: {\n port: MessagePort;\n sessionId?: string;\n }): Promise<{ success: boolean }> {\n const { port, sessionId } = payload;\n\n this.upstreamPort = port;\n this.clipId = sessionId || 'default';\n\n const composeChannel = new WorkerChannel(port, {\n name: 'Encode-VideoCompose',\n timeout: 30000,\n });\n\n composeChannel.receiveStream(async (stream, metadata) => {\n const streamSessionId = (metadata as any)?.sessionId || sessionId || 'unknown';\n\n if (metadata?.streamType === 'video') {\n if (!this.encoder) {\n console.error('[VideoEncoderWorker] error: no encoder');\n return;\n }\n\n const encodingTransform = this.encoder.createStream();\n const encodedStream = (stream as unknown as ReadableStream<VideoFrame>).pipeThrough(\n encodingTransform\n );\n\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 private async handleFlush(): Promise<{ success: boolean }> {\n if (this.encoder) {\n await this.encoder.flush();\n }\n return { success: true };\n }\n\n private async handleReset(): Promise<{ success: boolean }> {\n if (this.encoder) {\n await this.encoder.reset();\n }\n\n this.channel.notify('reset_complete', {\n type: 'video',\n });\n\n return { success: true };\n }\n\n private async handleGetStats(): Promise<{\n video?: any;\n }> {\n if (!this.encoder) {\n return {};\n }\n\n return {\n video: {\n clipId: this.clipId,\n configured: true,\n },\n };\n }\n\n private async handleDispose(): Promise<{ success: boolean }> {\n if (this.encoder) {\n await this.encoder.close();\n this.encoder = null;\n }\n\n this.upstreamPort?.close();\n this.upstreamPort = null;\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n}\n\nconst worker = new VideoEncodeWorker();\n\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null;\n"],"names":[],"mappings":"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"}