@meframe/core 0.0.2 → 0.0.4

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 (193) hide show
  1. package/dist/Meframe.d.ts.map +1 -1
  2. package/dist/Meframe.js +6 -4
  3. package/dist/Meframe.js.map +1 -1
  4. package/dist/cache/CacheManager.d.ts +2 -2
  5. package/dist/cache/CacheManager.d.ts.map +1 -1
  6. package/dist/cache/CacheManager.js +4 -3
  7. package/dist/cache/CacheManager.js.map +1 -1
  8. package/dist/cache/l1/VideoL1Cache.d.ts +2 -2
  9. package/dist/cache/l1/VideoL1Cache.d.ts.map +1 -1
  10. package/dist/cache/l1/VideoL1Cache.js +13 -8
  11. package/dist/cache/l1/VideoL1Cache.js.map +1 -1
  12. package/dist/config/defaults.d.ts.map +1 -1
  13. package/dist/config/defaults.js +3 -1
  14. package/dist/config/defaults.js.map +1 -1
  15. package/dist/config/types.d.ts +6 -0
  16. package/dist/config/types.d.ts.map +1 -1
  17. package/dist/controllers/PlaybackController.d.ts +7 -8
  18. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  19. package/dist/controllers/PlaybackController.js +56 -76
  20. package/dist/controllers/PlaybackController.js.map +1 -1
  21. package/dist/controllers/types.d.ts +2 -3
  22. package/dist/controllers/types.d.ts.map +1 -1
  23. package/dist/event/events.d.ts +1 -4
  24. package/dist/event/events.d.ts.map +1 -1
  25. package/dist/event/events.js.map +1 -1
  26. package/dist/model/CompositionModel.d.ts +1 -0
  27. package/dist/model/CompositionModel.d.ts.map +1 -1
  28. package/dist/model/CompositionModel.js +2 -0
  29. package/dist/model/CompositionModel.js.map +1 -1
  30. package/dist/model/patch.d.ts +6 -2
  31. package/dist/model/patch.d.ts.map +1 -1
  32. package/dist/model/patch.js +76 -2
  33. package/dist/model/patch.js.map +1 -1
  34. package/dist/model/types.d.ts +1 -0
  35. package/dist/model/types.d.ts.map +1 -1
  36. package/dist/orchestrator/CompositionPlanner.d.ts +8 -7
  37. package/dist/orchestrator/CompositionPlanner.d.ts.map +1 -1
  38. package/dist/orchestrator/CompositionPlanner.js +33 -56
  39. package/dist/orchestrator/CompositionPlanner.js.map +1 -1
  40. package/dist/orchestrator/Orchestrator.d.ts +0 -1
  41. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  42. package/dist/orchestrator/Orchestrator.js +40 -19
  43. package/dist/orchestrator/Orchestrator.js.map +1 -1
  44. package/dist/orchestrator/VideoClipSession.d.ts +3 -5
  45. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
  46. package/dist/orchestrator/VideoClipSession.js +66 -69
  47. package/dist/orchestrator/VideoClipSession.js.map +1 -1
  48. package/dist/orchestrator/types.d.ts +2 -0
  49. package/dist/orchestrator/types.d.ts.map +1 -1
  50. package/dist/stages/compose/GlobalAudioSession.d.ts +6 -0
  51. package/dist/stages/compose/GlobalAudioSession.d.ts.map +1 -1
  52. package/dist/stages/compose/GlobalAudioSession.js +17 -1
  53. package/dist/stages/compose/GlobalAudioSession.js.map +1 -1
  54. package/dist/stages/compose/types.d.ts +2 -1
  55. package/dist/stages/compose/types.d.ts.map +1 -1
  56. package/dist/stages/demux/MP4Demuxer.d.ts +0 -1
  57. package/dist/stages/demux/MP4Demuxer.d.ts.map +1 -1
  58. package/dist/stages/load/ResourceLoader.d.ts +22 -1
  59. package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
  60. package/dist/stages/load/ResourceLoader.js +71 -25
  61. package/dist/stages/load/ResourceLoader.js.map +1 -1
  62. package/dist/stages/load/TaskManager.d.ts +1 -1
  63. package/dist/stages/load/TaskManager.d.ts.map +1 -1
  64. package/dist/stages/load/TaskManager.js +3 -2
  65. package/dist/stages/load/TaskManager.js.map +1 -1
  66. package/dist/stages/load/types.d.ts +2 -0
  67. package/dist/stages/load/types.d.ts.map +1 -1
  68. package/dist/utils/time-utils.d.ts +3 -2
  69. package/dist/utils/time-utils.d.ts.map +1 -1
  70. package/dist/utils/time-utils.js +2 -1
  71. package/dist/utils/time-utils.js.map +1 -1
  72. package/dist/vite-plugin.d.ts +5 -3
  73. package/dist/vite-plugin.d.ts.map +1 -1
  74. package/dist/vite-plugin.js +109 -52
  75. package/dist/vite-plugin.js.map +1 -1
  76. package/dist/worker/WorkerPool.d.ts +9 -0
  77. package/dist/worker/WorkerPool.d.ts.map +1 -1
  78. package/dist/worker/WorkerPool.js +32 -5
  79. package/dist/worker/WorkerPool.js.map +1 -1
  80. package/dist/{stages/demux → workers}/MP4Demuxer.js +4 -13
  81. package/dist/workers/MP4Demuxer.js.map +1 -0
  82. package/dist/workers/WorkerChannel.js +486 -0
  83. package/dist/workers/WorkerChannel.js.map +1 -0
  84. package/dist/{assets/video-demux.worker-D019I7GQ.js → workers/mp4box.all.js} +4 -912
  85. package/dist/workers/mp4box.all.js.map +1 -0
  86. package/dist/{assets/audio-compose.worker-nGVvHD5Q.js → workers/stages/compose/audio-compose.worker.js} +7 -481
  87. package/dist/workers/stages/compose/audio-compose.worker.js.map +1 -0
  88. package/dist/{assets/video-compose.worker-DPzsC21d.js → workers/stages/compose/video-compose.worker.js} +120 -562
  89. package/dist/workers/stages/compose/video-compose.worker.js.map +1 -0
  90. package/dist/{assets/decode.worker-DpWHsc7R.js → workers/stages/decode/decode.worker.js} +7 -481
  91. package/dist/workers/stages/decode/decode.worker.js.map +1 -0
  92. package/dist/{stages → workers/stages}/demux/audio-demux.worker.js +184 -4
  93. package/dist/workers/stages/demux/audio-demux.worker.js.map +1 -0
  94. package/dist/{stages → workers/stages}/demux/video-demux.worker.js +2 -3
  95. package/dist/workers/stages/demux/video-demux.worker.js.map +1 -0
  96. package/dist/{stages → workers/stages}/encode/encode.worker.js +238 -4
  97. package/dist/workers/stages/encode/encode.worker.js.map +1 -0
  98. package/dist/{stages/mux/MP4Muxer.js → workers/stages/mux/mux.worker.js} +244 -5
  99. package/dist/workers/stages/mux/mux.worker.js.map +1 -0
  100. package/package.json +21 -21
  101. package/dist/assets/audio-compose.worker-nGVvHD5Q.js.map +0 -1
  102. package/dist/assets/audio-demux.worker-xwWBtbAe.js +0 -8299
  103. package/dist/assets/audio-demux.worker-xwWBtbAe.js.map +0 -1
  104. package/dist/assets/decode.worker-DpWHsc7R.js.map +0 -1
  105. package/dist/assets/encode.worker-nfOb3kw6.js +0 -1026
  106. package/dist/assets/encode.worker-nfOb3kw6.js.map +0 -1
  107. package/dist/assets/mux.worker-uEMQY066.js +0 -8019
  108. package/dist/assets/mux.worker-uEMQY066.js.map +0 -1
  109. package/dist/assets/video-compose.worker-DPzsC21d.js.map +0 -1
  110. package/dist/assets/video-demux.worker-D019I7GQ.js.map +0 -1
  111. package/dist/controllers/PreviewHandle.d.ts +0 -25
  112. package/dist/controllers/PreviewHandle.d.ts.map +0 -1
  113. package/dist/controllers/PreviewHandle.js +0 -45
  114. package/dist/controllers/PreviewHandle.js.map +0 -1
  115. package/dist/model/dirty-range.js +0 -220
  116. package/dist/model/dirty-range.js.map +0 -1
  117. package/dist/model/types.js +0 -5
  118. package/dist/model/types.js.map +0 -1
  119. package/dist/plugins/BackpressureMonitor.js +0 -62
  120. package/dist/plugins/BackpressureMonitor.js.map +0 -1
  121. package/dist/stages/compose/AudioDucker.js +0 -161
  122. package/dist/stages/compose/AudioDucker.js.map +0 -1
  123. package/dist/stages/compose/AudioMixer.js +0 -373
  124. package/dist/stages/compose/AudioMixer.js.map +0 -1
  125. package/dist/stages/compose/FilterProcessor.js +0 -226
  126. package/dist/stages/compose/FilterProcessor.js.map +0 -1
  127. package/dist/stages/compose/LayerRenderer.js +0 -215
  128. package/dist/stages/compose/LayerRenderer.js.map +0 -1
  129. package/dist/stages/compose/TransitionProcessor.js +0 -189
  130. package/dist/stages/compose/TransitionProcessor.js.map +0 -1
  131. package/dist/stages/compose/VideoComposer.js +0 -186
  132. package/dist/stages/compose/VideoComposer.js.map +0 -1
  133. package/dist/stages/compose/audio-compose.worker.d.ts +0 -79
  134. package/dist/stages/compose/audio-compose.worker.d.ts.map +0 -1
  135. package/dist/stages/compose/audio-compose.worker.js +0 -540
  136. package/dist/stages/compose/audio-compose.worker.js.map +0 -1
  137. package/dist/stages/compose/audio-compose.worker2.js +0 -5
  138. package/dist/stages/compose/audio-compose.worker2.js.map +0 -1
  139. package/dist/stages/compose/video-compose.worker.d.ts +0 -60
  140. package/dist/stages/compose/video-compose.worker.d.ts.map +0 -1
  141. package/dist/stages/compose/video-compose.worker.js +0 -379
  142. package/dist/stages/compose/video-compose.worker.js.map +0 -1
  143. package/dist/stages/compose/video-compose.worker2.js +0 -5
  144. package/dist/stages/compose/video-compose.worker2.js.map +0 -1
  145. package/dist/stages/decode/AudioChunkDecoder.js +0 -82
  146. package/dist/stages/decode/AudioChunkDecoder.js.map +0 -1
  147. package/dist/stages/decode/BaseDecoder.js +0 -130
  148. package/dist/stages/decode/BaseDecoder.js.map +0 -1
  149. package/dist/stages/decode/VideoChunkDecoder.js +0 -199
  150. package/dist/stages/decode/VideoChunkDecoder.js.map +0 -1
  151. package/dist/stages/decode/decode.worker.d.ts +0 -70
  152. package/dist/stages/decode/decode.worker.d.ts.map +0 -1
  153. package/dist/stages/decode/decode.worker.js +0 -423
  154. package/dist/stages/decode/decode.worker.js.map +0 -1
  155. package/dist/stages/decode/decode.worker2.js +0 -5
  156. package/dist/stages/decode/decode.worker2.js.map +0 -1
  157. package/dist/stages/demux/MP3FrameParser.js +0 -186
  158. package/dist/stages/demux/MP3FrameParser.js.map +0 -1
  159. package/dist/stages/demux/MP4Demuxer.js.map +0 -1
  160. package/dist/stages/demux/audio-demux.worker.d.ts +0 -51
  161. package/dist/stages/demux/audio-demux.worker.d.ts.map +0 -1
  162. package/dist/stages/demux/audio-demux.worker.js.map +0 -1
  163. package/dist/stages/demux/audio-demux.worker2.js +0 -5
  164. package/dist/stages/demux/audio-demux.worker2.js.map +0 -1
  165. package/dist/stages/demux/video-demux.worker.d.ts +0 -51
  166. package/dist/stages/demux/video-demux.worker.d.ts.map +0 -1
  167. package/dist/stages/demux/video-demux.worker.js.map +0 -1
  168. package/dist/stages/demux/video-demux.worker2.js +0 -5
  169. package/dist/stages/demux/video-demux.worker2.js.map +0 -1
  170. package/dist/stages/encode/AudioChunkEncoder.js +0 -37
  171. package/dist/stages/encode/AudioChunkEncoder.js.map +0 -1
  172. package/dist/stages/encode/BaseEncoder.js +0 -164
  173. package/dist/stages/encode/BaseEncoder.js.map +0 -1
  174. package/dist/stages/encode/VideoChunkEncoder.js +0 -50
  175. package/dist/stages/encode/VideoChunkEncoder.js.map +0 -1
  176. package/dist/stages/encode/encode.worker.d.ts +0 -3
  177. package/dist/stages/encode/encode.worker.d.ts.map +0 -1
  178. package/dist/stages/encode/encode.worker.js.map +0 -1
  179. package/dist/stages/encode/encode.worker2.js +0 -5
  180. package/dist/stages/encode/encode.worker2.js.map +0 -1
  181. package/dist/stages/mux/MP4Muxer.js.map +0 -1
  182. package/dist/stages/mux/mux.worker.d.ts +0 -65
  183. package/dist/stages/mux/mux.worker.d.ts.map +0 -1
  184. package/dist/stages/mux/mux.worker.js +0 -219
  185. package/dist/stages/mux/mux.worker.js.map +0 -1
  186. package/dist/stages/mux/mux.worker2.js +0 -5
  187. package/dist/stages/mux/mux.worker2.js.map +0 -1
  188. package/dist/stages/mux/utils.js +0 -34
  189. package/dist/stages/mux/utils.js.map +0 -1
  190. package/dist/worker/worker-registry.d.ts +0 -12
  191. package/dist/worker/worker-registry.d.ts.map +0 -1
  192. package/dist/worker/worker-registry.js +0 -20
  193. package/dist/worker/worker-registry.js.map +0 -1
