node-av 5.2.4-beta.1 → 6.0.0-beta.10

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 (106) hide show
  1. package/README.md +15 -1
  2. package/dist/api/bitstream-filter.d.ts +110 -87
  3. package/dist/api/bitstream-filter.js +162 -102
  4. package/dist/api/bitstream-filter.js.map +1 -1
  5. package/dist/api/decoder.d.ts +87 -8
  6. package/dist/api/decoder.js +179 -4
  7. package/dist/api/decoder.js.map +1 -1
  8. package/dist/api/demuxer.d.ts +30 -24
  9. package/dist/api/demuxer.js +4 -5
  10. package/dist/api/demuxer.js.map +1 -1
  11. package/dist/api/device.js.map +1 -1
  12. package/dist/api/encoder-pool.d.ts +220 -0
  13. package/dist/api/encoder-pool.js +285 -0
  14. package/dist/api/encoder-pool.js.map +1 -0
  15. package/dist/api/encoder.d.ts +133 -7
  16. package/dist/api/encoder.js +392 -68
  17. package/dist/api/encoder.js.map +1 -1
  18. package/dist/api/filter-complex.d.ts +2 -1
  19. package/dist/api/filter-complex.js +11 -7
  20. package/dist/api/filter-complex.js.map +1 -1
  21. package/dist/api/filter-presets.d.ts +130 -654
  22. package/dist/api/filter-presets.js +180 -858
  23. package/dist/api/filter-presets.js.map +1 -1
  24. package/dist/api/filter.js +13 -8
  25. package/dist/api/filter.js.map +1 -1
  26. package/dist/api/fmp4-stream.js +1 -1
  27. package/dist/api/fmp4-stream.js.map +1 -1
  28. package/dist/api/index.d.ts +6 -6
  29. package/dist/api/index.js +8 -8
  30. package/dist/api/index.js.map +1 -1
  31. package/dist/api/muxer.d.ts +43 -15
  32. package/dist/api/muxer.js +79 -27
  33. package/dist/api/muxer.js.map +1 -1
  34. package/dist/api/pipeline.d.ts +50 -0
  35. package/dist/api/pipeline.js +138 -22
  36. package/dist/api/pipeline.js.map +1 -1
  37. package/dist/api/probe.d.ts +128 -0
  38. package/dist/api/probe.js +227 -0
  39. package/dist/api/probe.js.map +1 -0
  40. package/dist/api/rtp-stream.js +1 -1
  41. package/dist/api/rtp-stream.js.map +1 -1
  42. package/dist/api/scaler.d.ts +431 -0
  43. package/dist/api/scaler.js +620 -0
  44. package/dist/api/scaler.js.map +1 -0
  45. package/dist/api/utilities/async-queue.d.ts +27 -1
  46. package/dist/api/utilities/async-queue.js +38 -1
  47. package/dist/api/utilities/async-queue.js.map +1 -1
  48. package/dist/api/utilities/electron-shared-texture.d.ts +41 -1
  49. package/dist/api/utilities/electron-shared-texture.js +41 -4
  50. package/dist/api/utilities/electron-shared-texture.js.map +1 -1
  51. package/dist/api/utilities/index.d.ts +1 -1
  52. package/dist/api/utilities/index.js.map +1 -1
  53. package/dist/api/webrtc-stream.d.ts +0 -1
  54. package/dist/api/webrtc-stream.js +0 -1
  55. package/dist/api/webrtc-stream.js.map +1 -1
  56. package/dist/constants/bsf-options.d.ts +333 -0
  57. package/dist/constants/bsf-options.js +7 -0
  58. package/dist/constants/bsf-options.js.map +1 -0
  59. package/dist/constants/constants.d.ts +109 -0
  60. package/dist/constants/constants.js +110 -0
  61. package/dist/constants/constants.js.map +1 -1
  62. package/dist/constants/decoders.d.ts +636 -618
  63. package/dist/constants/decoders.js +1 -3
  64. package/dist/constants/decoders.js.map +1 -1
  65. package/dist/constants/encoders.d.ts +300 -282
  66. package/dist/constants/encoders.js +0 -2
  67. package/dist/constants/encoders.js.map +1 -1
  68. package/dist/constants/filter-options.d.ts +10915 -0
  69. package/dist/constants/filter-options.js +7 -0
  70. package/dist/constants/filter-options.js.map +1 -0
  71. package/dist/constants/format-options.d.ts +3056 -0
  72. package/dist/constants/format-options.js +7 -0
  73. package/dist/constants/format-options.js.map +1 -0
  74. package/dist/constants/formats.d.ts +18 -0
  75. package/dist/constants/formats.js +7 -0
  76. package/dist/constants/formats.js.map +1 -0
  77. package/dist/constants/index.d.ts +5 -0
  78. package/dist/constants/options.d.ts +4073 -0
  79. package/dist/constants/options.js +7 -0
  80. package/dist/constants/options.js.map +1 -0
  81. package/dist/lib/binding.d.ts +4 -1
  82. package/dist/lib/binding.js.map +1 -1
  83. package/dist/lib/codec.d.ts +36 -5
  84. package/dist/lib/codec.js +37 -4
  85. package/dist/lib/codec.js.map +1 -1
  86. package/dist/lib/dictionary.d.ts +1 -1
  87. package/dist/lib/dictionary.js.map +1 -1
  88. package/dist/lib/error.d.ts +69 -0
  89. package/dist/lib/error.js +92 -0
  90. package/dist/lib/error.js.map +1 -1
  91. package/dist/lib/frame.d.ts +46 -3
  92. package/dist/lib/frame.js +50 -3
  93. package/dist/lib/frame.js.map +1 -1
  94. package/dist/lib/index.d.ts +1 -1
  95. package/dist/lib/index.js.map +1 -1
  96. package/dist/lib/native-types.d.ts +68 -0
  97. package/dist/lib/packet.d.ts +17 -3
  98. package/dist/lib/packet.js +19 -3
  99. package/dist/lib/packet.js.map +1 -1
  100. package/dist/lib/utilities.d.ts +21 -0
  101. package/dist/lib/utilities.js +23 -0
  102. package/dist/lib/utilities.js.map +1 -1
  103. package/dist/webrtc/index.d.ts +3 -0
  104. package/dist/webrtc/index.js +7 -0
  105. package/dist/webrtc/index.js.map +1 -0
  106. package/package.json +33 -22
