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.
- package/README.md +15 -1
- package/dist/api/bitstream-filter.d.ts +110 -87
- package/dist/api/bitstream-filter.js +162 -102
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +87 -8
- package/dist/api/decoder.js +179 -4
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/demuxer.d.ts +30 -24
- package/dist/api/demuxer.js +4 -5
- package/dist/api/demuxer.js.map +1 -1
- package/dist/api/device.js.map +1 -1
- package/dist/api/encoder-pool.d.ts +220 -0
- package/dist/api/encoder-pool.js +285 -0
- package/dist/api/encoder-pool.js.map +1 -0
- package/dist/api/encoder.d.ts +133 -7
- package/dist/api/encoder.js +392 -68
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-complex.d.ts +2 -1
- package/dist/api/filter-complex.js +11 -7
- package/dist/api/filter-complex.js.map +1 -1
- package/dist/api/filter-presets.d.ts +130 -654
- package/dist/api/filter-presets.js +180 -858
- package/dist/api/filter-presets.js.map +1 -1
- package/dist/api/filter.js +13 -8
- package/dist/api/filter.js.map +1 -1
- package/dist/api/fmp4-stream.js +1 -1
- package/dist/api/fmp4-stream.js.map +1 -1
- package/dist/api/index.d.ts +6 -6
- package/dist/api/index.js +8 -8
- package/dist/api/index.js.map +1 -1
- package/dist/api/muxer.d.ts +43 -15
- package/dist/api/muxer.js +79 -27
- package/dist/api/muxer.js.map +1 -1
- package/dist/api/pipeline.d.ts +50 -0
- package/dist/api/pipeline.js +138 -22
- package/dist/api/pipeline.js.map +1 -1
- package/dist/api/probe.d.ts +128 -0
- package/dist/api/probe.js +227 -0
- package/dist/api/probe.js.map +1 -0
- package/dist/api/rtp-stream.js +1 -1
- package/dist/api/rtp-stream.js.map +1 -1
- package/dist/api/scaler.d.ts +431 -0
- package/dist/api/scaler.js +620 -0
- package/dist/api/scaler.js.map +1 -0
- package/dist/api/utilities/async-queue.d.ts +27 -1
- package/dist/api/utilities/async-queue.js +38 -1
- package/dist/api/utilities/async-queue.js.map +1 -1
- package/dist/api/utilities/electron-shared-texture.d.ts +41 -1
- package/dist/api/utilities/electron-shared-texture.js +41 -4
- package/dist/api/utilities/electron-shared-texture.js.map +1 -1
- package/dist/api/utilities/index.d.ts +1 -1
- package/dist/api/utilities/index.js.map +1 -1
- package/dist/api/webrtc-stream.d.ts +0 -1
- package/dist/api/webrtc-stream.js +0 -1
- package/dist/api/webrtc-stream.js.map +1 -1
- package/dist/constants/bsf-options.d.ts +333 -0
- package/dist/constants/bsf-options.js +7 -0
- package/dist/constants/bsf-options.js.map +1 -0
- package/dist/constants/constants.d.ts +109 -0
- package/dist/constants/constants.js +110 -0
- package/dist/constants/constants.js.map +1 -1
- package/dist/constants/decoders.d.ts +636 -618
- package/dist/constants/decoders.js +1 -3
- package/dist/constants/decoders.js.map +1 -1
- package/dist/constants/encoders.d.ts +300 -282
- package/dist/constants/encoders.js +0 -2
- package/dist/constants/encoders.js.map +1 -1
- package/dist/constants/filter-options.d.ts +10915 -0
- package/dist/constants/filter-options.js +7 -0
- package/dist/constants/filter-options.js.map +1 -0
- package/dist/constants/format-options.d.ts +3056 -0
- package/dist/constants/format-options.js +7 -0
- package/dist/constants/format-options.js.map +1 -0
- package/dist/constants/formats.d.ts +18 -0
- package/dist/constants/formats.js +7 -0
- package/dist/constants/formats.js.map +1 -0
- package/dist/constants/index.d.ts +5 -0
- package/dist/constants/options.d.ts +4073 -0
- package/dist/constants/options.js +7 -0
- package/dist/constants/options.js.map +1 -0
- package/dist/lib/binding.d.ts +4 -1
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/codec.d.ts +36 -5
- package/dist/lib/codec.js +37 -4
- package/dist/lib/codec.js.map +1 -1
- package/dist/lib/dictionary.d.ts +1 -1
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.d.ts +69 -0
- package/dist/lib/error.js +92 -0
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/frame.d.ts +46 -3
- package/dist/lib/frame.js +50 -3
- package/dist/lib/frame.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/native-types.d.ts +68 -0
- package/dist/lib/packet.d.ts +17 -3
- package/dist/lib/packet.js +19 -3
- package/dist/lib/packet.js.map +1 -1
- package/dist/lib/utilities.d.ts +21 -0
- package/dist/lib/utilities.js +23 -0
- package/dist/lib/utilities.js.map +1 -1
- package/dist/webrtc/index.d.ts +3 -0
- package/dist/webrtc/index.js +7 -0
- package/dist/webrtc/index.js.map +1 -0
- 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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"}
|
package/dist/api/encoder.d.ts
CHANGED
|
@@ -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
|
|
97
|
-
*
|
|
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?:
|
|
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
|
|
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
|
|
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
|
*
|