@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,5 +0,0 @@
1
- const audioComposeWorkerUrl = "" + new URL("../../assets/audio-compose.worker-nGVvHD5Q.js", import.meta.url).href;
2
- export {
3
- audioComposeWorkerUrl as default
4
- };
5
- //# sourceMappingURL=audio-compose.worker2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"audio-compose.worker2.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,60 +0,0 @@
1
- /**
2
- * VideoComposeWorker - Visual composition in the pipeline
3
- * Receives decoded video frames and outputs composed frames
4
- *
5
- * Pipeline: DecodeWorker → VideoComposeWorker → EncodeWorker
6
- *
7
- * Features:
8
- * - Multi-layer composition with Canvas2D/WebGL
9
- * - Transition effects and filters
10
- * - Text and image overlay support
11
- * - Stream-based processing with configurable backpressure
12
- */
13
- export declare class VideoComposeWorker {
14
- private channel;
15
- private composer;
16
- private composeStream;
17
- private downstreamPorts;
18
- private upstreamPorts;
19
- private instructionRegistry;
20
- private pendingReplay;
21
- private streamState;
22
- constructor();
23
- private setupHandlers;
24
- /**
25
- * Unified connect handler used by stream pipeline
26
- */
27
- private handleConnect;
28
- /**
29
- * Configure composer
30
- * According to docs/impl/14-config, only reinitialize when initial=true
31
- */
32
- private handleConfigure;
33
- private handleReceiveStream;
34
- /**
35
- * Flush the composition pipeline
36
- */
37
- private handleFlush;
38
- /**
39
- * Get composer statistics
40
- */
41
- private handleGetStats;
42
- /**
43
- * Dispose worker and cleanup resources
44
- */
45
- private handleDispose;
46
- private handleInstallInstructions;
47
- private handleSyncClip;
48
- private handleDisposeClip;
49
- /**
50
- * Check if frame should be skipped (outside dirty range)
51
- * Returns true if frame is NOT in the dirty range and should use cached version
52
- */
53
- private shouldSkipFrame;
54
- private buildComposeRequest;
55
- private static buildTransition;
56
- private computeTimelineTimestamp;
57
- }
58
- declare const _default: null;
59
- export default _default;
60
- //# sourceMappingURL=video-compose.worker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video-compose.worker.d.ts","sourceRoot":"","sources":["../../../src/stages/compose/video-compose.worker.ts"],"names":[],"mappings":"AAmFA;;;;;;;;;;;GAWG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,aAAa,CAA4D;IAEjF,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,mBAAmB,CAAyC;IACpE,OAAO,CAAC,aAAa,CAA2E;IAChG,OAAO,CAAC,WAAW,CAAkC;;IAYrD,OAAO,CAAC,aAAa;IAarB;;OAEG;YACW,aAAa;IAqB3B;;;OAGG;YACW,eAAe;YAiDf,mBAAmB;IA0EjC;;OAEG;YACW,WAAW;IAezB;;OAEG;YACW,cAAc;IAY5B;;OAEG;YACW,aAAa;YAoBb,yBAAyB;YAWzB,cAAc;YAgBd,iBAAiB;IAW/B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,MAAM,CAAC,eAAe;IAuB9B,OAAO,CAAC,wBAAwB;CA+EjC;;AAgBD,wBAAoB"}
@@ -1,379 +0,0 @@
1
- import { WorkerChannel } from "../../worker/WorkerChannel.js";
2
- import { WorkerMessageType, WorkerState } from "../../worker/types.js";
3
- import { VideoComposer } from "./VideoComposer.js";
4
- import { frameIndexFromTimestamp, quantizeTimestampToFrame, frameDurationFromFps } from "../../utils/time-utils.js";
5
- function resolveActiveLayers(layers, timestamp, _frame) {
6
- return layers.filter((layer) => {
7
- if (layer.status !== "ready") {
8
- return false;
9
- }
10
- return layer.activeRanges.some(
11
- (range) => timestamp >= range.startUs && timestamp < range.endUs
12
- );
13
- });
14
- }
15
- function materializeLayer(layer, frame) {
16
- const baseLayer = {
17
- id: layer.layerId,
18
- type: layer.type,
19
- zIndex: layer.zIndex ?? 0,
20
- visible: true,
21
- opacity: layer.opacity ?? 1
22
- };
23
- if (layer.type === "video") {
24
- return {
25
- ...baseLayer,
26
- type: "video",
27
- videoFrame: frame
28
- };
29
- }
30
- if (layer.type === "text") {
31
- const payload = layer.payload;
32
- return {
33
- ...baseLayer,
34
- type: "text",
35
- text: payload.text,
36
- fontFamily: payload.fontFamily,
37
- fontSize: payload.fontSize,
38
- fontWeight: payload.fontWeight,
39
- color: payload.color,
40
- strokeColor: payload.strokeColor,
41
- strokeWidth: payload.strokeWidth,
42
- lineHeight: payload.lineHeight,
43
- textAlign: payload.align,
44
- verticalAlign: "bottom"
45
- // Subtitles positioned at bottom
46
- };
47
- }
48
- if (layer.type === "image") {
49
- const payload = layer.payload;
50
- const source = payload.bitmapHandle ?? null;
51
- if (source) {
52
- return {
53
- ...baseLayer,
54
- type: "image",
55
- source
56
- };
57
- }
58
- }
59
- return baseLayer;
60
- }
61
- class VideoComposeWorker {
62
- channel;
63
- composer = null;
64
- composeStream = null;
65
- downstreamPorts = /* @__PURE__ */ new Map();
66
- upstreamPorts = /* @__PURE__ */ new Map();
67
- instructionRegistry = /* @__PURE__ */ new Map();
68
- pendingReplay = /* @__PURE__ */ new Map();
69
- streamState = /* @__PURE__ */ new Map();
70
- constructor() {
71
- this.channel = new WorkerChannel(self, {
72
- name: "VideoComposeWorker",
73
- timeout: 3e4
74
- });
75
- this.setupHandlers();
76
- }
77
- setupHandlers() {
78
- this.channel.registerHandler("configure", this.handleConfigure.bind(this));
79
- this.channel.registerHandler("connect", this.handleConnect.bind(this));
80
- this.channel.registerHandler("flush", this.handleFlush.bind(this));
81
- this.channel.registerHandler("get_stats", this.handleGetStats.bind(this));
82
- this.channel.registerHandler("install_instructions", this.handleInstallInstructions.bind(this));
83
- this.channel.registerHandler("sync_clip", this.handleSyncClip.bind(this));
84
- this.channel.registerHandler("dispose_clip", this.handleDisposeClip.bind(this));
85
- this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));
86
- }
87
- /**
88
- * Unified connect handler used by stream pipeline
89
- */
90
- async handleConnect(payload) {
91
- const { port, direction, clipId = "default" } = payload;
92
- if (direction === "upstream") {
93
- this.upstreamPorts.set(clipId, port);
94
- const channel = new WorkerChannel(port, {
95
- name: "VideoCompose-Decode",
96
- timeout: 3e4
97
- });
98
- channel.receiveStream(this.handleReceiveStream.bind(this));
99
- }
100
- if (direction === "downstream") {
101
- this.downstreamPorts.set(clipId, port);
102
- }
103
- return { success: true };
104
- }
105
- /**
106
- * Configure composer
107
- * According to docs/impl/14-config, only reinitialize when initial=true
108
- */
109
- async handleConfigure(payload) {
110
- const { config, initial } = payload;
111
- const hasValidDimensions = config.width > 0 && config.height > 0;
112
- const hasValidFps = config.fps > 0;
113
- if (!hasValidDimensions || !hasValidFps) {
114
- throw new Error(
115
- `VideoComposeWorker: invalid canvas config width=${config.width}, height=${config.height}, fps=${config.fps}`
116
- );
117
- }
118
- if (initial) {
119
- this.channel.state = WorkerState.Ready;
120
- }
121
- if (initial || !this.composer) {
122
- if (this.composer) {
123
- this.composer.dispose();
124
- this.composeStream = null;
125
- }
126
- this.composer = new VideoComposer(config);
127
- } else {
128
- this.composer.updateConfig(config);
129
- }
130
- this.channel.notify("configured", {
131
- config: this.composer.config,
132
- initialized: initial || false
133
- });
134
- return {
135
- success: true,
136
- config: this.composer.config
137
- };
138
- }
139
- async handleReceiveStream(stream, metadata) {
140
- const { clipId = "default" } = metadata || {};
141
- if (!this.composer) {
142
- console.error("[VideoComposeWorker] Composer not configured");
143
- return;
144
- }
145
- const instruction = this.instructionRegistry.get(clipId);
146
- if (!instruction) {
147
- console.warn("[VideoComposeWorker] No instructions for clip", clipId);
148
- return;
149
- }
150
- const filteredStream = stream.pipeThrough(
151
- new TransformStream({
152
- transform: (wrappedFrame, controller) => {
153
- try {
154
- const frame = wrappedFrame.frame || wrappedFrame;
155
- const gopSerial = wrappedFrame.gopSerial;
156
- const isKeyframe = wrappedFrame.isKeyframe;
157
- const timestamp = frame.timestamp ?? 0;
158
- if (this.shouldSkipFrame(clipId, timestamp)) {
159
- frame.close();
160
- return;
161
- }
162
- const request = this.buildComposeRequest(clipId, instruction, frame, timestamp);
163
- if (!request) {
164
- frame.close();
165
- return;
166
- }
167
- request.gopSerial = gopSerial;
168
- request.isKeyframe = isKeyframe;
169
- controller.enqueue(request);
170
- } catch (error) {
171
- const frame = wrappedFrame.frame || wrappedFrame;
172
- frame?.close?.();
173
- throw error;
174
- }
175
- }
176
- })
177
- );
178
- const { composeStream, cacheStream } = this.composer.createStreams();
179
- this.channel.sendStream(cacheStream, metadata);
180
- filteredStream.pipeTo(composeStream).catch((error) => {
181
- console.error("[VideoComposeWorker] compose stream error", clipId, error);
182
- });
183
- }
184
- // private handleGetStream(): ReadableStream<VideoFrame> | undefined {
185
- // return this.composer?.createStreams()?.cacheStream;
186
- // }
187
- /**
188
- * Flush the composition pipeline
189
- */
190
- async handleFlush() {
191
- try {
192
- this.channel.notify("flush_complete", {});
193
- return { success: true };
194
- } catch (error) {
195
- throw {
196
- code: "FLUSH_ERROR",
197
- message: error.message
198
- };
199
- }
200
- }
201
- /**
202
- * Get composer statistics
203
- */
204
- async handleGetStats() {
205
- return {
206
- configured: this.composer !== null,
207
- config: this.composer?.config,
208
- streaming: this.composeStream !== null
209
- };
210
- }
211
- /**
212
- * Dispose worker and cleanup resources
213
- */
214
- async handleDispose() {
215
- if (this.composer) {
216
- this.composer.dispose();
217
- this.composer = null;
218
- }
219
- this.composeStream = null;
220
- this.downstreamPorts.get("default")?.close();
221
- this.upstreamPorts.get("default")?.close();
222
- this.downstreamPorts.clear();
223
- this.upstreamPorts.clear();
224
- this.channel.state = WorkerState.Disposed;
225
- return { success: true };
226
- }
227
- async handleInstallInstructions(data) {
228
- const { clipId, revision } = data;
229
- const current = this.instructionRegistry.get(clipId);
230
- if (current && current.revision > revision) {
231
- return { success: false };
232
- }
233
- this.instructionRegistry.set(clipId, data);
234
- return { success: true };
235
- }
236
- async handleSyncClip(payload) {
237
- const { clipId, revision, range } = payload;
238
- const current = this.instructionRegistry.get(clipId);
239
- if (!current || current.revision > revision) {
240
- return { success: false };
241
- }
242
- this.pendingReplay.set(clipId, { ...range, revision });
243
- this.channel.notify("sync_ack", { clipId, revision });
244
- return { success: true };
245
- }
246
- async handleDisposeClip(payload) {
247
- const { clipId } = payload;
248
- this.instructionRegistry.delete(clipId);
249
- this.pendingReplay.delete(clipId);
250
- this.downstreamPorts.get(clipId)?.close();
251
- this.upstreamPorts.get(clipId)?.close();
252
- this.downstreamPorts.delete(clipId);
253
- this.upstreamPorts.delete(clipId);
254
- return { success: true };
255
- }
256
- /**
257
- * Check if frame should be skipped (outside dirty range)
258
- * Returns true if frame is NOT in the dirty range and should use cached version
259
- */
260
- shouldSkipFrame(clipId, timestamp) {
261
- const dirtyRange = this.pendingReplay.get(clipId);
262
- if (!dirtyRange) {
263
- return false;
264
- }
265
- if (timestamp >= dirtyRange.startUs && timestamp <= dirtyRange.endUs) {
266
- return false;
267
- }
268
- if (timestamp > dirtyRange.endUs) {
269
- this.pendingReplay.delete(clipId);
270
- }
271
- return true;
272
- }
273
- buildComposeRequest(clipId, instruction, frame, _timestamp) {
274
- const normalizedTime = this.computeTimelineTimestamp(clipId, frame, instruction.baseConfig);
275
- const clipStartUs = instruction.baseConfig.timeline?.clipStartUs ?? 0;
276
- const clipDurationUs = instruction.baseConfig.timeline?.clipDurationUs ?? Infinity;
277
- const clipEndUs = clipStartUs + clipDurationUs;
278
- if (normalizedTime < clipStartUs || normalizedTime >= clipEndUs) {
279
- return null;
280
- }
281
- const clipRelativeTime = normalizedTime - clipStartUs;
282
- const activeLayers = resolveActiveLayers(instruction.layers, clipRelativeTime);
283
- if (!activeLayers.length) {
284
- return null;
285
- }
286
- const layers = activeLayers.map((layer) => materializeLayer(layer, frame));
287
- return {
288
- timeUs: normalizedTime,
289
- layers,
290
- transition: VideoComposeWorker.buildTransition(
291
- instruction.transitions,
292
- clipRelativeTime,
293
- instruction.baseConfig.timeline
294
- )
295
- };
296
- }
297
- static buildTransition(transitions, timeUs, _timeline) {
298
- const entry = transitions.find((transition) => {
299
- const { startUs, endUs } = transition.range;
300
- return timeUs >= startUs && timeUs < endUs;
301
- });
302
- if (!entry) {
303
- return void 0;
304
- }
305
- const durationUs = entry.range.endUs - entry.range.startUs;
306
- const progress = durationUs > 0 ? (timeUs - entry.range.startUs) / durationUs : 0;
307
- return {
308
- type: entry.params.type,
309
- progress: Math.min(Math.max(progress, 0), 1),
310
- easing: entry.params.easing,
311
- params: entry.params.payload,
312
- direction: entry.params.payload?.direction
313
- };
314
- }
315
- computeTimelineTimestamp(clipId, frame, config) {
316
- const key = clipId;
317
- let state = this.streamState.get(key);
318
- if (!state) {
319
- state = {
320
- baseTimestamp: null,
321
- lastSourceTimestamp: null,
322
- nextFrameIndex: 0
323
- };
324
- this.streamState.set(key, state);
325
- }
326
- const timeline = config.timeline;
327
- if (!timeline) {
328
- const ts = frame.timestamp ?? 0;
329
- state.lastSourceTimestamp = frame.timestamp ?? null;
330
- return ts;
331
- }
332
- const { clipStartUs, compositionFps } = timeline;
333
- const sourceTimestamp = frame.timestamp ?? null;
334
- if (sourceTimestamp !== null && state.lastSourceTimestamp !== null && sourceTimestamp < state.lastSourceTimestamp) {
335
- state.baseTimestamp = null;
336
- state.nextFrameIndex = 0;
337
- }
338
- if (state.baseTimestamp === null) {
339
- state.baseTimestamp = sourceTimestamp ?? 0;
340
- state.nextFrameIndex = 0;
341
- if (state.baseTimestamp > 1e3) {
342
- console.warn(
343
- `[VideoComposeWorker] First frame timestamp is ${state.baseTimestamp}us, expected ~0. Check MP4Demuxer normalization.`
344
- );
345
- }
346
- }
347
- const frameDuration = frameDurationFromFps(compositionFps);
348
- let frameIndex = state.nextFrameIndex;
349
- if (sourceTimestamp !== null) {
350
- const approxIndex = frameIndexFromTimestamp(
351
- state.baseTimestamp,
352
- sourceTimestamp,
353
- compositionFps,
354
- "nearest"
355
- );
356
- frameIndex = Math.max(frameIndex, approxIndex);
357
- }
358
- const rawTimeline = clipStartUs + frameIndex * frameDuration;
359
- const timelineTime = quantizeTimestampToFrame(
360
- rawTimeline,
361
- clipStartUs,
362
- compositionFps,
363
- "nearest"
364
- );
365
- state.nextFrameIndex = frameIndex + 1;
366
- state.lastSourceTimestamp = sourceTimestamp;
367
- return timelineTime;
368
- }
369
- }
370
- const worker = new VideoComposeWorker();
371
- self.addEventListener("beforeunload", () => {
372
- worker["handleDispose"]();
373
- });
374
- const videoCompose_worker = null;
375
- export {
376
- VideoComposeWorker,
377
- videoCompose_worker as default
378
- };
379
- //# sourceMappingURL=video-compose.worker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video-compose.worker.js","sources":["../../../src/stages/compose/video-compose.worker.ts"],"sourcesContent":["import { WorkerChannel } from '../../worker/WorkerChannel';\nimport { WorkerMessageType, WorkerState } from '../../worker/types';\nimport { VideoComposer } from './VideoComposer';\nimport type { VideoComposeConfig, ComposeRequest, Layer } from './types';\nimport type {\n ClipInstructionSet,\n SerializedLayerPlan,\n SerializedTransitionPlan,\n SerializedImageLayerPayload,\n SerializedTextLayerPayload,\n} from './instructions';\nimport {\n frameDurationFromFps,\n frameIndexFromTimestamp,\n quantizeTimestampToFrame,\n} from '../../utils/time-utils';\nimport type { TimeUs } from '../../model/types';\n\nfunction resolveActiveLayers(\n layers: SerializedLayerPlan[],\n timestamp: number,\n _frame: VideoFrame\n): SerializedLayerPlan[] {\n return layers.filter((layer) => {\n if (layer.status !== 'ready') {\n return false;\n }\n return layer.activeRanges.some(\n (range) => timestamp >= range.startUs && timestamp < range.endUs\n );\n });\n}\n\nfunction materializeLayer(layer: SerializedLayerPlan, frame: VideoFrame): Layer {\n const baseLayer: Layer = {\n id: layer.layerId,\n type: layer.type as any,\n zIndex: layer.zIndex ?? 0,\n visible: true,\n opacity: layer.opacity ?? 1,\n };\n\n if (layer.type === 'video') {\n return {\n ...baseLayer,\n type: 'video',\n videoFrame: frame,\n } as Layer;\n }\n\n if (layer.type === 'text') {\n const payload = layer.payload as SerializedTextLayerPayload;\n return {\n ...baseLayer,\n type: 'text',\n text: payload.text,\n fontFamily: payload.fontFamily,\n fontSize: payload.fontSize,\n fontWeight: payload.fontWeight,\n color: payload.color,\n strokeColor: payload.strokeColor,\n strokeWidth: payload.strokeWidth,\n lineHeight: payload.lineHeight,\n textAlign: payload.align,\n verticalAlign: 'bottom', // Subtitles positioned at bottom\n } as Layer;\n }\n\n if (layer.type === 'image') {\n const payload = layer.payload as SerializedImageLayerPayload;\n const source = payload.bitmapHandle ?? null;\n if (source) {\n return {\n ...baseLayer,\n type: 'image',\n source,\n } as Layer;\n }\n }\n\n return baseLayer;\n}\n\n/**\n * VideoComposeWorker - Visual composition in the pipeline\n * Receives decoded video frames and outputs composed frames\n *\n * Pipeline: DecodeWorker → VideoComposeWorker → EncodeWorker\n *\n * Features:\n * - Multi-layer composition with Canvas2D/WebGL\n * - Transition effects and filters\n * - Text and image overlay support\n * - Stream-based processing with configurable backpressure\n */\nexport class VideoComposeWorker {\n private channel: WorkerChannel;\n private composer: VideoComposer | null = null;\n private composeStream: TransformStream<ComposeRequest, VideoFrame> | null = null;\n\n private downstreamPorts = new Map<string, MessagePort>();\n private upstreamPorts = new Map<string, MessagePort>();\n private instructionRegistry = new Map<string, ClipInstructionSet>();\n private pendingReplay = new Map<string, { startUs: number; endUs: number; revision: number }>();\n private streamState = new Map<string, StreamState>();\n\n constructor() {\n // Initialize WorkerChannel\n this.channel = new WorkerChannel(self as any, {\n name: 'VideoComposeWorker',\n timeout: 30000,\n });\n\n this.setupHandlers();\n }\n\n private setupHandlers(): void {\n // Register message handlers\n this.channel.registerHandler('configure', this.handleConfigure.bind(this));\n this.channel.registerHandler('connect' as any, this.handleConnect.bind(this));\n this.channel.registerHandler('flush', this.handleFlush.bind(this));\n // this.channel.registerHandler('get_stream', this.handleGetStream.bind(this));\n this.channel.registerHandler('get_stats', this.handleGetStats.bind(this));\n this.channel.registerHandler('install_instructions', this.handleInstallInstructions.bind(this));\n this.channel.registerHandler('sync_clip', this.handleSyncClip.bind(this));\n this.channel.registerHandler('dispose_clip', this.handleDisposeClip.bind(this));\n this.channel.registerHandler(WorkerMessageType.Dispose, this.handleDispose.bind(this));\n }\n\n /**\n * Unified connect handler used by stream pipeline\n */\n private async handleConnect(payload: {\n direction: 'upstream' | 'downstream';\n port: MessagePort;\n streamType: 'video' | 'audio' | 'frame' | 'chunk';\n clipId?: string;\n }): Promise<{ success: boolean }> {\n const { port, direction, clipId = 'default' } = payload;\n if (direction === 'upstream') {\n this.upstreamPorts.set(clipId, port);\n const channel = new WorkerChannel(port, {\n name: 'VideoCompose-Decode',\n timeout: 30000,\n });\n channel.receiveStream(this.handleReceiveStream.bind(this));\n }\n if (direction === 'downstream') {\n this.downstreamPorts.set(clipId, port);\n }\n return { success: true };\n }\n\n /**\n * Configure composer\n * According to docs/impl/14-config, only reinitialize when initial=true\n */\n private async handleConfigure(payload: {\n config: VideoComposeConfig;\n initial?: boolean;\n }): Promise<{\n success: boolean;\n config: VideoComposeConfig;\n }> {\n const { config, initial } = payload;\n\n const hasValidDimensions = config.width > 0 && config.height > 0;\n const hasValidFps = config.fps > 0;\n\n if (!hasValidDimensions || !hasValidFps) {\n throw new Error(\n `VideoComposeWorker: invalid canvas config width=${config.width}, height=${config.height}, fps=${config.fps}`\n );\n }\n\n // Set worker state to ready on initial configuration\n if (initial) {\n this.channel.state = WorkerState.Ready;\n }\n\n if (initial || !this.composer) {\n // Initial configuration or composer doesn't exist\n if (this.composer) {\n this.composer.dispose();\n this.composeStream = null;\n }\n\n // Create new composer\n this.composer = new VideoComposer(config);\n } else {\n // Just update configuration\n this.composer.updateConfig(config);\n }\n\n // Notify configuration complete\n this.channel.notify('configured', {\n config: this.composer.config,\n initialized: initial || false,\n });\n\n return {\n success: true,\n config: this.composer.config,\n };\n }\n\n private async handleReceiveStream(\n stream: ReadableStream,\n metadata?: Record<string, any>\n ): Promise<void> {\n const { clipId = 'default' } = metadata || {};\n\n if (!this.composer) {\n console.error('[VideoComposeWorker] Composer not configured');\n return;\n }\n\n const instruction = this.instructionRegistry.get(clipId);\n if (!instruction) {\n console.warn('[VideoComposeWorker] No instructions for clip', clipId);\n return;\n }\n\n // TODO: ENCODE\n // const downstreamPort = this.downstreamPorts.get(clipId);\n // if (downstreamPort) {\n // const channel = new WorkerChannel(downstreamPort, {\n // name: 'VideoCompose-Encoder',\n // timeout: 30000,\n // });\n // channel.sendStream(encodeStream, {\n // streamType: 'video',\n // ...metadata,\n // });\n // }\n\n const filteredStream = stream.pipeThrough(\n new TransformStream<any, ComposeRequest>({\n transform: (wrappedFrame, controller) => {\n try {\n // Extract frame and metadata from wrapped object\n const frame = wrappedFrame.frame || wrappedFrame;\n const gopSerial = wrappedFrame.gopSerial;\n const isKeyframe = wrappedFrame.isKeyframe;\n\n const timestamp = frame.timestamp ?? 0;\n if (this.shouldSkipFrame(clipId, timestamp)) {\n frame.close();\n return;\n }\n\n const request = this.buildComposeRequest(clipId, instruction, frame, timestamp);\n if (!request) {\n frame.close();\n return;\n }\n (request as any).gopSerial = gopSerial;\n (request as any).isKeyframe = isKeyframe;\n controller.enqueue(request);\n } catch (error) {\n const frame = wrappedFrame.frame || wrappedFrame;\n frame?.close?.();\n throw error;\n }\n },\n })\n );\n\n const { composeStream, cacheStream } = this.composer.createStreams();\n this.channel.sendStream(cacheStream, metadata);\n\n filteredStream.pipeTo(composeStream).catch((error) => {\n console.error('[VideoComposeWorker] compose stream error', clipId, error);\n });\n }\n\n // private handleGetStream(): ReadableStream<VideoFrame> | undefined {\n // return this.composer?.createStreams()?.cacheStream;\n // }\n\n /**\n * Flush the composition pipeline\n */\n private async handleFlush(): Promise<{ success: boolean }> {\n try {\n // Flush any pending frames in the stream\n // The stream will handle this automatically\n\n this.channel.notify('flush_complete', {});\n return { success: true };\n } catch (error: any) {\n throw {\n code: 'FLUSH_ERROR',\n message: error.message,\n };\n }\n }\n\n /**\n * Get composer statistics\n */\n private async handleGetStats(): Promise<{\n configured: boolean;\n config?: VideoComposeConfig;\n streaming: boolean;\n }> {\n return {\n configured: this.composer !== null,\n config: this.composer?.config,\n streaming: this.composeStream !== null,\n };\n }\n\n /**\n * Dispose worker and cleanup resources\n */\n private async handleDispose(): Promise<{ success: boolean }> {\n // Dispose composer\n if (this.composer) {\n this.composer.dispose();\n this.composer = null;\n }\n\n this.composeStream = null;\n\n // Close connections\n this.downstreamPorts.get('default')?.close();\n this.upstreamPorts.get('default')?.close();\n this.downstreamPorts.clear();\n this.upstreamPorts.clear();\n\n this.channel.state = WorkerState.Disposed;\n\n return { success: true };\n }\n\n private async handleInstallInstructions(data: ClipInstructionSet): Promise<{ success: boolean }> {\n const { clipId, revision } = data;\n const current = this.instructionRegistry.get(clipId);\n if (current && current.revision > revision) {\n return { success: false };\n }\n\n this.instructionRegistry.set(clipId, data);\n return { success: true };\n }\n\n private async handleSyncClip(payload: {\n clipId: string;\n revision: number;\n range: { startUs: number; endUs: number };\n }): Promise<{ success: boolean }> {\n const { clipId, revision, range } = payload;\n const current = this.instructionRegistry.get(clipId);\n if (!current || current.revision > revision) {\n return { success: false };\n }\n\n this.pendingReplay.set(clipId, { ...range, revision });\n this.channel.notify('sync_ack', { clipId, revision });\n return { success: true };\n }\n\n private async handleDisposeClip(payload: { clipId: string }): Promise<{ success: boolean }> {\n const { clipId } = payload;\n this.instructionRegistry.delete(clipId);\n this.pendingReplay.delete(clipId);\n this.downstreamPorts.get(clipId)?.close();\n this.upstreamPorts.get(clipId)?.close();\n this.downstreamPorts.delete(clipId);\n this.upstreamPorts.delete(clipId);\n return { success: true };\n }\n\n /**\n * Check if frame should be skipped (outside dirty range)\n * Returns true if frame is NOT in the dirty range and should use cached version\n */\n private shouldSkipFrame(clipId: string, timestamp: number): boolean {\n const dirtyRange = this.pendingReplay.get(clipId);\n if (!dirtyRange) {\n return false; // No dirty range, don't skip (first render or no updates)\n }\n\n // Frame is within dirty range → don't skip, re-compose\n if (timestamp >= dirtyRange.startUs && timestamp <= dirtyRange.endUs) {\n return false;\n }\n\n // Passed dirty range end → clean up\n if (timestamp > dirtyRange.endUs) {\n this.pendingReplay.delete(clipId);\n }\n\n // Frame outside dirty range → skip, use cache\n return true;\n }\n\n private buildComposeRequest(\n clipId: string,\n instruction: ClipInstructionSet,\n frame: VideoFrame,\n _timestamp: number\n ): ComposeRequest | null {\n const normalizedTime = this.computeTimelineTimestamp(clipId, frame, instruction.baseConfig);\n const clipStartUs = instruction.baseConfig.timeline?.clipStartUs ?? 0;\n const clipDurationUs = instruction.baseConfig.timeline?.clipDurationUs ?? Infinity;\n const clipEndUs = clipStartUs + clipDurationUs;\n\n // Check if frame is within clip boundary\n if (normalizedTime < clipStartUs || normalizedTime >= clipEndUs) {\n return null;\n }\n\n const clipRelativeTime = normalizedTime - clipStartUs;\n const activeLayers = resolveActiveLayers(instruction.layers, clipRelativeTime, frame);\n\n if (!activeLayers.length) {\n return null;\n }\n const layers = activeLayers.map((layer) => materializeLayer(layer, frame));\n return {\n timeUs: normalizedTime,\n layers,\n transition: VideoComposeWorker.buildTransition(\n instruction.transitions,\n clipRelativeTime,\n instruction.baseConfig.timeline\n ),\n };\n }\n\n private static buildTransition(\n transitions: SerializedTransitionPlan[],\n timeUs: TimeUs,\n _timeline?: VideoComposeConfig['timeline']\n ) {\n const entry = transitions.find((transition) => {\n const { startUs, endUs } = transition.range;\n return timeUs >= startUs && timeUs < endUs;\n });\n if (!entry) {\n return undefined;\n }\n const durationUs = entry.range.endUs - entry.range.startUs;\n const progress = durationUs > 0 ? (timeUs - entry.range.startUs) / durationUs : 0;\n return {\n type: entry.params.type,\n progress: Math.min(Math.max(progress, 0), 1),\n easing: entry.params.easing,\n params: entry.params.payload,\n direction: entry.params.payload?.direction,\n } as any;\n }\n\n private computeTimelineTimestamp(\n clipId: string,\n frame: VideoFrame,\n config: VideoComposeConfig\n ): TimeUs {\n const key = clipId;\n let state = this.streamState.get(key);\n if (!state) {\n state = {\n baseTimestamp: null,\n lastSourceTimestamp: null,\n nextFrameIndex: 0,\n };\n this.streamState.set(key, state);\n }\n\n const timeline = config.timeline;\n if (!timeline) {\n const ts = frame.timestamp ?? 0;\n state.lastSourceTimestamp = frame.timestamp ?? null;\n return ts;\n }\n\n const { clipStartUs, compositionFps } = timeline;\n const sourceTimestamp = frame.timestamp ?? null;\n\n // Detect stream reset (e.g., after seek)\n if (\n sourceTimestamp !== null &&\n state.lastSourceTimestamp !== null &&\n sourceTimestamp < state.lastSourceTimestamp\n ) {\n state.baseTimestamp = null;\n state.nextFrameIndex = 0;\n }\n\n // Initialize base timestamp (should be 0 or close to 0 after demuxer normalization)\n if (state.baseTimestamp === null) {\n state.baseTimestamp = sourceTimestamp ?? 0;\n state.nextFrameIndex = 0;\n\n // Warn if base is not near zero (indicates demuxer normalization issue)\n if (state.baseTimestamp > 1000) {\n console.warn(\n `[VideoComposeWorker] First frame timestamp is ${state.baseTimestamp}us, expected ~0. ` +\n `Check MP4Demuxer normalization.`\n );\n }\n }\n\n // Since demuxer normalizes to 0, we can directly calculate frame index\n const frameDuration = frameDurationFromFps(compositionFps);\n let frameIndex = state.nextFrameIndex;\n\n if (sourceTimestamp !== null) {\n // Calculate frame index from normalized timestamp\n const approxIndex = frameIndexFromTimestamp(\n state.baseTimestamp,\n sourceTimestamp,\n compositionFps,\n 'nearest'\n );\n frameIndex = Math.max(frameIndex, approxIndex);\n }\n\n // Map to timeline position\n const rawTimeline = clipStartUs + frameIndex * frameDuration;\n const timelineTime = quantizeTimestampToFrame(\n rawTimeline,\n clipStartUs,\n compositionFps,\n 'nearest'\n );\n\n state.nextFrameIndex = frameIndex + 1;\n state.lastSourceTimestamp = sourceTimestamp;\n\n return timelineTime;\n }\n}\n\ninterface StreamState {\n baseTimestamp: number | null;\n lastSourceTimestamp: number | null;\n nextFrameIndex: number;\n}\n\n// Initialize worker\nconst worker = new VideoComposeWorker();\n\n// Handle worker termination\nself.addEventListener('beforeunload', () => {\n worker['handleDispose']();\n});\n\nexport default null; // Required for TypeScript worker compilation\n"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- const videoComposeWorkerUrl = "" + new URL("../../assets/video-compose.worker-DPzsC21d.js", import.meta.url).href;
2
- export {
3
- videoComposeWorkerUrl as default
4
- };
5
- //# sourceMappingURL=video-compose.worker2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video-compose.worker2.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,82 +0,0 @@
1
- import { BaseDecoder } from "./BaseDecoder.js";
2
- class AudioChunkDecoder extends BaseDecoder {
3
- // Default values
4
- static DEFAULT_HIGH_WATER_MARK = 20;
5
- static DEFAULT_DECODE_QUEUE_THRESHOLD = 16;
6
- // Exposed properties
7
- trackId;
8
- // Backpressure configuration
9
- highWaterMark;
10
- decodeQueueThreshold;
11
- constructor(trackId, config) {
12
- super(config);
13
- this.trackId = trackId;
14
- this.highWaterMark = config?.backpressure?.highWaterMark ?? AudioChunkDecoder.DEFAULT_HIGH_WATER_MARK;
15
- this.decodeQueueThreshold = AudioChunkDecoder.DEFAULT_DECODE_QUEUE_THRESHOLD;
16
- }
17
- // Computed properties
18
- get isConfigured() {
19
- return this.isReady;
20
- }
21
- get state() {
22
- return this.decoder?.state || "unconfigured";
23
- }
24
- /**
25
- * Update configuration - can be called before or after initialization
26
- */
27
- async updateConfig(config) {
28
- if (!this.isReady && config.codec) {
29
- await this.configure(config);
30
- await this.processBufferedChunks();
31
- return;
32
- }
33
- }
34
- // Implement abstract methods
35
- async isConfigSupported(config) {
36
- const result = await AudioDecoder.isConfigSupported({
37
- codec: config.codec,
38
- sampleRate: config.sampleRate,
39
- numberOfChannels: config.numberOfChannels
40
- });
41
- return { supported: result.supported ?? false };
42
- }
43
- createDecoder(init) {
44
- return new AudioDecoder(init);
45
- }
46
- getDecoderType() {
47
- return "Audio";
48
- }
49
- async configureDecoder(config) {
50
- if (!this.decoder) return;
51
- await this.decoder.configure({
52
- codec: config.codec,
53
- sampleRate: config.sampleRate,
54
- numberOfChannels: config.numberOfChannels,
55
- ...config.description && { description: config.description }
56
- });
57
- }
58
- decode(chunk) {
59
- this.decoder?.decode(chunk);
60
- }
61
- /**
62
- * Configure the decoder with codec info (can be called after creation)
63
- */
64
- async configure(config) {
65
- if (this.isReady) {
66
- await this.reconfigure(config);
67
- return;
68
- }
69
- this.config = config;
70
- await this.initialize();
71
- }
72
- /**
73
- * Process any buffered chunks after configuration
74
- * Note: Audio doesn't buffer in current implementation, but keeping for interface consistency
75
- */
76
- async processBufferedChunks() {
77
- }
78
- }
79
- export {
80
- AudioChunkDecoder
81
- };
82
- //# sourceMappingURL=AudioChunkDecoder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AudioChunkDecoder.js","sources":["../../../src/stages/decode/AudioChunkDecoder.ts"],"sourcesContent":["import { AudioDecoderConfig } from './types';\nimport { BaseDecoder } from './BaseDecoder';\n\n/**\n * Audio decoder with streaming support\n * Extends BaseDecoder for common WebCodecs operations\n */\nexport class AudioChunkDecoder extends BaseDecoder<\n AudioDecoder,\n AudioDecoderConfig,\n EncodedAudioChunk,\n AudioData\n> {\n // Default values\n private static readonly DEFAULT_HIGH_WATER_MARK = 20;\n private static readonly DEFAULT_DECODE_QUEUE_THRESHOLD = 16;\n\n // Exposed properties\n readonly trackId: string;\n\n // Backpressure configuration\n protected readonly highWaterMark: number;\n protected readonly decodeQueueThreshold: number;\n\n constructor(trackId: string, config?: Partial<AudioDecoderConfig>) {\n // Initialize with empty config, will be configured later\n super(config as AudioDecoderConfig);\n\n this.trackId = trackId;\n\n // Set backpressure configuration\n this.highWaterMark =\n config?.backpressure?.highWaterMark ?? AudioChunkDecoder.DEFAULT_HIGH_WATER_MARK;\n this.decodeQueueThreshold = AudioChunkDecoder.DEFAULT_DECODE_QUEUE_THRESHOLD;\n }\n\n // Computed properties\n get isConfigured(): boolean {\n return this.isReady;\n }\n\n get state(): string {\n return this.decoder?.state || 'unconfigured';\n }\n\n /**\n * Update configuration - can be called before or after initialization\n */\n async updateConfig(config: Partial<AudioDecoderConfig>): Promise<void> {\n // If decoder is not ready and we have codec info, configure it\n if (!this.isReady && config.codec) {\n await this.configure(config as AudioDecoderConfig);\n await this.processBufferedChunks();\n return;\n }\n\n // Note: AudioDecoder doesn't have many runtime-configurable options\n // Backpressure settings are readonly in this implementation\n // if (config.backpressure) {\n // console.warn('Backpressure settings cannot be changed at runtime');\n // }\n }\n\n // Implement abstract methods\n protected async isConfigSupported(config: AudioDecoderConfig): Promise<{ supported: boolean }> {\n const result = await AudioDecoder.isConfigSupported({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n });\n return { supported: result.supported ?? false };\n }\n\n protected createDecoder(init: {\n output: (data: AudioData) => void;\n error: (error: DOMException) => void;\n }): AudioDecoder {\n return new AudioDecoder(init);\n }\n\n protected getDecoderType(): string {\n return 'Audio';\n }\n\n protected async configureDecoder(config: AudioDecoderConfig): Promise<void> {\n if (!this.decoder) return;\n\n await this.decoder.configure({\n codec: config.codec,\n sampleRate: config.sampleRate,\n numberOfChannels: config.numberOfChannels,\n ...(config.description && { description: config.description }),\n });\n }\n\n protected decode(chunk: EncodedAudioChunk): void {\n this.decoder?.decode(chunk);\n }\n\n /**\n * Configure the decoder with codec info (can be called after creation)\n */\n async configure(config: AudioDecoderConfig): Promise<void> {\n if (this.isReady) {\n // If already configured, reconfigure\n await this.reconfigure(config);\n return;\n }\n\n this.config = config as any;\n\n // Initialize decoder with new config\n await this.initialize();\n }\n\n /**\n * Process any buffered chunks after configuration\n * Note: Audio doesn't buffer in current implementation, but keeping for interface consistency\n */\n async processBufferedChunks(): Promise<void> {\n // No-op for audio in current implementation\n }\n}\n"],"names":[],"mappings":";AAOO,MAAM,0BAA0B,YAKrC;AAAA;AAAA,EAEA,OAAwB,0BAA0B;AAAA,EAClD,OAAwB,iCAAiC;AAAA;AAAA,EAGhD;AAAA;AAAA,EAGU;AAAA,EACA;AAAA,EAEnB,YAAY,SAAiB,QAAsC;AAEjE,UAAM,MAA4B;AAElC,SAAK,UAAU;AAGf,SAAK,gBACH,QAAQ,cAAc,iBAAiB,kBAAkB;AAC3D,SAAK,uBAAuB,kBAAkB;AAAA,EAChD;AAAA;AAAA,EAGA,IAAI,eAAwB;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK,SAAS,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,QAAoD;AAErE,QAAI,CAAC,KAAK,WAAW,OAAO,OAAO;AACjC,YAAM,KAAK,UAAU,MAA4B;AACjD,YAAM,KAAK,sBAAA;AACX;AAAA,IACF;AAAA,EAOF;AAAA;AAAA,EAGA,MAAgB,kBAAkB,QAA6D;AAC7F,UAAM,SAAS,MAAM,aAAa,kBAAkB;AAAA,MAClD,OAAO,OAAO;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,kBAAkB,OAAO;AAAA,IAAA,CAC1B;AACD,WAAO,EAAE,WAAW,OAAO,aAAa,MAAA;AAAA,EAC1C;AAAA,EAEU,cAAc,MAGP;AACf,WAAO,IAAI,aAAa,IAAI;AAAA,EAC9B;AAAA,EAEU,iBAAyB;AACjC,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,iBAAiB,QAA2C;AAC1E,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,KAAK,QAAQ,UAAU;AAAA,MAC3B,OAAO,OAAO;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,kBAAkB,OAAO;AAAA,MACzB,GAAI,OAAO,eAAe,EAAE,aAAa,OAAO,YAAA;AAAA,IAAY,CAC7D;AAAA,EACH;AAAA,EAEU,OAAO,OAAgC;AAC/C,SAAK,SAAS,OAAO,KAAK;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,QAA2C;AACzD,QAAI,KAAK,SAAS;AAEhB,YAAM,KAAK,YAAY,MAAM;AAC7B;AAAA,IACF;AAEA,SAAK,SAAS;AAGd,UAAM,KAAK,WAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBAAuC;AAAA,EAE7C;AACF;"}