@@ -1,483 +1,4 @@
1
- var WorkerMessageType = /* @__PURE__ */ ((WorkerMessageType2) => {
2
- WorkerMessageType2["Ready"] = "ready";
3
- WorkerMessageType2["Error"] = "error";
4
- WorkerMessageType2["Dispose"] = "dispose";
5
- WorkerMessageType2["Configure"] = "configure";
6
- WorkerMessageType2["LoadResource"] = "load_resource";
7
- WorkerMessageType2["ResourceLoaded"] = "resource_loaded";
8
- WorkerMessageType2["ResourceProgress"] = "resource_progress";
9
- WorkerMessageType2["ConfigureDemux"] = "configure_demux";
10
- WorkerMessageType2["AppendBuffer"] = "append_buffer";
11
- WorkerMessageType2["DemuxSamples"] = "demux_samples";
12
- WorkerMessageType2["FlushDemux"] = "flush_demux";
13
- WorkerMessageType2["ConfigureDecode"] = "configure_decode";
14
- WorkerMessageType2["DecodeChunk"] = "decode_chunk";
15
- WorkerMessageType2["DecodedFrame"] = "decoded_frame";
16
- WorkerMessageType2["SeekGop"] = "seek_gop";
17
- WorkerMessageType2["SetComposition"] = "set_composition";
18
- WorkerMessageType2["ApplyPatch"] = "apply_patch";
19
- WorkerMessageType2["RenderFrame"] = "render_frame";
20
- WorkerMessageType2["ComposeFrameReady"] = "compose_frame_ready";
21
- WorkerMessageType2["ConfigureEncode"] = "configure_encode";
22
- WorkerMessageType2["EncodeFrame"] = "encode_frame";
23
- WorkerMessageType2["EncodeAudio"] = "encode_audio";
24
- WorkerMessageType2["EncodedChunk"] = "encoded_chunk";
25
- WorkerMessageType2["FlushEncode"] = "flush_encode";
26
- WorkerMessageType2["ConfigureMux"] = "configure_mux";
27
- WorkerMessageType2["AddChunk"] = "add_chunk";
28
- WorkerMessageType2["FinishMux"] = "finish_mux";
29
- WorkerMessageType2["MuxComplete"] = "mux_complete";
30
- WorkerMessageType2["PerformanceStats"] = "performance_stats";
31
- WorkerMessageType2["RenderWindow"] = "renderWindow";
32
- WorkerMessageType2["AudioTrackAdd"] = "audio_track:add";
33
- WorkerMessageType2["AudioTrackRemove"] = "audio_track:remove";
34
- WorkerMessageType2["AudioTrackUpdate"] = "audio_track:update";
35
- return WorkerMessageType2;
36
- })(WorkerMessageType || {});
37
- var WorkerState = /* @__PURE__ */ ((WorkerState2) => {
38
- WorkerState2["Idle"] = "idle";
39
- WorkerState2["Initializing"] = "initializing";
40
- WorkerState2["Ready"] = "ready";
41
- WorkerState2["Processing"] = "processing";
42
- WorkerState2["Error"] = "error";
43
- WorkerState2["Disposed"] = "disposed";
44
- return WorkerState2;
45
- })(WorkerState || {});
46
- const defaultRetryConfig = {
47
- maxRetries: 3,
48
- initialDelay: 100,
49
- maxDelay: 5e3,
50
- backoffFactor: 2,
51
- retryableErrors: ["TIMEOUT", "NETWORK_ERROR", "WORKER_BUSY"]
52
- };
53
- function calculateRetryDelay(attempt, config) {
54
- const { initialDelay = 100, maxDelay = 5e3, backoffFactor = 2 } = config;
55
- const delay = initialDelay * Math.pow(backoffFactor, attempt - 1);
56
- return Math.min(delay, maxDelay);
57
- }
58
- function isRetryableError(error, config) {
59
- const { retryableErrors = defaultRetryConfig.retryableErrors } = config;
60
- if (!error) return false;
61
- const errorCode = error.code || error.name;
62
- if (errorCode && retryableErrors.includes(errorCode)) {
63
- return true;
64
- }
65
- const message = error.message || "";
66
- if (message.includes("timeout") || message.includes("Timeout")) {
67
- return true;
68
- }
69
- return false;
70
- }
71
- async function withRetry(fn, config) {
72
- const { maxRetries } = config;
73
- let lastError;
74
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
75
- try {
76
- return await fn();
77
- } catch (error) {
78
- lastError = error;
79
- if (!isRetryableError(error, config)) {
80
- throw error;
81
- }
82
- if (attempt === maxRetries) {
83
- throw error;
84
- }
85
- const delay = calculateRetryDelay(attempt, config);
86
- await sleep(delay);
87
- }
88
- }
89
- throw lastError || new Error("Retry failed");
90
- }
91
- function sleep(ms) {
92
- return new Promise((resolve) => setTimeout(resolve, ms));
93
- }
94
- function isTransferable(obj) {
95
- return obj instanceof ArrayBuffer || obj instanceof MessagePort || typeof ImageBitmap !== "undefined" && obj instanceof ImageBitmap || typeof OffscreenCanvas !== "undefined" && obj instanceof OffscreenCanvas || typeof ReadableStream !== "undefined" && obj instanceof ReadableStream || typeof WritableStream !== "undefined" && obj instanceof WritableStream || typeof TransformStream !== "undefined" && obj instanceof TransformStream;
96
- }
97
- function findTransferables(obj, transferables) {
98
- if (!obj || typeof obj !== "object") {
99
- return;
100
- }
101
- if (isTransferable(obj)) {
102
- transferables.push(obj);
103
- return;
104
- }
105
- if (obj instanceof VideoFrame) {
106
- transferables.push(obj);
107
- return;
108
- }
109
- if (typeof AudioData !== "undefined" && obj instanceof AudioData) {
110
- transferables.push(obj);
111
- return;
112
- }
113
- if (typeof EncodedVideoChunk !== "undefined" && obj instanceof EncodedVideoChunk || typeof EncodedAudioChunk !== "undefined" && obj instanceof EncodedAudioChunk) {
114
- return;
115
- }
116
- if (Array.isArray(obj)) {
117
- for (const item of obj) {
118
- findTransferables(item, transferables);
119
- }
120
- } else {
121
- for (const key in obj) {
122
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
123
- findTransferables(obj[key], transferables);
124
- }
125
- }
126
- }
127
- }
128
- function extractTransferables(payload) {
129
- const transferables = [];
130
- findTransferables(payload, transferables);
131
- return transferables;
132
- }
133
- class WorkerChannel {
134
- name;
135
- port;
136
- pendingRequests = /* @__PURE__ */ new Map();
137
- messageHandlers = {};
138
- state = WorkerState.Idle;
139
- defaultTimeout;
140
- defaultMaxRetries;
141
- constructor(port, config) {
142
- this.name = config.name;
143
- this.port = port;
144
- this.defaultTimeout = config.timeout ?? 3e4;
145
- this.defaultMaxRetries = config.maxRetries ?? 3;
146
- this.setupMessageHandler();
147
- this.state = WorkerState.Ready;
148
- }
149
- /**
150
- * Send a message and wait for response with retry support
151
- */
152
- async send(type, payload, options) {
153
- const maxRetries = options?.maxRetries ?? this.defaultMaxRetries;
154
- const retryConfig = {
155
- ...defaultRetryConfig,
156
- maxRetries,
157
- ...options?.retryConfig
158
- };
159
- return withRetry(() => this.sendOnce(type, payload, options), retryConfig);
160
- }
161
- /**
162
- * Send a message once (without retry)
163
- */
164
- async sendOnce(type, payload, options) {
165
- const id = this.generateMessageId();
166
- const timeout = options?.timeout ?? this.defaultTimeout;
167
- const message = {
168
- type,
169
- id,
170
- payload,
171
- timestamp: Date.now()
172
- };
173
- return new Promise((resolve, reject) => {
174
- const request = {
175
- id,
176
- type,
177
- timestamp: Date.now(),
178
- timeout,
179
- resolve,
180
- reject
181
- };
182
- this.pendingRequests.set(id, request);
183
- const timeoutId = setTimeout(() => {
184
- const pending = this.pendingRequests.get(id);
185
- if (pending) {
186
- this.pendingRequests.delete(id);
187
- const error = new Error(`Request timeout: ${id} ${type} (${timeout}ms)`);
188
- error.code = "TIMEOUT";
189
- pending.reject(error);
190
- }
191
- }, timeout);
192
- request.timeoutId = timeoutId;
193
- if (options?.transfer) {
194
- this.port.postMessage(message, options.transfer);
195
- } else {
196
- this.port.postMessage(message);
197
- }
198
- });
199
- }
200
- /**
201
- * Send a message without waiting for response
202
- */
203
- post(type, payload, transfer) {
204
- const message = {
205
- type,
206
- id: this.generateMessageId(),
207
- payload,
208
- timestamp: Date.now()
209
- };
210
- if (transfer) {
211
- this.port.postMessage(message, transfer);
212
- } else {
213
- this.port.postMessage(message);
214
- }
215
- }
216
- /**
217
- * Register a message handler
218
- */
219
- on(type, handler) {
220
- this.messageHandlers[type] = handler;
221
- }
222
- /**
223
- * Unregister a message handler
224
- */
225
- off(type) {
226
- delete this.messageHandlers[type];
227
- }
228
- /**
229
- * Dispose the channel
230
- */
231
- dispose() {
232
- this.state = WorkerState.Disposed;
233
- for (const [, request] of this.pendingRequests) {
234
- if (request.timeoutId) {
235
- clearTimeout(request.timeoutId);
236
- }
237
- request.reject(new Error("Channel disposed"));
238
- }
239
- this.pendingRequests.clear();
240
- this.port.onmessage = null;
241
- }
242
- /**
243
- * Setup message handler for incoming messages
244
- */
245
- setupMessageHandler() {
246
- this.port.onmessage = async (event) => {
247
- const data = event.data;
248
- if (this.isResponse(data)) {
249
- this.handleResponse(data);
250
- return;
251
- }
252
- if (this.isRequest(data)) {
253
- await this.handleRequest(data);
254
- return;
255
- }
256
- };
257
- }
258
- /**
259
- * Handle incoming request
260
- */
261
- async handleRequest(message) {
262
- const handler = this.messageHandlers[message.type];
263
- if (!handler) {
264
- this.sendResponse(message.id, false, null, {
265
- code: "NO_HANDLER",
266
- message: `No handler registered for message type: ${message.type}`
267
- });
268
- return;
269
- }
270
- this.state = WorkerState.Processing;
271
- Promise.resolve().then(() => handler(message.payload, message.transfer)).then((result) => {
272
- this.sendResponse(message.id, true, result);
273
- this.state = WorkerState.Ready;
274
- }).catch((error) => {
275
- const workerError = {
276
- code: "HANDLER_ERROR",
277
- message: error instanceof Error ? error.message : String(error),
278
- stack: error instanceof Error ? error.stack : void 0
279
- };
280
- this.sendResponse(message.id, false, null, workerError);
281
- this.state = WorkerState.Ready;
282
- });
283
- }
284
- /**
285
- * Handle incoming response
286
- */
287
- handleResponse(response) {
288
- const request = this.pendingRequests.get(response.id);
289
- if (!request) {
290
- return;
291
- }
292
- this.pendingRequests.delete(response.id);
293
- if (request.timeoutId) {
294
- clearTimeout(request.timeoutId);
295
- }
296
- if (response.success) {
297
- request.resolve(response.result);
298
- } else {
299
- const error = new Error(response.error?.message || "Unknown error");
300
- if (response.error) {
301
- Object.assign(error, response.error);
302
- }
303
- request.reject(error);
304
- }
305
- }
306
- /**
307
- * Send a response message
308
- */
309
- sendResponse(id, success, result, error) {
310
- let transfer = [];
311
- if (isTransferable(result)) {
312
- transfer.push(result);
313
- }
314
- const response = {
315
- id,
316
- success,
317
- result,
318
- error,
319
- timestamp: Date.now()
320
- };
321
- this.port.postMessage(response, transfer);
322
- }
323
- /**
324
- * Check if message is a response
325
- */
326
- isResponse(data) {
327
- return data && typeof data === "object" && "id" in data && "success" in data && !("type" in data);
328
- }
329
- /**
330
- * Check if message is a request
331
- */
332
- isRequest(data) {
333
- return data && typeof data === "object" && "id" in data && "type" in data;
334
- }
335
- /**
336
- * Generate unique message ID
337
- */
338
- generateMessageId() {
339
- return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
340
- }
341
- /**
342
- * Send a notification message without waiting for response
343
- * Alias for post() method for compatibility
344
- */
345
- notify(type, payload, transfer) {
346
- this.post(type, payload, transfer);
347
- }
348
- /**
349
- * Register a message handler
350
- * Alias for on() method for compatibility
351
- */
352
- registerHandler(type, handler) {
353
- this.on(type, handler);
354
- }
355
- /**
356
- * Send a ReadableStream to another worker
357
- * Automatically handles transferable streams vs chunk-by-chunk fallback
358
- */
359
- async sendStream(stream, metadata) {
360
- const streamId = metadata?.streamId || this.generateMessageId();
361
- if (isTransferable(stream)) {
362
- this.port.postMessage(
363
- {
364
- type: "stream_transfer",
365
- ...metadata,
366
- stream,
367
- streamId
368
- },
369
- [stream]
370
- // Transfer ownership
371
- );
372
- } else {
373
- await this.streamChunks(stream, streamId, metadata);
374
- }
375
- }
376
- /**
377
- * Stream chunks from a ReadableStream (fallback when transfer is not supported)
378
- */
379
- async streamChunks(stream, streamId, metadata) {
380
- const reader = stream.getReader();
381
- this.post("stream_start", {
382
- streamId,
383
- ...metadata,
384
- mode: "chunk_transfer"
385
- });
386
- try {
387
- while (true) {
388
- const { done, value } = await reader.read();
389
- if (done) {
390
- this.post("stream_end", {
391
- streamId,
392
- ...metadata
393
- });
394
- break;
395
- }
396
- const transfer = [];
397
- if (value instanceof ArrayBuffer) {
398
- transfer.push(value);
399
- } else if (value instanceof Uint8Array) {
400
- transfer.push(value.buffer);
401
- } else if (typeof AudioData !== "undefined" && value instanceof AudioData) {
402
- transfer.push(value);
403
- } else if (typeof VideoFrame !== "undefined" && value instanceof VideoFrame) {
404
- transfer.push(value);
405
- } else if (typeof value === "object" && value !== null) {
406
- const extracted = extractTransferables(value);
407
- transfer.push(...extracted);
408
- }
409
- this.post(
410
- "stream_chunk",
411
- {
412
- streamId,
413
- chunk: value,
414
- ...metadata
415
- },
416
- transfer
417
- );
418
- }
419
- } catch (error) {
420
- this.post("stream_error", {
421
- streamId,
422
- error: error instanceof Error ? error.message : String(error),
423
- ...metadata
424
- });
425
- throw error;
426
- } finally {
427
- reader.releaseLock();
428
- }
429
- }
430
- /**
431
- * Receive a stream from another worker
432
- * Handles both transferable streams and chunk-by-chunk reconstruction
433
- */
434
- async receiveStream(onStream) {
435
- const chunkedStreams = /* @__PURE__ */ new Map();
436
- const prev = this.port.onmessage;
437
- const handler = (event) => {
438
- const raw = event.data;
439
- const envelopeType = raw?.type;
440
- const hasPayload = raw && typeof raw === "object" && "payload" in raw;
441
- const payload = hasPayload ? raw.payload : raw;
442
- if (envelopeType === "stream_transfer" && payload?.stream) {
443
- onStream(payload.stream, payload);
444
- return;
445
- }
446
- if (envelopeType === "stream_start" && payload?.streamId) {
447
- const stream = new ReadableStream({
448
- start(controller) {
449
- chunkedStreams.set(payload.streamId, { controller, metadata: payload });
450
- }
451
- });
452
- onStream(stream, payload);
453
- return;
454
- }
455
- if (envelopeType === "stream_chunk" && payload?.streamId && chunkedStreams.has(payload.streamId)) {
456
- const s = chunkedStreams.get(payload.streamId);
457
- if (s) s.controller.enqueue(payload.chunk);
458
- return;
459
- }
460
- if (envelopeType === "stream_end" && payload?.streamId && chunkedStreams.has(payload.streamId)) {
461
- const s = chunkedStreams.get(payload.streamId);
462
- if (s) {
463
- s.controller.close();
464
- chunkedStreams.delete(payload.streamId);
465
- }
466
- return;
467
- }
468
- if (envelopeType === "stream_error" && payload?.streamId && chunkedStreams.has(payload.streamId)) {
469
- const s = chunkedStreams.get(payload.streamId);
470
- if (s) {
471
- s.controller.error(new Error(String(payload.error || "stream error")));
472
- chunkedStreams.delete(payload.streamId);
473
- }
474
- return;
475
- }
476
- if (typeof prev === "function") prev.call(this.port, event);
477
- };
478
- this.port.onmessage = handler;
479
- }
480
- }
1
+ import { W as WorkerChannel, a as WorkerMessageType, b as WorkerState } from "../../WorkerChannel.js";
481
2
  const MICROSECONDS_PER_SECOND = 1e6;
