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,620 @@
|
|
|
1
|
+
import { AV_CODEC_FLAG_QSCALE, AV_HWDEVICE_TYPE_OPENCL, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE, AV_PIX_FMT_NV12, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_YUV420P, AVCOL_RANGE_JPEG, FF_QP2LAMBDA, SWS_BILINEAR, } from '../constants/constants.js';
|
|
2
|
+
import { FF_ENCODER_MJPEG, FF_ENCODER_PNG } from '../constants/encoders.js';
|
|
3
|
+
import { bindings } from '../lib/binding.js';
|
|
4
|
+
import { FFmpegError } from '../lib/error.js';
|
|
5
|
+
import { Frame } from '../lib/frame.js';
|
|
6
|
+
import { EncoderPool } from './encoder-pool.js';
|
|
7
|
+
import { FilterPreset } from './filter-presets.js';
|
|
8
|
+
import { FilterAPI } from './filter.js';
|
|
9
|
+
const FORMAT_TO_PIXFMT = {
|
|
10
|
+
rgb: AV_PIX_FMT_RGB24,
|
|
11
|
+
rgba: AV_PIX_FMT_RGBA,
|
|
12
|
+
gray: AV_PIX_FMT_GRAY8,
|
|
13
|
+
nv12: AV_PIX_FMT_NV12,
|
|
14
|
+
yuv420p: AV_PIX_FMT_YUV420P,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* High-level image scaler, cropper, and pixel-format converter.
|
|
18
|
+
*
|
|
19
|
+
* Scales, crops, and converts decoded frames to raw pixel buffers or encoded
|
|
20
|
+
* JPEG/PNG images. Built for the detection/thumbnail/snapshot workload: one
|
|
21
|
+
* instance pools its swscale contexts, GPU filter graphs, and encoders, so
|
|
22
|
+
* reusing it for every frame and every crop avoids per-frame allocation.
|
|
23
|
+
* Software frames are scaled with swscale; hardware frames are cropped, scaled,
|
|
24
|
+
* and converted on the GPU with only the small result downloaded.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { Scaler } from 'node-av/api';
|
|
29
|
+
*
|
|
30
|
+
* using scaler = new Scaler({ hardware });
|
|
31
|
+
*
|
|
32
|
+
* // Scale + convert to RGB (on the GPU for hardware frames)
|
|
33
|
+
* const rgb = await scaler.toBuffer(frame, { resize: { width: 640, height: 360 }, format: 'rgb' });
|
|
34
|
+
*
|
|
35
|
+
* // Crop a detected region and encode a snapshot
|
|
36
|
+
* const jpeg = await scaler.toJpeg(frame, { crop: { x, y, width: w, height: h }, quality: 85 });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @see {@link EncoderPool} For pooled image encoders
|
|
40
|
+
* @see {@link FilterAPI} For streaming filtergraphs
|
|
41
|
+
*/
|
|
42
|
+
export class Scaler {
|
|
43
|
+
native;
|
|
44
|
+
hardware;
|
|
45
|
+
flags;
|
|
46
|
+
maxCacheSize;
|
|
47
|
+
graphs = new Map();
|
|
48
|
+
jpegPool;
|
|
49
|
+
pngPool;
|
|
50
|
+
downloadFrame;
|
|
51
|
+
disposed = false;
|
|
52
|
+
/**
|
|
53
|
+
* Create a new scaler.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Scaler options
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* using scaler = new Scaler({ hardware: HardwareContext.auto() });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
constructor(options = {}) {
|
|
63
|
+
this.flags = options.flags ?? SWS_BILINEAR;
|
|
64
|
+
this.hardware = options.hardware;
|
|
65
|
+
this.maxCacheSize = options.maxCacheSize ?? 16;
|
|
66
|
+
this.native = new bindings.Scaler(this.flags);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Scale, crop, and/or convert a frame and return the raw pixel data.
|
|
70
|
+
*
|
|
71
|
+
* The returned buffer is tightly packed (no row padding). For planar formats
|
|
72
|
+
* (`nv12`, `yuv420p`) planes are concatenated.
|
|
73
|
+
*
|
|
74
|
+
* @param frame - Source frame (software or hardware; hardware frames are processed on the GPU and downloaded)
|
|
75
|
+
*
|
|
76
|
+
* @param options - Crop, resize, and format options
|
|
77
|
+
*
|
|
78
|
+
* @returns Tightly packed pixel data
|
|
79
|
+
*
|
|
80
|
+
* @throws {FFmpegError} If scaling fails
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const gray = await scaler.toBuffer(frame, { resize: { width: 320, height: 180 }, format: 'gray' });
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @see {@link toBufferSync} For synchronous version
|
|
88
|
+
*/
|
|
89
|
+
async toBuffer(frame, options = {}) {
|
|
90
|
+
if (this.disposed) {
|
|
91
|
+
throw new Error('Scaler has been disposed');
|
|
92
|
+
}
|
|
93
|
+
if (frame.isHwFrame()) {
|
|
94
|
+
// With a hardware context, crop/scale/convert on the GPU and download only
|
|
95
|
+
// the small result. Without one, fall back to downloading the full frame
|
|
96
|
+
// and processing it in software.
|
|
97
|
+
if (this.hardware) {
|
|
98
|
+
const out = await this.toFrame(frame, options.crop, options.resize, options.format ?? 'nv12');
|
|
99
|
+
try {
|
|
100
|
+
return out.toBuffer();
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
out.free();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return await this.native.process((await this.downloadToSoftware(frame)).getNative(), options);
|
|
107
|
+
}
|
|
108
|
+
return await this.native.process(frame.getNative(), options);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Scale, crop, and/or convert a frame and return the raw pixel data.
|
|
112
|
+
* Synchronous version of toBuffer.
|
|
113
|
+
*
|
|
114
|
+
* @param frame - Source frame (software or hardware; hardware frames are processed on the GPU and downloaded)
|
|
115
|
+
*
|
|
116
|
+
* @param options - Crop, resize, and format options
|
|
117
|
+
*
|
|
118
|
+
* @returns Tightly packed pixel data
|
|
119
|
+
*
|
|
120
|
+
* @throws {FFmpegError} If scaling fails
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const gray = scaler.toBufferSync(frame, { resize: { width: 320, height: 180 }, format: 'gray' });
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @see {@link toBuffer} For async version
|
|
128
|
+
*/
|
|
129
|
+
toBufferSync(frame, options = {}) {
|
|
130
|
+
if (this.disposed) {
|
|
131
|
+
throw new Error('Scaler has been disposed');
|
|
132
|
+
}
|
|
133
|
+
if (frame.isHwFrame()) {
|
|
134
|
+
if (this.hardware) {
|
|
135
|
+
const out = this.toFrameSync(frame, options.crop, options.resize, options.format ?? 'nv12');
|
|
136
|
+
try {
|
|
137
|
+
return out.toBuffer();
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
out.free();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return this.native.processSync(this.downloadToSoftwareSync(frame).getNative(), options);
|
|
144
|
+
}
|
|
145
|
+
return this.native.processSync(frame.getNative(), options);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Scale/crop a frame and encode it to a JPEG image.
|
|
149
|
+
*
|
|
150
|
+
* The encoder is pooled per output size and reused across calls - no encoder is
|
|
151
|
+
* rebuilt per snapshot. Hardware frames are scaled on the GPU and downloaded;
|
|
152
|
+
* software frames are scaled with swscale.
|
|
153
|
+
*
|
|
154
|
+
* @param frame - Source frame (software or hardware)
|
|
155
|
+
*
|
|
156
|
+
* @param options - Crop, resize, and quality options
|
|
157
|
+
*
|
|
158
|
+
* @returns Encoded JPEG bytes
|
|
159
|
+
*
|
|
160
|
+
* @throws {FFmpegError} If scaling or encoding fails
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* const jpeg = await scaler.toJpeg(frame, { resize: { width: 1280, height: 720 }, quality: 85 });
|
|
165
|
+
* await writeFile('snapshot.jpg', jpeg);
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @see {@link toJpegSync} For synchronous version
|
|
169
|
+
*/
|
|
170
|
+
async toJpeg(frame, options = {}) {
|
|
171
|
+
if (this.disposed) {
|
|
172
|
+
throw new Error('Scaler has been disposed');
|
|
173
|
+
}
|
|
174
|
+
const quality = options.quality ?? 90;
|
|
175
|
+
const src = frame.isHwFrame() && !this.hardware ? await this.downloadToSoftware(frame) : frame;
|
|
176
|
+
// mjpeg wants planar YUV; tag it full-range so colors are correct without the
|
|
177
|
+
// deprecated yuvj* formats.
|
|
178
|
+
const out = await this.toFrame(src, options.crop, options.resize, 'yuv420p');
|
|
179
|
+
try {
|
|
180
|
+
this.prepareJpegFrame(out, quality);
|
|
181
|
+
return await this.getJpegPool().encode(out);
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
out.free();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Scale/crop a frame and encode it to a JPEG image.
|
|
189
|
+
* Synchronous version of toJpeg.
|
|
190
|
+
*
|
|
191
|
+
* @param frame - Source frame (software or hardware)
|
|
192
|
+
*
|
|
193
|
+
* @param options - Crop, resize, and quality options
|
|
194
|
+
*
|
|
195
|
+
* @returns Encoded JPEG bytes
|
|
196
|
+
*
|
|
197
|
+
* @throws {FFmpegError} If scaling or encoding fails
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const jpeg = scaler.toJpegSync(frame, { resize: { width: 1280, height: 720 }, quality: 85 });
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @see {@link toJpeg} For async version
|
|
205
|
+
*/
|
|
206
|
+
toJpegSync(frame, options = {}) {
|
|
207
|
+
if (this.disposed) {
|
|
208
|
+
throw new Error('Scaler has been disposed');
|
|
209
|
+
}
|
|
210
|
+
const quality = options.quality ?? 90;
|
|
211
|
+
const src = frame.isHwFrame() && !this.hardware ? this.downloadToSoftwareSync(frame) : frame;
|
|
212
|
+
const out = this.toFrameSync(src, options.crop, options.resize, 'yuv420p');
|
|
213
|
+
try {
|
|
214
|
+
this.prepareJpegFrame(out, quality);
|
|
215
|
+
return this.getJpegPool().encodeSync(out);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
out.free();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Scale/crop a frame and encode it to a PNG image.
|
|
223
|
+
*
|
|
224
|
+
* The encoder is pooled per output size/format and reused across calls. Hardware
|
|
225
|
+
* frames are scaled on the GPU and downloaded; software frames use swscale.
|
|
226
|
+
*
|
|
227
|
+
* @param frame - Source frame (software or hardware)
|
|
228
|
+
*
|
|
229
|
+
* @param options - Crop, resize, and color-format options
|
|
230
|
+
*
|
|
231
|
+
* @returns Encoded PNG bytes
|
|
232
|
+
*
|
|
233
|
+
* @throws {FFmpegError} If scaling or encoding fails
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```typescript
|
|
237
|
+
* const png = await scaler.toPng(frame, { crop: { x, y, width: w, height: h } });
|
|
238
|
+
* await writeFile('region.png', png);
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @see {@link toPngSync} For synchronous version
|
|
242
|
+
*/
|
|
243
|
+
async toPng(frame, options = {}) {
|
|
244
|
+
if (this.disposed) {
|
|
245
|
+
throw new Error('Scaler has been disposed');
|
|
246
|
+
}
|
|
247
|
+
const format = options.format ?? 'rgb';
|
|
248
|
+
const src = frame.isHwFrame() && !this.hardware ? await this.downloadToSoftware(frame) : frame;
|
|
249
|
+
const out = await this.toFrame(src, options.crop, options.resize, format);
|
|
250
|
+
try {
|
|
251
|
+
return await this.getPngPool().encode(out);
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
out.free();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Scale/crop a frame and encode it to a PNG image.
|
|
259
|
+
* Synchronous version of toPng.
|
|
260
|
+
*
|
|
261
|
+
* @param frame - Source frame (software or hardware)
|
|
262
|
+
*
|
|
263
|
+
* @param options - Crop, resize, and color-format options
|
|
264
|
+
*
|
|
265
|
+
* @returns Encoded PNG bytes
|
|
266
|
+
*
|
|
267
|
+
* @throws {FFmpegError} If scaling or encoding fails
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* const png = scaler.toPngSync(frame, { crop: { x, y, width: w, height: h } });
|
|
272
|
+
* ```
|
|
273
|
+
*
|
|
274
|
+
* @see {@link toPng} For async version
|
|
275
|
+
*/
|
|
276
|
+
toPngSync(frame, options = {}) {
|
|
277
|
+
if (this.disposed) {
|
|
278
|
+
throw new Error('Scaler has been disposed');
|
|
279
|
+
}
|
|
280
|
+
const format = options.format ?? 'rgb';
|
|
281
|
+
const src = frame.isHwFrame() && !this.hardware ? this.downloadToSoftwareSync(frame) : frame;
|
|
282
|
+
const out = this.toFrameSync(src, options.crop, options.resize, format);
|
|
283
|
+
try {
|
|
284
|
+
return this.getPngPool().encodeSync(out);
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
out.free();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Release all pooled scaling contexts, graphs, and frames.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* scaler.close();
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
close() {
|
|
299
|
+
if (this.disposed) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.disposed = true;
|
|
303
|
+
this.native.close();
|
|
304
|
+
for (const entry of this.graphs.values()) {
|
|
305
|
+
entry.filter[Symbol.dispose]();
|
|
306
|
+
}
|
|
307
|
+
this.graphs.clear();
|
|
308
|
+
this.jpegPool?.close();
|
|
309
|
+
this.jpegPool = undefined;
|
|
310
|
+
this.pngPool?.close();
|
|
311
|
+
this.pngPool = undefined;
|
|
312
|
+
this.downloadFrame?.free();
|
|
313
|
+
this.downloadFrame = undefined;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Download a hardware frame to system memory (no hardware context available).
|
|
317
|
+
*
|
|
318
|
+
* Reuses a single target frame across calls. The frame's own hwframe context
|
|
319
|
+
* selects a supported software format.
|
|
320
|
+
*
|
|
321
|
+
* @param frame - Hardware source frame
|
|
322
|
+
*
|
|
323
|
+
* @returns Software frame
|
|
324
|
+
*
|
|
325
|
+
* @throws {FFmpegError} If the transfer fails
|
|
326
|
+
*
|
|
327
|
+
* @internal
|
|
328
|
+
*/
|
|
329
|
+
async downloadToSoftware(frame) {
|
|
330
|
+
const dst = this.prepareDownloadTarget();
|
|
331
|
+
const ret = await frame.hwframeTransferData(dst, 0);
|
|
332
|
+
FFmpegError.throwIfError(ret, 'Failed to download hardware frame');
|
|
333
|
+
dst.copyProps(frame);
|
|
334
|
+
return dst;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Synchronous version of downloadToSoftware.
|
|
338
|
+
*
|
|
339
|
+
* @param frame - Hardware source frame
|
|
340
|
+
*
|
|
341
|
+
* @returns Software frame
|
|
342
|
+
*
|
|
343
|
+
* @throws {FFmpegError} If the transfer fails
|
|
344
|
+
*
|
|
345
|
+
* @internal
|
|
346
|
+
*/
|
|
347
|
+
downloadToSoftwareSync(frame) {
|
|
348
|
+
const dst = this.prepareDownloadTarget();
|
|
349
|
+
const ret = frame.hwframeTransferDataSync(dst, 0);
|
|
350
|
+
FFmpegError.throwIfError(ret, 'Failed to download hardware frame');
|
|
351
|
+
dst.copyProps(frame);
|
|
352
|
+
return dst;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Lazily allocate and reset the reused download target frame.
|
|
356
|
+
*
|
|
357
|
+
* @returns The cleared download frame
|
|
358
|
+
*
|
|
359
|
+
* @internal
|
|
360
|
+
*/
|
|
361
|
+
prepareDownloadTarget() {
|
|
362
|
+
if (!this.downloadFrame) {
|
|
363
|
+
this.downloadFrame = new Frame();
|
|
364
|
+
this.downloadFrame.alloc();
|
|
365
|
+
}
|
|
366
|
+
const dst = this.downloadFrame;
|
|
367
|
+
dst.unref();
|
|
368
|
+
dst.format = AV_PIX_FMT_NONE;
|
|
369
|
+
return dst;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Scale/crop/convert a frame through a cached filter graph and return the
|
|
373
|
+
* resulting frame (caller must free it).
|
|
374
|
+
*
|
|
375
|
+
* Software frames are scaled with swscale filters; hardware frames are
|
|
376
|
+
* cropped/scaled/converted on the GPU and downloaded. The crop region is
|
|
377
|
+
* reconfigured per frame via a runtime command on a graph shared per output
|
|
378
|
+
* size (except OpenCL, where the crop is baked in).
|
|
379
|
+
*
|
|
380
|
+
* @param frame - Source frame (software, or hardware with a hardware context)
|
|
381
|
+
*
|
|
382
|
+
* @param crop - Crop region, or undefined for the full frame
|
|
383
|
+
*
|
|
384
|
+
* @param resize - Target dimensions, or undefined to keep the cropped size
|
|
385
|
+
*
|
|
386
|
+
* @param format - Output pixel format
|
|
387
|
+
*
|
|
388
|
+
* @returns The scaled output frame (caller frees)
|
|
389
|
+
*
|
|
390
|
+
* @throws {Error} If the crop is out of bounds or the graph produces no frame
|
|
391
|
+
*
|
|
392
|
+
* @internal
|
|
393
|
+
*/
|
|
394
|
+
async toFrame(frame, crop, resize, format) {
|
|
395
|
+
const entry = this.resolveGraph(frame, crop, resize, format);
|
|
396
|
+
await entry.filter.process(frame);
|
|
397
|
+
const out = await entry.filter.receive();
|
|
398
|
+
if (out == null) {
|
|
399
|
+
throw new Error('Scaler: filter produced no frame');
|
|
400
|
+
}
|
|
401
|
+
return out;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Synchronous version of toFrame.
|
|
405
|
+
*
|
|
406
|
+
* @param frame - Source frame (software, or hardware with a hardware context)
|
|
407
|
+
*
|
|
408
|
+
* @param crop - Crop region, or undefined for the full frame
|
|
409
|
+
*
|
|
410
|
+
* @param resize - Target dimensions, or undefined to keep the cropped size
|
|
411
|
+
*
|
|
412
|
+
* @param format - Output pixel format
|
|
413
|
+
*
|
|
414
|
+
* @returns The scaled output frame (caller frees)
|
|
415
|
+
*
|
|
416
|
+
* @internal
|
|
417
|
+
*/
|
|
418
|
+
toFrameSync(frame, crop, resize, format) {
|
|
419
|
+
const entry = this.resolveGraph(frame, crop, resize, format);
|
|
420
|
+
entry.filter.processSync(frame);
|
|
421
|
+
const out = entry.filter.receiveSync();
|
|
422
|
+
if (out == null) {
|
|
423
|
+
throw new Error('Scaler: filter produced no frame');
|
|
424
|
+
}
|
|
425
|
+
return out;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Resolve (and, on demand, build) the cached filter graph for a frame, applying
|
|
429
|
+
* the crop reconfiguration. Shared by the sync and async scaling paths; all of
|
|
430
|
+
* this work (parse, config, sendCommand) is synchronous.
|
|
431
|
+
*
|
|
432
|
+
* @param frame - Source frame (software, or hardware with a hardware context)
|
|
433
|
+
*
|
|
434
|
+
* @param crop - Crop region, or undefined for the full frame
|
|
435
|
+
*
|
|
436
|
+
* @param resize - Target dimensions, or undefined to keep the cropped size
|
|
437
|
+
*
|
|
438
|
+
* @param format - Output pixel format
|
|
439
|
+
*
|
|
440
|
+
* @returns The cached graph entry, ready to process the frame
|
|
441
|
+
*
|
|
442
|
+
* @throws {Error} If the crop is out of bounds
|
|
443
|
+
*
|
|
444
|
+
* @internal
|
|
445
|
+
*/
|
|
446
|
+
resolveGraph(frame, crop, resize, format) {
|
|
447
|
+
const isHw = frame.isHwFrame();
|
|
448
|
+
if (isHw && !this.hardware) {
|
|
449
|
+
throw new Error('Scaler received a hardware frame but was created without a HardwareContext');
|
|
450
|
+
}
|
|
451
|
+
const cropW = crop?.width ?? frame.width;
|
|
452
|
+
const cropH = crop?.height ?? frame.height;
|
|
453
|
+
const cropX = crop?.x ?? 0;
|
|
454
|
+
const cropY = crop?.y ?? 0;
|
|
455
|
+
if (cropX < 0 || cropY < 0 || cropW <= 0 || cropH <= 0 || cropX + cropW > frame.width || cropY + cropH > frame.height) {
|
|
456
|
+
throw new Error(`Scaler: crop region {x:${cropX}, y:${cropY}, width:${cropW}, height:${cropH}} is out of bounds for ${frame.width}x${frame.height} frame`);
|
|
457
|
+
}
|
|
458
|
+
const outW = resize?.width ?? cropW;
|
|
459
|
+
const outH = resize?.height ?? cropH;
|
|
460
|
+
// The standard `crop` filter is runtime-commandable for software frames and on
|
|
461
|
+
// every hardware backend except OpenCL (where crop is folded into scale_opencl).
|
|
462
|
+
// When commandable we share one graph per output size and re-aim the crop per
|
|
463
|
+
// frame; otherwise the crop is baked in and the key must include it.
|
|
464
|
+
const commandable = !isHw || this.hardware.deviceType !== AV_HWDEVICE_TYPE_OPENCL;
|
|
465
|
+
const prefix = isHw ? 'hw' : 'sw';
|
|
466
|
+
const key = commandable ? `${prefix}_${outW}x${outH}_${format}` : `${prefix}_${cropX},${cropY},${cropW},${cropH}->${outW}x${outH}_${format}`;
|
|
467
|
+
const cropRegion = { x: cropX, y: cropY, width: cropW, height: cropH };
|
|
468
|
+
let entry = this.graphs.get(key);
|
|
469
|
+
if (!entry) {
|
|
470
|
+
// Bake the first crop in as the graph default: the graph initializes lazily
|
|
471
|
+
// on the first processed frame, before any command can be sent, so the
|
|
472
|
+
// initial crop must already be in place. Later crops use sendCommand.
|
|
473
|
+
const filter = FilterAPI.create(this.buildGraph(isHw, outW, outH, format, cropRegion, commandable), isHw ? { hardware: this.hardware } : {});
|
|
474
|
+
entry = { filter, lastCrop: commandable ? { x: cropX, y: cropY, w: cropW, h: cropH } : null };
|
|
475
|
+
this.cacheSet(key, entry);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
// Bump LRU recency.
|
|
479
|
+
this.graphs.delete(key);
|
|
480
|
+
this.graphs.set(key, entry);
|
|
481
|
+
}
|
|
482
|
+
if (commandable) {
|
|
483
|
+
// Reconfigure the crop only when it actually changed - identical crops reuse
|
|
484
|
+
// the graph untouched (no config_input/config_output re-run).
|
|
485
|
+
const c = entry.lastCrop;
|
|
486
|
+
if (c?.x !== cropX || c?.y !== cropY || c?.w !== cropW || c?.h !== cropH) {
|
|
487
|
+
// w/h are validated against the input dims (above); x/y are clamped per
|
|
488
|
+
// frame by the crop filter, so this order never produces a transient error.
|
|
489
|
+
entry.filter.sendCommand('crop@sc', 'w', String(cropW));
|
|
490
|
+
entry.filter.sendCommand('crop@sc', 'h', String(cropH));
|
|
491
|
+
entry.filter.sendCommand('crop@sc', 'x', String(cropX));
|
|
492
|
+
entry.filter.sendCommand('crop@sc', 'y', String(cropY));
|
|
493
|
+
entry.lastCrop = { x: cropX, y: cropY, w: cropW, h: cropH };
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return entry;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Tag a frame for MJPEG encoding: full color range and a per-frame quality.
|
|
500
|
+
*
|
|
501
|
+
* MJPEG quality is carried on the frame (the encoder pool sets the QSCALE flag),
|
|
502
|
+
* so one pooled encoder serves every quality for a given output size.
|
|
503
|
+
*
|
|
504
|
+
* @param frame - Frame about to be JPEG-encoded
|
|
505
|
+
*
|
|
506
|
+
* @param quality - Quality from 1 (worst) to 100 (best)
|
|
507
|
+
*
|
|
508
|
+
* @internal
|
|
509
|
+
*/
|
|
510
|
+
prepareJpegFrame(frame, quality) {
|
|
511
|
+
frame.colorRange = AVCOL_RANGE_JPEG;
|
|
512
|
+
const q = Math.max(1, Math.min(100, quality));
|
|
513
|
+
const qscale = Math.max(2, Math.min(31, Math.round(2 + ((100 - q) / 99) * 29)));
|
|
514
|
+
frame.quality = qscale * FF_QP2LAMBDA;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* The lazily created MJPEG encoder pool (QSCALE flag set for per-frame quality).
|
|
518
|
+
*
|
|
519
|
+
* @returns The JPEG encoder pool
|
|
520
|
+
*
|
|
521
|
+
* @internal
|
|
522
|
+
*/
|
|
523
|
+
getJpegPool() {
|
|
524
|
+
this.jpegPool ??= new EncoderPool(FF_ENCODER_MJPEG, { maxSize: this.maxCacheSize, flags: AV_CODEC_FLAG_QSCALE });
|
|
525
|
+
return this.jpegPool;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* The lazily created PNG encoder pool.
|
|
529
|
+
*
|
|
530
|
+
* @returns The PNG encoder pool
|
|
531
|
+
*
|
|
532
|
+
* @internal
|
|
533
|
+
*/
|
|
534
|
+
getPngPool() {
|
|
535
|
+
this.pngPool ??= new EncoderPool(FF_ENCODER_PNG, { maxSize: this.maxCacheSize });
|
|
536
|
+
return this.pngPool;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Build a crop+scale+convert graph.
|
|
540
|
+
*
|
|
541
|
+
* For software frames this is `crop,scale,format`. For hardware frames the crop
|
|
542
|
+
* filter sets crop metadata that the hardware scaler (scale_vt/scale_cuda/
|
|
543
|
+
* scale_vaapi) applies on the GPU; the result is kept in NV12, downloaded, and
|
|
544
|
+
* converted on the CPU. When `commandable` the crop is a labeled instance
|
|
545
|
+
* (`crop@sc`) whose initial region is `crop` but which is re-aimed per frame via
|
|
546
|
+
* `sendCommand`. Otherwise (OpenCL) the crop is fixed in the graph.
|
|
547
|
+
*
|
|
548
|
+
* @param isHw - Whether the input is a hardware frame
|
|
549
|
+
*
|
|
550
|
+
* @param outW - Output width
|
|
551
|
+
*
|
|
552
|
+
* @param outH - Output height
|
|
553
|
+
*
|
|
554
|
+
* @param format - Output pixel format
|
|
555
|
+
*
|
|
556
|
+
* @param crop - Initial crop region
|
|
557
|
+
*
|
|
558
|
+
* @param commandable - Whether the crop can be reconfigured at runtime
|
|
559
|
+
*
|
|
560
|
+
* @returns Filtergraph description
|
|
561
|
+
*
|
|
562
|
+
* @internal
|
|
563
|
+
*/
|
|
564
|
+
buildGraph(isHw, outW, outH, format, crop, commandable) {
|
|
565
|
+
let chain = FilterPreset.chain(isHw ? this.hardware : undefined);
|
|
566
|
+
if (commandable) {
|
|
567
|
+
// Labeled crop so sendCommand('crop@sc', ...) can re-aim it per frame.
|
|
568
|
+
chain = chain.custom(`crop@sc=${crop.width}:${crop.height}:${crop.x}:${crop.y}`);
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
chain = chain.crop(crop.width, crop.height, crop.x, crop.y);
|
|
572
|
+
}
|
|
573
|
+
chain = chain.scale(outW, outH);
|
|
574
|
+
if (isHw) {
|
|
575
|
+
// Keep the GPU result in NV12, download the small frame, then convert on CPU.
|
|
576
|
+
chain = chain.scaleFormat(AV_PIX_FMT_NV12).hwdownload().format(AV_PIX_FMT_NV12);
|
|
577
|
+
if (format !== 'nv12') {
|
|
578
|
+
chain = chain.format(FORMAT_TO_PIXFMT[format]);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
chain = chain.format(FORMAT_TO_PIXFMT[format]);
|
|
583
|
+
}
|
|
584
|
+
return chain.build();
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Insert a graph, evicting the least-recently-used entry if over capacity.
|
|
588
|
+
*
|
|
589
|
+
* @param key - Operation-configuration key
|
|
590
|
+
*
|
|
591
|
+
* @param entry - Graph entry to cache
|
|
592
|
+
*
|
|
593
|
+
* @internal
|
|
594
|
+
*/
|
|
595
|
+
cacheSet(key, entry) {
|
|
596
|
+
this.graphs.set(key, entry);
|
|
597
|
+
while (this.graphs.size > this.maxCacheSize) {
|
|
598
|
+
const oldest = this.graphs.keys().next().value;
|
|
599
|
+
if (oldest === undefined) {
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
this.graphs.get(oldest)?.filter[Symbol.dispose]();
|
|
603
|
+
this.graphs.delete(oldest);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Dispose of the scaler (for `using` statements).
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```typescript
|
|
611
|
+
* using scaler = new Scaler();
|
|
612
|
+
* // ... use scaler ...
|
|
613
|
+
* // automatically disposed at end of scope
|
|
614
|
+
* ```
|
|
615
|
+
*/
|
|
616
|
+
[Symbol.dispose]() {
|
|
617
|
+
this.close();
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
//# sourceMappingURL=scaler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaler.js","sourceRoot":"","sources":["../../src/api/scaler.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,12 +25,17 @@ export declare class AsyncQueue<T> {
|
|
|
25
25
|
private maxSize;
|
|
26
26
|
private closed;
|
|
27
27
|
private error;
|
|
28
|
+
private disposeItem?;
|
|
28
29
|
/**
|
|
29
30
|
* Creates a new AsyncQueue.
|
|
30
31
|
*
|
|
31
32
|
* @param maxSize Maximum number of items in queue before send() blocks
|
|
33
|
+
*
|
|
34
|
+
* @param disposeItem Optional disposer for items still buffered at teardown
|
|
35
|
+
* (see {@link clear}). Pass `(item) => item.free()` for queues of owned
|
|
36
|
+
* native resources (Frame/Packet) so aborted pipelines don't leak them.
|
|
32
37
|
*/
|
|
33
|
-
constructor(maxSize: number);
|
|
38
|
+
constructor(maxSize: number, disposeItem?: (item: T) => void);
|
|
34
39
|
/**
|
|
35
40
|
* Current number of items in the queue.
|
|
36
41
|
*/
|
|
@@ -117,4 +122,25 @@ export declare class AsyncQueue<T> {
|
|
|
117
122
|
* ```
|
|
118
123
|
*/
|
|
119
124
|
closeWithError(error: Error): void;
|
|
125
|
+
/**
|
|
126
|
+
* Drop and dispose any items still buffered in the queue.
|
|
127
|
+
*
|
|
128
|
+
* Call during final teardown (a component's `close()`, after the worker and
|
|
129
|
+
* consumer tasks have settled) to deterministically free items that were
|
|
130
|
+
* produced but never consumed - e.g. when a pipeline is aborted before
|
|
131
|
+
* draining. Without this they are only reclaimed by GC, which for hardware
|
|
132
|
+
* frames pins GPU/hwframe memory in the meantime.
|
|
133
|
+
*
|
|
134
|
+
* Items are owned by the queue (the consumer frees what it receives), so
|
|
135
|
+
* disposing buffered items here cannot double-free. Do NOT call this while a
|
|
136
|
+
* consumer may still drain the queue after `close()` (the flush path relies on
|
|
137
|
+
* that) - only at final teardown.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* this.outputQueue.close();
|
|
142
|
+
* this.outputQueue.clear(); // free anything left behind on abort
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
clear(): void;
|
|
120
146
|
}
|