node-av 6.0.0-beta.6 → 6.0.0-beta.8

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 (40) hide show
  1. package/README.md +5 -0
  2. package/dist/api/bitstream-filter.js +5 -2
  3. package/dist/api/bitstream-filter.js.map +1 -1
  4. package/dist/api/decoder.js +5 -2
  5. package/dist/api/decoder.js.map +1 -1
  6. package/dist/api/demuxer.js.map +1 -1
  7. package/dist/api/encoder-pool.d.ts +220 -0
  8. package/dist/api/encoder-pool.js +285 -0
  9. package/dist/api/encoder-pool.js.map +1 -0
  10. package/dist/api/encoder.d.ts +58 -0
  11. package/dist/api/encoder.js +159 -44
  12. package/dist/api/encoder.js.map +1 -1
  13. package/dist/api/filter-complex.js +8 -6
  14. package/dist/api/filter-complex.js.map +1 -1
  15. package/dist/api/filter.js +13 -8
  16. package/dist/api/filter.js.map +1 -1
  17. package/dist/api/index.d.ts +2 -0
  18. package/dist/api/index.js +4 -0
  19. package/dist/api/index.js.map +1 -1
  20. package/dist/api/muxer.js +8 -3
  21. package/dist/api/muxer.js.map +1 -1
  22. package/dist/api/scaler.d.ts +431 -0
  23. package/dist/api/scaler.js +620 -0
  24. package/dist/api/scaler.js.map +1 -0
  25. package/dist/api/utilities/async-queue.d.ts +27 -1
  26. package/dist/api/utilities/async-queue.js +38 -1
  27. package/dist/api/utilities/async-queue.js.map +1 -1
  28. package/dist/constants/constants.d.ts +98 -0
  29. package/dist/constants/constants.js +99 -0
  30. package/dist/constants/constants.js.map +1 -1
  31. package/dist/lib/binding.d.ts +3 -1
  32. package/dist/lib/binding.js.map +1 -1
  33. package/dist/lib/frame.d.ts +9 -3
  34. package/dist/lib/frame.js +9 -3
  35. package/dist/lib/frame.js.map +1 -1
  36. package/dist/lib/native-types.d.ts +37 -0
  37. package/dist/lib/packet.d.ts +9 -3
  38. package/dist/lib/packet.js +9 -3
  39. package/dist/lib/packet.js.map +1 -1
  40. package/package.json +9 -9
