webcodecs-node 0.5.1 → 0.7.0

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 (144) hide show
  1. package/README.md +328 -169
  2. package/dist/backends/types.d.ts +2 -0
  3. package/dist/backends/types.d.ts.map +1 -1
  4. package/dist/backends/types.js.map +1 -1
  5. package/dist/canvas/canvas-utils.d.ts +115 -0
  6. package/dist/canvas/canvas-utils.d.ts.map +1 -0
  7. package/dist/canvas/canvas-utils.js +169 -0
  8. package/dist/canvas/canvas-utils.js.map +1 -0
  9. package/dist/canvas/frame-loop.d.ts +113 -0
  10. package/dist/canvas/frame-loop.d.ts.map +1 -0
  11. package/dist/canvas/frame-loop.js +291 -0
  12. package/dist/canvas/frame-loop.js.map +1 -0
  13. package/dist/canvas/gpu-context.d.ts +61 -0
  14. package/dist/canvas/gpu-context.d.ts.map +1 -0
  15. package/dist/canvas/gpu-context.js +134 -0
  16. package/dist/canvas/gpu-context.js.map +1 -0
  17. package/dist/canvas/index.d.ts +22 -0
  18. package/dist/canvas/index.d.ts.map +1 -0
  19. package/dist/canvas/index.js +25 -0
  20. package/dist/canvas/index.js.map +1 -0
  21. package/dist/canvas/types.d.ts +101 -0
  22. package/dist/canvas/types.d.ts.map +1 -0
  23. package/dist/canvas/types.js +7 -0
  24. package/dist/canvas/types.js.map +1 -0
  25. package/dist/codec-utils/formats.d.ts.map +1 -1
  26. package/dist/codec-utils/formats.js +31 -0
  27. package/dist/codec-utils/formats.js.map +1 -1
  28. package/dist/config/ffmpeg-quality.d.ts +14 -0
  29. package/dist/config/ffmpeg-quality.d.ts.map +1 -0
  30. package/dist/config/ffmpeg-quality.js +41 -0
  31. package/dist/config/ffmpeg-quality.js.map +1 -0
  32. package/dist/containers/Muxer.d.ts.map +1 -1
  33. package/dist/containers/Muxer.js +4 -1
  34. package/dist/containers/Muxer.js.map +1 -1
  35. package/dist/core/AudioData.d.ts +2 -1
  36. package/dist/core/AudioData.d.ts.map +1 -1
  37. package/dist/core/AudioData.js.map +1 -1
  38. package/dist/core/VideoFrame.d.ts +2 -2
  39. package/dist/core/VideoFrame.d.ts.map +1 -1
  40. package/dist/core/VideoFrame.js +49 -47
  41. package/dist/core/VideoFrame.js.map +1 -1
  42. package/dist/decoders/AudioDecoder.d.ts +1 -0
  43. package/dist/decoders/AudioDecoder.d.ts.map +1 -1
  44. package/dist/decoders/AudioDecoder.js +39 -17
  45. package/dist/decoders/AudioDecoder.js.map +1 -1
  46. package/dist/decoders/ImageDecoder.d.ts +1 -0
  47. package/dist/decoders/ImageDecoder.d.ts.map +1 -1
  48. package/dist/decoders/ImageDecoder.js +40 -3
  49. package/dist/decoders/ImageDecoder.js.map +1 -1
  50. package/dist/decoders/VideoDecoder.d.ts +12 -0
  51. package/dist/decoders/VideoDecoder.d.ts.map +1 -1
  52. package/dist/decoders/VideoDecoder.js +50 -8
  53. package/dist/decoders/VideoDecoder.js.map +1 -1
  54. package/dist/demos/demo-1080p-transcode.js +8 -2
  55. package/dist/demos/demo-1080p-transcode.js.map +1 -1
  56. package/dist/demos/demo-audio-visualizer.d.ts +11 -0
  57. package/dist/demos/demo-audio-visualizer.d.ts.map +1 -0
  58. package/dist/demos/demo-audio-visualizer.js +281 -0
  59. package/dist/demos/demo-audio-visualizer.js.map +1 -0
  60. package/dist/demos/demo-dvd-logo.d.ts +8 -0
  61. package/dist/demos/demo-dvd-logo.d.ts.map +1 -0
  62. package/dist/demos/demo-dvd-logo.js +196 -0
  63. package/dist/demos/demo-dvd-logo.js.map +1 -0
  64. package/dist/demos/demo-four-corners.js +9 -0
  65. package/dist/demos/demo-four-corners.js.map +1 -1
  66. package/dist/demos/demo-streaming.js +6 -0
  67. package/dist/demos/demo-streaming.js.map +1 -1
  68. package/dist/demos/demo-webcodecs.js +1 -0
  69. package/dist/demos/demo-webcodecs.js.map +1 -1
  70. package/dist/encoders/AudioEncoder.d.ts +3 -0
  71. package/dist/encoders/AudioEncoder.d.ts.map +1 -1
  72. package/dist/encoders/AudioEncoder.js +70 -28
  73. package/dist/encoders/AudioEncoder.js.map +1 -1
  74. package/dist/encoders/ImageEncoder.d.ts +80 -0
  75. package/dist/encoders/ImageEncoder.d.ts.map +1 -0
  76. package/dist/encoders/ImageEncoder.js +156 -0
  77. package/dist/encoders/ImageEncoder.js.map +1 -0
  78. package/dist/encoders/VideoEncoder.d.ts +11 -0
  79. package/dist/encoders/VideoEncoder.d.ts.map +1 -1
  80. package/dist/encoders/VideoEncoder.js +46 -4
  81. package/dist/encoders/VideoEncoder.js.map +1 -1
  82. package/dist/encoders/index.d.ts +1 -0
  83. package/dist/encoders/index.d.ts.map +1 -1
  84. package/dist/encoders/index.js +1 -0
  85. package/dist/encoders/index.js.map +1 -1
  86. package/dist/formats/color-space.d.ts +88 -0
  87. package/dist/formats/color-space.d.ts.map +1 -1
  88. package/dist/formats/color-space.js +55 -1
  89. package/dist/formats/color-space.js.map +1 -1
  90. package/dist/formats/pixel-formats.d.ts +17 -1
  91. package/dist/formats/pixel-formats.d.ts.map +1 -1
  92. package/dist/formats/pixel-formats.js +74 -4
  93. package/dist/formats/pixel-formats.js.map +1 -1
  94. package/dist/hardware/detection.d.ts.map +1 -1
  95. package/dist/hardware/detection.js +5 -2
  96. package/dist/hardware/detection.js.map +1 -1
  97. package/dist/hardware/encoder-args.d.ts.map +1 -1
  98. package/dist/hardware/encoder-args.js +6 -6
  99. package/dist/hardware/encoder-args.js.map +1 -1
  100. package/dist/index.d.ts +11 -3
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +8 -2
  103. package/dist/index.js.map +1 -1
  104. package/dist/node-av/NodeAvAudioDecoder.d.ts.map +1 -1
  105. package/dist/node-av/NodeAvAudioDecoder.js +3 -0
  106. package/dist/node-av/NodeAvAudioDecoder.js.map +1 -1
  107. package/dist/node-av/NodeAvAudioEncoder.d.ts +5 -0
  108. package/dist/node-av/NodeAvAudioEncoder.d.ts.map +1 -1
  109. package/dist/node-av/NodeAvAudioEncoder.js +102 -9
  110. package/dist/node-av/NodeAvAudioEncoder.js.map +1 -1
  111. package/dist/node-av/NodeAvVideoEncoder.d.ts +2 -0
  112. package/dist/node-av/NodeAvVideoEncoder.d.ts.map +1 -1
  113. package/dist/node-av/NodeAvVideoEncoder.js +44 -6
  114. package/dist/node-av/NodeAvVideoEncoder.js.map +1 -1
  115. package/dist/node-av/WebPImageDecoder.d.ts +54 -0
  116. package/dist/node-av/WebPImageDecoder.d.ts.map +1 -0
  117. package/dist/node-av/WebPImageDecoder.js +176 -0
  118. package/dist/node-av/WebPImageDecoder.js.map +1 -0
  119. package/dist/polyfills/OffscreenCanvas.d.ts +141 -7
  120. package/dist/polyfills/OffscreenCanvas.d.ts.map +1 -1
  121. package/dist/polyfills/OffscreenCanvas.js +217 -17
  122. package/dist/polyfills/OffscreenCanvas.js.map +1 -1
  123. package/dist/types/index.d.ts +1 -0
  124. package/dist/types/index.d.ts.map +1 -1
  125. package/dist/types/index.js +2 -0
  126. package/dist/types/index.js.map +1 -1
  127. package/dist/types/native-frame.d.ts +74 -0
  128. package/dist/types/native-frame.d.ts.map +1 -0
  129. package/dist/types/native-frame.js +32 -0
  130. package/dist/types/native-frame.js.map +1 -0
  131. package/dist/utils/index.d.ts +1 -1
  132. package/dist/utils/index.d.ts.map +1 -1
  133. package/dist/utils/index.js +1 -1
  134. package/dist/utils/index.js.map +1 -1
  135. package/dist/utils/type-guards.d.ts +29 -1
  136. package/dist/utils/type-guards.d.ts.map +1 -1
  137. package/dist/utils/type-guards.js +47 -2
  138. package/dist/utils/type-guards.js.map +1 -1
  139. package/docs/api.md +156 -1
  140. package/docs/configuration.md +30 -14
  141. package/examples/README.md +28 -1
  142. package/examples/canvas-encoding.ts +222 -0
  143. package/examples/offscreen-canvas.ts +230 -0
  144. package/package.json +10 -4