482
3
  const DEFAULT_FPS = 30;
483
4
  function normalizeFps(value) {
@@ -1311,8 +832,11 @@ class VideoComposer {
1311
832
  this.filterProcessor.clearCache();
1312
833
  }
1313
834
  }
1314
- function resolveActiveLayers(layers, timestamp, _frame) {
835
+ function resolveActiveLayers(layers, timestamp) {
1315
836
  return layers.filter((layer) => {
837
+ if (layer.layerId.includes("base-video")) {
838
+ return true;
839
+ }
1316
840
  if (layer.status !== "ready") {
1317
841
  return false;
1318
842
  }
@@ -1371,11 +895,12 @@ class VideoComposeWorker {
1371
895
  channel;
1372
896
  composer = null;
1373
897
  composeStream = null;
1374
- downstreamPorts = /* @__PURE__ */ new Map();
1375
- upstreamPorts = /* @__PURE__ */ new Map();
1376
- instructionRegistry = /* @__PURE__ */ new Map();
1377
- pendingReplay = /* @__PURE__ */ new Map();
1378
- streamState = /* @__PURE__ */ new Map();
898
+ clipId = null;
899
+ downstreamPort = null;
900
+ upstreamPort = null;
901
+ instructions = null;
902
+ streamState = null;
903
+ imageBitmap = null;
1379
904
  constructor() {
1380
905
  this.channel = new WorkerChannel(self, {
1381
906
  name: "VideoComposeWorker",
@@ -1389,7 +914,7 @@ class VideoComposeWorker {
1389
914
  this.channel.registerHandler("flush", this.handleFlush.bind(this));
1390
915
  this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
1391
916
  this.channel.registerHandler("install_instructions", this.handleInstallInstructions.bind(this));
1392
- this.channel.registerHandler("sync_clip", this.handleSyncClip.bind(this));
917
+ this.channel.registerHandler("receive_image", this.handleReceiveImage.bind(this));
1393
918
  this.channel.registerHandler("dispose_clip", this.handleDisposeClip.bind(this));
1394
919
  this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
1395
920
  }
@@ -1397,9 +922,12 @@ class VideoComposeWorker {
1397
922
  * Unified connect handler used by stream pipeline
1398
923
  */
1399
924
  async handleConnect(payload) {
1400
- const { port, direction, clipId = "default" } = payload;
925
+ const { port, direction, clipId } = payload;
926
+ if (clipId && !this.clipId) {
927
+ this.clipId = clipId;
928
+ }
1401
929
  if (direction === "upstream") {
1402
- this.upstreamPorts.set(clipId, port);
930
+ this.upstreamPort = port;
1403
931
  const channel = new WorkerChannel(port, {
1404
932
  name: "VideoCompose-Decode",
1405
933
  timeout: 3e4
@@ -1407,7 +935,7 @@ class VideoComposeWorker {
1407
935
  channel.receiveStream(this.handleReceiveStream.bind(this));
1408
936
  }
1409
937
  if (direction === "downstream") {
1410
- this.downstreamPorts.set(clipId, port);
938
+ this.downstreamPort = port;
1411
939
  }
1412
940
  return { success: true };
1413
941
  }
@@ -1446,14 +974,12 @@ class VideoComposeWorker {
1446
974
  };
1447
975
  }
1448
976
  async handleReceiveStream(stream, metadata) {
1449
- const { clipId = "default" } = metadata || {};
1450
977
  if (!this.composer) {
1451
978
  console.error("[VideoComposeWorker] Composer not configured");
1452
979
  return;
1453
980
  }
1454
- const instruction = this.instructionRegistry.get(clipId);
1455
- if (!instruction) {
1456
- console.warn("[VideoComposeWorker] No instructions for clip", clipId);
981
+ if (!this.instructions) {
982
+ console.warn("[VideoComposeWorker] No instructions installed");
1457
983
  return;
1458
984
  }
1459
985
  const filteredStream = stream.pipeThrough(
@@ -1463,12 +989,7 @@ class VideoComposeWorker {
1463
989
  const frame = wrappedFrame.frame || wrappedFrame;
1464
990
  const gopSerial = wrappedFrame.gopSerial;
1465
991
  const isKeyframe = wrappedFrame.isKeyframe;
1466
- const timestamp = frame.timestamp ?? 0;
1467
- if (this.shouldSkipFrame(clipId, timestamp)) {
1468
- frame.close();
1469
- return;
1470
- }
1471
- const request = this.buildComposeRequest(clipId, instruction, frame, timestamp);
992
+ const request = this.buildComposeRequest(this.instructions, frame);
1472
993
  if (!request) {
1473
994
  frame.close();
1474
995
  return;
@@ -1487,7 +1008,7 @@ class VideoComposeWorker {
1487
1008
  const { composeStream, cacheStream } = this.composer.createStreams();
1488
1009
  this.channel.sendStream(cacheStream, metadata);
1489
1010
  filteredStream.pipeTo(composeStream).catch((error) => {
1490
- console.error("[VideoComposeWorker] compose stream error", clipId, error);
1011
+ console.error("[VideoComposeWorker] compose stream error", this.clipId, error);
1491
1012
  });
1492
1013
  }
1493
1014
  // private handleGetStream(): ReadableStream<VideoFrame> | undefined {
@@ -1526,61 +1047,96 @@ class VideoComposeWorker {
1526
1047
  this.composer = null;
1527
1048
  }
1528
1049
  this.composeStream = null;
1529
- this.downstreamPorts.get("default")?.close();
1530
- this.upstreamPorts.get("default")?.close();
1531
- this.downstreamPorts.clear();
1532
- this.upstreamPorts.clear();
1050
+ this.downstreamPort?.close();
1051
+ this.upstreamPort?.close();
1052
+ this.downstreamPort = null;
1053
+ this.upstreamPort = null;
1054
+ this.imageBitmap?.close();
1055
+ this.imageBitmap = null;
1056
+ this.instructions = null;
1057
+ this.streamState = null;
1533
1058
  this.channel.state = WorkerState.Disposed;
1534
1059
  return { success: true };
1535
1060
  }
1536
- async handleInstallInstructions(data) {
1537
- const { clipId, revision } = data;
1538
- const current = this.instructionRegistry.get(clipId);
1539
- if (current && current.revision > revision) {
1061
+ async handleInstallInstructions(payload) {
1062
+ const { clipId, revision } = payload;
1063
+ if (!this.clipId) {
1064
+ this.clipId = clipId;
1065
+ }
1066
+ if (this.instructions && this.instructions.revision > revision) {
1540
1067
  return { success: false };
1541
1068
  }
1542
- this.instructionRegistry.set(clipId, data);
1069
+ this.instructions = payload;
1543
1070
  return { success: true };
1544
1071
  }
1545
- async handleSyncClip(payload) {
1546
- const { clipId, revision, range } = payload;
1547
- const current = this.instructionRegistry.get(clipId);
1548
- if (!current || current.revision > revision) {
1549
- return { success: false };
1072
+ /**
1073
+ * Receive image data from ResourceLoader
1074
+ * Note: ImageBitmap is required because VideoFrame constructor in Worker context
1075
+ * only accepts ImageBitmap/OffscreenCanvas, not HTMLImageElement or Blob
1076
+ */
1077
+ async handleReceiveImage(payload) {
1078
+ const { clipId, imageBitmap } = payload;
1079
+ if (!this.clipId) {
1080
+ this.clipId = clipId;
1081
+ }
1082
+ if (this.imageBitmap) {
1083
+ this.imageBitmap.close();
1084
+ }
1085
+ this.imageBitmap = imageBitmap;
1086
+ if (this.instructions) {
1087
+ await this.startImageFrameStream();
1550
1088
  }
1551
- this.pendingReplay.set(clipId, { ...range, revision });
1552
- this.channel.notify("sync_ack", { clipId, revision });
1553
1089
  return { success: true };
1554
1090
  }
1555
- async handleDisposeClip(payload) {
1556
- const { clipId } = payload;
1557
- this.instructionRegistry.delete(clipId);
1558
- this.pendingReplay.delete(clipId);
1559
- this.downstreamPorts.get(clipId)?.close();
1560
- this.upstreamPorts.get(clipId)?.close();
1561
- this.downstreamPorts.delete(clipId);
1562
- this.upstreamPorts.delete(clipId);
1091
+ async handleDisposeClip() {
1092
+ this.instructions = null;
1093
+ this.streamState = null;
1094
+ this.downstreamPort?.close();
1095
+ this.upstreamPort?.close();
1096
+ this.downstreamPort = null;
1097
+ this.upstreamPort = null;
1098
+ this.imageBitmap?.close();
1099
+ this.imageBitmap = null;
1563
1100
  return { success: true };
1564
1101
  }
1565
- /**
1566
- * Check if frame should be skipped (outside dirty range)
1567
- * Returns true if frame is NOT in the dirty range and should use cached version
1568
- */
1569
- shouldSkipFrame(clipId, timestamp) {
1570
- const dirtyRange = this.pendingReplay.get(clipId);
1571
- if (!dirtyRange) {
1572
- return false;
1573
- }
1574
- if (timestamp >= dirtyRange.startUs && timestamp <= dirtyRange.endUs) {
1575
- return false;
1102
+ async startImageFrameStream() {
1103
+ if (!this.instructions || !this.composer) {
1104
+ return;
1576
1105
  }
1577
- if (timestamp > dirtyRange.endUs) {
1578
- this.pendingReplay.delete(clipId);
1106
+ const timeline = this.instructions.baseConfig.timeline;
1107
+ if (!timeline) {
1108
+ return;
1579
1109
  }
1580
- return true;
1110
+ const { composeStream, cacheStream } = this.composer.createStreams();
1111
+ const { clipDurationUs, compositionFps } = timeline;
1112
+ let currentTimeUs = 0;
1113
+ const readableStream = new ReadableStream({
1114
+ pull: (controller) => {
1115
+ if (currentTimeUs >= clipDurationUs) {
1116
+ controller.close();
1117
+ return;
1118
+ }
1119
+ const videoFrame = new VideoFrame(this.imageBitmap, {
1120
+ timestamp: currentTimeUs,
1121
+ duration: frameDurationFromFps(compositionFps)
1122
+ });
1123
+ const request = this.buildComposeRequest(this.instructions, videoFrame);
1124
+ if (request) {
1125
+ controller.enqueue(request);
1126
+ }
1127
+ currentTimeUs += frameDurationFromFps(compositionFps);
1128
+ }
1129
+ });
1130
+ this.channel.sendStream(cacheStream, {
1131
+ streamType: "video",
1132
+ clipId: this.clipId
1133
+ });
1134
+ readableStream.pipeTo(composeStream).catch((error) => {
1135
+ console.error("[VideoComposeWorker] image frame stream error", this.clipId, error);
1136
+ });
1581
1137
  }
1582
- buildComposeRequest(clipId, instruction, frame, _timestamp) {
1583
- const normalizedTime = this.computeTimelineTimestamp(clipId, frame, instruction.baseConfig);
1138
+ buildComposeRequest(instruction, frame) {
1139
+ const normalizedTime = this.computeTimelineTimestamp(frame, instruction.baseConfig);
1584
1140
  const clipStartUs = instruction.baseConfig.timeline?.clipStartUs ?? 0;
1585
1141
  const clipDurationUs = instruction.baseConfig.timeline?.clipDurationUs ?? Infinity;
1586
1142
  const clipEndUs = clipStartUs + clipDurationUs;
@@ -1621,43 +1177,40 @@ class VideoComposeWorker {
1621
1177
  direction: entry.params.payload?.direction
1622
1178
  };
1623
1179
  }
1624
- computeTimelineTimestamp(clipId, frame, config) {
1625
- const key = clipId;
1626
- let state = this.streamState.get(key);
1627
- if (!state) {
1628
- state = {
1180
+ computeTimelineTimestamp(frame, config) {
1181
+ if (!this.streamState) {
1182
+ this.streamState = {
1629
1183
  baseTimestamp: null,
1630
1184
  lastSourceTimestamp: null,
1631
1185
  nextFrameIndex: 0
1632
1186
  };
1633
- this.streamState.set(key, state);
1634
1187
  }
1635
1188
  const timeline = config.timeline;
1636
1189
  if (!timeline) {
1637
1190
  const ts = frame.timestamp ?? 0;
1638
- state.lastSourceTimestamp = frame.timestamp ?? null;
1191
+ this.streamState.lastSourceTimestamp = frame.timestamp ?? null;
1639
1192
  return ts;
1640
1193
  }
1641
1194
  const { clipStartUs, compositionFps } = timeline;
1642
1195
  const sourceTimestamp = frame.timestamp ?? null;
1643
- if (sourceTimestamp !== null && state.lastSourceTimestamp !== null && sourceTimestamp < state.lastSourceTimestamp) {
1644
- state.baseTimestamp = null;
1645
- state.nextFrameIndex = 0;
1646
- }
1647
- if (state.baseTimestamp === null) {
1648
- state.baseTimestamp = sourceTimestamp ?? 0;
1649
- state.nextFrameIndex = 0;
1650
- if (state.baseTimestamp > 1e3) {
1196
+ if (sourceTimestamp !== null && this.streamState.lastSourceTimestamp !== null && sourceTimestamp < this.streamState.lastSourceTimestamp) {
1197
+ this.streamState.baseTimestamp = null;
1198
+ this.streamState.nextFrameIndex = 0;
1199
+ }
1200
+ if (this.streamState.baseTimestamp === null) {
1201
+ this.streamState.baseTimestamp = sourceTimestamp ?? 0;
1202
+ this.streamState.nextFrameIndex = 0;
1203
+ if (this.streamState.baseTimestamp > 1e3) {
1651
1204
  console.warn(
1652
- `[VideoComposeWorker] First frame timestamp is ${state.baseTimestamp}us, expected ~0. Check MP4Demuxer normalization.`
1205
+ `[VideoComposeWorker] First frame timestamp is ${this.streamState.baseTimestamp}us, expected ~0. Check MP4Demuxer normalization.`
1653
1206
  );
1654
1207
  }
1655
1208
  }
1656
1209
  const frameDuration = frameDurationFromFps(compositionFps);
1657
- let frameIndex = state.nextFrameIndex;
1210
+ let frameIndex = this.streamState.nextFrameIndex;
1658
1211
  if (sourceTimestamp !== null) {
1659
1212
  const approxIndex = frameIndexFromTimestamp(
1660
- state.baseTimestamp,
1213
+ this.streamState.baseTimestamp,
1661
1214
  sourceTimestamp,
1662
1215
  compositionFps,
1663
1216
  "nearest"
@@ -1671,8 +1224,8 @@ class VideoComposeWorker {
1671
1224
  compositionFps,
1672
1225
  "nearest"
1673
1226
  );
1674
- state.nextFrameIndex = frameIndex + 1;
1675
- state.lastSourceTimestamp = sourceTimestamp;
1227
+ this.streamState.nextFrameIndex = frameIndex + 1;
1228
+ this.streamState.lastSourceTimestamp = sourceTimestamp;
1676
1229
  return timelineTime;
1677
1230
  }
1678
1231
  }
@@ -1680,4 +1233,9 @@ const worker = new VideoComposeWorker();
1680
1233
  self.addEventListener("beforeunload", () => {
1681
1234
  worker["handleDispose"]();
1682
1235
  });
1683
- //# sourceMappingURL=video-compose.worker-DPzsC21d.js.map
1236
+ const videoCompose_worker = null;
1237
+ export {
1238
+ VideoComposeWorker,
1239
+ videoCompose_worker as default
1240
+ };
1241
+ //# sourceMappingURL=video-compose.worker.js.map