@@ -0,0 +1,220 @@
1
+ import type { AVCodecFlag, AVCodecID, FFEncoderCodec } from '../constants/index.js';
2
+ import type { Codec } from '../lib/codec.js';
3
+ import type { Frame } from '../lib/frame.js';
4
+ import type { EncoderOptions } from './encoder.js';
5
+ /**
6
+ * Options for encoder pool creation.
7
+ *
8
+ * Extends {@link EncoderOptions} with the pool size limit.
9
+ */
10
+ export type EncoderPoolOptions<C = unknown> = EncoderOptions<C> & {
11
+ /**
12
+ * Maximum number of encoders kept alive at once.
13
+ *
14
+ * When exceeded, the least-recently-used encoder is closed. In the worst case
15
+ * (every frame a unique size) the pool degrades to per-frame open/close, never leaking.
16
+ *
17
+ * @default 8
18
+ */
19
+ maxSize?: number;
20
+ /**
21
+ * Codec flags applied to every pooled encoder before its first frame.
22
+ *
23
+ * Needed for flags that change encode behaviour, e.g. `AV_CODEC_FLAG_QSCALE` so
24
+ * MJPEG honours per-frame `frame.quality`.
25
+ */
26
+ flags?: AVCodecFlag | AVCodecFlag[];
27
+ };
28
+ /**
29
+ * Bounded LRU pool of image encoders keyed by resolution and pixel format.
30
+ *
31
+ * A single encoder cannot change dimensions after opening, so encoding frames of
32
+ * varying sizes needs one encoder per resolution. This pool routes each frame to
33
+ * the encoder matching its `width x height x pixelFormat`, creating one on demand
34
+ * and reusing it afterwards. Each frame is given a monotonic PTS internally, so
35
+ * callers can feed independent snapshots without managing timestamps.
36
+ *
37
+ * Pooled encoders are never flushed between frames, so this only suits intra-only
38
+ * image codecs (MJPEG, PNG, WebP, ...). Hardware frames work as-is: the encoder
39
+ * adopts the frame's hardware context. For a single one-off conversion use
40
+ * {@link Encoder.encodeOne} instead.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { EncoderPool } from 'node-av/api';
45
+ * import { FF_ENCODER_MJPEG } from 'node-av/constants';
46
+ *
47
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG);
48
+ * const a = await pool.encode(frame1920); // opens + caches
49
+ * const b = await pool.encode(frame640); // opens + caches
50
+ * const c = await pool.encode(frame1920); // reuses, no open
51
+ * ```
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // MJPEG quality: set the QSCALE flag on the pool, then carry the quality on
56
+ * // each frame (qscale 2 = best, 31 = worst). The `q` private option has no
57
+ * // effect on MJPEG.
58
+ * import { AV_CODEC_FLAG_QSCALE, FF_QP2LAMBDA } from 'node-av/constants';
59
+ *
60
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4, flags: AV_CODEC_FLAG_QSCALE });
61
+ * frame.quality = 3 * FF_QP2LAMBDA;
62
+ * const jpeg = await pool.encode(frame);
63
+ * ```
64
+ *
65
+ * @see {@link Encoder.encodeOne} For a one-shot, stateless single-frame encode
66
+ */
67
+ export declare class EncoderPool<const C extends FFEncoderCodec | AVCodecID | Codec> implements Disposable {
68
+ private readonly encoderCodec;
69
+ private readonly options;
70
+ private readonly maxSize;
71
+ private readonly flags;
72
+ private readonly encoders;
73
+ /**
74
+ * Create a new encoder pool.
75
+ *
76
+ * @param encoderCodec - Encoder codec applied to every pooled encoder
77
+ *
78
+ * @param options - Encoder options forwarded to each encoder, plus the optional `maxSize` limit
79
+ *
80
+ * @throws {Error} If maxSize is less than 1
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4, flags: AV_CODEC_FLAG_QSCALE });
85
+ * ```
86
+ */
87
+ constructor(encoderCodec: C, options?: EncoderPoolOptions<C>);
88
+ /**
89
+ * Number of encoders currently held alive.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * console.log(`Pool holds ${pool.size} encoders`);
94
+ * ```
95
+ */
96
+ get size(): number;
97
+ /**
98
+ * Encode a frame into a self-contained image buffer.
99
+ *
100
+ * Routes the frame to the encoder matching its dimensions and pixel format,
101
+ * creating and caching one if necessary.
102
+ *
103
+ * @param frame - Frame to encode
104
+ *
105
+ * @returns Encoded image bytes
106
+ *
107
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
108
+ *
109
+ * @throws {Error} If the encoder produced no output
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const jpeg = await pool.encode(frame);
114
+ * ```
115
+ *
116
+ * @see {@link encodeSync} For synchronous version
117
+ */
118
+ encode(frame: Frame): Promise<Buffer>;
119
+ /**
120
+ * Encode a frame into a self-contained image buffer synchronously.
121
+ * Synchronous version of encode.
122
+ *
123
+ * @param frame - Frame to encode
124
+ *
125
+ * @returns Encoded image bytes
126
+ *
127
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
128
+ *
129
+ * @throws {Error} If the encoder produced no output
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * const jpeg = pool.encodeSync(frame);
134
+ * ```
135
+ *
136
+ * @see {@link encode} For asynchronous version
137
+ */
138
+ encodeSync(frame: Frame): Buffer;
139
+ /**
140
+ * Close all pooled encoders and clear the pool.
141
+ *
142
+ * Automatically called by Symbol.dispose.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * pool.close();
147
+ * ```
148
+ *
149
+ * @see {@link Symbol.dispose} For automatic cleanup
150
+ */
151
+ close(): void;
152
+ /**
153
+ * Build the cache key from frame dimensions and pixel format.
154
+ *
155
+ * Pixel format is part of the key because the encoder is opened with the frame's
156
+ * format; a cached encoder for the same size but a different format would be invalid.
157
+ *
158
+ * @param frame - Frame to derive the key from
159
+ *
160
+ * @returns Cache key `width x height x pixelFormat`
161
+ *
162
+ * @internal
163
+ */
164
+ private keyFor;
165
+ /**
166
+ * Look up an encoder and mark it as most-recently-used.
167
+ *
168
+ * @param key - Cache key to look up
169
+ *
170
+ * @returns Pooled encoder, or undefined if not cached
171
+ *
172
+ * @internal
173
+ */
174
+ private touch;
175
+ /**
176
+ * Insert a freshly created encoder, evicting the least-recently-used one if full.
177
+ *
178
+ * @param key - Cache key for the encoder
179
+ *
180
+ * @param encoder - Freshly created encoder to cache
181
+ *
182
+ * @returns The pooled encoder entry
183
+ *
184
+ * @internal
185
+ */
186
+ private set;
187
+ /**
188
+ * Extract the encoded bytes from the produced packets and free them.
189
+ *
190
+ * packet.data returns a JS-owned copy, so the buffer stays valid after freeing.
191
+ *
192
+ * @param packets - Packets produced by the encoder
193
+ *
194
+ * @param encoder - Encoder that produced the packets (for error messages)
195
+ *
196
+ * @returns Encoded image bytes
197
+ *
198
+ * @throws {Error} If no packet was produced
199
+ *
200
+ * @internal
201
+ */
202
+ private extract;
203
+ /**
204
+ * Dispose of the pool.
205
+ *
206
+ * Implements Disposable interface for automatic cleanup.
207
+ * Equivalent to calling close().
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * {
212
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4 });
213
+ * // Encode frames...
214
+ * } // All encoders automatically closed
215
+ * ```
216
+ *
217
+ * @see {@link close} For manual cleanup
218
+ */
219
+ [Symbol.dispose](): void;
220
+ }
@@ -0,0 +1,285 @@
1
+ import { Encoder } from './encoder.js';
2
+ /**
3
+ * Bounded LRU pool of image encoders keyed by resolution and pixel format.
4
+ *
5
+ * A single encoder cannot change dimensions after opening, so encoding frames of
6
+ * varying sizes needs one encoder per resolution. This pool routes each frame to
7
+ * the encoder matching its `width x height x pixelFormat`, creating one on demand
8
+ * and reusing it afterwards. Each frame is given a monotonic PTS internally, so
9
+ * callers can feed independent snapshots without managing timestamps.
10
+ *
11
+ * Pooled encoders are never flushed between frames, so this only suits intra-only
12
+ * image codecs (MJPEG, PNG, WebP, ...). Hardware frames work as-is: the encoder
13
+ * adopts the frame's hardware context. For a single one-off conversion use
14
+ * {@link Encoder.encodeOne} instead.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { EncoderPool } from 'node-av/api';
19
+ * import { FF_ENCODER_MJPEG } from 'node-av/constants';
20
+ *
21
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG);
22
+ * const a = await pool.encode(frame1920); // opens + caches
23
+ * const b = await pool.encode(frame640); // opens + caches
24
+ * const c = await pool.encode(frame1920); // reuses, no open
25
+ * ```
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // MJPEG quality: set the QSCALE flag on the pool, then carry the quality on
30
+ * // each frame (qscale 2 = best, 31 = worst). The `q` private option has no
31
+ * // effect on MJPEG.
32
+ * import { AV_CODEC_FLAG_QSCALE, FF_QP2LAMBDA } from 'node-av/constants';
33
+ *
34
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4, flags: AV_CODEC_FLAG_QSCALE });
35
+ * frame.quality = 3 * FF_QP2LAMBDA;
36
+ * const jpeg = await pool.encode(frame);
37
+ * ```
38
+ *
39
+ * @see {@link Encoder.encodeOne} For a one-shot, stateless single-frame encode
40
+ */
41
+ export class EncoderPool {
42
+ encoderCodec;
43
+ options;
44
+ maxSize;
45
+ flags;
46
+ // Insertion order doubles as LRU order: touched entries move to the end,
47
+ // so the first key is always the least-recently-used.
48
+ encoders = new Map();
49
+ /**
50
+ * Create a new encoder pool.
51
+ *
52
+ * @param encoderCodec - Encoder codec applied to every pooled encoder
53
+ *
54
+ * @param options - Encoder options forwarded to each encoder, plus the optional `maxSize` limit
55
+ *
56
+ * @throws {Error} If maxSize is less than 1
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4, flags: AV_CODEC_FLAG_QSCALE });
61
+ * ```
62
+ */
63
+ constructor(encoderCodec, options = {}) {
64
+ const { maxSize = 8, flags, ...encoderOptions } = options;
65
+ if (maxSize < 1) {
66
+ throw new Error(`EncoderPool maxSize must be at least 1, got ${maxSize}`);
67
+ }
68
+ this.encoderCodec = encoderCodec;
69
+ this.options = { threadCount: 1, ...encoderOptions };
70
+ this.maxSize = maxSize;
71
+ this.flags = flags === undefined ? [] : Array.isArray(flags) ? flags : [flags];
72
+ }
73
+ /**
74
+ * Number of encoders currently held alive.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * console.log(`Pool holds ${pool.size} encoders`);
79
+ * ```
80
+ */
81
+ get size() {
82
+ return this.encoders.size;
83
+ }
84
+ /**
85
+ * Encode a frame into a self-contained image buffer.
86
+ *
87
+ * Routes the frame to the encoder matching its dimensions and pixel format,
88
+ * creating and caching one if necessary.
89
+ *
90
+ * @param frame - Frame to encode
91
+ *
92
+ * @returns Encoded image bytes
93
+ *
94
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
95
+ *
96
+ * @throws {Error} If the encoder produced no output
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const jpeg = await pool.encode(frame);
101
+ * ```
102
+ *
103
+ * @see {@link encodeSync} For synchronous version
104
+ */
105
+ async encode(frame) {
106
+ const key = this.keyFor(frame);
107
+ let pooled = this.touch(key);
108
+ if (!pooled) {
109
+ const encoder = await Encoder.create(this.encoderCodec, this.options);
110
+ pooled = this.touch(key);
111
+ if (pooled) {
112
+ encoder.close();
113
+ }
114
+ else {
115
+ pooled = this.set(key, encoder);
116
+ }
117
+ }
118
+ const savedPts = frame.pts;
119
+ frame.pts = pooled.nextPts++;
120
+ try {
121
+ return this.extract(await pooled.encoder.encodeAll(frame), pooled.encoder);
122
+ }
123
+ finally {
124
+ frame.pts = savedPts;
125
+ }
126
+ }
127
+ /**
128
+ * Encode a frame into a self-contained image buffer synchronously.
129
+ * Synchronous version of encode.
130
+ *
131
+ * @param frame - Frame to encode
132
+ *
133
+ * @returns Encoded image bytes
134
+ *
135
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
136
+ *
137
+ * @throws {Error} If the encoder produced no output
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const jpeg = pool.encodeSync(frame);
142
+ * ```
143
+ *
144
+ * @see {@link encode} For asynchronous version
145
+ */
146
+ encodeSync(frame) {
147
+ const key = this.keyFor(frame);
148
+ let pooled = this.touch(key);
149
+ pooled ??= this.set(key, Encoder.createSync(this.encoderCodec, this.options));
150
+ const savedPts = frame.pts;
151
+ frame.pts = pooled.nextPts++;
152
+ try {
153
+ return this.extract(pooled.encoder.encodeAllSync(frame), pooled.encoder);
154
+ }
155
+ finally {
156
+ frame.pts = savedPts;
157
+ }
158
+ }
159
+ /**
160
+ * Close all pooled encoders and clear the pool.
161
+ *
162
+ * Automatically called by Symbol.dispose.
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * pool.close();
167
+ * ```
168
+ *
169
+ * @see {@link Symbol.dispose} For automatic cleanup
170
+ */
171
+ close() {
172
+ for (const { encoder } of this.encoders.values()) {
173
+ encoder.close();
174
+ }
175
+ this.encoders.clear();
176
+ }
177
+ /**
178
+ * Build the cache key from frame dimensions and pixel format.
179
+ *
180
+ * Pixel format is part of the key because the encoder is opened with the frame's
181
+ * format; a cached encoder for the same size but a different format would be invalid.
182
+ *
183
+ * @param frame - Frame to derive the key from
184
+ *
185
+ * @returns Cache key `width x height x pixelFormat`
186
+ *
187
+ * @internal
188
+ */
189
+ keyFor(frame) {
190
+ return `${frame.width}x${frame.height}x${frame.format}`;
191
+ }
192
+ /**
193
+ * Look up an encoder and mark it as most-recently-used.
194
+ *
195
+ * @param key - Cache key to look up
196
+ *
197
+ * @returns Pooled encoder, or undefined if not cached
198
+ *
199
+ * @internal
200
+ */
201
+ touch(key) {
202
+ const pooled = this.encoders.get(key);
203
+ if (pooled) {
204
+ this.encoders.delete(key);
205
+ this.encoders.set(key, pooled);
206
+ }
207
+ return pooled;
208
+ }
209
+ /**
210
+ * Insert a freshly created encoder, evicting the least-recently-used one if full.
211
+ *
212
+ * @param key - Cache key for the encoder
213
+ *
214
+ * @param encoder - Freshly created encoder to cache
215
+ *
216
+ * @returns The pooled encoder entry
217
+ *
218
+ * @internal
219
+ */
220
+ set(key, encoder) {
221
+ if (this.flags.length > 0) {
222
+ encoder.setCodecFlags(...this.flags);
223
+ }
224
+ const pooled = { encoder, nextPts: 0n };
225
+ this.encoders.set(key, pooled);
226
+ if (this.encoders.size > this.maxSize) {
227
+ const oldestKey = this.encoders.keys().next().value;
228
+ if (oldestKey !== undefined) {
229
+ const oldest = this.encoders.get(oldestKey);
230
+ this.encoders.delete(oldestKey);
231
+ oldest?.encoder.close();
232
+ }
233
+ }
234
+ return pooled;
235
+ }
236
+ /**
237
+ * Extract the encoded bytes from the produced packets and free them.
238
+ *
239
+ * packet.data returns a JS-owned copy, so the buffer stays valid after freeing.
240
+ *
241
+ * @param packets - Packets produced by the encoder
242
+ *
243
+ * @param encoder - Encoder that produced the packets (for error messages)
244
+ *
245
+ * @returns Encoded image bytes
246
+ *
247
+ * @throws {Error} If no packet was produced
248
+ *
249
+ * @internal
250
+ */
251
+ extract(packets, encoder) {
252
+ try {
253
+ const data = packets[0]?.data;
254
+ if (!data) {
255
+ throw new Error(`Encoder '${encoder.getCodec().name}' produced no output for frame`);
256
+ }
257
+ return data;
258
+ }
259
+ finally {
260
+ for (const packet of packets) {
261
+ packet.free();
262
+ }
263
+ }
264
+ }
265
+ /**
266
+ * Dispose of the pool.
267
+ *
268
+ * Implements Disposable interface for automatic cleanup.
269
+ * Equivalent to calling close().
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * {
274
+ * using pool = new EncoderPool(FF_ENCODER_MJPEG, { maxSize: 4 });
275
+ * // Encode frames...
276
+ * } // All encoders automatically closed
277
+ * ```
278
+ *
279
+ * @see {@link close} For manual cleanup
280
+ */
281
+ [Symbol.dispose]() {
282
+ this.close();
283
+ }
284
+ }
285
+ //# sourceMappingURL=encoder-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder-pool.js","sourceRoot":"","sources":["../../src/api/encoder-pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA2CvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,OAAO,WAAW;IACL,YAAY,CAAI;IAChB,OAAO,CAAoB;IAC3B,OAAO,CAAS;IAChB,KAAK,CAAgB;IAEtC,yEAAyE;IACzE,sDAAsD;IACrC,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE7D;;;;;;;;;;;;;OAaG;IACH,YAAY,YAAe,EAAE,UAAiC,EAAE;QAC9D,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC;QAE1D,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,+CAA+C,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,cAAc,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACjF,CAAC;IAED;;;;;;;OAOG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,MAAM,CAAC,KAAY;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE/B,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAEtE,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC;QAC3B,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7E,CAAC;gBAAS,CAAC;YACT,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,KAAY;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE/B,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAE9E,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC;QAC3B,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3E,CAAC;gBAAS,CAAC;YACT,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK;QACH,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACjD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACK,MAAM,CAAC,KAAY;QACzB,OAAO,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;IAC1D,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,GAAW;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;OAUG;IACK,GAAG,CAAC,GAAW,EAAE,OAAgB;QACvC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,MAAM,GAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAE/B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACpD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC5C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAChC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACK,OAAO,CAAC,OAAiB,EAAE,OAAgB;QACjD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;YAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,YAAY,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,gCAAgC,CAAC,CAAC;YACvF,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACd,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACF"}
@@ -304,6 +304,64 @@ export declare class Encoder implements Disposable {
304
304
  * @see {@link create} For async version
305
305
  */
306
306
  static createSync<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, options?: EncoderOptions<C>): Encoder;