@@ -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":"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"}
@@ -3,7 +3,7 @@ import { Codec } from '../lib/codec.js';
3
3
  import { Frame } from '../lib/frame.js';
4
4
  import { Packet } from '../lib/packet.js';
5
5
  import { SchedulerControl } from './utilities/scheduler.js';
6
- import type { AVCodecFlag, AVCodecID, AVThreadType, EOFSignal, FFEncoderCodec } from '../constants/index.js';
6
+ import type { AVCodecFlag, AVCodecID, AVThreadType, EncoderOptionsFor, EOFSignal, FFEncoderCodec } from '../constants/index.js';
7
7
  import type { Decoder } from './decoder.js';
8
8
  import type { FilterComplexAPI } from './filter-complex.js';
9
9
  import type { FilterAPI } from './filter.js';
@@ -11,7 +11,7 @@ import type { Muxer } from './muxer.js';
11
11
  /**
12
12
  * Options for encoder creation.
13
13
  */
14
- export interface EncoderOptions {
14
+ export interface EncoderOptions<C = unknown> {
15
15
  /**
16
16
  * Target bitrate.
17
17
  *
@@ -90,13 +90,30 @@ export interface EncoderOptions {
90
90
  * @default FFmpeg default (both methods, codec chooses best)
91
91
  */
92
92
  threadType?: AVThreadType;
93
+ /**
94
+ * Automatically resample incoming audio to a format the codec supports.
95
+ *
96
+ * Audio encoders only accept specific sample rates, sample formats, and channel
97
+ * layouts (e.g. libmp3lame rejects 96 kHz; AAC needs planar `fltp`). When `true`,
98
+ * the encoder transparently converts each frame to the nearest supported
99
+ * sample rate / sample format / channel layout (like `ffmpeg`'s automatic
100
+ * `aresample`). When `false` (default), an unsupported input raises a descriptive
101
+ * error instead — keeping behaviour explicit and 1:1 with the codec.
102
+ *
103
+ * Has no effect on video.
104
+ *
105
+ * @default false
106
+ */
107
+ autoResample?: boolean;
93
108
  /**
94
109
  * Additional codec-specific options.
95
110
  *
96
- * Key-value pairs of FFmpeg AVCodecContext options.
97
- * These are passed directly to the encoder.
111
+ * Key-value pairs of FFmpeg private codec options, passed directly to the encoder.
112
+ * When the codec is created from a branded constant (e.g. `FF_ENCODER_LIBX264`),
113
+ * these are strongly typed to that codec's known options (autocomplete + validation);
114
+ * otherwise any string/number/boolean values are accepted.
98
115
  */
99
- options?: Record<string, string | number | boolean | undefined | null>;
116
+ options?: EncoderOptionsFor<C>;
100
117
  /**
101
118
  * AbortSignal for cancellation.
102
119
  *
@@ -172,6 +189,10 @@ export declare class Encoder implements Disposable {
172
189
  private opts?;
173
190
  private options;
174
191
  private audioFrameBuffer?;
192
+ private autoResample;
193
+ private audioResampler?;
194
+ private resampledFrame?;
195
+ private audioInputLayout?;
175
196
  private inputQueue;
176
197
  private outputQueue;
177
198
  private workerPromise;
@@ -243,7 +264,7 @@ export declare class Encoder implements Disposable {
243
264
  * @see {@link EncoderOptions} For configuration options
244
265
  * @see {@link createSync} For synchronous version
245
266
  */
246
- static create(encoderCodec: FFEncoderCodec | AVCodecID | Codec, options?: EncoderOptions): Promise<Encoder>;
267
+ static create<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, options?: EncoderOptions<C>): Promise<Encoder>;
247
268
  /**
248
269
  * Create an encoder with specified codec and options synchronously.
249
270
  * Synchronous version of create.
@@ -301,7 +322,65 @@ export declare class Encoder implements Disposable {
301
322
  * @see {@link EncoderOptions} For configuration options
302
323
  * @see {@link create} For async version
303
324
  */
304
- static createSync(encoderCodec: FFEncoderCodec | AVCodecID | Codec, options?: EncoderOptions): Encoder;
325
+ static createSync<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, options?: EncoderOptions<C>): Encoder;
326
+ /**
327
+ * Encode a single frame into a self-contained image buffer.
328
+ *
329
+ * One-shot, stateless helper for intra-only image codecs (MJPEG, PNG, WebP, ...).
330
+ * Creates a fresh encoder, encodes the frame, flushes and frees everything in one call.
331
+ * The encoder adopts dimensions, pixel format and hardware context from the frame,
332
+ * so any frame size works without reconfiguration.
333
+ *
334
+ * @param encoderCodec - Encoder codec (name, ID, branded constant, or Codec)
335
+ *
336
+ * @param frame - Frame to encode
337
+ *
338
+ * @param options - Optional encoder configuration (e.g. `{ options: { q: 3 } }` for MJPEG quality)
339
+ *
340
+ * @returns Encoded image bytes
341
+ *
342
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
343
+ *
344
+ * @throws {Error} If the encoder produced no output
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * const jpeg = await Encoder.encodeOne(FF_ENCODER_MJPEG, frame, { options: { q: 3 } });
349
+ * ```
350
+ *
351
+ * @see {@link EncoderPool} For reusing encoders across recurring resolutions
352
+ */
353
+ static encodeOne<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, frame: Frame, options?: EncoderOptions<C>): Promise<Buffer>;
354
+ /**
355
+ * Encode a single frame into a self-contained image buffer synchronously.
356
+ * Synchronous version of encodeOne.
357
+ *
358
+ * One-shot, stateless helper for intra-only image codecs (MJPEG, PNG, WebP, ...).
359
+ * Creates a fresh encoder, encodes the frame, flushes and frees everything in one call.
360
+ * The encoder adopts dimensions, pixel format and hardware context from the frame,
361
+ * so any frame size works without reconfiguration.
362
+ *
363
+ * @param encoderCodec - Encoder codec (name, ID, branded constant, or Codec)
364
+ *
365
+ * @param frame - Frame to encode
366
+ *
367
+ * @param options - Optional encoder configuration (e.g. `{ options: { q: 3 } }` for MJPEG quality)
368
+ *
369
+ * @returns Encoded image bytes
370
+ *
371
+ * @throws {FFmpegError} If the encoder is not found or encoding fails
372
+ *
373
+ * @throws {Error} If the encoder produced no output
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * const jpeg = Encoder.encodeOneSync(FF_ENCODER_MJPEG, frame, { options: { q: 3 } });
378
+ * ```
379
+ *
380
+ * @see {@link encodeOne} For async version
381
+ * @see {@link EncoderPool} For reusing encoders across recurring resolutions
382
+ */
383
+ static encodeOneSync<const C extends FFEncoderCodec | AVCodecID | Codec>(encoderCodec: C, frame: Frame, options?: EncoderOptions<C>): Buffer;
305
384
  /**
306
385
  * Check if encoder is open.
307
386
  *
@@ -1096,6 +1175,53 @@ export declare class Encoder implements Disposable {
1096
1175
  * @internal
1097
1176
  */
