@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,3 @@
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
- }
481
1
  var mp4box_all = {};
482
2
  (function(exports) {
483
3
  var Log = /* @__PURE__ */ function() {
@@ -7523,435 +7043,7 @@ var mp4box_all = {};
7523
7043
  exports.createFile = MP4Box.createFile;
7524
7044
  }
7525
7045
  })(mp4box_all);
7526
- class BackpressureMonitor {
7527
- metrics = /* @__PURE__ */ new Map();
7528
- /**
7529
- * Update metrics for a stage
7530
- */
7531
- updateMetrics(stage, desiredSize, queueSize = 0) {
7532
- const isPaused = desiredSize <= 0;
7533
- this.metrics.set(stage, {
7534
- desiredSize,
7535
- queueSize,
7536
- isPaused,
7537
- lastUpdate: Date.now()
7538
- });
7539
- }
7540
- /**
7541
- * Get current metrics snapshot
7542
- */
7543
- getSnapshot() {
7544
- const now = Date.now();
7545
- const snapshot = {};
7546
- for (const [stage, metrics] of this.metrics) {
7547
- snapshot[stage] = {
7548
- ...metrics,
7549
- age: now - metrics.lastUpdate
7550
- };
7551
- }
7552
- return snapshot;
7553
- }
7554
- /**
7555
- * Check if any stage is experiencing backpressure
7556
- */
7557
- hasBackpressure() {
7558
- for (const metrics of this.metrics.values()) {
7559
- if (metrics.isPaused) {
7560
- return true;
7561
- }
7562
- }
7563
- return false;
7564
- }
7565
- /**
7566
- * Get stages currently experiencing backpressure
7567
- */
7568
- getBottlenecks() {
7569
- const bottlenecks = [];
7570
- for (const [stage, metrics] of this.metrics) {
7571
- if (metrics.isPaused) {
7572
- bottlenecks.push(stage);
7573
- }
7574
- }
7575
- return bottlenecks;
7576
- }
7577
- /**
7578
- * Clear all metrics
7579
- */
7580
- clear() {
7581
- this.metrics.clear();
7582
- }
7583
- }
7584
- class MP4Demuxer {
7585
- mp4boxFile;
7586
- tracks = /* @__PURE__ */ new Map();
7587
- isReady = false;
7588
- videoController;
7589
- audioController;
7590
- backpressureMonitor;
7591
- demuxHighWaterMark;
7592
- onReadyCallback;
7593
- fileOffset = 0;
7594
- videoTimestampOffset = null;
7595
- audioTimestampOffset = null;
7596
- constructor(config = {}) {
7597
- this.mp4boxFile = mp4box_all.createFile();
7598
- this.backpressureMonitor = new BackpressureMonitor();
7599
- this.onReadyCallback = config.onReady;
7600
- const DEFAULT_HIGH_WATER_MARK = 10;
7601
- this.demuxHighWaterMark = config.highWaterMark ?? DEFAULT_HIGH_WATER_MARK;
7602
- this.setupHandlers();
7603
- }
7604
- updateConfig(config) {
7605
- this.demuxHighWaterMark = config.highWaterMark ?? this.demuxHighWaterMark;
7606
- }
7607
- setupHandlers() {
7608
- this.mp4boxFile.onError = (error) => {
7609
- console.error("MP4Box error:", error);
7610
- this.videoController?.error(new Error(error));
7611
- this.audioController?.error(new Error(error));
7612
- };
7613
- this.mp4boxFile.onReady = (info) => {
7614
- this.processTracks(info.tracks);
7615
- this.isReady = true;
7616
- if (this.onReadyCallback) {
7617
- this.onReadyCallback();
7618
- }
7619
- this.mp4boxFile.start();
7620
- };
7621
- this.mp4boxFile.onSamples = (trackId, _user, samples) => {
7622
- this.processSamples(trackId, samples);
7623
- };
7624
- }
7625
- processTracks(tracks) {
7626
- for (const track of tracks) {
7627
- const trackInfo = {
7628
- id: track.id,
7629
- type: track.type === "video" ? "video" : "audio",
7630
- codec: track.codec,
7631
- timescale: track.timescale
7632
- };
7633
- if (track.type === "video") {
7634
- trackInfo.width = track.video?.width;
7635
- trackInfo.height = track.video?.height;
7636
- trackInfo.description = this.getVideoDescription(track);
7637
- } else if (track.type === "audio") {
7638
- trackInfo.sampleRate = track.audio?.sample_rate;
7639
- trackInfo.numberOfChannels = track.audio?.channel_count;
7640
- trackInfo.description = this.getAudioDescription(track);
7641
- }
7642
- this.tracks.set(track.id, trackInfo);
7643
- this.mp4boxFile.setExtractionOptions(track.id, track, {
7644
- nbSamples: 30
7645
- // Batch size per callback (balance between latency and overhead)
7646
- });
7647
- }
7648
- }
7649
- processSamples(trackId, samples) {
7650
- const track = this.tracks.get(trackId);
7651
- if (!track) return;
7652
- const timescale = track.timescale || 9e4;
7653
- for (const sample of samples) {
7654
- const rawTimestamp = sample.cts * 1e6 / timescale;
7655
- const duration = sample.duration * 1e6 / timescale;
7656
- if (track.type === "video") {
7657
- if (!this.videoController) {
7658
- console.error("[MP4Demuxer] videoController is null when trying to output chunk!");
7659
- return;
7660
- }
7661
- if (this.videoTimestampOffset === null) {
7662
- this.videoTimestampOffset = rawTimestamp;
7663
- }
7664
- const timestamp = rawTimestamp - this.videoTimestampOffset;
7665
- const chunk = new EncodedVideoChunk({
7666
- type: sample.is_sync ? "key" : "delta",
7667
- timestamp,
7668
- duration,
7669
- data: sample.data
7670
- });
7671
- this.videoController.enqueue(chunk);
7672
- } else if (track.type === "audio" && this.audioController) {
7673
- if (this.audioTimestampOffset === null) {
7674
- this.audioTimestampOffset = rawTimestamp;
7675
- }
7676
- const timestamp = rawTimestamp - this.audioTimestampOffset;
7677
- const chunk = new EncodedAudioChunk({
7678
- type: "key",
7679
- timestamp,
7680
- duration,
7681
- data: sample.data
7682
- });
7683
- this.audioController.enqueue(chunk);
7684
- }
7685
- }
7686
- const last = samples[samples.length - 1].number;
7687
- this.mp4boxFile.releaseUsedSamples(trackId, last + 1);
7688
- }
7689
- getVideoDescription(track) {
7690
- try {
7691
- const fullTrack = this.mp4boxFile.getTrackById(track.id);
7692
- for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {
7693
- const box2 = entry.avcC ?? entry.hvcC ?? entry.av1C ?? entry.vpcC;
7694
- if (box2) {
7695
- const stream = new mp4box_all.DataStream(
7696
- void 0,
7697
- 0,
7698
- mp4box_all.DataStream.BIG_ENDIAN
7699
- // IMPORTANT: must be BIG_ENDIAN
7700
- );
7701
- box2.write(stream);
7702
- return new Uint8Array(stream.buffer.slice(8)).buffer;
7703
- }
7704
- }
7705
- } catch (error) {
7706
- console.error("Failed to get video description:", error);
7707
- }
7708
- return void 0;
7709
- }
7710
- // private getVideoDescription(track: any): ArrayBuffer | undefined {
7711
- // if (!this.mp4boxFile) return undefined;
7712
- // return getVideoDescription(this.mp4boxFile, track);
7713
- // }
7714
- getAudioDescription(track) {
7715
- try {
7716
- const fullTrack = this.mp4boxFile.getTrackById(track.id);
7717
- for (const entry of fullTrack.mdia.minf.stbl.stsd.entries) {
7718
- if (entry.esds || entry.dOps) {
7719
- const stream = new mp4box_all.DataStream();
7720
- (entry.esds || entry.dOps).write(stream);
7721
- return new Uint8Array(stream.buffer.slice(8)).buffer;
7722
- }
7723
- }
7724
- } catch (error) {
7725
- console.error("Failed to get audio description:", error);
7726
- }
7727
- return void 0;
7728
- }
7729
- /**
7730
- * Create transform stream for video track
7731
- */
7732
- createVideoStream() {
7733
- return new TransformStream(
7734
- {
7735
- start: (controller) => {
7736
- this.videoController = controller;
7737
- },
7738
- transform: (chunk, controller) => {
7739
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
7740
- this.backpressureMonitor.updateMetrics("demux-video", desiredSize);
7741
- const chunkData = new Uint8Array(chunk);
7742
- this.appendBuffer(chunkData);
7743
- this.mp4boxFile.flush();
7744
- },
7745
- flush: async () => {
7746
- this.mp4boxFile.flush();
7747
- await new Promise((resolve) => setTimeout(resolve, 100));
7748
- }
7749
- },
7750
- // Queuing strategy: use configuration
7751
- {
7752
- highWaterMark: this.demuxHighWaterMark,
7753
- size: () => 1
7754
- // Count-based
7755
- }
7756
- );
7757
- }
7758
- /**
7759
- * Create transform stream for audio track
7760
- */
7761
- createAudioStream() {
7762
- const hasAudio = Array.from(this.tracks.values()).some((t) => t.type === "audio");
7763
- if (!hasAudio) return null;
7764
- return new TransformStream(
7765
- {
7766
- start: (controller) => {
7767
- this.audioController = controller;
7768
- },
7769
- transform: (chunk, controller) => {
7770
- const desiredSize = controller.desiredSize ?? this.demuxHighWaterMark;
7771
- this.backpressureMonitor.updateMetrics("demux-audio", desiredSize);
7772
- const chunkData = new Uint8Array(chunk);
7773
- this.appendBuffer(chunkData);
7774
- this.mp4boxFile.flush();
7775
- },
7776
- flush: () => {
7777
- this.mp4boxFile.flush();
7778
- }
7779
- },
7780
- // Queuing strategy: use configuration
7781
- {
7782
- highWaterMark: this.demuxHighWaterMark,
7783
- size: () => 1
7784
- }
7785
- );
7786
- }
7787
- appendBuffer(chunk) {
7788
- const buffer = chunk.buffer;
7789
- buffer.fileStart = this.fileOffset;
7790
- this.mp4boxFile.appendBuffer(buffer);
7791
- this.fileOffset += chunk.byteLength;
7792
- }
7793
- /**
7794
- * Get video track info if available
7795
- */
7796
- get videoTrackInfo() {
7797
- return Array.from(this.tracks.values()).find((track) => track.type === "video");
7798
- }
7799
- /**
7800
- * Get audio track info if available
7801
- */
7802
- get audioTrackInfo() {
7803
- return Array.from(this.tracks.values()).find((track) => track.type === "audio");
7804
- }
7805
- destroy() {
7806
- this.mp4boxFile?.stop();
7807
- this.mp4boxFile = null;
7808
- this.tracks.clear();
7809
- this.backpressureMonitor.clear();
7810
- this.isReady = false;
7811
- this.videoTimestampOffset = null;
7812
- this.audioTimestampOffset = null;
7813
- }
7814
- }
7815
- class VideoDemuxWorker {
7816
- channel;
7817
- demuxer = null;
7818
- clipId = null;
7819
- downstreamPort = null;
7820
- constructor() {
7821
- this.channel = new WorkerChannel(self, {
7822
- name: "VideoDemuxWorker",
7823
- timeout: 3e4
7824
- });
7825
- this.setupHandlers();
7826
- }
7827
- /* @better-ai.mdc For test visibility */
7828
- setupHandlers() {
7829
- this.channel.registerHandler("configure", this.handleConfigure.bind(this));
7830
- this.channel.registerHandler("connect", this.handleConnect.bind(this));
7831
- this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
7832
- this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
7833
- this.channel.receiveStream(this.handleReceiveStream.bind(this));
7834
- }
7835
- /**
7836
- * Handle connection from orchestrator
7837
- */
7838
- async handleConnect(payload) {
7839
- const { port, clipId } = payload;
7840
- if (!port) {
7841
- return { success: false };
7842
- }
7843
- this.downstreamPort = port;
7844
- this.clipId = clipId || null;
7845
- return { success: true };
7846
- }
7847
- /**
7848
- * Configure demuxer with format settings
7849
- * @param payload.config - Demuxer configuration
7850
- * @param payload.initial - If true, initialize worker state; otherwise just update config
7851
- */
7852
- async handleConfigure(payload) {
7853
- const { config, initial = false } = payload;
7854
- try {
7855
- if (initial) {
7856
- this.channel.state = WorkerState.Ready;
7857
- if (this.demuxer) {
7858
- this.demuxer.destroy();
7859
- }
7860
- this.demuxer = new MP4Demuxer({
7861
- ...config,
7862
- skipAudio: true,
7863
- // Video only
7864
- onReady: () => this.handleDemuxerReady()
7865
- });
7866
- this.channel.notify("configured");
7867
- return { success: true };
7868
- } else {
7869
- this.demuxer?.updateConfig(config);
7870
- return { success: true };
7871
- }
7872
- } catch (error) {
7873
- throw {
7874
- code: error.code || "CONFIG_ERROR",
7875
- message: error.message
7876
- };
7877
- }
7878
- }
7879
- /**
7880
- * Handle input stream from ResourceLoader (main thread)
7881
- * Strategy: Stream immediately, send codec info when ready
7882
- */
7883
- async handleReceiveStream(stream, metadata) {
7884
- this.clipId = metadata?.clipId || this.clipId;
7885
- if (!this.demuxer) {
7886
- this.demuxer = new MP4Demuxer({
7887
- highWaterMark: 10,
7888
- skipAudio: true,
7889
- onReady: () => this.handleDemuxerReady()
7890
- });
7891
- }
7892
- if (!this.downstreamPort) {
7893
- throw new Error("Decoder not connected");
7894
- }
7895
- const videoStream = this.demuxer.createVideoStream();
7896
- const downstreamChannel = new WorkerChannel(this.downstreamPort, {
7897
- name: "VideoDemux-Decoder",
7898
- timeout: 3e4
7899
- });
7900
- downstreamChannel.sendStream(videoStream.readable, {
7901
- streamType: "video",
7902
- clipId: this.clipId
7903
- });
7904
- await stream.pipeTo(videoStream.writable);
7905
- }
7906
- handleDemuxerReady() {
7907
- if (!this.demuxer || !this.downstreamPort) {
7908
- return;
7909
- }
7910
- const videoTrackInfo = this.demuxer.videoTrackInfo;
7911
- if (!videoTrackInfo) {
7912
- console.error("[VideoDemuxWorker] No video track found after ready");
7913
- return;
7914
- }
7915
- const downstreamChannel = new WorkerChannel(this.downstreamPort, {
7916
- name: "VideoDemux-Decoder",
7917
- timeout: 3e4
7918
- });
7919
- downstreamChannel.send("configure", {
7920
- clipId: this.clipId,
7921
- streamType: "video",
7922
- codec: videoTrackInfo.codec,
7923
- width: videoTrackInfo.width,
7924
- height: videoTrackInfo.height,
7925
- description: videoTrackInfo.description
7926
- });
7927
- }
7928
- /**
7929
- * Get demuxer statistics
7930
- */
7931
- async handleGetStats() {
7932
- if (!this.demuxer) {
7933
- return { state: this.channel.state };
7934
- }
7935
- return {
7936
- tracksInfo: Array.from(this.demuxer.tracks.values()),
7937
- state: this.channel.state
7938
- };
7939
- }
7940
- /**
7941
- * Dispose worker and cleanup resources
7942
- */
7943
- async handleDispose() {
7944
- this.demuxer?.destroy();
7945
- this.demuxer = null;
7946
- this.clipId = null;
7947
- this.downstreamPort?.close();
7948
- this.downstreamPort = null;
7949
- this.channel.state = WorkerState.Disposed;
7950
- return { success: true };
7951
- }
7952
- }
7953
- const worker = new VideoDemuxWorker();
7954
- self.addEventListener("beforeunload", () => {
7955
- worker["handleDispose"]();
7956
- });
7957
- //# sourceMappingURL=video-demux.worker-D019I7GQ.js.map
7046
+ export {
7047
+ mp4box_all as m
7048
+ };
7049
+ //# sourceMappingURL=mp4box.all.js.map