307
+ /**
308
+ * Encode a single frame into a self-contained image buffer.
309
+ *
310
+ * One-shot, stateless helper for intra-only image codecs (MJPEG, PNG, WebP, ...).
311
+ * Creates a fresh encoder, encodes the frame, flushes and frees everything in one call.
312
+ * The encoder adopts dimensions, pixel format and hardware context from the frame,
313
+ * so any frame size works without reconfiguration.
314
+ *
315
+ * @param encoderCodec - Encoder codec (name, ID, branded constant, or Codec)
316
+ *
317
+ * @param frame - Frame to encode
318
+ *
319
+ * @param options - Optional encoder configuration (e.g. `{ options: { q: 3 } }` for MJPEG quality)
320
+ *
321
+ * @returns Encoded image bytes
322
+ *
323
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
324
+ *
325
+ * @throws {Error} If the encoder produced no output
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const jpeg = await Encoder.encodeOne(FF_ENCODER_MJPEG, frame, { options: { q: 3 } });
330
+ * ```
331
+ *
332
+ * @see {@link EncoderPool} For reusing encoders across recurring resolutions
333
+ */
334
+ static encodeOne<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, frame: Frame, options?: EncoderOptions<C>): Promise<Buffer>;
335
+ /**
336
+ * Encode a single frame into a self-contained image buffer synchronously.
337
+ * Synchronous version of encodeOne.
338
+ *
339
+ * One-shot, stateless helper for intra-only image codecs (MJPEG, PNG, WebP, ...).
340
+ * Creates a fresh encoder, encodes the frame, flushes and frees everything in one call.
341
+ * The encoder adopts dimensions, pixel format and hardware context from the frame,
342
+ * so any frame size works without reconfiguration.
343
+ *
344
+ * @param encoderCodec - Encoder codec (name, ID, branded constant, or Codec)
345
+ *
346
+ * @param frame - Frame to encode
347
+ *
348
+ * @param options - Optional encoder configuration (e.g. `{ options: { q: 3 } }` for MJPEG quality)
349
+ *
350
+ * @returns Encoded image bytes
351
+ *
352
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
353
+ *
354
+ * @throws {Error} If the encoder produced no output
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * const jpeg = Encoder.encodeOneSync(FF_ENCODER_MJPEG, frame, { options: { q: 3 } });
359
+ * ```
360
+ *
361
+ * @see {@link encodeOne} For async version
362
+ * @see {@link EncoderPool} For reusing encoders across recurring resolutions
363
+ */
364
+ static encodeOneSync<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, frame: Frame, options?: EncoderOptions<C>): Buffer;
307
365
  /**
308
366
  * Check if encoder is open.
309
367
  *