1098
1177
  private setupHardwareAcceleration;
1178
+ /**
1179
+ * Configure the codec context's audio parameters from the first frame.
1180
+ *
1181
+ * Audio encoders only accept specific sample rates / sample formats / channel
1182
+ * layouts. This picks codec-supported targets; if they differ from the input it
1183
+ * either sets up a resampler (when `autoResample`) or throws a descriptive error.
1184
+ *
1185
+ * @param frame - First audio frame
1186
+ *
1187
+ * @throws {Error} If the input is unsupported and `autoResample` is disabled
1188
+ *
1189
+ * @throws {FFmpegError} If the resampler fails to configure
1190
+ *
1191
+ * @internal
1192
+ */
1193
+ private setupAudioParams;
1194
+ /**
1195
+ * Lazily allocate the reused resampler output frame.
1196
+ *
1197
+ * @returns The allocated output frame
1198
+ *
1199
+ * @internal
1200
+ */
1201
+ private getResampleFrame;
1202
+ /**
1203
+ * Resample an incoming audio frame to the codec's target format.
1204
+ *
1205
+ * Reuses a single output frame; `swr_convert_frame` allocates/sizes its buffer.
1206
+ * The (fixed-frame-size) audio FIFO copies the samples and re-stamps PTS, so the
1207
+ * reused frame and its carried timing are only relevant on the non-FIFO path.
1208
+ *
1209
+ * @param frame - Source audio frame
1210
+ *
1211
+ * @returns The resampled frame (owned by the encoder, reused across calls)
1212
+ *
1213
+ * @internal
1214
+ */
1215
+ private resampleAudio;
1216
+ /**
1217
+ * Drain samples buffered inside the resampler (rate-conversion delay) into the
1218
+ * encoder path. Returns the drained frame if any, else null.
1219
+ *
1220
+ * @returns The drained frame (reused), or null when the resampler is empty
1221
+ *
1222
+ * @internal
1223
+ */
1224
+ private drainResampler;
1099
1225
  /**
1100
1226
  * Prepare frame for encoding.
1101
1227
  *