@@ -0,0 +1,291 @@
1
+ /**
2
+ * FrameLoop - High-performance frame generation with backpressure
3
+ *
4
+ * Manages frame generation with:
5
+ * - Backpressure via maxQueueSize (default: 8)
6
+ * - Automatic canvas reset before each frame
7
+ * - Proper VideoFrame lifecycle management
8
+ * - Async pipelining for optimal throughput
9
+ *
10
+ * Best practices implemented:
11
+ * 1. Memory lifecycle: Explicit frame closing with try...finally
12
+ * 2. Canvas state: ctx.reset() or clearRect at start of every frame
13
+ * 3. Color formats: RGBA output, even dimensions for YUV420
14
+ * 4. Pipeline optimization: Async pipelining with backpressure
15
+ * 5. Raw buffer export: Always uses toBuffer('raw')
16
+ */
17
+ import { VideoFrame } from '../core/VideoFrame.js';
18
+ import { createLogger } from '../utils/logger.js';
19
+ import { createCanvas, ensureEvenDimensions } from './gpu-context.js';
20
+ import { getRawPixels, resetCanvas, bufferToUint8Array } from './canvas-utils.js';
21
+ const logger = createLogger('FrameLoop');
22
+ const DEFAULT_MAX_QUEUE_SIZE = 8;
23
+ /**
24
+ * FrameLoop class for generating video frames with backpressure control
25
+ */
26
+ export class FrameLoop {
27
+ canvas;
28
+ ctx;
29
+ config;
30
+ state = 'idle';
31
+ frameIndex = 0;
32
+ queueSize = 0;
33
+ pendingFrames = [];
34
+ resolveWaitForDrain = null;
35
+ // Frame timing
36
+ startTime = 0;
37
+ frameDurationUs;
38
+ constructor(config) {
39
+ // Ensure even dimensions for YUV420 compatibility
40
+ const dims = ensureEvenDimensions(config.width, config.height);
41
+ this.config = {
42
+ width: dims.width,
43
+ height: dims.height,
44
+ frameRate: config.frameRate,
45
+ maxQueueSize: config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,
46
+ gpu: config.gpu ?? true,
47
+ onFrame: config.onFrame,
48
+ onComplete: config.onComplete ?? (() => { }),
49
+ onError: config.onError ?? (() => { }),
50
+ };
51
+ // Frame duration in microseconds
52
+ this.frameDurationUs = Math.round(1_000_000 / this.config.frameRate);
53
+ // Create GPU-accelerated canvas
54
+ this.canvas = createCanvas({
55
+ width: dims.width,
56
+ height: dims.height,
57
+ gpu: config.gpu,
58
+ });
59
+ this.ctx = this.canvas.getContext('2d');
60
+ // Log creation info (engine property may not be available until first render)
61
+ const engineInfo = this.canvas.engine;
62
+ logger.info(`FrameLoop created: ${dims.width}x${dims.height} @ ${config.frameRate}fps` +
63
+ (engineInfo ? `, GPU: ${engineInfo.renderer}` : ''));
64
+ }
65
+ /**
66
+ * Get current state
67
+ */
68
+ getState() {
69
+ return this.state;
70
+ }
71
+ /**
72
+ * Get current queue size
73
+ */
74
+ getQueueSize() {
75
+ return this.queueSize;
76
+ }
77
+ /**
78
+ * Get canvas width
79
+ */
80
+ getWidth() {
81
+ return this.config.width;
82
+ }
83
+ /**
84
+ * Get canvas height
85
+ */
86
+ getHeight() {
87
+ return this.config.height;
88
+ }
89
+ /**
90
+ * Get the underlying canvas for direct access
91
+ */
92
+ getCanvas() {
93
+ return this.canvas;
94
+ }
95
+ /**
96
+ * Get the 2D context for direct access
97
+ */
98
+ getContext() {
99
+ return this.ctx;
100
+ }
101
+ /**
102
+ * Start frame generation
103
+ *
104
+ * @param totalFrames - Total number of frames to generate (Infinity for continuous)
105
+ */
106
+ async start(totalFrames = Infinity) {
107
+ if (this.state === 'running') {
108
+ throw new Error('FrameLoop is already running');
109
+ }
110
+ this.state = 'running';
111
+ this.startTime = performance.now();
112
+ this.frameIndex = 0;
113
+ try {
114
+ while (this.state === 'running' && this.frameIndex < totalFrames) {
115
+ // Backpressure: wait if queue is full
116
+ if (this.queueSize >= this.config.maxQueueSize) {
117
+ logger.debug(`Backpressure: waiting (queue: ${this.queueSize})`);
118
+ await this.waitForDrain();
119
+ if (this.state !== 'running')
120
+ break;
121
+ }
122
+ // Generate frame
123
+ await this.generateFrame();
124
+ this.frameIndex++;
125
+ }
126
+ // Wait for all pending frames to be consumed
127
+ while (this.pendingFrames.length > 0 && this.getState() !== 'stopped') {
128
+ await this.waitForDrain();
129
+ }
130
+ if (this.getState() !== 'stopped') {
131
+ this.state = 'stopped';
132
+ this.config.onComplete();
133
+ }
134
+ }
135
+ catch (error) {
136
+ this.state = 'stopped';
137
+ const err = error instanceof Error ? error : new Error(String(error));
138
+ this.config.onError(err);
139
+ throw err;
140
+ }
141
+ }
142
+ /**
143
+ * Stop frame generation immediately
144
+ */
145
+ stop() {
146
+ this.state = 'stopped';
147
+ // Close any pending frames
148
+ for (const frame of this.pendingFrames) {
149
+ try {
150
+ frame.close();
151
+ }
152
+ catch {
153
+ // Ignore close errors
154
+ }
155
+ }
156
+ this.pendingFrames = [];
157
+ this.queueSize = 0;
158
+ // Unblock any waiting drain
159
+ if (this.resolveWaitForDrain) {
160
+ this.resolveWaitForDrain();
161
+ this.resolveWaitForDrain = null;
162
+ }
163
+ }
164
+ /**
165
+ * Pause frame generation
166
+ */
167
+ pause() {
168
+ if (this.state === 'running') {
169
+ this.state = 'paused';
170
+ }
171
+ }
172
+ /**
173
+ * Resume frame generation
174
+ */
175
+ resume() {
176
+ if (this.state === 'paused') {
177
+ this.state = 'running';
178
+ // Unblock any waiting drain
179
+ if (this.resolveWaitForDrain) {
180
+ this.resolveWaitForDrain();
181
+ this.resolveWaitForDrain = null;
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Get the next frame from the loop
187
+ *
188
+ * Called by the encoder to consume frames. The caller takes ownership
189
+ * of the frame and MUST call frame.close() when done.
190
+ *
191
+ * @returns The next VideoFrame, or null if none available
192
+ */
193
+ takeFrame() {
194
+ const frame = this.pendingFrames.shift();
195
+ if (frame) {
196
+ this.queueSize--;
197
+ // Notify that there's room for more frames
198
+ if (this.resolveWaitForDrain &&
199
+ this.queueSize < this.config.maxQueueSize) {
200
+ this.resolveWaitForDrain();
201
+ this.resolveWaitForDrain = null;
202
+ }
203
+ }
204
+ return frame ?? null;
205
+ }
206
+ /**
207
+ * Signal that a frame has been consumed externally
208
+ *
209
+ * Use this when frames are consumed outside of takeFrame(),
210
+ * to maintain correct backpressure accounting.
211
+ */
212
+ frameConsumed() {
213
+ this.queueSize = Math.max(0, this.queueSize - 1);
214
+ if (this.resolveWaitForDrain &&
215
+ this.queueSize < this.config.maxQueueSize) {
216
+ this.resolveWaitForDrain();
217
+ this.resolveWaitForDrain = null;
218
+ }
219
+ }
220
+ /**
221
+ * Check if there are frames available
222
+ */
223
+ hasFrames() {
224
+ return this.pendingFrames.length > 0;
225
+ }
226
+ /**
227
+ * Get the current frame index
228
+ */
229
+ getCurrentFrameIndex() {
230
+ return this.frameIndex;
231
+ }
232
+ // ─────────────────────────────────────────────────────────────────────────────
233
+ // Private methods
234
+ // ─────────────────────────────────────────────────────────────────────────────
235
+ async generateFrame() {
236
+ const timing = {
237
+ frameIndex: this.frameIndex,
238
+ timestamp: this.frameIndex * this.frameDurationUs,
239
+ duration: this.frameDurationUs,
240
+ presentationTime: performance.now() - this.startTime,
241
+ };
242
+ // Best practice: Reset canvas at start of every frame
243
+ // This prevents Skia command history buildup
244
+ resetCanvas(this.ctx);
245
+ // Call user's frame rendering function
246
+ await this.config.onFrame(this.ctx, timing);
247
+ // Get raw RGBA pixels (never PNG!)
248
+ const pixels = getRawPixels(this.canvas);
249
+ const pixelArray = bufferToUint8Array(pixels);
250
+ // Create VideoFrame with proper lifecycle
251
+ let frame = null;
252
+ try {
253
+ frame = new VideoFrame(new Uint8Array(pixelArray), {
254
+ format: 'RGBA',
255
+ codedWidth: this.config.width,
256
+ codedHeight: this.config.height,
257
+ timestamp: timing.timestamp,
258
+ duration: timing.duration,
259
+ });
260
+ this.pendingFrames.push(frame);
261
+ this.queueSize++;
262
+ }
263
+ catch (error) {
264
+ // Best practice: Close frame on error
265
+ if (frame) {
266
+ try {
267
+ frame.close();
268
+ }
269
+ catch {
270
+ // Ignore close errors
271
+ }
272
+ }
273
+ throw error;
274
+ }
275
+ }
276
+ waitForDrain() {
277
+ return new Promise((resolve) => {
278
+ this.resolveWaitForDrain = resolve;
279
+ });
280
+ }
281
+ }
282
+ /**
283
+ * Create a FrameLoop with the given configuration
284
+ *
285
+ * @param config - FrameLoop configuration
286
+ * @returns A new FrameLoop instance
287
+ */
288
+ export function createFrameLoop(config) {
289
+ return new FrameLoop(config);
290
+ }
291
+ //# sourceMappingURL=frame-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-loop.js","sourceRoot":"","sources":["../../src/canvas/frame-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * GPU Context Management for skia-canvas
3
+ *
4
+ * Provides GPU detection and canvas factory with auto-detection
5
+ * for Metal (macOS), Vulkan (Linux/Windows), and D3D (Windows).
6
+ */
7
+ import { Canvas } from 'skia-canvas';
8
+ import type { GpuEngineInfo, CanvasConfig } from './types.js';
9
+ /**
10
+ * Detect available GPU acceleration
11
+ * Uses a minimal probe canvas to check GPU availability.
12
+ * Results are cached for performance.
13
+ */
14
+ export declare function detectGpuAcceleration(): GpuEngineInfo;
15
+ /**
16
+ * Check if GPU acceleration is available
17
+ */
18
+ export declare function isGpuAvailable(): boolean;
19
+ /**
20
+ * Get the GPU API name (Metal, Vulkan, D3D, or null for CPU)
21
+ */
22
+ export declare function getGpuApi(): 'Metal' | 'Vulkan' | 'D3D' | null;
23
+ /**
24
+ * Create a canvas with optimal GPU settings
25
+ *
26
+ * @param config - Canvas configuration
27
+ * @returns A new skia-canvas Canvas instance
28
+ */
29
+ export declare function createCanvas(config: CanvasConfig): Canvas;
30
+ /**
31
+ * Ensure dimensions are even (required for YUV420 compatibility)
32
+ *
33
+ * Most video codecs (H.264, HEVC, VP9) require even dimensions
34
+ * for chroma subsampling. This utility rounds up odd dimensions.
35
+ *
36
+ * @param width - Original width
37
+ * @param height - Original height
38
+ * @returns Dimensions rounded up to even values
39
+ */
40
+ export declare function ensureEvenDimensions(width: number, height: number): {
41
+ width: number;
42
+ height: number;
43
+ };
44
+ /**
45
+ * Validate that dimensions are even (throws if not)
46
+ *
47
+ * Many hardware encoders (NVENC, QuickSync, VideoToolbox) will fail
48
+ * silently or crash if dimensions are not divisible by 2. Use this
49
+ * for strict validation in encoder configuration.
50
+ *
51
+ * @param width - Width to validate
52
+ * @param height - Height to validate
53
+ * @throws Error if width or height is odd
54
+ */
55
+ export declare function validateEvenDimensions(width: number, height: number): void;
56
+ /**
57
+ * Reset the GPU detection cache
58
+ * Useful for testing or when GPU availability may have changed
59
+ */
60
+ export declare function resetGpuCache(): void;
61
+ //# sourceMappingURL=gpu-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpu-context.d.ts","sourceRoot":"","sources":["../../src/canvas/gpu-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ9D;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,CAyCrD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAGxC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,IAAI,CAG7D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAYzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAKnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAiB1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * GPU Context Management for skia-canvas
3
+ *
4
+ * Provides GPU detection and canvas factory with auto-detection
5
+ * for Metal (macOS), Vulkan (Linux/Windows), and D3D (Windows).
6
+ */
7
+ import { Canvas } from 'skia-canvas';
8
+ import { createLogger } from '../utils/logger.js';
9
+ const logger = createLogger('GpuContext');
10
+ // Cached GPU availability result
11
+ let gpuAvailability = null;
12
+ let gpuCheckPerformed = false;
13
+ /**
14
+ * Detect available GPU acceleration
15
+ * Uses a minimal probe canvas to check GPU availability.
16
+ * Results are cached for performance.
17
+ */
18
+ export function detectGpuAcceleration() {
19
+ if (gpuCheckPerformed && gpuAvailability) {
20
+ return gpuAvailability;
21
+ }
22
+ try {
23
+ // Create minimal probe canvas
24
+ const probe = new Canvas(1, 1);
25
+ probe.gpu = true; // Request GPU
26
+ // Access engine info to trigger GPU initialization
27
+ const engine = probe.engine;
28
+ gpuAvailability = {
29
+ renderer: engine.renderer === 'GPU' ? 'GPU' : 'CPU',
30
+ api: engine.api,
31
+ device: engine.device,
32
+ driver: engine.driver,
33
+ threads: engine.threads,
34
+ error: engine.error,
35
+ };
36
+ gpuCheckPerformed = true;
37
+ logger.info(`GPU Detection: ${engine.renderer}${engine.api ? ` (${engine.api})` : ''}`);
38
+ if (engine.error) {
39
+ logger.warn(`GPU fallback reason: ${engine.error}`);
40
+ }
41
+ return gpuAvailability;
42
+ }
43
+ catch (error) {
44
+ gpuAvailability = {
45
+ renderer: 'CPU',
46
+ error: error instanceof Error ? error.message : String(error),
47
+ };
48
+ gpuCheckPerformed = true;
49
+ logger.warn('GPU detection failed, using CPU rendering');
50
+ return gpuAvailability;
51
+ }
52
+ }
53
+ /**
54
+ * Check if GPU acceleration is available
55
+ */
56
+ export function isGpuAvailable() {
57
+ const info = detectGpuAcceleration();
58
+ return info.renderer === 'GPU';
59
+ }
60
+ /**
61
+ * Get the GPU API name (Metal, Vulkan, D3D, or null for CPU)
62
+ */
63
+ export function getGpuApi() {
64
+ const info = detectGpuAcceleration();
65
+ return info.api ?? null;
66
+ }
67
+ /**
68
+ * Create a canvas with optimal GPU settings
69
+ *
70
+ * @param config - Canvas configuration
71
+ * @returns A new skia-canvas Canvas instance
72
+ */
73
+ export function createCanvas(config) {
74
+ const canvas = new Canvas(config.width, config.height);
75
+ // Set GPU preference (auto-detect if not specified)
76
+ if (config.gpu !== undefined) {
77
+ canvas.gpu = config.gpu;
78
+ }
79
+ else {
80
+ // Auto-detect: use GPU if available
81
+ canvas.gpu = isGpuAvailable();
82
+ }
83
+ return canvas;
84
+ }
85
+ /**
86
+ * Ensure dimensions are even (required for YUV420 compatibility)
87
+ *
88
+ * Most video codecs (H.264, HEVC, VP9) require even dimensions
89
+ * for chroma subsampling. This utility rounds up odd dimensions.
90
+ *
91
+ * @param width - Original width
92
+ * @param height - Original height
93
+ * @returns Dimensions rounded up to even values
94
+ */
95
+ export function ensureEvenDimensions(width, height) {
96
+ return {
97
+ width: width % 2 === 0 ? width : width + 1,
98
+ height: height % 2 === 0 ? height : height + 1,
99
+ };
100
+ }
101
+ /**
102
+ * Validate that dimensions are even (throws if not)
103
+ *
104
+ * Many hardware encoders (NVENC, QuickSync, VideoToolbox) will fail
105
+ * silently or crash if dimensions are not divisible by 2. Use this
106
+ * for strict validation in encoder configuration.
107
+ *
108
+ * @param width - Width to validate
109
+ * @param height - Height to validate
110
+ * @throws Error if width or height is odd
111
+ */
112
+ export function validateEvenDimensions(width, height) {
113
+ const errors = [];
114
+ if (width % 2 !== 0) {
115
+ errors.push(`width (${width}) must be even for video encoding`);
116
+ }
117
+ if (height % 2 !== 0) {
118
+ errors.push(`height (${height}) must be even for video encoding`);
119
+ }
120
+ if (errors.length > 0) {
121
+ throw new Error(`Invalid dimensions: ${errors.join(', ')}. ` +
122
+ `Hardware encoders require even dimensions for YUV420 chroma subsampling. ` +
123
+ `Use ensureEvenDimensions() to auto-fix, or adjust your source dimensions.`);
124
+ }
125
+ }
126
+ /**
127
+ * Reset the GPU detection cache
128
+ * Useful for testing or when GPU availability may have changed
129
+ */
130
+ export function resetGpuCache() {
131
+ gpuAvailability = null;
132
+ gpuCheckPerformed = false;
133
+ }
134
+ //# sourceMappingURL=gpu-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpu-context.js","sourceRoot":"","sources":["../../src/canvas/gpu-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Canvas Module - skia-canvas integration for WebCodecs
3
+ *
4
+ * Provides GPU-accelerated canvas operations using skia-canvas:
5
+ * - Metal acceleration on macOS
6
+ * - Vulkan acceleration on Linux/Windows
7
+ * - D3D acceleration on Windows
8
+ * - Automatic CPU fallback
9
+ *
10
+ * Best practices implemented:
11
+ * - Memory lifecycle with explicit frame closing
12
+ * - Canvas state reset before each frame
13
+ * - RGBA raw buffer export (never PNG)
14
+ * - Even dimensions for YUV420 compatibility
15
+ * - Backpressure with configurable queue size
16
+ */
17
+ export { Canvas, loadImage, FontLibrary } from 'skia-canvas';
18
+ export { detectGpuAcceleration, isGpuAvailable, getGpuApi, createCanvas, ensureEvenDimensions, validateEvenDimensions, resetGpuCache, } from './gpu-context.js';
19
+ export { createPixelBuffer, createPixelBufferWithColor, getRawPixels, getRawPixelsAsync, resetCanvas, pixelsToImageData, drawPixelsToCanvas, bufferToUint8Array, resizePixels, } from './canvas-utils.js';
20
+ export { FrameLoop, createFrameLoop } from './frame-loop.js';
21
+ export type { GpuEngineInfo, CanvasConfig, FrameTiming, FrameLoopConfig, FrameLoopState, RawBufferOptions, FrameCallback, SkiaCanvas, SkiaEngineInfo, } from './types.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG7D,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAG7D,YAAY,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Canvas Module - skia-canvas integration for WebCodecs
3
+ *
4
+ * Provides GPU-accelerated canvas operations using skia-canvas:
5
+ * - Metal acceleration on macOS
6
+ * - Vulkan acceleration on Linux/Windows
7
+ * - D3D acceleration on Windows
8
+ * - Automatic CPU fallback
9
+ *
10
+ * Best practices implemented:
11
+ * - Memory lifecycle with explicit frame closing
12
+ * - Canvas state reset before each frame
13
+ * - RGBA raw buffer export (never PNG)
14
+ * - Even dimensions for YUV420 compatibility
15
+ * - Backpressure with configurable queue size
16
+ */
17
+ // Re-export skia-canvas for direct use
18
+ export { Canvas, loadImage, FontLibrary } from 'skia-canvas';
19
+ // GPU context management
20
+ export { detectGpuAcceleration, isGpuAvailable, getGpuApi, createCanvas, ensureEvenDimensions, validateEvenDimensions, resetGpuCache, } from './gpu-context.js';
21
+ // Canvas utilities
22
+ export { createPixelBuffer, createPixelBufferWithColor, getRawPixels, getRawPixelsAsync, resetCanvas, pixelsToImageData, drawPixelsToCanvas, bufferToUint8Array, resizePixels, } from './canvas-utils.js';
23
+ // FrameLoop helper
24
+ export { FrameLoop, createFrameLoop } from './frame-loop.js';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,yBAAyB;AACzB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAE1B,mBAAmB;AACnB,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAE3B,mBAAmB;AACnB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Canvas Module Types
3
+ *
4
+ * TypeScript interfaces for skia-canvas integration with WebCodecs
5
+ */
6
+ /**
7
+ * GPU rendering engine information from skia-canvas
8
+ */
9
+ export interface GpuEngineInfo {
10
+ renderer: 'CPU' | 'GPU';
11
+ api?: 'Metal' | 'Vulkan' | 'D3D';
12
+ device?: string;
13
+ driver?: string;
14
+ threads?: number;
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Canvas configuration options
19
+ */
20
+ export interface CanvasConfig {
21
+ width: number;
22
+ height: number;
23
+ /** Enable GPU acceleration (default: auto-detect) */
24
+ gpu?: boolean;
25
+ }
26
+ /**
27
+ * Frame timing information for the FrameLoop
28
+ */
29
+ export interface FrameTiming {
30
+ /** Current frame index (0-based) */
31
+ frameIndex: number;
32
+ /** Timestamp in microseconds, for VideoFrame */
33
+ timestamp: number;
34
+ /** Duration in microseconds */
35
+ duration?: number;
36
+ /** High-resolution presentation time (performance.now() offset) */
37
+ presentationTime: number;
38
+ }
39
+ /**
40
+ * Callback for rendering a frame
41
+ * The ctx parameter is a skia-canvas CanvasRenderingContext2D
42
+ */
43
+ export type FrameCallback = (ctx: any, timing: FrameTiming) => void | Promise<void>;
44
+ /**
45
+ * FrameLoop configuration
46
+ */
47
+ export interface FrameLoopConfig {
48
+ /** Canvas width in pixels */
49
+ width: number;
50
+ /** Canvas height in pixels */
51
+ height: number;
52
+ /** Target frame rate (frames per second) */
53
+ frameRate: number;
54
+ /** Maximum frames in queue before backpressure (default: 8) */
55
+ maxQueueSize?: number;
56
+ /** Enable GPU acceleration (default: auto-detect) */
57
+ gpu?: boolean;
58
+ /** Called for each frame to render content */
59
+ onFrame: FrameCallback;
60
+ /** Called when all frames have been generated and consumed */
61
+ onComplete?: () => void;
62
+ /** Called when an error occurs */
63
+ onError?: (error: Error) => void;
64
+ }
65
+ /**
66
+ * FrameLoop state machine
67
+ */
68
+ export type FrameLoopState = 'idle' | 'running' | 'paused' | 'stopped';
69
+ /**
70
+ * Raw buffer format options for toBuffer
71
+ */
72
+ export interface RawBufferOptions {
73
+ /** Color type for raw buffer (default: 'rgba') */
74
+ colorType?: 'rgba' | 'bgra';
75
+ }
76
+ /**
77
+ * skia-canvas engine info interface
78
+ */
79
+ export interface SkiaEngineInfo {
80
+ renderer: string;
81
+ api?: string;
82
+ device?: string;
83
+ driver?: string;
84
+ threads?: number;
85
+ error?: string;
86
+ }
87
+ /**
88
+ * skia-canvas Canvas interface for type checking
89
+ */
90
+ export interface SkiaCanvas {
91
+ width: number;
92
+ height: number;
93
+ gpu: boolean;
94
+ readonly engine: SkiaEngineInfo;
95
+ getContext(type: '2d'): any;
96
+ toBuffer(format: 'raw', options?: RawBufferOptions): Promise<Buffer>;
97
+ toBufferSync(format: 'raw', options?: RawBufferOptions): Buffer;
98
+ saveAs(filename: string, options?: unknown): Promise<void>;
99
+ saveAsSync(filename: string, options?: unknown): void;
100
+ }
101
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/canvas/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,KAAK,GAAG,KAAK,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AAEH,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,WAAW,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,OAAO,EAAE,aAAa,CAAC;IACvB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,kCAAkC;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAEhC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,GAAG,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAChE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACvD"}