node-av 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -59
- package/dist/api/bitstream-filter.d.ts +183 -123
- package/dist/api/bitstream-filter.js +185 -127
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +282 -130
- package/dist/api/decoder.js +290 -142
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/encoder.d.ts +249 -160
- package/dist/api/encoder.js +276 -207
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-presets.d.ts +1944 -96
- package/dist/api/filter-presets.js +2059 -105
- package/dist/api/filter-presets.js.map +1 -1
- package/dist/api/filter.d.ts +264 -200
- package/dist/api/filter.js +269 -231
- package/dist/api/filter.js.map +1 -1
- package/dist/api/hardware.d.ts +246 -117
- package/dist/api/hardware.js +440 -217
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/index.d.ts +3 -3
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/io-stream.d.ts +65 -55
- package/dist/api/io-stream.js +43 -40
- package/dist/api/io-stream.js.map +1 -1
- package/dist/api/media-input.d.ts +242 -139
- package/dist/api/media-input.js +205 -103
- package/dist/api/media-input.js.map +1 -1
- package/dist/api/media-output.d.ts +208 -126
- package/dist/api/media-output.js +212 -126
- package/dist/api/media-output.js.map +1 -1
- package/dist/api/pipeline.d.ts +361 -38
- package/dist/api/pipeline.js +255 -14
- package/dist/api/pipeline.js.map +1 -1
- package/dist/api/types.d.ts +26 -187
- package/dist/api/utilities/audio-sample.d.ts +0 -8
- package/dist/api/utilities/audio-sample.js +0 -8
- package/dist/api/utilities/audio-sample.js.map +1 -1
- package/dist/api/utilities/channel-layout.d.ts +0 -8
- package/dist/api/utilities/channel-layout.js +0 -8
- package/dist/api/utilities/channel-layout.js.map +1 -1
- package/dist/api/utilities/image.d.ts +0 -8
- package/dist/api/utilities/image.js +0 -8
- package/dist/api/utilities/image.js.map +1 -1
- package/dist/api/utilities/index.d.ts +3 -3
- package/dist/api/utilities/index.js +3 -3
- package/dist/api/utilities/index.js.map +1 -1
- package/dist/api/utilities/media-type.d.ts +1 -9
- package/dist/api/utilities/media-type.js +1 -9
- package/dist/api/utilities/media-type.js.map +1 -1
- package/dist/api/utilities/pixel-format.d.ts +1 -9
- package/dist/api/utilities/pixel-format.js +1 -9
- package/dist/api/utilities/pixel-format.js.map +1 -1
- package/dist/api/utilities/sample-format.d.ts +1 -9
- package/dist/api/utilities/sample-format.js +1 -9
- package/dist/api/utilities/sample-format.js.map +1 -1
- package/dist/api/utilities/streaming.d.ts +0 -8
- package/dist/api/utilities/streaming.js +0 -8
- package/dist/api/utilities/streaming.js.map +1 -1
- package/dist/api/utilities/timestamp.d.ts +0 -8
- package/dist/api/utilities/timestamp.js +0 -8
- package/dist/api/utilities/timestamp.js.map +1 -1
- package/dist/api/utils.d.ts +1 -2
- package/dist/api/utils.js +11 -0
- package/dist/api/utils.js.map +1 -1
- package/dist/constants/constants.d.ts +1 -1
- package/dist/constants/constants.js +2 -0
- package/dist/constants/constants.js.map +1 -1
- package/dist/lib/audio-fifo.d.ts +127 -170
- package/dist/lib/audio-fifo.js +130 -173
- package/dist/lib/audio-fifo.js.map +1 -1
- package/dist/lib/binding.d.ts +1 -0
- package/dist/lib/binding.js +7 -0
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/bitstream-filter-context.d.ts +139 -184
- package/dist/lib/bitstream-filter-context.js +139 -188
- package/dist/lib/bitstream-filter-context.js.map +1 -1
- package/dist/lib/bitstream-filter.d.ts +68 -54
- package/dist/lib/bitstream-filter.js +68 -54
- package/dist/lib/bitstream-filter.js.map +1 -1
- package/dist/lib/codec-context.d.ts +316 -380
- package/dist/lib/codec-context.js +316 -381
- package/dist/lib/codec-context.js.map +1 -1
- package/dist/lib/codec-parameters.d.ts +160 -170
- package/dist/lib/codec-parameters.js +162 -172
- package/dist/lib/codec-parameters.js.map +1 -1
- package/dist/lib/codec-parser.d.ts +91 -104
- package/dist/lib/codec-parser.js +92 -103
- package/dist/lib/codec-parser.js.map +1 -1
- package/dist/lib/codec.d.ts +266 -283
- package/dist/lib/codec.js +270 -287
- package/dist/lib/codec.js.map +1 -1
- package/dist/lib/dictionary.d.ts +149 -203
- package/dist/lib/dictionary.js +158 -212
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.d.ts +96 -130
- package/dist/lib/error.js +98 -128
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/filter-context.d.ts +284 -218
- package/dist/lib/filter-context.js +290 -227
- package/dist/lib/filter-context.js.map +1 -1
- package/dist/lib/filter-graph.d.ts +251 -292
- package/dist/lib/filter-graph.js +253 -294
- package/dist/lib/filter-graph.js.map +1 -1
- package/dist/lib/filter-inout.d.ts +87 -95
- package/dist/lib/filter-inout.js +87 -95
- package/dist/lib/filter-inout.js.map +1 -1
- package/dist/lib/filter.d.ts +93 -111
- package/dist/lib/filter.js +93 -111
- package/dist/lib/filter.js.map +1 -1
- package/dist/lib/format-context.d.ts +320 -428
- package/dist/lib/format-context.js +313 -385
- package/dist/lib/format-context.js.map +1 -1
- package/dist/lib/frame.d.ts +262 -405
- package/dist/lib/frame.js +263 -408
- package/dist/lib/frame.js.map +1 -1
- package/dist/lib/hardware-device-context.d.ts +149 -203
- package/dist/lib/hardware-device-context.js +149 -203
- package/dist/lib/hardware-device-context.js.map +1 -1
- package/dist/lib/hardware-frames-context.d.ts +170 -180
- package/dist/lib/hardware-frames-context.js +171 -181
- package/dist/lib/hardware-frames-context.js.map +1 -1
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.js +3 -3
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/input-format.d.ts +89 -117
- package/dist/lib/input-format.js +89 -117
- package/dist/lib/input-format.js.map +1 -1
- package/dist/lib/io-context.d.ts +209 -241
- package/dist/lib/io-context.js +220 -252
- package/dist/lib/io-context.js.map +1 -1
- package/dist/lib/log.d.ts +85 -119
- package/dist/lib/log.js +85 -122
- package/dist/lib/log.js.map +1 -1
- package/dist/lib/native-types.d.ts +118 -106
- package/dist/lib/native-types.js +0 -7
- package/dist/lib/native-types.js.map +1 -1
- package/dist/lib/option.d.ts +437 -218
- package/dist/lib/option.js +462 -226
- package/dist/lib/option.js.map +1 -1
- package/dist/lib/output-format.d.ts +77 -101
- package/dist/lib/output-format.js +77 -101
- package/dist/lib/output-format.js.map +1 -1
- package/dist/lib/packet.d.ts +172 -240
- package/dist/lib/packet.js +172 -241
- package/dist/lib/packet.js.map +1 -1
- package/dist/lib/rational.d.ts +0 -2
- package/dist/lib/rational.js +0 -2
- package/dist/lib/rational.js.map +1 -1
- package/dist/lib/software-resample-context.d.ts +241 -325
- package/dist/lib/software-resample-context.js +242 -326
- package/dist/lib/software-resample-context.js.map +1 -1
- package/dist/lib/software-scale-context.d.ts +129 -173
- package/dist/lib/software-scale-context.js +131 -175
- package/dist/lib/software-scale-context.js.map +1 -1
- package/dist/lib/stream.d.ts +87 -197
- package/dist/lib/stream.js +87 -197
- package/dist/lib/stream.js.map +1 -1
- package/dist/lib/utilities.d.ts +435 -181
- package/dist/lib/utilities.js +438 -182
- package/dist/lib/utilities.js.map +1 -1
- package/install/check.js +0 -1
- package/install/ffmpeg.js +0 -11
- package/package.json +25 -18
- package/release_notes.md +24 -59
- package/CHANGELOG.md +0 -8
|
@@ -1,25 +1,41 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FilterPresets - Pre-defined filter configurations
|
|
3
|
-
*
|
|
4
|
-
* Provides convenient filter string builders for common operations.
|
|
5
|
-
* Includes both software and hardware-accelerated filter presets.
|
|
6
|
-
*
|
|
7
|
-
* Simplifies filter creation with type-safe parameter handling.
|
|
8
|
-
* Supports platform-specific hardware acceleration capabilities.
|
|
9
|
-
*
|
|
10
|
-
* @module api/filter-presets
|
|
11
|
-
*/
|
|
12
1
|
import { AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_D3D12VA, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_MEDIACODEC, AV_HWDEVICE_TYPE_OPENCL, AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_RKMPP, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VULKAN, AVFILTER_FLAG_HWDEVICE, } from '../constants/constants.js';
|
|
13
2
|
import { Filter } from '../lib/filter.js';
|
|
3
|
+
import { HardwareDeviceContext } from '../lib/hardware-device-context.js';
|
|
14
4
|
import { avGetPixFmtName, avGetSampleFmtName } from '../lib/utilities.js';
|
|
15
5
|
/**
|
|
16
6
|
* Base class for filter preset implementations.
|
|
17
|
-
* Provides common filter building methods that can be overridden.
|
|
7
|
+
* Provides common filter building methods that can be overridden by hardware-specific implementations.
|
|
8
|
+
*
|
|
9
|
+
* This class defines the standard filter operations available in FFmpeg,
|
|
10
|
+
* with each method returning a filter string that can be used in a filter graph.
|
|
11
|
+
* Hardware-specific implementations may override these methods to use optimized
|
|
12
|
+
* hardware filters instead of software implementations.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* class CustomPresets extends FilterPresetBase {
|
|
17
|
+
* override scale(width: number, height: number): string | null {
|
|
18
|
+
* return `custom_scale=${width}:${height}`;
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
18
22
|
*/
|
|
19
23
|
export class FilterPresetBase {
|
|
20
24
|
/**
|
|
21
|
-
*
|
|
25
|
+
* Creates a scale filter string.
|
|
26
|
+
*
|
|
27
|
+
* @param width - Target width in pixels
|
|
28
|
+
* @param height - Target height in pixels
|
|
29
|
+
* @param options - Additional scaling options (e.g., flags for algorithm)
|
|
22
30
|
* @returns Filter string or null if not supported
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* presets.scale(1920, 1080) // Scale to Full HD
|
|
35
|
+
* presets.scale(640, 480, { flags: 'lanczos' }) // With specific algorithm
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#scale | FFmpeg scale filter}
|
|
23
39
|
*/
|
|
24
40
|
scale(width, height, options) {
|
|
25
41
|
const flags = options?.flags;
|
|
@@ -27,21 +43,59 @@ export class FilterPresetBase {
|
|
|
27
43
|
return flags ? `${base}:flags=${flags}` : base;
|
|
28
44
|
}
|
|
29
45
|
/**
|
|
30
|
-
*
|
|
46
|
+
* Creates a crop filter string.
|
|
47
|
+
*
|
|
48
|
+
* @param width - Width of the cropped area
|
|
49
|
+
* @param height - Height of the cropped area
|
|
50
|
+
* @param x - X coordinate of top-left corner (default: 0)
|
|
51
|
+
* @param y - Y coordinate of top-left corner (default: 0)
|
|
52
|
+
* @returns Filter string or null if not supported
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* presets.crop(640, 480, 100, 100) // Crop 640x480 area starting at (100,100)
|
|
57
|
+
* presets.crop(1280, 720) // Crop from top-left corner
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#crop | FFmpeg crop filter}
|
|
31
61
|
*/
|
|
32
62
|
crop(width, height, x = 0, y = 0) {
|
|
33
63
|
return `crop=${width}:${height}:${x}:${y}`;
|
|
34
64
|
}
|
|
35
65
|
/**
|
|
36
|
-
*
|
|
66
|
+
* Creates an FPS filter string to change frame rate.
|
|
67
|
+
*
|
|
68
|
+
* @param fps - Target frames per second
|
|
69
|
+
* @returns Filter string or null if not supported
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* presets.fps(30) // Convert to 30 FPS
|
|
74
|
+
* presets.fps(23.976) // Film frame rate
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#fps | FFmpeg fps filter}
|
|
37
78
|
*/
|
|
38
79
|
fps(fps) {
|
|
39
80
|
return `fps=${fps}`;
|
|
40
81
|
}
|
|
41
82
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
83
|
+
* Creates a format filter string to convert pixel format.
|
|
84
|
+
*
|
|
85
|
+
* @param pixelFormat - Target pixel format(s) - can be string, AVPixelFormat enum, or array
|
|
86
|
+
* @returns Filter string or null if not supported
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Single format
|
|
91
|
+
* presets.format('yuv420p');
|
|
92
|
+
* presets.format(AV_PIX_FMT_YUV420P);
|
|
93
|
+
*
|
|
94
|
+
* // Multiple formats (creates a chain)
|
|
95
|
+
* presets.format(['yuv420p', 'rgb24']);
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#format | FFmpeg format filter}
|
|
45
99
|
*/
|
|
46
100
|
format(pixelFormat) {
|
|
47
101
|
if (Array.isArray(pixelFormat)) {
|
|
@@ -56,31 +110,89 @@ export class FilterPresetBase {
|
|
|
56
110
|
return `format=${formatName}`;
|
|
57
111
|
}
|
|
58
112
|
/**
|
|
59
|
-
*
|
|
113
|
+
* Creates a rotate filter string.
|
|
114
|
+
*
|
|
115
|
+
* @param angle - Rotation angle in degrees
|
|
116
|
+
* @returns Filter string or null if not supported
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* presets.rotate(90) // Rotate 90 degrees clockwise
|
|
121
|
+
* presets.rotate(-45) // Rotate 45 degrees counter-clockwise
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#rotate | FFmpeg rotate filter}
|
|
60
125
|
*/
|
|
61
126
|
rotate(angle) {
|
|
62
127
|
return `rotate=${angle}*PI/180`;
|
|
63
128
|
}
|
|
64
129
|
/**
|
|
65
|
-
*
|
|
130
|
+
* Creates a horizontal flip filter string.
|
|
131
|
+
*
|
|
132
|
+
* @returns Filter string or null if not supported
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* presets.hflip() // Mirror horizontally
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#hflip | FFmpeg hflip filter}
|
|
66
140
|
*/
|
|
67
141
|
hflip() {
|
|
68
142
|
return 'hflip';
|
|
69
143
|
}
|
|
70
144
|
/**
|
|
71
|
-
*
|
|
145
|
+
* Creates a vertical flip filter string.
|
|
146
|
+
*
|
|
147
|
+
* @returns Filter string or null if not supported
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* presets.vflip() // Flip upside down
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#vflip | FFmpeg vflip filter}
|
|
72
155
|
*/
|
|
73
156
|
vflip() {
|
|
74
157
|
return 'vflip';
|
|
75
158
|
}
|
|
76
159
|
/**
|
|
77
|
-
*
|
|
160
|
+
* Creates a fade filter string for video.
|
|
161
|
+
*
|
|
162
|
+
* @param type - Fade type ('in' or 'out')
|
|
163
|
+
* @param start - Start time in seconds
|
|
164
|
+
* @param duration - Fade duration in seconds
|
|
165
|
+
* @returns Filter string or null if not supported
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* presets.fade('in', 0, 2) // 2-second fade in from start
|
|
170
|
+
* presets.fade('out', 10, 1) // 1-second fade out at 10 seconds
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#fade | FFmpeg fade filter}
|
|
78
174
|
*/
|
|
79
175
|
fade(type, start, duration) {
|
|
80
176
|
return `fade=t=${type}:st=${start}:d=${duration}`;
|
|
81
177
|
}
|
|
82
178
|
/**
|
|
83
|
-
*
|
|
179
|
+
* Creates an overlay filter string to composite two video streams.
|
|
180
|
+
*
|
|
181
|
+
* @param x - X position for overlay (default: 0)
|
|
182
|
+
* @param y - Y position for overlay (default: 0)
|
|
183
|
+
* @param options - Additional overlay options
|
|
184
|
+
* @returns Filter string or null if not supported
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* // Basic overlay at position
|
|
189
|
+
* presets.overlay(100, 50);
|
|
190
|
+
*
|
|
191
|
+
* // With additional options
|
|
192
|
+
* presets.overlay(0, 0, { format: 'yuv420' });
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#overlay | FFmpeg overlay filter}
|
|
84
196
|
*/
|
|
85
197
|
overlay(x = 0, y = 0, options) {
|
|
86
198
|
let filter = `overlay=${x}:${y}`;
|
|
@@ -92,13 +204,43 @@ export class FilterPresetBase {
|
|
|
92
204
|
return filter;
|
|
93
205
|
}
|
|
94
206
|
/**
|
|
95
|
-
*
|
|
207
|
+
* Creates a volume filter string for audio.
|
|
208
|
+
*
|
|
209
|
+
* @param factor - Volume multiplication factor (1.0 = unchanged, 2.0 = double)
|
|
210
|
+
* @returns Filter string or null if not supported
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* presets.volume(0.5) // Reduce volume by 50%
|
|
215
|
+
* presets.volume(1.5) // Increase volume by 50%
|
|
216
|
+
* ```
|
|
217
|
+
*
|
|
218
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#volume | FFmpeg volume filter}
|
|
96
219
|
*/
|
|
97
220
|
volume(factor) {
|
|
98
221
|
return `volume=${factor}`;
|
|
99
222
|
}
|
|
100
223
|
/**
|
|
101
|
-
*
|
|
224
|
+
* Creates an audio format filter string.
|
|
225
|
+
*
|
|
226
|
+
* @param sampleFormat - Target sample format (e.g., 's16', 'fltp')
|
|
227
|
+
* @param sampleRate - Target sample rate in Hz (optional)
|
|
228
|
+
* @param channelLayout - Target channel layout (optional)
|
|
229
|
+
* @returns Filter string or null if not supported
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* // Change sample format only
|
|
234
|
+
* presets.aformat('s16');
|
|
235
|
+
*
|
|
236
|
+
* // Change format and sample rate
|
|
237
|
+
* presets.aformat('fltp', 48000);
|
|
238
|
+
*
|
|
239
|
+
* // Full conversion
|
|
240
|
+
* presets.aformat('s16', 44100, 'stereo');
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#aformat | FFmpeg aformat filter}
|
|
102
244
|
*/
|
|
103
245
|
aformat(sampleFormat, sampleRate, channelLayout) {
|
|
104
246
|
const formatName = typeof sampleFormat === 'string' ? sampleFormat : (avGetSampleFmtName(sampleFormat) ?? 's16');
|
|
@@ -110,33 +252,453 @@ export class FilterPresetBase {
|
|
|
110
252
|
return filter;
|
|
111
253
|
}
|
|
112
254
|
/**
|
|
113
|
-
*
|
|
255
|
+
* Creates an asetnsamples filter string to set the number of samples per frame.
|
|
256
|
+
* This is crucial for encoders like Opus that require specific frame sizes.
|
|
257
|
+
*
|
|
258
|
+
* @param samples - Number of samples per frame
|
|
259
|
+
* @param padding - Whether to pad or drop samples (default: true)
|
|
260
|
+
* @returns Filter string or null if not supported
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* // For Opus encoder (requires 960 samples)
|
|
265
|
+
* presets.asetnsamples(960);
|
|
266
|
+
*
|
|
267
|
+
* // Drop samples instead of padding
|
|
268
|
+
* presets.asetnsamples(1024, false);
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#asetnsamples | FFmpeg asetnsamples filter}
|
|
272
|
+
*/
|
|
273
|
+
asetnsamples(samples, padding = true) {
|
|
274
|
+
const p = padding ? 1 : 0;
|
|
275
|
+
return `asetnsamples=n=${samples}:p=${p}`;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Creates an atempo filter string to change audio playback speed.
|
|
279
|
+
* Factor must be between 0.5 and 2.0. For larger changes, chain multiple atempo filters.
|
|
280
|
+
*
|
|
281
|
+
* @param factor - Tempo factor (0.5 = half speed, 2.0 = double speed)
|
|
282
|
+
* @returns Filter string or null if not supported
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* presets.atempo(1.5) // 1.5x speed
|
|
287
|
+
* presets.atempo(0.8) // Slow down to 80% speed
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#atempo | FFmpeg atempo filter}
|
|
114
291
|
*/
|
|
115
292
|
atempo(factor) {
|
|
116
293
|
return `atempo=${factor}`;
|
|
117
294
|
}
|
|
118
295
|
/**
|
|
119
|
-
*
|
|
296
|
+
* Creates an audio fade filter string.
|
|
297
|
+
*
|
|
298
|
+
* @param type - Fade type ('in' or 'out')
|
|
299
|
+
* @param start - Start time in seconds
|
|
300
|
+
* @param duration - Fade duration in seconds
|
|
301
|
+
* @returns Filter string or null if not supported
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* presets.afade('in', 0, 3) // 3-second audio fade in
|
|
306
|
+
* presets.afade('out', 20, 2) // 2-second fade out at 20s
|
|
307
|
+
* ```
|
|
308
|
+
*
|
|
309
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#afade | FFmpeg afade filter}
|
|
120
310
|
*/
|
|
121
311
|
afade(type, start, duration) {
|
|
122
312
|
return `afade=t=${type}:st=${start}:d=${duration}`;
|
|
123
313
|
}
|
|
124
314
|
/**
|
|
125
|
-
*
|
|
315
|
+
* Creates an amix filter string to mix multiple audio streams.
|
|
316
|
+
*
|
|
317
|
+
* @param inputs - Number of input streams to mix (default: 2)
|
|
318
|
+
* @param duration - How to determine output duration (default: 'longest')
|
|
319
|
+
* @returns Filter string or null if not supported
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* presets.amix(3, 'longest') // Mix 3 audio streams
|
|
324
|
+
* presets.amix(2, 'first') // Mix 2 streams, use first's duration
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#amix | FFmpeg amix filter}
|
|
126
328
|
*/
|
|
127
329
|
amix(inputs = 2, duration = 'longest') {
|
|
128
330
|
return `amix=inputs=${inputs}:duration=${duration}`;
|
|
129
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Creates a pad filter string to add padding to video.
|
|
334
|
+
* Essential for aspect ratio adjustments and letterboxing.
|
|
335
|
+
*
|
|
336
|
+
* @param width - Output width (can use expressions like 'iw+100')
|
|
337
|
+
* @param height - Output height (can use expressions like 'ih+100')
|
|
338
|
+
* @param x - X position of input video (default: '(ow-iw)/2' for center)
|
|
339
|
+
* @param y - Y position of input video (default: '(oh-ih)/2' for center)
|
|
340
|
+
* @param color - Padding color (default: 'black')
|
|
341
|
+
* @returns Filter string or null if not supported
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* // Add black bars for 16:9 aspect ratio
|
|
346
|
+
* presets.pad('iw', 'iw*9/16');
|
|
347
|
+
*
|
|
348
|
+
* // Add 50px padding on all sides
|
|
349
|
+
* presets.pad('iw+100', 'ih+100');
|
|
350
|
+
* ```
|
|
351
|
+
*
|
|
352
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#pad | FFmpeg pad filter}
|
|
353
|
+
*/
|
|
354
|
+
pad(width, height, x, y, color = 'black') {
|
|
355
|
+
let filter = `pad=${width}:${height}`;
|
|
356
|
+
if (x !== undefined)
|
|
357
|
+
filter += `:${x}`;
|
|
358
|
+
if (y !== undefined)
|
|
359
|
+
filter += `:${y}`;
|
|
360
|
+
filter += `:${color}`;
|
|
361
|
+
return filter;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Creates a trim filter string to cut a portion of the stream.
|
|
365
|
+
* Crucial for cutting segments from media.
|
|
366
|
+
*
|
|
367
|
+
* @param start - Start time in seconds
|
|
368
|
+
* @param end - End time in seconds (optional)
|
|
369
|
+
* @param duration - Duration in seconds (optional, alternative to end)
|
|
370
|
+
* @returns Filter string or null if not supported
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* presets.trim(10, 30) // Extract from 10s to 30s
|
|
375
|
+
* presets.trim(5, undefined, 10) // Extract 10s starting at 5s
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#trim | FFmpeg trim filter}
|
|
379
|
+
*/
|
|
380
|
+
trim(start, end, duration) {
|
|
381
|
+
let filter = `trim=start=${start}`;
|
|
382
|
+
if (end !== undefined)
|
|
383
|
+
filter += `:end=${end}`;
|
|
384
|
+
if (duration !== undefined)
|
|
385
|
+
filter += `:duration=${duration}`;
|
|
386
|
+
return filter;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Creates a setpts filter string to change presentation timestamps.
|
|
390
|
+
* Essential for speed changes and timestamp manipulation.
|
|
391
|
+
*
|
|
392
|
+
* @param expression - PTS expression (e.g., 'PTS*2' for half speed, 'PTS/2' for double speed)
|
|
393
|
+
* @returns Filter string or null if not supported
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* ```typescript
|
|
397
|
+
* // Double speed
|
|
398
|
+
* presets.setpts('PTS/2');
|
|
399
|
+
*
|
|
400
|
+
* // Half speed
|
|
401
|
+
* presets.setpts('PTS*2');
|
|
402
|
+
*
|
|
403
|
+
* // Reset timestamps
|
|
404
|
+
* presets.setpts('PTS-STARTPTS');
|
|
405
|
+
* ```
|
|
406
|
+
*
|
|
407
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#setpts | FFmpeg setpts filter}
|
|
408
|
+
*/
|
|
409
|
+
setpts(expression) {
|
|
410
|
+
return `setpts=${expression}`;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Creates an asetpts filter string for audio timestamp manipulation.
|
|
414
|
+
*
|
|
415
|
+
* @param expression - PTS expression
|
|
416
|
+
* @returns Filter string or null if not supported
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* presets.asetpts('PTS-STARTPTS') // Reset timestamps to start from 0
|
|
421
|
+
* ```
|
|
422
|
+
*
|
|
423
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#asetpts | FFmpeg asetpts filter}
|
|
424
|
+
*/
|
|
425
|
+
asetpts(expression) {
|
|
426
|
+
return `asetpts=${expression}`;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Creates a transpose filter string for rotation/flipping.
|
|
430
|
+
* More efficient than rotate for 90-degree rotations.
|
|
431
|
+
*
|
|
432
|
+
* @param mode - Transpose mode (0-3, or named constants)
|
|
433
|
+
* @returns Filter string or null if not supported
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```typescript
|
|
437
|
+
* presets.transpose(1) // Rotate 90 degrees clockwise
|
|
438
|
+
* presets.transpose('cclock') // Rotate 90 degrees counter-clockwise
|
|
439
|
+
* ```
|
|
440
|
+
*
|
|
441
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#transpose | FFmpeg transpose filter}
|
|
442
|
+
*/
|
|
443
|
+
transpose(mode) {
|
|
444
|
+
return `transpose=${mode}`;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Creates a setsar filter string to set sample aspect ratio.
|
|
448
|
+
* Important for correcting aspect ratio issues.
|
|
449
|
+
*
|
|
450
|
+
* @param ratio - Aspect ratio (e.g., '1:1', '16:9', or number)
|
|
451
|
+
* @returns Filter string or null if not supported
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* ```typescript
|
|
455
|
+
* presets.setsar('1:1') // Square pixels
|
|
456
|
+
* presets.setsar(1.333) // 4:3 aspect ratio
|
|
457
|
+
* ```
|
|
458
|
+
*
|
|
459
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#setsar | FFmpeg setsar/setdar filter}
|
|
460
|
+
*/
|
|
461
|
+
setsar(ratio) {
|
|
462
|
+
return `setsar=${ratio}`;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Creates a setdar filter string to set display aspect ratio.
|
|
466
|
+
*
|
|
467
|
+
* @param ratio - Aspect ratio (e.g., '16:9', '4:3')
|
|
468
|
+
* @returns Filter string or null if not supported
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```typescript
|
|
472
|
+
* presets.setdar('16:9') // Widescreen
|
|
473
|
+
* presets.setdar('4:3') // Traditional TV aspect
|
|
474
|
+
* ```
|
|
475
|
+
*
|
|
476
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#setsar | FFmpeg setsar/setdar filter}
|
|
477
|
+
*/
|
|
478
|
+
setdar(ratio) {
|
|
479
|
+
return `setdar=${ratio}`;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Creates an apad filter string to add audio padding.
|
|
483
|
+
* Useful for ensuring minimum audio duration.
|
|
484
|
+
*
|
|
485
|
+
* @param wholeDuration - Minimum duration in seconds (optional)
|
|
486
|
+
* @param padDuration - Amount of padding to add in seconds (optional)
|
|
487
|
+
* @returns Filter string or null if not supported
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* presets.apad(30) // Ensure at least 30 seconds total
|
|
492
|
+
* presets.apad(undefined, 5) // Add 5 seconds of padding
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#apad | FFmpeg apad filter}
|
|
496
|
+
*/
|
|
497
|
+
apad(wholeDuration, padDuration) {
|
|
498
|
+
if (!wholeDuration && !padDuration)
|
|
499
|
+
return 'apad';
|
|
500
|
+
let filter = 'apad';
|
|
501
|
+
if (wholeDuration)
|
|
502
|
+
filter += `=whole_dur=${wholeDuration}`;
|
|
503
|
+
if (padDuration)
|
|
504
|
+
filter += wholeDuration ? `:pad_dur=${padDuration}` : `=pad_dur=${padDuration}`;
|
|
505
|
+
return filter;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Creates a deinterlace filter string.
|
|
509
|
+
* Essential for processing interlaced content.
|
|
510
|
+
*
|
|
511
|
+
* @param mode - Deinterlace mode (default: 'yadif')
|
|
512
|
+
* @returns Filter string or null if not supported
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* presets.deinterlace('yadif') // Standard deinterlacing
|
|
517
|
+
* presets.deinterlace('bwdif') // Bob Weaver deinterlacing
|
|
518
|
+
* ```
|
|
519
|
+
*
|
|
520
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#yadif | FFmpeg yadif filter}
|
|
521
|
+
*/
|
|
522
|
+
deinterlace(mode = 'yadif') {
|
|
523
|
+
return mode;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Creates a select filter string to select specific frames.
|
|
527
|
+
* Powerful for extracting keyframes, specific frame types, etc.
|
|
528
|
+
*
|
|
529
|
+
* @param expression - Selection expression
|
|
530
|
+
* @returns Filter string or null if not supported
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```typescript
|
|
534
|
+
* presets.select('eq(pict_type,I)') // Select only keyframes
|
|
535
|
+
* presets.select('not(mod(n,10))') // Select every 10th frame
|
|
536
|
+
* ```
|
|
537
|
+
*
|
|
538
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#select | FFmpeg select filter}
|
|
539
|
+
*/
|
|
540
|
+
select(expression) {
|
|
541
|
+
return `select='${expression}'`;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Creates an aselect filter string for audio selection.
|
|
545
|
+
*
|
|
546
|
+
* @param expression - Selection expression
|
|
547
|
+
* @returns Filter string or null if not supported
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```typescript
|
|
551
|
+
* presets.aselect('between(t,10,20)') // Select audio between 10-20 seconds
|
|
552
|
+
* ```
|
|
553
|
+
*
|
|
554
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#aselect | FFmpeg aselect filter}
|
|
555
|
+
*/
|
|
556
|
+
aselect(expression) {
|
|
557
|
+
return `aselect='${expression}'`;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Creates a concat filter string to concatenate multiple inputs.
|
|
561
|
+
* Essential for joining multiple video/audio segments.
|
|
562
|
+
*
|
|
563
|
+
* @param n - Number of input segments
|
|
564
|
+
* @param v - Number of output video streams (0 or 1)
|
|
565
|
+
* @param a - Number of output audio streams (0 or 1)
|
|
566
|
+
* @returns Filter string or null if not supported
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ```typescript
|
|
570
|
+
* presets.concat(3, 1, 1) // Join 3 segments with video and audio
|
|
571
|
+
* presets.concat(2, 1, 0) // Join 2 video-only segments
|
|
572
|
+
* ```
|
|
573
|
+
*
|
|
574
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#concat | FFmpeg concat filter}
|
|
575
|
+
*/
|
|
576
|
+
concat(n, v = 1, a = 1) {
|
|
577
|
+
return `concat=n=${n}:v=${v}:a=${a}`;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Creates an amerge filter string to merge multiple audio streams into one.
|
|
581
|
+
* Different from amix - this creates multi-channel output.
|
|
582
|
+
*
|
|
583
|
+
* @param inputs - Number of input streams
|
|
584
|
+
* @returns Filter string or null if not supported
|
|
585
|
+
*
|
|
586
|
+
* @example
|
|
587
|
+
* ```typescript
|
|
588
|
+
* presets.amerge(2) // Merge 2 mono streams to stereo
|
|
589
|
+
* presets.amerge(6) // Merge 6 channels for 5.1 surround
|
|
590
|
+
* ```
|
|
591
|
+
*
|
|
592
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#amerge | FFmpeg amerge filter}
|
|
593
|
+
*/
|
|
594
|
+
amerge(inputs = 2) {
|
|
595
|
+
return `amerge=inputs=${inputs}`;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Creates a channelmap filter string to remap audio channels.
|
|
599
|
+
* Critical for audio channel manipulation.
|
|
600
|
+
*
|
|
601
|
+
* @param map - Channel mapping (e.g., '0-0|1-1' or 'FL-FR|FR-FL' to swap stereo)
|
|
602
|
+
* @returns Filter string or null if not supported
|
|
603
|
+
*
|
|
604
|
+
* @example
|
|
605
|
+
* ```typescript
|
|
606
|
+
* presets.channelmap('FL-FR|FR-FL') // Swap left and right channels
|
|
607
|
+
* presets.channelmap('0-0|0-1') // Duplicate mono to stereo
|
|
608
|
+
* ```
|
|
609
|
+
*
|
|
610
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#channelmap | FFmpeg channelmap filter}
|
|
611
|
+
*/
|
|
612
|
+
channelmap(map) {
|
|
613
|
+
return `channelmap=${map}`;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Creates a channelsplit filter string to split audio channels.
|
|
617
|
+
*
|
|
618
|
+
* @param channelLayout - Channel layout to split (optional)
|
|
619
|
+
* @returns Filter string or null if not supported
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* presets.channelsplit('stereo') // Split stereo to 2 mono
|
|
624
|
+
* presets.channelsplit('5.1') // Split 5.1 to individual channels
|
|
625
|
+
* ```
|
|
626
|
+
*
|
|
627
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#channelsplit | FFmpeg channelsplit filter}
|
|
628
|
+
*/
|
|
629
|
+
channelsplit(channelLayout) {
|
|
630
|
+
return channelLayout ? `channelsplit=channel_layout=${channelLayout}` : 'channelsplit';
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Creates a loudnorm filter string for loudness normalization.
|
|
634
|
+
* Essential for broadcast compliance and consistent audio levels.
|
|
635
|
+
*
|
|
636
|
+
* @param I - Integrated loudness target (default: -24 LUFS)
|
|
637
|
+
* @param TP - True peak (default: -2 dBTP)
|
|
638
|
+
* @param LRA - Loudness range (default: 7 LU)
|
|
639
|
+
* @returns Filter string or null if not supported
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```typescript
|
|
643
|
+
* presets.loudnorm(-23, -1, 7) // EBU R128 broadcast standard
|
|
644
|
+
* presets.loudnorm(-16, -1.5, 11) // Streaming platforms standard
|
|
645
|
+
* ```
|
|
646
|
+
*
|
|
647
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#loudnorm | FFmpeg loudnorm filter}
|
|
648
|
+
*/
|
|
649
|
+
loudnorm(I = -24, TP = -2, LRA = 7) {
|
|
650
|
+
return `loudnorm=I=${I}:TP=${TP}:LRA=${LRA}`;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Creates a compand filter string for audio compression/expansion.
|
|
654
|
+
* Important for dynamic range control.
|
|
655
|
+
*
|
|
656
|
+
* @param attacks - Attack times
|
|
657
|
+
* @param decays - Decay times
|
|
658
|
+
* @param points - Transfer function points
|
|
659
|
+
* @param gain - Output gain
|
|
660
|
+
* @returns Filter string or null if not supported
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```typescript
|
|
664
|
+
* presets.compand('0.3|0.3', '1|1', '-90/-60|-60/-40|-40/-30|-20/-20', 6)
|
|
665
|
+
* ```
|
|
666
|
+
*
|
|
667
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#compand | FFmpeg compand filter}
|
|
668
|
+
*/
|
|
669
|
+
compand(attacks, decays, points, gain) {
|
|
670
|
+
let filter = `compand=attacks=${attacks}:decays=${decays}:points=${points}`;
|
|
671
|
+
if (gain !== undefined)
|
|
672
|
+
filter += `:gain=${gain}`;
|
|
673
|
+
return filter;
|
|
674
|
+
}
|
|
130
675
|
}
|
|
131
676
|
/**
|
|
132
677
|
* Filter chain builder for composing multiple filters.
|
|
133
|
-
* Allows fluent API for building complex filter graphs.
|
|
678
|
+
* Allows fluent API for building complex filter graphs by chaining filter operations.
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```typescript
|
|
682
|
+
* const chain = new FilterChain()
|
|
683
|
+
* .add('scale=1920:1080')
|
|
684
|
+
* .add('fps=30')
|
|
685
|
+
* .custom('rotate=45*PI/180')
|
|
686
|
+
* .build();
|
|
687
|
+
* // Result: "scale=1920:1080,fps=30,rotate=45*PI/180"
|
|
688
|
+
* ```
|
|
134
689
|
*/
|
|
135
690
|
export class FilterChain {
|
|
136
691
|
filters = [];
|
|
137
692
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
693
|
+
* Adds a filter to the chain.
|
|
694
|
+
*
|
|
695
|
+
* @param filter - Filter string to add (ignored if null/undefined)
|
|
696
|
+
* @returns This instance for chaining
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```typescript
|
|
700
|
+
* chain.add('scale=1920:1080')
|
|
701
|
+
* ```
|
|
140
702
|
*/
|
|
141
703
|
add(filter) {
|
|
142
704
|
if (filter) {
|
|
@@ -145,20 +707,42 @@ export class FilterChain {
|
|
|
145
707
|
return this;
|
|
146
708
|
}
|
|
147
709
|
/**
|
|
148
|
-
*
|
|
710
|
+
* Adds a custom filter string to the chain.
|
|
711
|
+
*
|
|
712
|
+
* @param filter - Custom filter string
|
|
713
|
+
* @returns This instance for chaining
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```typescript
|
|
717
|
+
* chain.custom('myfilter=param1:param2')
|
|
718
|
+
* ```
|
|
149
719
|
*/
|
|
150
720
|
custom(filter) {
|
|
151
721
|
return this.add(filter);
|
|
152
722
|
}
|
|
153
723
|
/**
|
|
154
|
-
*
|
|
724
|
+
* Builds the final filter string.
|
|
725
|
+
*
|
|
155
726
|
* @param separator - Separator between filters (default: ',')
|
|
727
|
+
* @returns Combined filter string
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```typescript
|
|
731
|
+
* const filterString = chain.build() // "scale=1920:1080,fps=30"
|
|
732
|
+
* ```
|
|
156
733
|
*/
|
|
157
734
|
build(separator = ',') {
|
|
158
735
|
return this.filters.join(separator);
|
|
159
736
|
}
|
|
160
737
|
/**
|
|
161
|
-
*
|
|
738
|
+
* Returns the filters as an array.
|
|
739
|
+
*
|
|
740
|
+
* @returns Array of filter strings
|
|
741
|
+
*
|
|
742
|
+
* @example
|
|
743
|
+
* ```typescript
|
|
744
|
+
* const filters = chain.toArray() // ["scale=1920:1080", "fps=30"]
|
|
745
|
+
* ```
|
|
162
746
|
*/
|
|
163
747
|
toArray() {
|
|
164
748
|
return [...this.filters];
|
|
@@ -166,75 +750,792 @@ export class FilterChain {
|
|
|
166
750
|
}
|
|
167
751
|
/**
|
|
168
752
|
* Base chain builder with common filter methods.
|
|
753
|
+
* Provides a fluent API for building filter chains using preset methods.
|
|
754
|
+
*
|
|
169
755
|
* @template T The preset type this builder uses
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```typescript
|
|
759
|
+
* const chain = new ChainBuilderBase(presets)
|
|
760
|
+
* .scale(1920, 1080)
|
|
761
|
+
* .fps(30)
|
|
762
|
+
* .fade('in', 0, 2)
|
|
763
|
+
* .build();
|
|
764
|
+
* ```
|
|
170
765
|
*/
|
|
171
766
|
export class ChainBuilderBase extends FilterChain {
|
|
172
767
|
presets;
|
|
768
|
+
/**
|
|
769
|
+
* @param presets - The filter presets to use
|
|
770
|
+
* @internal
|
|
771
|
+
*/
|
|
173
772
|
constructor(presets) {
|
|
174
773
|
super();
|
|
175
774
|
this.presets = presets;
|
|
176
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* Adds a scale filter to the chain.
|
|
778
|
+
*
|
|
779
|
+
* @param width - Target width
|
|
780
|
+
* @param height - Target height
|
|
781
|
+
* @param options - Additional scaling options
|
|
782
|
+
*
|
|
783
|
+
* @returns This instance for chaining
|
|
784
|
+
*
|
|
785
|
+
* @example
|
|
786
|
+
* ```typescript
|
|
787
|
+
* const chain = FilterPresets.chain()
|
|
788
|
+
* .scale(1920, 1080)
|
|
789
|
+
* .build();
|
|
790
|
+
* ```
|
|
791
|
+
*
|
|
792
|
+
* @example
|
|
793
|
+
* ```typescript
|
|
794
|
+
* const chain = FilterPresets.chain()
|
|
795
|
+
* .scale(1280, 720, { flags: 'lanczos' })
|
|
796
|
+
* .build();
|
|
797
|
+
* ```
|
|
798
|
+
*
|
|
799
|
+
* @see {@link FilterPresetBase.scale}
|
|
800
|
+
*/
|
|
177
801
|
scale(width, height, options) {
|
|
178
802
|
return this.add(this.presets.scale(width, height, options));
|
|
179
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Adds a crop filter to the chain.
|
|
806
|
+
*
|
|
807
|
+
* @param width - Crop width
|
|
808
|
+
* @param height - Crop height
|
|
809
|
+
* @param x - X position (default: 0)
|
|
810
|
+
* @param y - Y position (default: 0)
|
|
811
|
+
*
|
|
812
|
+
* @returns This instance for chaining
|
|
813
|
+
*
|
|
814
|
+
* @example
|
|
815
|
+
* ```typescript
|
|
816
|
+
* const chain = FilterPresets.chain()
|
|
817
|
+
* .crop(640, 480)
|
|
818
|
+
* .build();
|
|
819
|
+
* ```
|
|
820
|
+
*
|
|
821
|
+
* @example
|
|
822
|
+
* ```typescript
|
|
823
|
+
* const chain = FilterPresets.chain()
|
|
824
|
+
* .crop(1920, 1080, 100, 50)
|
|
825
|
+
* .build();
|
|
826
|
+
* ```
|
|
827
|
+
*
|
|
828
|
+
* @see {@link FilterPresetBase.crop}
|
|
829
|
+
*/
|
|
180
830
|
crop(width, height, x = 0, y = 0) {
|
|
181
831
|
return this.add(this.presets.crop(width, height, x, y));
|
|
182
832
|
}
|
|
833
|
+
/**
|
|
834
|
+
* Adds an FPS filter to the chain.
|
|
835
|
+
*
|
|
836
|
+
* @param fps - Target frame rate
|
|
837
|
+
*
|
|
838
|
+
* @returns This instance for chaining
|
|
839
|
+
*
|
|
840
|
+
* @example
|
|
841
|
+
* ```typescript
|
|
842
|
+
* const chain = FilterPresets.chain()
|
|
843
|
+
* .fps(30)
|
|
844
|
+
* .build();
|
|
845
|
+
* ```
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* ```typescript
|
|
849
|
+
* const chain = FilterPresets.chain()
|
|
850
|
+
* .fps(23.976)
|
|
851
|
+
* .build();
|
|
852
|
+
* ```
|
|
853
|
+
*
|
|
854
|
+
* @see {@link FilterPresetBase.fps}
|
|
855
|
+
*/
|
|
183
856
|
fps(fps) {
|
|
184
857
|
return this.add(this.presets.fps(fps));
|
|
185
858
|
}
|
|
859
|
+
/**
|
|
860
|
+
* Adds a format filter to the chain.
|
|
861
|
+
*
|
|
862
|
+
* @param pixelFormat - Target pixel format(s)
|
|
863
|
+
*
|
|
864
|
+
* @returns This instance for chaining
|
|
865
|
+
*
|
|
866
|
+
* @example
|
|
867
|
+
* ```typescript
|
|
868
|
+
* const chain = FilterPresets.chain()
|
|
869
|
+
* .format('yuv420p')
|
|
870
|
+
* .build();
|
|
871
|
+
* ```
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* ```typescript
|
|
875
|
+
* const chain = FilterPresets.chain()
|
|
876
|
+
* .format(AV_PIX_FMT_RGB24)
|
|
877
|
+
* .build();
|
|
878
|
+
* ```
|
|
879
|
+
*
|
|
880
|
+
* @see {@link FilterPresetBase.format}
|
|
881
|
+
*/
|
|
186
882
|
format(pixelFormat) {
|
|
187
883
|
return this.add(this.presets.format(pixelFormat));
|
|
188
884
|
}
|
|
885
|
+
/**
|
|
886
|
+
* Adds a rotate filter to the chain.
|
|
887
|
+
*
|
|
888
|
+
* @param angle - Rotation angle in degrees
|
|
889
|
+
*
|
|
890
|
+
* @returns This instance for chaining
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```typescript
|
|
894
|
+
* const chain = FilterPresets.chain()
|
|
895
|
+
* .rotate(45)
|
|
896
|
+
* .build();
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @example
|
|
900
|
+
* ```typescript
|
|
901
|
+
* const chain = FilterPresets.chain()
|
|
902
|
+
* .rotate(-90)
|
|
903
|
+
* .build();
|
|
904
|
+
* ```
|
|
905
|
+
*
|
|
906
|
+
* @see {@link FilterPresetBase.rotate}
|
|
907
|
+
*/
|
|
189
908
|
rotate(angle) {
|
|
190
909
|
return this.add(this.presets.rotate(angle));
|
|
191
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Adds a horizontal flip filter to the chain.
|
|
913
|
+
*
|
|
914
|
+
* @returns This instance for chaining
|
|
915
|
+
*
|
|
916
|
+
* @example
|
|
917
|
+
* ```typescript
|
|
918
|
+
* const chain = FilterPresets.chain()
|
|
919
|
+
* .hflip()
|
|
920
|
+
* .build();
|
|
921
|
+
* ```
|
|
922
|
+
*
|
|
923
|
+
* @see {@link FilterPresetBase.hflip}
|
|
924
|
+
*/
|
|
192
925
|
hflip() {
|
|
193
926
|
return this.add(this.presets.hflip());
|
|
194
927
|
}
|
|
928
|
+
/**
|
|
929
|
+
* Adds a vertical flip filter to the chain.
|
|
930
|
+
*
|
|
931
|
+
* @returns This instance for chaining
|
|
932
|
+
*
|
|
933
|
+
* @example
|
|
934
|
+
* ```typescript
|
|
935
|
+
* const chain = FilterPresets.chain()
|
|
936
|
+
* .vflip()
|
|
937
|
+
* .build();
|
|
938
|
+
* ```
|
|
939
|
+
*
|
|
940
|
+
* @see {@link FilterPresetBase.vflip}
|
|
941
|
+
*/
|
|
195
942
|
vflip() {
|
|
196
943
|
return this.add(this.presets.vflip());
|
|
197
944
|
}
|
|
945
|
+
/**
|
|
946
|
+
* Adds a fade filter to the chain.
|
|
947
|
+
*
|
|
948
|
+
* @param type - Fade type ('in' or 'out')
|
|
949
|
+
* @param start - Start time in seconds
|
|
950
|
+
* @param duration - Fade duration in seconds
|
|
951
|
+
*
|
|
952
|
+
* @returns This instance for chaining
|
|
953
|
+
*
|
|
954
|
+
* @example
|
|
955
|
+
* ```typescript
|
|
956
|
+
* const chain = FilterPresets.chain()
|
|
957
|
+
* .fade('in', 0, 2)
|
|
958
|
+
* .build();
|
|
959
|
+
* ```
|
|
960
|
+
*
|
|
961
|
+
* @example
|
|
962
|
+
* ```typescript
|
|
963
|
+
* const chain = FilterPresets.chain()
|
|
964
|
+
* .fade('out', 10, 1.5)
|
|
965
|
+
* .build();
|
|
966
|
+
* ```
|
|
967
|
+
*
|
|
968
|
+
* @see {@link FilterPresetBase.fade}
|
|
969
|
+
*/
|
|
198
970
|
fade(type, start, duration) {
|
|
199
971
|
return this.add(this.presets.fade(type, start, duration));
|
|
200
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* Adds an overlay filter to the chain.
|
|
975
|
+
*
|
|
976
|
+
* @param x - X position (default: 0)
|
|
977
|
+
* @param y - Y position (default: 0)
|
|
978
|
+
* @param options - Additional overlay options
|
|
979
|
+
*
|
|
980
|
+
* @returns This instance for chaining
|
|
981
|
+
*
|
|
982
|
+
* @example
|
|
983
|
+
* ```typescript
|
|
984
|
+
* const chain = FilterPresets.chain()
|
|
985
|
+
* .overlay(100, 50)
|
|
986
|
+
* .build();
|
|
987
|
+
* ```
|
|
988
|
+
*
|
|
989
|
+
* @example
|
|
990
|
+
* ```typescript
|
|
991
|
+
* const chain = FilterPresets.chain()
|
|
992
|
+
* .overlay(10, 10, { enable: 'between(t,5,10)' })
|
|
993
|
+
* .build();
|
|
994
|
+
* ```
|
|
995
|
+
*
|
|
996
|
+
* @see {@link FilterPresetBase.overlay}
|
|
997
|
+
*/
|
|
201
998
|
overlay(x = 0, y = 0, options) {
|
|
202
999
|
return this.add(this.presets.overlay(x, y, options));
|
|
203
1000
|
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Adds a volume filter to the chain.
|
|
1003
|
+
*
|
|
1004
|
+
* @param factor - Volume factor
|
|
1005
|
+
*
|
|
1006
|
+
* @returns This instance for chaining
|
|
1007
|
+
*
|
|
1008
|
+
* @example
|
|
1009
|
+
* ```typescript
|
|
1010
|
+
* const chain = FilterPresets.chain()
|
|
1011
|
+
* .volume(0.5)
|
|
1012
|
+
* .build();
|
|
1013
|
+
* ```
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* ```typescript
|
|
1017
|
+
* const chain = FilterPresets.chain()
|
|
1018
|
+
* .volume(2.0)
|
|
1019
|
+
* .build();
|
|
1020
|
+
* ```
|
|
1021
|
+
*
|
|
1022
|
+
* @see {@link FilterPresetBase.volume}
|
|
1023
|
+
*/
|
|
204
1024
|
volume(factor) {
|
|
205
1025
|
return this.add(this.presets.volume(factor));
|
|
206
1026
|
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Adds an audio format filter to the chain.
|
|
1029
|
+
*
|
|
1030
|
+
* @param sampleFormat - Target sample format
|
|
1031
|
+
* @param sampleRate - Target sample rate (optional)
|
|
1032
|
+
* @param channelLayout - Target channel layout (optional)
|
|
1033
|
+
*
|
|
1034
|
+
* @returns This instance for chaining
|
|
1035
|
+
*
|
|
1036
|
+
* @example
|
|
1037
|
+
* ```typescript
|
|
1038
|
+
* const chain = FilterPresets.chain()
|
|
1039
|
+
* .aformat(AV_SAMPLE_FMT_FLT, 48000, 'stereo')
|
|
1040
|
+
* .build();
|
|
1041
|
+
* ```
|
|
1042
|
+
*
|
|
1043
|
+
* @example
|
|
1044
|
+
* ```typescript
|
|
1045
|
+
* const chain = FilterPresets.chain()
|
|
1046
|
+
* .aformat('s16', 44100)
|
|
1047
|
+
* .build();
|
|
1048
|
+
* ```
|
|
1049
|
+
*
|
|
1050
|
+
* @see {@link FilterPresetBase.aformat}
|
|
1051
|
+
*/
|
|
207
1052
|
aformat(sampleFormat, sampleRate, channelLayout) {
|
|
208
1053
|
return this.add(this.presets.aformat(sampleFormat, sampleRate, channelLayout));
|
|
209
1054
|
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Adds an asetnsamples filter to the chain.
|
|
1057
|
+
*
|
|
1058
|
+
* @param samples - Number of samples per frame
|
|
1059
|
+
* @param padding - Whether to pad or drop samples (default: true)
|
|
1060
|
+
*
|
|
1061
|
+
* @returns This instance for chaining
|
|
1062
|
+
*
|
|
1063
|
+
* @example
|
|
1064
|
+
* ```typescript
|
|
1065
|
+
* const chain = FilterPresets.chain()
|
|
1066
|
+
* .asetnsamples(960)
|
|
1067
|
+
* .build();
|
|
1068
|
+
* ```
|
|
1069
|
+
*
|
|
1070
|
+
* @example
|
|
1071
|
+
* ```typescript
|
|
1072
|
+
* const chain = FilterPresets.chain()
|
|
1073
|
+
* .asetnsamples(1024, false)
|
|
1074
|
+
* .build();
|
|
1075
|
+
* ```
|
|
1076
|
+
*
|
|
1077
|
+
* @see {@link FilterPresetBase.asetnsamples}
|
|
1078
|
+
*/
|
|
1079
|
+
asetnsamples(samples, padding = true) {
|
|
1080
|
+
return this.add(this.presets.asetnsamples(samples, padding));
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Adds an atempo filter to the chain.
|
|
1084
|
+
*
|
|
1085
|
+
* @param factor - Tempo factor (0.5 to 2.0)
|
|
1086
|
+
*
|
|
1087
|
+
* @returns This instance for chaining
|
|
1088
|
+
*
|
|
1089
|
+
* @example
|
|
1090
|
+
* ```typescript
|
|
1091
|
+
* const chain = FilterPresets.chain()
|
|
1092
|
+
* .atempo(1.5)
|
|
1093
|
+
* .build();
|
|
1094
|
+
* ```
|
|
1095
|
+
*
|
|
1096
|
+
* @example
|
|
1097
|
+
* ```typescript
|
|
1098
|
+
* const chain = FilterPresets.chain()
|
|
1099
|
+
* .atempo(0.8)
|
|
1100
|
+
* .build();
|
|
1101
|
+
* ```
|
|
1102
|
+
*
|
|
1103
|
+
* @see {@link FilterPresetBase.atempo}
|
|
1104
|
+
*/
|
|
210
1105
|
atempo(factor) {
|
|
211
1106
|
return this.add(this.presets.atempo(factor));
|
|
212
1107
|
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Adds an audio fade filter to the chain.
|
|
1110
|
+
*
|
|
1111
|
+
* @param type - Fade type ('in' or 'out')
|
|
1112
|
+
* @param start - Start time in seconds
|
|
1113
|
+
* @param duration - Fade duration in seconds
|
|
1114
|
+
*
|
|
1115
|
+
* @returns This instance for chaining
|
|
1116
|
+
*
|
|
1117
|
+
* @example
|
|
1118
|
+
* ```typescript
|
|
1119
|
+
* const chain = FilterPresets.chain()
|
|
1120
|
+
* .afade('in', 0, 3)
|
|
1121
|
+
* .build();
|
|
1122
|
+
* ```
|
|
1123
|
+
*
|
|
1124
|
+
* @example
|
|
1125
|
+
* ```typescript
|
|
1126
|
+
* const chain = FilterPresets.chain()
|
|
1127
|
+
* .afade('out', 25, 2)
|
|
1128
|
+
* .build();
|
|
1129
|
+
* ```
|
|
1130
|
+
*
|
|
1131
|
+
* @see {@link FilterPresetBase.afade}
|
|
1132
|
+
*/
|
|
213
1133
|
afade(type, start, duration) {
|
|
214
1134
|
return this.add(this.presets.afade(type, start, duration));
|
|
215
1135
|
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Adds an amix filter to the chain.
|
|
1138
|
+
*
|
|
1139
|
+
* @param inputs - Number of inputs (default: 2)
|
|
1140
|
+
* @param duration - Duration mode (default: 'longest')
|
|
1141
|
+
*
|
|
1142
|
+
* @returns This instance for chaining
|
|
1143
|
+
*
|
|
1144
|
+
* @example
|
|
1145
|
+
* ```typescript
|
|
1146
|
+
* const chain = FilterPresets.chain()
|
|
1147
|
+
* .amix(3, 'longest')
|
|
1148
|
+
* .build();
|
|
1149
|
+
* ```
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* const chain = FilterPresets.chain()
|
|
1154
|
+
* .amix(2, 'first')
|
|
1155
|
+
* .build();
|
|
1156
|
+
* ```
|
|
1157
|
+
*
|
|
1158
|
+
* @see {@link FilterPresetBase.amix}
|
|
1159
|
+
*/
|
|
216
1160
|
amix(inputs = 2, duration = 'longest') {
|
|
217
1161
|
return this.add(this.presets.amix(inputs, duration));
|
|
218
1162
|
}
|
|
219
|
-
//
|
|
220
|
-
|
|
1163
|
+
// ========== New Critical Filter Chain Methods ==========
|
|
1164
|
+
/**
|
|
1165
|
+
* Adds a pad filter to the chain.
|
|
1166
|
+
*
|
|
1167
|
+
* @param width - Target width
|
|
1168
|
+
* @param height - Target height
|
|
1169
|
+
* @param x - X position of input
|
|
1170
|
+
* @param y - Y position of input
|
|
1171
|
+
* @param color - Padding color
|
|
1172
|
+
*
|
|
1173
|
+
* @returns This instance for chaining
|
|
1174
|
+
*
|
|
1175
|
+
* @example
|
|
1176
|
+
* ```typescript
|
|
1177
|
+
* chain.pad('iw*2', 'ih*2') // Double the canvas size
|
|
1178
|
+
* ```
|
|
1179
|
+
*
|
|
1180
|
+
* @see {@link FilterPresetBase.pad}
|
|
1181
|
+
*/
|
|
1182
|
+
pad(width, height, x, y, color = 'black') {
|
|
1183
|
+
return this.add(this.presets.pad(width, height, x, y, color));
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Adds a trim filter to the chain.
|
|
1187
|
+
*
|
|
1188
|
+
* @param start - Start time in seconds
|
|
1189
|
+
* @param end - End time in seconds
|
|
1190
|
+
* @param duration - Duration in seconds
|
|
1191
|
+
*
|
|
1192
|
+
* @returns This instance for chaining
|
|
1193
|
+
*
|
|
1194
|
+
* @example
|
|
1195
|
+
* ```typescript
|
|
1196
|
+
* chain.trim(10, 20) // Extract 10 seconds from t=10 to t=20
|
|
1197
|
+
* ```
|
|
1198
|
+
*
|
|
1199
|
+
* @see {@link FilterPresetBase.trim}
|
|
1200
|
+
*/
|
|
1201
|
+
trim(start, end, duration) {
|
|
1202
|
+
return this.add(this.presets.trim(start, end, duration));
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Adds a setpts filter to the chain.
|
|
1206
|
+
*
|
|
1207
|
+
* @param expression - PTS expression
|
|
1208
|
+
*
|
|
1209
|
+
* @returns This instance for chaining
|
|
1210
|
+
*
|
|
1211
|
+
* @example
|
|
1212
|
+
* ```typescript
|
|
1213
|
+
* chain.setpts('PTS/2') // Double playback speed
|
|
1214
|
+
* ```
|
|
1215
|
+
*
|
|
1216
|
+
* @see {@link FilterPresetBase.setpts}
|
|
1217
|
+
*/
|
|
1218
|
+
setpts(expression) {
|
|
1219
|
+
return this.add(this.presets.setpts(expression));
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Adds an asetpts filter to the chain.
|
|
1223
|
+
*
|
|
1224
|
+
* @param expression - PTS expression
|
|
1225
|
+
*
|
|
1226
|
+
* @returns This instance for chaining
|
|
1227
|
+
*
|
|
1228
|
+
* @example
|
|
1229
|
+
* ```typescript
|
|
1230
|
+
* chain.asetpts('PTS-STARTPTS') // Reset audio timestamps
|
|
1231
|
+
* ```
|
|
1232
|
+
*
|
|
1233
|
+
* @see {@link FilterPresetBase.asetpts}
|
|
1234
|
+
*/
|
|
1235
|
+
asetpts(expression) {
|
|
1236
|
+
return this.add(this.presets.asetpts(expression));
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Adds a setsar filter to the chain.
|
|
1240
|
+
*
|
|
1241
|
+
* @param ratio - Sample aspect ratio
|
|
1242
|
+
*
|
|
1243
|
+
* @returns This instance for chaining
|
|
1244
|
+
*
|
|
1245
|
+
* @example
|
|
1246
|
+
* ```typescript
|
|
1247
|
+
* chain.setsar('1:1') // Square pixels
|
|
1248
|
+
* ```
|
|
1249
|
+
*
|
|
1250
|
+
* @see {@link FilterPresetBase.setsar}
|
|
1251
|
+
*/
|
|
1252
|
+
setsar(ratio) {
|
|
1253
|
+
return this.add(this.presets.setsar(ratio));
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Adds a setdar filter to the chain.
|
|
1257
|
+
*
|
|
1258
|
+
* @param ratio - Display aspect ratio
|
|
1259
|
+
*
|
|
1260
|
+
* @returns This instance for chaining
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```typescript
|
|
1264
|
+
* chain.setdar('16:9') // Set widescreen aspect
|
|
1265
|
+
* ```
|
|
1266
|
+
*
|
|
1267
|
+
* @see {@link FilterPresetBase.setdar}
|
|
1268
|
+
*/
|
|
1269
|
+
setdar(ratio) {
|
|
1270
|
+
return this.add(this.presets.setdar(ratio));
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Adds an apad filter to the chain.
|
|
1274
|
+
*
|
|
1275
|
+
* @param wholeDuration - Minimum total duration
|
|
1276
|
+
* @param padDuration - Padding duration to add
|
|
1277
|
+
*
|
|
1278
|
+
* @returns This instance for chaining
|
|
1279
|
+
*
|
|
1280
|
+
* @example
|
|
1281
|
+
* ```typescript
|
|
1282
|
+
* chain.apad(10) // Ensure at least 10 seconds of audio
|
|
1283
|
+
* ```
|
|
1284
|
+
*
|
|
1285
|
+
* @see {@link FilterPresetBase.apad}
|
|
1286
|
+
*/
|
|
1287
|
+
apad(wholeDuration, padDuration) {
|
|
1288
|
+
return this.add(this.presets.apad(wholeDuration, padDuration));
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Adds a select filter to the chain.
|
|
1292
|
+
*
|
|
1293
|
+
* @param expression - Selection expression
|
|
1294
|
+
*
|
|
1295
|
+
* @returns This instance for chaining
|
|
1296
|
+
*
|
|
1297
|
+
* @example
|
|
1298
|
+
* ```typescript
|
|
1299
|
+
* chain.select('eq(pict_type,I)') // Select only I-frames
|
|
1300
|
+
* ```
|
|
1301
|
+
*
|
|
1302
|
+
* @see {@link FilterPresetBase.select}
|
|
1303
|
+
*/
|
|
1304
|
+
select(expression) {
|
|
1305
|
+
return this.add(this.presets.select(expression));
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Adds an aselect filter to the chain.
|
|
1309
|
+
*
|
|
1310
|
+
* @param expression - Selection expression
|
|
1311
|
+
*
|
|
1312
|
+
* @returns This instance for chaining
|
|
1313
|
+
*
|
|
1314
|
+
* @example
|
|
1315
|
+
* ```typescript
|
|
1316
|
+
* chain.aselect('between(t,10,20)') // Select audio between 10-20s
|
|
1317
|
+
* ```
|
|
1318
|
+
*
|
|
1319
|
+
* @see {@link FilterPresetBase.aselect}
|
|
1320
|
+
*/
|
|
1321
|
+
aselect(expression) {
|
|
1322
|
+
return this.add(this.presets.aselect(expression));
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Adds a concat filter to the chain.
|
|
1326
|
+
*
|
|
1327
|
+
* @param n - Number of input segments
|
|
1328
|
+
* @param v - Number of video streams
|
|
1329
|
+
* @param a - Number of audio streams
|
|
1330
|
+
*
|
|
1331
|
+
* @returns This instance for chaining
|
|
1332
|
+
*
|
|
1333
|
+
* @example
|
|
1334
|
+
* ```typescript
|
|
1335
|
+
* chain.concat(3, 1, 1) // Concatenate 3 segments with video and audio
|
|
1336
|
+
* ```
|
|
1337
|
+
*
|
|
1338
|
+
* @see {@link FilterPresetBase.concat}
|
|
1339
|
+
*/
|
|
1340
|
+
concat(n, v = 1, a = 1) {
|
|
1341
|
+
return this.add(this.presets.concat(n, v, a));
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Adds an amerge filter to the chain.
|
|
1345
|
+
*
|
|
1346
|
+
* @param inputs - Number of input streams
|
|
1347
|
+
*
|
|
1348
|
+
* @returns This instance for chaining
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* ```typescript
|
|
1352
|
+
* chain.amerge(2) // Merge 2 audio streams
|
|
1353
|
+
* ```
|
|
1354
|
+
*
|
|
1355
|
+
* @see {@link FilterPresetBase.amerge}
|
|
1356
|
+
*/
|
|
1357
|
+
amerge(inputs = 2) {
|
|
1358
|
+
return this.add(this.presets.amerge(inputs));
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Adds a channelmap filter to the chain.
|
|
1362
|
+
*
|
|
1363
|
+
* @param map - Channel mapping string
|
|
1364
|
+
*
|
|
1365
|
+
* @returns This instance for chaining
|
|
1366
|
+
*
|
|
1367
|
+
* @example
|
|
1368
|
+
* ```typescript
|
|
1369
|
+
* chain.channelmap('FL-FR|FR-FL') // Swap stereo channels
|
|
1370
|
+
* ```
|
|
1371
|
+
*
|
|
1372
|
+
* @see {@link FilterPresetBase.channelmap}
|
|
1373
|
+
*/
|
|
1374
|
+
channelmap(map) {
|
|
1375
|
+
return this.add(this.presets.channelmap(map));
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Adds a channelsplit filter to the chain.
|
|
1379
|
+
*
|
|
1380
|
+
* @param channelLayout - Channel layout to split
|
|
1381
|
+
*
|
|
1382
|
+
* @returns This instance for chaining
|
|
1383
|
+
*
|
|
1384
|
+
* @example
|
|
1385
|
+
* ```typescript
|
|
1386
|
+
* chain.channelsplit('stereo') // Split stereo into two mono streams
|
|
1387
|
+
* ```
|
|
1388
|
+
*
|
|
1389
|
+
* @see {@link FilterPresetBase.channelsplit}
|
|
1390
|
+
*/
|
|
1391
|
+
channelsplit(channelLayout) {
|
|
1392
|
+
return this.add(this.presets.channelsplit(channelLayout));
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Adds a loudnorm filter to the chain.
|
|
1396
|
+
*
|
|
1397
|
+
* @param I - Integrated loudness target (LUFS)
|
|
1398
|
+
* @param TP - True peak (dBTP)
|
|
1399
|
+
* @param LRA - Loudness range (LU)
|
|
1400
|
+
*
|
|
1401
|
+
* @returns This instance for chaining
|
|
1402
|
+
*
|
|
1403
|
+
* @example
|
|
1404
|
+
* ```typescript
|
|
1405
|
+
* chain.loudnorm(-16, -1.5, 11) // Streaming loudness standard
|
|
1406
|
+
* ```
|
|
1407
|
+
*
|
|
1408
|
+
* @see {@link FilterPresetBase.loudnorm}
|
|
1409
|
+
*/
|
|
1410
|
+
loudnorm(I = -24, TP = -2, LRA = 7) {
|
|
1411
|
+
return this.add(this.presets.loudnorm(I, TP, LRA));
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Adds a compand filter to the chain.
|
|
1415
|
+
*
|
|
1416
|
+
* @param attacks - Attack times
|
|
1417
|
+
* @param decays - Decay times
|
|
1418
|
+
* @param points - Transfer function points
|
|
1419
|
+
* @param gain - Output gain
|
|
1420
|
+
*
|
|
1421
|
+
* @returns This instance for chaining
|
|
1422
|
+
*
|
|
1423
|
+
* @example
|
|
1424
|
+
* ```typescript
|
|
1425
|
+
* chain.compand('0.3|0.3', '1|1', '-90/-60|-60/-40|-40/-30|-20/-20', 6)
|
|
1426
|
+
* ```
|
|
1427
|
+
*
|
|
1428
|
+
* @see {@link FilterPresetBase.compand}
|
|
1429
|
+
*/
|
|
1430
|
+
compand(attacks, decays, points, gain) {
|
|
1431
|
+
return this.add(this.presets.compand(attacks, decays, points, gain));
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Adds a transpose filter to the chain (hardware-specific).
|
|
1435
|
+
* Only available for hardware presets that support transpose
|
|
1436
|
+
*
|
|
1437
|
+
* @param mode - Transpose mode (number or string)
|
|
1438
|
+
*
|
|
1439
|
+
* @returns This instance for chaining
|
|
1440
|
+
*
|
|
1441
|
+
* @example
|
|
1442
|
+
* ```typescript
|
|
1443
|
+
* const chain = FilterPresets.chain()
|
|
1444
|
+
* .transpose('clock')
|
|
1445
|
+
* .build();
|
|
1446
|
+
* ```
|
|
1447
|
+
*
|
|
1448
|
+
* @example
|
|
1449
|
+
* ```typescript
|
|
1450
|
+
* const chain = FilterPresets.chain()
|
|
1451
|
+
* .transpose('cclock_flip')
|
|
1452
|
+
* .build();
|
|
1453
|
+
* ```
|
|
1454
|
+
*/
|
|
1455
|
+
transpose(mode = 0) {
|
|
221
1456
|
if ('transpose' in this.presets) {
|
|
222
|
-
return this.add(this.presets.transpose(
|
|
1457
|
+
return this.add(this.presets.transpose(mode));
|
|
223
1458
|
}
|
|
224
1459
|
return this.add(null);
|
|
225
1460
|
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Adds a tonemap filter to the chain (hardware-specific).
|
|
1463
|
+
* Only available for hardware presets that support tonemapping
|
|
1464
|
+
*
|
|
1465
|
+
* @param options - Tonemapping options
|
|
1466
|
+
*
|
|
1467
|
+
* @returns This instance for chaining
|
|
1468
|
+
*
|
|
1469
|
+
* @example
|
|
1470
|
+
* ```typescript
|
|
1471
|
+
* const chain = FilterPresets.chain()
|
|
1472
|
+
* .tonemap()
|
|
1473
|
+
* .build();
|
|
1474
|
+
* ```
|
|
1475
|
+
*
|
|
1476
|
+
* @example
|
|
1477
|
+
* ```typescript
|
|
1478
|
+
* const chain = FilterPresets.chain()
|
|
1479
|
+
* .tonemap({ tonemap: 'hable', desat: '0' })
|
|
1480
|
+
* .build();
|
|
1481
|
+
* ```
|
|
1482
|
+
*/
|
|
226
1483
|
tonemap(options) {
|
|
227
1484
|
if ('tonemap' in this.presets) {
|
|
228
1485
|
return this.add(this.presets.tonemap(options));
|
|
229
1486
|
}
|
|
230
1487
|
return this.add(null);
|
|
231
1488
|
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Adds a deinterlace filter to the chain (hardware-specific).
|
|
1491
|
+
* Only available for hardware presets that support deinterlacing
|
|
1492
|
+
*
|
|
1493
|
+
* @param mode - Deinterlace mode (optional)
|
|
1494
|
+
*
|
|
1495
|
+
* @returns This instance for chaining
|
|
1496
|
+
*
|
|
1497
|
+
* @example
|
|
1498
|
+
* ```typescript
|
|
1499
|
+
* const chain = FilterPresets.chain()
|
|
1500
|
+
* .deinterlace()
|
|
1501
|
+
* .build();
|
|
1502
|
+
* ```
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```typescript
|
|
1506
|
+
* const chain = FilterPresets.chain()
|
|
1507
|
+
* .deinterlace('yadif')
|
|
1508
|
+
* .build();
|
|
1509
|
+
* ```
|
|
1510
|
+
*/
|
|
232
1511
|
deinterlace(mode) {
|
|
233
1512
|
if ('deinterlace' in this.presets) {
|
|
234
1513
|
return this.add(this.presets.deinterlace(mode));
|
|
235
1514
|
}
|
|
236
1515
|
return this.add(null);
|
|
237
1516
|
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Adds a flip filter to the chain (hardware-specific).
|
|
1519
|
+
* Falls back to hflip/vflip if hardware flip not available
|
|
1520
|
+
*
|
|
1521
|
+
* @param direction - Flip direction ('h' or 'v')
|
|
1522
|
+
*
|
|
1523
|
+
* @returns This instance for chaining
|
|
1524
|
+
*
|
|
1525
|
+
* @example
|
|
1526
|
+
* ```typescript
|
|
1527
|
+
* const chain = FilterPresets.chain()
|
|
1528
|
+
* .flip('h')
|
|
1529
|
+
* .build();
|
|
1530
|
+
* ```
|
|
1531
|
+
*
|
|
1532
|
+
* @example
|
|
1533
|
+
* ```typescript
|
|
1534
|
+
* const chain = FilterPresets.chain()
|
|
1535
|
+
* .flip('v')
|
|
1536
|
+
* .build();
|
|
1537
|
+
* ```
|
|
1538
|
+
*/
|
|
238
1539
|
flip(direction) {
|
|
239
1540
|
if ('flip' in this.presets) {
|
|
240
1541
|
return this.add(this.presets.flip(direction));
|
|
@@ -242,36 +1543,151 @@ export class ChainBuilderBase extends FilterChain {
|
|
|
242
1543
|
// Fallback to hflip/vflip
|
|
243
1544
|
return direction === 'h' ? this.hflip() : this.vflip();
|
|
244
1545
|
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Adds a blur filter to the chain (hardware-specific).
|
|
1548
|
+
* Only available for hardware presets that support blur
|
|
1549
|
+
*
|
|
1550
|
+
* @param type - Blur type (default: 'avg')
|
|
1551
|
+
* @param radius - Blur radius (optional)
|
|
1552
|
+
*
|
|
1553
|
+
* @returns This instance for chaining
|
|
1554
|
+
*
|
|
1555
|
+
* @example
|
|
1556
|
+
* ```typescript
|
|
1557
|
+
* const chain = FilterPresets.chain()
|
|
1558
|
+
* .blur('gaussian', 5)
|
|
1559
|
+
* .build();
|
|
1560
|
+
* ```
|
|
1561
|
+
*
|
|
1562
|
+
* @example
|
|
1563
|
+
* ```typescript
|
|
1564
|
+
* const chain = FilterPresets.chain()
|
|
1565
|
+
* .blur('box')
|
|
1566
|
+
* .build();
|
|
1567
|
+
* ```
|
|
1568
|
+
*/
|
|
245
1569
|
blur(type = 'avg', radius) {
|
|
246
1570
|
if ('blur' in this.presets) {
|
|
247
1571
|
return this.add(this.presets.blur(type, radius));
|
|
248
1572
|
}
|
|
249
1573
|
return this.add(null);
|
|
250
1574
|
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Adds a sharpen filter to the chain (hardware-specific).
|
|
1577
|
+
* Only available for hardware presets that support sharpening
|
|
1578
|
+
*
|
|
1579
|
+
* @param amount - Sharpen amount (optional)
|
|
1580
|
+
*
|
|
1581
|
+
* @returns This instance for chaining
|
|
1582
|
+
*
|
|
1583
|
+
* @example
|
|
1584
|
+
* ```typescript
|
|
1585
|
+
* const chain = FilterPresets.chain()
|
|
1586
|
+
* .sharpen(1.5)
|
|
1587
|
+
* .build();
|
|
1588
|
+
* ```
|
|
1589
|
+
*
|
|
1590
|
+
* @example
|
|
1591
|
+
* ```typescript
|
|
1592
|
+
* const chain = FilterPresets.chain()
|
|
1593
|
+
* .sharpen()
|
|
1594
|
+
* .build();
|
|
1595
|
+
* ```
|
|
1596
|
+
*/
|
|
251
1597
|
sharpen(amount) {
|
|
252
1598
|
if ('sharpen' in this.presets) {
|
|
253
1599
|
return this.add(this.presets.sharpen(amount));
|
|
254
1600
|
}
|
|
255
1601
|
return this.add(null);
|
|
256
1602
|
}
|
|
1603
|
+
/**
|
|
1604
|
+
* Adds a stack filter to the chain (hardware-specific).
|
|
1605
|
+
* Only available for hardware presets that support stacking
|
|
1606
|
+
*
|
|
1607
|
+
* @param type - Stack type ('h' for horizontal, 'v' for vertical, 'x' for grid)
|
|
1608
|
+
* @param inputs - Number of inputs (default: 2)
|
|
1609
|
+
*
|
|
1610
|
+
* @returns This instance for chaining
|
|
1611
|
+
*
|
|
1612
|
+
* @example
|
|
1613
|
+
* ```typescript
|
|
1614
|
+
* const chain = FilterPresets.chain()
|
|
1615
|
+
* .stack('h', 2)
|
|
1616
|
+
* .build();
|
|
1617
|
+
* ```
|
|
1618
|
+
*
|
|
1619
|
+
* @example
|
|
1620
|
+
* ```typescript
|
|
1621
|
+
* const chain = FilterPresets.chain()
|
|
1622
|
+
* .stack('x', 4)
|
|
1623
|
+
* .build();
|
|
1624
|
+
* ```
|
|
1625
|
+
*/
|
|
257
1626
|
stack(type, inputs = 2) {
|
|
258
1627
|
if ('stack' in this.presets) {
|
|
259
1628
|
return this.add(this.presets.stack(type, inputs));
|
|
260
1629
|
}
|
|
261
1630
|
return this.add(null);
|
|
262
1631
|
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Adds a hwupload filter to upload frames to hardware.
|
|
1634
|
+
*
|
|
1635
|
+
* @returns This instance for chaining
|
|
1636
|
+
*
|
|
1637
|
+
* @example
|
|
1638
|
+
* ```typescript
|
|
1639
|
+
* const chain = FilterPresets.chain()
|
|
1640
|
+
* .hwupload()
|
|
1641
|
+
* .scale(1920, 1080)
|
|
1642
|
+
* .build();
|
|
1643
|
+
* ```
|
|
1644
|
+
*/
|
|
263
1645
|
hwupload() {
|
|
264
1646
|
if ('hwupload' in this.presets) {
|
|
265
1647
|
return this.add(this.presets.hwupload());
|
|
266
1648
|
}
|
|
267
1649
|
return this.add('hwupload');
|
|
268
1650
|
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Adds a hwdownload filter to download frames from hardware.
|
|
1653
|
+
*
|
|
1654
|
+
* @returns This instance for chaining
|
|
1655
|
+
*
|
|
1656
|
+
* @example
|
|
1657
|
+
* ```typescript
|
|
1658
|
+
* const chain = FilterPresets.chain()
|
|
1659
|
+
* .scale(1920, 1080)
|
|
1660
|
+
* .hwdownload()
|
|
1661
|
+
* .build();
|
|
1662
|
+
* ```
|
|
1663
|
+
*/
|
|
269
1664
|
hwdownload() {
|
|
270
1665
|
if ('hwdownload' in this.presets) {
|
|
271
1666
|
return this.add(this.presets.hwdownload());
|
|
272
1667
|
}
|
|
273
1668
|
return this.add('hwdownload');
|
|
274
1669
|
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Adds a hwmap filter to map frames between hardware devices.
|
|
1672
|
+
*
|
|
1673
|
+
* @param derive - Device to derive from (optional)
|
|
1674
|
+
*
|
|
1675
|
+
* @returns This instance for chaining
|
|
1676
|
+
*
|
|
1677
|
+
* @example
|
|
1678
|
+
* ```typescript
|
|
1679
|
+
* const chain = FilterPresets.chain()
|
|
1680
|
+
* .hwmap('cuda')
|
|
1681
|
+
* .build();
|
|
1682
|
+
* ```
|
|
1683
|
+
*
|
|
1684
|
+
* @example
|
|
1685
|
+
* ```typescript
|
|
1686
|
+
* const chain = FilterPresets.chain()
|
|
1687
|
+
* .hwmap()
|
|
1688
|
+
* .build();
|
|
1689
|
+
* ```
|
|
1690
|
+
*/
|
|
275
1691
|
hwmap(derive) {
|
|
276
1692
|
if ('hwmap' in this.presets) {
|
|
277
1693
|
return this.add(this.presets.hwmap(derive));
|
|
@@ -281,91 +1697,368 @@ export class ChainBuilderBase extends FilterChain {
|
|
|
281
1697
|
}
|
|
282
1698
|
/**
|
|
283
1699
|
* Fluent filter chain builder with preset methods.
|
|
1700
|
+
* Provides a convenient API for building filter chains using standard presets.
|
|
1701
|
+
*
|
|
1702
|
+
* @example
|
|
1703
|
+
* ```typescript
|
|
1704
|
+
* const filter = FilterPresets.chain()
|
|
1705
|
+
* .scale(1920, 1080)
|
|
1706
|
+
* .fps(30)
|
|
1707
|
+
* .fade('in', 0, 2)
|
|
1708
|
+
* .format('yuv420p')
|
|
1709
|
+
* .build();
|
|
1710
|
+
* ```
|
|
284
1711
|
*/
|
|
285
1712
|
export class FilterChainBuilder extends ChainBuilderBase {
|
|
286
1713
|
}
|
|
287
1714
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
* Can be used with Filter.create() for quick setup.
|
|
1715
|
+
* Standard filter presets for software filtering.
|
|
1716
|
+
* Provides static methods for creating common filter strings and
|
|
1717
|
+
* a chain builder for composing complex filter graphs.
|
|
292
1718
|
*
|
|
293
1719
|
* @example
|
|
294
1720
|
* ```typescript
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* );
|
|
1721
|
+
* // Static methods for individual filters
|
|
1722
|
+
* const scaleFilter = FilterPresets.scale(1920, 1080);
|
|
1723
|
+
* const fpsFilter = FilterPresets.fps(30);
|
|
299
1724
|
*
|
|
300
|
-
* //
|
|
1725
|
+
* // Chain builder for complex graphs
|
|
301
1726
|
* const chain = FilterPresets.chain()
|
|
302
1727
|
* .scale(1920, 1080)
|
|
303
|
-
* .
|
|
304
|
-
* .
|
|
1728
|
+
* .fps(30)
|
|
1729
|
+
* .fade('in', 0, 2)
|
|
305
1730
|
* .build();
|
|
306
1731
|
* ```
|
|
307
1732
|
*/
|
|
308
1733
|
export class FilterPresets extends FilterPresetBase {
|
|
309
1734
|
static instance = new FilterPresets();
|
|
310
1735
|
/**
|
|
311
|
-
*
|
|
1736
|
+
* Creates a new filter chain builder.
|
|
1737
|
+
*
|
|
1738
|
+
* @returns A new FilterChainBuilder instance
|
|
1739
|
+
*
|
|
1740
|
+
* @example
|
|
1741
|
+
* ```typescript
|
|
1742
|
+
* const filter = FilterPresets.chain()
|
|
1743
|
+
* .scale(1280, 720)
|
|
1744
|
+
* .fps(30)
|
|
1745
|
+
* .build();
|
|
1746
|
+
* ```
|
|
312
1747
|
*/
|
|
313
1748
|
static chain() {
|
|
314
1749
|
return new FilterChainBuilder(FilterPresets.instance);
|
|
315
1750
|
}
|
|
316
|
-
|
|
1751
|
+
/**
|
|
1752
|
+
* Creates a scale filter string.
|
|
1753
|
+
*
|
|
1754
|
+
* @param width - Target width
|
|
1755
|
+
* @param height - Target height
|
|
1756
|
+
* @param flags - Scaling algorithm flags (optional)
|
|
1757
|
+
*
|
|
1758
|
+
* @returns Scale filter string
|
|
1759
|
+
*
|
|
1760
|
+
* @example
|
|
1761
|
+
* ```typescript
|
|
1762
|
+
* const filter = FilterPresets.scale(1920, 1080);
|
|
1763
|
+
* ```
|
|
1764
|
+
*
|
|
1765
|
+
* @example
|
|
1766
|
+
* ```typescript
|
|
1767
|
+
* const filter = FilterPresets.scale(1280, 720, 'lanczos');
|
|
1768
|
+
* ```
|
|
1769
|
+
*/
|
|
317
1770
|
static scale(width, height, flags) {
|
|
318
1771
|
const result = FilterPresets.instance.scale(width, height, { flags });
|
|
319
1772
|
return result ?? '';
|
|
320
1773
|
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Creates a crop filter string.
|
|
1776
|
+
*
|
|
1777
|
+
* @param width - Crop width
|
|
1778
|
+
* @param height - Crop height
|
|
1779
|
+
* @param x - X position (default: 0)
|
|
1780
|
+
* @param y - Y position (default: 0)
|
|
1781
|
+
*
|
|
1782
|
+
* @returns Crop filter string
|
|
1783
|
+
*
|
|
1784
|
+
* @example
|
|
1785
|
+
* ```typescript
|
|
1786
|
+
* const filter = FilterPresets.crop(640, 480);
|
|
1787
|
+
* ```
|
|
1788
|
+
*
|
|
1789
|
+
* @example
|
|
1790
|
+
* ```typescript
|
|
1791
|
+
* const filter = FilterPresets.crop(1920, 1080, 100, 50);
|
|
1792
|
+
* ```
|
|
1793
|
+
*/
|
|
321
1794
|
static crop(width, height, x = 0, y = 0) {
|
|
322
1795
|
const result = FilterPresets.instance.crop(width, height, x, y);
|
|
323
1796
|
return result ?? '';
|
|
324
1797
|
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Creates an FPS filter string.
|
|
1800
|
+
*
|
|
1801
|
+
* @param fps - Target frame rate
|
|
1802
|
+
*
|
|
1803
|
+
* @returns FPS filter string
|
|
1804
|
+
*
|
|
1805
|
+
* @example
|
|
1806
|
+
* ```typescript
|
|
1807
|
+
* const filter = FilterPresets.fps(30);
|
|
1808
|
+
* ```
|
|
1809
|
+
*
|
|
1810
|
+
* @example
|
|
1811
|
+
* ```typescript
|
|
1812
|
+
* const filter = FilterPresets.fps(23.976);
|
|
1813
|
+
* ```
|
|
1814
|
+
*/
|
|
325
1815
|
static fps(fps) {
|
|
326
1816
|
const result = FilterPresets.instance.fps(fps);
|
|
327
1817
|
return result ?? '';
|
|
328
1818
|
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Creates a format filter string.
|
|
1821
|
+
*
|
|
1822
|
+
* @param pixelFormat - Target pixel format(s)
|
|
1823
|
+
*
|
|
1824
|
+
* @returns Format filter string
|
|
1825
|
+
*
|
|
1826
|
+
* @example
|
|
1827
|
+
* ```typescript
|
|
1828
|
+
* const filter = FilterPresets.format('yuv420p');
|
|
1829
|
+
* ```
|
|
1830
|
+
*
|
|
1831
|
+
* @example
|
|
1832
|
+
* ```typescript
|
|
1833
|
+
* const filter = FilterPresets.format(AV_PIX_FMT_RGB24);
|
|
1834
|
+
* ```
|
|
1835
|
+
*/
|
|
329
1836
|
static format(pixelFormat) {
|
|
330
1837
|
const result = FilterPresets.instance.format(pixelFormat);
|
|
331
1838
|
return result ?? '';
|
|
332
1839
|
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Creates a rotate filter string.
|
|
1842
|
+
*
|
|
1843
|
+
* @param angle - Rotation angle in degrees
|
|
1844
|
+
*
|
|
1845
|
+
* @returns Rotate filter string
|
|
1846
|
+
*
|
|
1847
|
+
* @example
|
|
1848
|
+
* ```typescript
|
|
1849
|
+
* const filter = FilterPresets.rotate(45);
|
|
1850
|
+
* ```
|
|
1851
|
+
*
|
|
1852
|
+
* @example
|
|
1853
|
+
* ```typescript
|
|
1854
|
+
* const filter = FilterPresets.rotate(-90);
|
|
1855
|
+
* ```
|
|
1856
|
+
*/
|
|
333
1857
|
static rotate(angle) {
|
|
334
1858
|
const result = FilterPresets.instance.rotate(angle);
|
|
335
1859
|
return result ?? '';
|
|
336
1860
|
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Creates a horizontal flip filter string.
|
|
1863
|
+
*
|
|
1864
|
+
* @returns Horizontal flip filter string
|
|
1865
|
+
*
|
|
1866
|
+
* @example
|
|
1867
|
+
* ```typescript
|
|
1868
|
+
* const filter = FilterPresets.hflip();
|
|
1869
|
+
* ```
|
|
1870
|
+
*/
|
|
337
1871
|
static hflip() {
|
|
338
1872
|
const result = FilterPresets.instance.hflip();
|
|
339
1873
|
return result ?? '';
|
|
340
1874
|
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Creates a vertical flip filter string.
|
|
1877
|
+
*
|
|
1878
|
+
* @returns Vertical flip filter string
|
|
1879
|
+
*
|
|
1880
|
+
* @example
|
|
1881
|
+
* ```typescript
|
|
1882
|
+
* const filter = FilterPresets.vflip();
|
|
1883
|
+
* ```
|
|
1884
|
+
*/
|
|
341
1885
|
static vflip() {
|
|
342
1886
|
const result = FilterPresets.instance.vflip();
|
|
343
1887
|
return result ?? '';
|
|
344
1888
|
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Creates a fade filter string.
|
|
1891
|
+
*
|
|
1892
|
+
* @param type - Fade type ('in' or 'out')
|
|
1893
|
+
* @param start - Start time in seconds
|
|
1894
|
+
* @param duration - Fade duration in seconds
|
|
1895
|
+
*
|
|
1896
|
+
* @returns Fade filter string
|
|
1897
|
+
*
|
|
1898
|
+
* @example
|
|
1899
|
+
* ```typescript
|
|
1900
|
+
* const filter = FilterPresets.fade('in', 0, 2);
|
|
1901
|
+
* ```
|
|
1902
|
+
*
|
|
1903
|
+
* @example
|
|
1904
|
+
* ```typescript
|
|
1905
|
+
* const filter = FilterPresets.fade('out', 10, 1.5);
|
|
1906
|
+
* ```
|
|
1907
|
+
*/
|
|
345
1908
|
static fade(type, start, duration) {
|
|
346
1909
|
const result = FilterPresets.instance.fade(type, start, duration);
|
|
347
1910
|
return result ?? '';
|
|
348
1911
|
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Creates an overlay filter string.
|
|
1914
|
+
*
|
|
1915
|
+
* @param x - X position (default: 0)
|
|
1916
|
+
* @param y - Y position (default: 0)
|
|
1917
|
+
*
|
|
1918
|
+
* @returns Overlay filter string
|
|
1919
|
+
*
|
|
1920
|
+
* @example
|
|
1921
|
+
* ```typescript
|
|
1922
|
+
* const filter = FilterPresets.overlay(100, 50);
|
|
1923
|
+
* ```
|
|
1924
|
+
*
|
|
1925
|
+
* @example
|
|
1926
|
+
* ```typescript
|
|
1927
|
+
* const filter = FilterPresets.overlay();
|
|
1928
|
+
* ```
|
|
1929
|
+
*/
|
|
349
1930
|
static overlay(x = 0, y = 0) {
|
|
350
1931
|
const result = FilterPresets.instance.overlay(x, y);
|
|
351
1932
|
return result ?? '';
|
|
352
1933
|
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Creates a volume filter string.
|
|
1936
|
+
*
|
|
1937
|
+
* @param factor - Volume multiplication factor
|
|
1938
|
+
*
|
|
1939
|
+
* @returns Volume filter string
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* ```typescript
|
|
1943
|
+
* const filter = FilterPresets.volume(0.5);
|
|
1944
|
+
* ```
|
|
1945
|
+
*
|
|
1946
|
+
* @example
|
|
1947
|
+
* ```typescript
|
|
1948
|
+
* const filter = FilterPresets.volume(2.0);
|
|
1949
|
+
* ```
|
|
1950
|
+
*/
|
|
353
1951
|
static volume(factor) {
|
|
354
1952
|
const result = FilterPresets.instance.volume(factor);
|
|
355
1953
|
return result ?? '';
|
|
356
1954
|
}
|
|
1955
|
+
/**
|
|
1956
|
+
* Creates an audio format filter string.
|
|
1957
|
+
*
|
|
1958
|
+
* @param sampleFormat - Target sample format
|
|
1959
|
+
* @param sampleRate - Target sample rate (optional)
|
|
1960
|
+
* @param channelLayout - Target channel layout (optional)
|
|
1961
|
+
*
|
|
1962
|
+
* @returns Audio format filter string
|
|
1963
|
+
*
|
|
1964
|
+
* @example
|
|
1965
|
+
* ```typescript
|
|
1966
|
+
* const filter = FilterPresets.aformat(AV_SAMPLE_FMT_FLT, 48000, 'stereo');
|
|
1967
|
+
* ```
|
|
1968
|
+
*
|
|
1969
|
+
* @example
|
|
1970
|
+
* ```typescript
|
|
1971
|
+
* const filter = FilterPresets.aformat('s16', 44100);
|
|
1972
|
+
* ```
|
|
1973
|
+
*/
|
|
357
1974
|
static aformat(sampleFormat, sampleRate, channelLayout) {
|
|
358
1975
|
const result = FilterPresets.instance.aformat(sampleFormat, sampleRate, channelLayout);
|
|
359
1976
|
return result ?? '';
|
|
360
1977
|
}
|
|
1978
|
+
/**
|
|
1979
|
+
* Creates an asetnsamples filter string.
|
|
1980
|
+
*
|
|
1981
|
+
* @param samples - Number of samples per frame
|
|
1982
|
+
* @param padding - Whether to pad or drop samples (default: true)
|
|
1983
|
+
*
|
|
1984
|
+
* @returns Asetnsamples filter string
|
|
1985
|
+
*
|
|
1986
|
+
* @example
|
|
1987
|
+
* ```typescript
|
|
1988
|
+
* const filter = FilterPresets.asetnsamples(960);
|
|
1989
|
+
* ```
|
|
1990
|
+
*
|
|
1991
|
+
* @example
|
|
1992
|
+
* ```typescript
|
|
1993
|
+
* const filter = FilterPresets.asetnsamples(1024, false);
|
|
1994
|
+
* ```
|
|
1995
|
+
*/
|
|
1996
|
+
static asetnsamples(samples, padding = true) {
|
|
1997
|
+
const result = FilterPresets.instance.asetnsamples(samples, padding);
|
|
1998
|
+
return result ?? '';
|
|
1999
|
+
}
|
|
2000
|
+
/**
|
|
2001
|
+
* Creates an atempo filter string.
|
|
2002
|
+
*
|
|
2003
|
+
* @param factor - Tempo factor (0.5 to 2.0)
|
|
2004
|
+
*
|
|
2005
|
+
* @returns Atempo filter string
|
|
2006
|
+
*
|
|
2007
|
+
* @example
|
|
2008
|
+
* ```typescript
|
|
2009
|
+
* const filter = FilterPresets.atempo(1.5);
|
|
2010
|
+
* ```
|
|
2011
|
+
*
|
|
2012
|
+
* @example
|
|
2013
|
+
* ```typescript
|
|
2014
|
+
* const filter = FilterPresets.atempo(0.8);
|
|
2015
|
+
* ```
|
|
2016
|
+
*/
|
|
361
2017
|
static atempo(factor) {
|
|
362
2018
|
const result = FilterPresets.instance.atempo(factor);
|
|
363
2019
|
return result ?? '';
|
|
364
2020
|
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Creates an audio fade filter string.
|
|
2023
|
+
*
|
|
2024
|
+
* @param type - Fade type ('in' or 'out')
|
|
2025
|
+
* @param start - Start time in seconds
|
|
2026
|
+
* @param duration - Fade duration in seconds
|
|
2027
|
+
*
|
|
2028
|
+
* @returns Audio fade filter string
|
|
2029
|
+
*
|
|
2030
|
+
* @example
|
|
2031
|
+
* ```typescript
|
|
2032
|
+
* const filter = FilterPresets.afade('in', 0, 3);
|
|
2033
|
+
* ```
|
|
2034
|
+
*
|
|
2035
|
+
* @example
|
|
2036
|
+
* ```typescript
|
|
2037
|
+
* const filter = FilterPresets.afade('out', 25, 2);
|
|
2038
|
+
* ```
|
|
2039
|
+
*/
|
|
365
2040
|
static afade(type, start, duration) {
|
|
366
2041
|
const result = FilterPresets.instance.afade(type, start, duration);
|
|
367
2042
|
return result ?? '';
|
|
368
2043
|
}
|
|
2044
|
+
/**
|
|
2045
|
+
* Creates an amix filter string.
|
|
2046
|
+
*
|
|
2047
|
+
* @param inputs - Number of inputs (default: 2)
|
|
2048
|
+
* @param duration - Duration mode (default: 'longest')
|
|
2049
|
+
*
|
|
2050
|
+
* @returns Amix filter string
|
|
2051
|
+
*
|
|
2052
|
+
* @example
|
|
2053
|
+
* ```typescript
|
|
2054
|
+
* const filter = FilterPresets.amix(3, 'longest');
|
|
2055
|
+
* ```
|
|
2056
|
+
*
|
|
2057
|
+
* @example
|
|
2058
|
+
* ```typescript
|
|
2059
|
+
* const filter = FilterPresets.amix(2, 'first');
|
|
2060
|
+
* ```
|
|
2061
|
+
*/
|
|
369
2062
|
static amix(inputs = 2, duration = 'longest') {
|
|
370
2063
|
const result = FilterPresets.instance.amix(inputs, duration);
|
|
371
2064
|
return result ?? '';
|
|
@@ -373,47 +2066,54 @@ export class FilterPresets extends FilterPresetBase {
|
|
|
373
2066
|
}
|
|
374
2067
|
/**
|
|
375
2068
|
* Hardware-accelerated filter presets.
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* Created and managed by HardwareContext for type-safe hardware operations.
|
|
2069
|
+
* Provides optimized filter implementations for specific hardware types,
|
|
2070
|
+
* with automatic fallback when operations aren't supported.
|
|
379
2071
|
*
|
|
380
2072
|
* @example
|
|
381
2073
|
* ```typescript
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* // Get hardware-specific scale filter (returns null if unsupported)
|
|
385
|
-
* const scaleFilter = hw.filterPresets.scale(1920, 1080);
|
|
2074
|
+
* // Create hardware presets for CUDA
|
|
2075
|
+
* const hw = new HardwareFilterPresets(AV_HWDEVICE_TYPE_CUDA);
|
|
386
2076
|
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* .scale(1920, 1080)
|
|
391
|
-
* .tonemap() // Skipped if not supported
|
|
392
|
-
* .custom('unsharp=5:5:1.0')
|
|
393
|
-
* .hwdownload()
|
|
394
|
-
* .build();
|
|
2077
|
+
* // Check capabilities
|
|
2078
|
+
* if (hw.support.scale) {
|
|
2079
|
+
* const scaleFilter = hw.scale(1920, 1080);
|
|
395
2080
|
* }
|
|
2081
|
+
*
|
|
2082
|
+
* // Use chain builder
|
|
2083
|
+
* const chain = hw.chain()
|
|
2084
|
+
* .hwupload()
|
|
2085
|
+
* .scale(1920, 1080)
|
|
2086
|
+
* .tonemap()
|
|
2087
|
+
* .hwdownload()
|
|
2088
|
+
* .build();
|
|
396
2089
|
* ```
|
|
397
2090
|
*/
|
|
398
2091
|
export class HardwareFilterPresets extends FilterPresetBase {
|
|
399
2092
|
deviceType;
|
|
400
|
-
|
|
2093
|
+
deviceTypeName;
|
|
401
2094
|
support;
|
|
402
2095
|
/**
|
|
403
|
-
*
|
|
404
|
-
* @
|
|
2096
|
+
* @param deviceType - Hardware device type enum
|
|
2097
|
+
* @param deviceTypeName - Optional hardware device type name (e.g., 'cuda', 'vaapi')
|
|
405
2098
|
*/
|
|
406
|
-
constructor(deviceType,
|
|
2099
|
+
constructor(deviceType, deviceTypeName) {
|
|
407
2100
|
super();
|
|
408
2101
|
this.deviceType = deviceType;
|
|
409
|
-
this.
|
|
2102
|
+
this.deviceTypeName = deviceTypeName ?? HardwareDeviceContext.getTypeName(deviceType);
|
|
410
2103
|
this.support = this.getSupport();
|
|
411
2104
|
}
|
|
412
2105
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* @param filterName -
|
|
416
|
-
* @returns True if
|
|
2106
|
+
* Checks if a filter is hardware-accelerated.
|
|
2107
|
+
*
|
|
2108
|
+
* @param filterName - Name of the filter to check
|
|
2109
|
+
* @returns True if the filter uses hardware acceleration
|
|
2110
|
+
*
|
|
2111
|
+
* @example
|
|
2112
|
+
* ```typescript
|
|
2113
|
+
* if (HardwareFilterPresets.isHardwareFilter('scale_cuda')) {
|
|
2114
|
+
* console.log('Hardware accelerated scaling');
|
|
2115
|
+
* }
|
|
2116
|
+
* ```
|
|
417
2117
|
*/
|
|
418
2118
|
static isHardwareFilter(filterName) {
|
|
419
2119
|
const filter = Filter.getByName(filterName);
|
|
@@ -424,14 +2124,49 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
424
2124
|
return (filter.flags & AVFILTER_FLAG_HWDEVICE) !== 0;
|
|
425
2125
|
}
|
|
426
2126
|
/**
|
|
427
|
-
*
|
|
2127
|
+
* Creates a hardware filter chain builder.
|
|
2128
|
+
*
|
|
2129
|
+
* @returns A new HardwareFilterChainBuilder instance
|
|
2130
|
+
*
|
|
2131
|
+
* @example
|
|
2132
|
+
* ```typescript
|
|
2133
|
+
* const filter = hw.chain()
|
|
2134
|
+
* .hwupload()
|
|
2135
|
+
* .scale(1920, 1080)
|
|
2136
|
+
* .hwdownload()
|
|
2137
|
+
* .build();
|
|
2138
|
+
* ```
|
|
428
2139
|
*/
|
|
429
2140
|
chain() {
|
|
430
2141
|
return new HardwareFilterChainBuilder(this);
|
|
431
2142
|
}
|
|
432
2143
|
/**
|
|
433
|
-
*
|
|
434
|
-
*
|
|
2144
|
+
* Creates a hardware-accelerated scale filter.
|
|
2145
|
+
*
|
|
2146
|
+
* Different hardware types use different scale filters:
|
|
2147
|
+
* - CUDA: scale_cuda or scale_npp (with npp option)
|
|
2148
|
+
* - VAAPI: scale_vaapi
|
|
2149
|
+
* - QSV: scale_qsv
|
|
2150
|
+
* - VideoToolbox: scale_vt
|
|
2151
|
+
* - RKMPP: scale_rkrga
|
|
2152
|
+
*
|
|
2153
|
+
* @param width - Target width
|
|
2154
|
+
* @param height - Target height
|
|
2155
|
+
* @param options - Hardware-specific scaling options
|
|
2156
|
+
*
|
|
2157
|
+
* @returns Hardware scale filter string or null if not supported
|
|
2158
|
+
*
|
|
2159
|
+
* @example
|
|
2160
|
+
* ```typescript
|
|
2161
|
+
* const filter = hwPresets.scale(1920, 1080);
|
|
2162
|
+
* ```
|
|
2163
|
+
*
|
|
2164
|
+
* @example
|
|
2165
|
+
* ```typescript
|
|
2166
|
+
* const filter = hwPresets.scale(1280, 720, { npp: true });
|
|
2167
|
+
* ```
|
|
2168
|
+
*
|
|
2169
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#scale_005fcuda | FFmpeg scale_cuda filter}
|
|
435
2170
|
*/
|
|
436
2171
|
scale(width, height, options) {
|
|
437
2172
|
if (!this.support.scale) {
|
|
@@ -449,7 +2184,7 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
449
2184
|
filterName = 'scale_vt'; // VideoToolbox uses scale_vt
|
|
450
2185
|
}
|
|
451
2186
|
else {
|
|
452
|
-
filterName = `scale_${this.
|
|
2187
|
+
filterName = `scale_${this.deviceTypeName}`;
|
|
453
2188
|
}
|
|
454
2189
|
let filter = `${filterName}=${width}:${height}`;
|
|
455
2190
|
if (options) {
|
|
@@ -463,15 +2198,32 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
463
2198
|
return filter;
|
|
464
2199
|
}
|
|
465
2200
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
2201
|
+
* Creates a hardware-accelerated overlay filter.
|
|
2202
|
+
*
|
|
2203
|
+
* @param x - X position (default: 0)
|
|
2204
|
+
* @param y - Y position (default: 0)
|
|
2205
|
+
* @param options - Hardware-specific overlay options
|
|
2206
|
+
*
|
|
2207
|
+
* @returns Hardware overlay filter string or null if not supported
|
|
2208
|
+
*
|
|
2209
|
+
* @example
|
|
2210
|
+
* ```typescript
|
|
2211
|
+
* const filter = hwPresets.overlay(100, 50);
|
|
2212
|
+
* ```
|
|
2213
|
+
*
|
|
2214
|
+
* @example
|
|
2215
|
+
* ```typescript
|
|
2216
|
+
* const filter = hwPresets.overlay(0, 0, { eof_action: 'pass' });
|
|
2217
|
+
* ```
|
|
2218
|
+
*
|
|
2219
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#overlay_005fcuda | FFmpeg overlay_cuda filter}
|
|
468
2220
|
*/
|
|
469
2221
|
overlay(x = 0, y = 0, options) {
|
|
470
2222
|
if (!this.support.overlay) {
|
|
471
2223
|
return null;
|
|
472
2224
|
}
|
|
473
2225
|
// Special handling for RKMPP which uses RGA
|
|
474
|
-
const filterName = this.deviceType === AV_HWDEVICE_TYPE_RKMPP ? 'overlay_rkrga' : `overlay_${this.
|
|
2226
|
+
const filterName = this.deviceType === AV_HWDEVICE_TYPE_RKMPP ? 'overlay_rkrga' : `overlay_${this.deviceTypeName}`;
|
|
475
2227
|
let filter = `${filterName}=${x}:${y}`;
|
|
476
2228
|
if (options) {
|
|
477
2229
|
for (const [key, value] of Object.entries(options)) {
|
|
@@ -481,13 +2233,55 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
481
2233
|
return filter;
|
|
482
2234
|
}
|
|
483
2235
|
/**
|
|
484
|
-
*
|
|
485
|
-
*
|
|
2236
|
+
* Creates a hardware-accelerated transpose filter.
|
|
2237
|
+
*
|
|
2238
|
+
* Direction values:
|
|
2239
|
+
* - 0: 90 degrees counter-clockwise and vertical flip
|
|
2240
|
+
* - 1 / 'clock': 90 degrees clockwise
|
|
2241
|
+
* - 2 / 'cclock': 90 degrees counter-clockwise
|
|
2242
|
+
* - 3 / 'clock_flip': 90 degrees clockwise and vertical flip
|
|
2243
|
+
*
|
|
2244
|
+
* @param mode - Transpose mode (number or string)
|
|
2245
|
+
*
|
|
2246
|
+
* @returns Hardware transpose filter string or null if not supported
|
|
2247
|
+
*
|
|
2248
|
+
* @example
|
|
2249
|
+
* ```typescript
|
|
2250
|
+
* const filter = hwPresets.transpose('clock');
|
|
2251
|
+
* ```
|
|
2252
|
+
*
|
|
2253
|
+
* @example
|
|
2254
|
+
* ```typescript
|
|
2255
|
+
* const filter = hwPresets.transpose(2);
|
|
2256
|
+
* ```
|
|
486
2257
|
*/
|
|
487
|
-
transpose(
|
|
2258
|
+
transpose(mode) {
|
|
488
2259
|
if (!this.support.transpose) {
|
|
489
2260
|
return null;
|
|
490
2261
|
}
|
|
2262
|
+
// Convert string modes to numbers
|
|
2263
|
+
let dir;
|
|
2264
|
+
if (typeof mode === 'string') {
|
|
2265
|
+
switch (mode) {
|
|
2266
|
+
case 'clock':
|
|
2267
|
+
dir = 1;
|
|
2268
|
+
break;
|
|
2269
|
+
case 'cclock':
|
|
2270
|
+
dir = 2;
|
|
2271
|
+
break;
|
|
2272
|
+
case 'clock_flip':
|
|
2273
|
+
dir = 3;
|
|
2274
|
+
break;
|
|
2275
|
+
case 'cclock_flip':
|
|
2276
|
+
dir = 0;
|
|
2277
|
+
break;
|
|
2278
|
+
default:
|
|
2279
|
+
dir = 0;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
else {
|
|
2283
|
+
dir = mode;
|
|
2284
|
+
}
|
|
491
2285
|
// Special handling for different hardware transpose implementations
|
|
492
2286
|
let filterName;
|
|
493
2287
|
if (this.deviceType === AV_HWDEVICE_TYPE_CUDA) {
|
|
@@ -497,20 +2291,34 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
497
2291
|
filterName = 'transpose_vt'; // CoreImage-based transpose
|
|
498
2292
|
}
|
|
499
2293
|
else {
|
|
500
|
-
filterName = `transpose_${this.
|
|
2294
|
+
filterName = `transpose_${this.deviceTypeName}`;
|
|
501
2295
|
}
|
|
502
2296
|
return `${filterName}=dir=${dir}`;
|
|
503
2297
|
}
|
|
504
2298
|
/**
|
|
505
|
-
*
|
|
506
|
-
*
|
|
2299
|
+
* Creates a hardware-accelerated tonemap filter.
|
|
2300
|
+
* Used for HDR to SDR conversion with hardware acceleration.
|
|
2301
|
+
*
|
|
2302
|
+
* @param options - Tonemapping options (algorithm, parameters)
|
|
2303
|
+
*
|
|
2304
|
+
* @returns Hardware tonemap filter string or null if not supported
|
|
2305
|
+
*
|
|
2306
|
+
* @example
|
|
2307
|
+
* ```typescript
|
|
2308
|
+
* const filter = hwPresets.tonemap();
|
|
2309
|
+
* ```
|
|
2310
|
+
*
|
|
2311
|
+
* @example
|
|
2312
|
+
* ```typescript
|
|
2313
|
+
* const filter = hwPresets.tonemap({ tonemap: 'hable', desat: '0' });
|
|
2314
|
+
* ```
|
|
507
2315
|
*/
|
|
508
2316
|
tonemap(options) {
|
|
509
2317
|
if (!this.support.tonemap) {
|
|
510
2318
|
return null;
|
|
511
2319
|
}
|
|
512
2320
|
// VideoToolbox uses different filter name
|
|
513
|
-
const filterName = this.deviceType === AV_HWDEVICE_TYPE_VIDEOTOOLBOX ? 'tonemap_videotoolbox' : `tonemap_${this.
|
|
2321
|
+
const filterName = this.deviceType === AV_HWDEVICE_TYPE_VIDEOTOOLBOX ? 'tonemap_videotoolbox' : `tonemap_${this.deviceTypeName}`;
|
|
514
2322
|
let filter = filterName;
|
|
515
2323
|
if (options) {
|
|
516
2324
|
const opts = Object.entries(options)
|
|
@@ -521,8 +2329,28 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
521
2329
|
return filter;
|
|
522
2330
|
}
|
|
523
2331
|
/**
|
|
524
|
-
*
|
|
525
|
-
*
|
|
2332
|
+
* Creates a hardware-accelerated deinterlace filter.
|
|
2333
|
+
*
|
|
2334
|
+
* Different hardware types use different deinterlacers:
|
|
2335
|
+
* - CUDA: yadif_cuda
|
|
2336
|
+
* - VAAPI: deinterlace_vaapi
|
|
2337
|
+
* - QSV: deinterlace_qsv
|
|
2338
|
+
* - Vulkan: bwdif_vulkan
|
|
2339
|
+
* - VideoToolbox: yadif_videotoolbox
|
|
2340
|
+
*
|
|
2341
|
+
* @param mode - Deinterlacing mode (optional)
|
|
2342
|
+
*
|
|
2343
|
+
* @returns Hardware deinterlace filter string or null if not supported
|
|
2344
|
+
*
|
|
2345
|
+
* @example
|
|
2346
|
+
* ```typescript
|
|
2347
|
+
* const filter = hwPresets.deinterlace();
|
|
2348
|
+
* ```
|
|
2349
|
+
*
|
|
2350
|
+
* @example
|
|
2351
|
+
* ```typescript
|
|
2352
|
+
* const filter = hwPresets.deinterlace('send_field');
|
|
2353
|
+
* ```
|
|
526
2354
|
*/
|
|
527
2355
|
deinterlace(mode) {
|
|
528
2356
|
if (!this.support.deinterlace) {
|
|
@@ -544,8 +2372,22 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
544
2372
|
}
|
|
545
2373
|
}
|
|
546
2374
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
2375
|
+
* Creates a hardware-accelerated flip filter.
|
|
2376
|
+
* Currently only Vulkan supports hardware flip filters.
|
|
2377
|
+
*
|
|
2378
|
+
* @param direction - Flip direction ('h' for horizontal, 'v' for vertical)
|
|
2379
|
+
*
|
|
2380
|
+
* @returns Hardware flip filter string or null if not supported
|
|
2381
|
+
*
|
|
2382
|
+
* @example
|
|
2383
|
+
* ```typescript
|
|
2384
|
+
* const filter = hwPresets.flip('h');
|
|
2385
|
+
* ```
|
|
2386
|
+
*
|
|
2387
|
+
* @example
|
|
2388
|
+
* ```typescript
|
|
2389
|
+
* const filter = hwPresets.flip('v');
|
|
2390
|
+
* ```
|
|
549
2391
|
*/
|
|
550
2392
|
flip(direction) {
|
|
551
2393
|
if (!this.support.flip) {
|
|
@@ -557,8 +2399,27 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
557
2399
|
return null;
|
|
558
2400
|
}
|
|
559
2401
|
/**
|
|
560
|
-
*
|
|
561
|
-
*
|
|
2402
|
+
* Creates a hardware-accelerated blur filter.
|
|
2403
|
+
*
|
|
2404
|
+
* Different hardware types support different blur filters:
|
|
2405
|
+
* - CUDA: bilateral_cuda
|
|
2406
|
+
* - Vulkan: avgblur_vulkan, gblur_vulkan
|
|
2407
|
+
* - OpenCL: avgblur_opencl, boxblur_opencl
|
|
2408
|
+
*
|
|
2409
|
+
* @param type - Blur type ('avg', 'gaussian', or 'box', default: 'avg')
|
|
2410
|
+
* @param radius - Blur radius (optional)
|
|
2411
|
+
*
|
|
2412
|
+
* @returns Hardware blur filter string or null if not supported
|
|
2413
|
+
*
|
|
2414
|
+
* @example
|
|
2415
|
+
* ```typescript
|
|
2416
|
+
* const filter = hwPresets.blur('gaussian', 5);
|
|
2417
|
+
* ```
|
|
2418
|
+
*
|
|
2419
|
+
* @example
|
|
2420
|
+
* ```typescript
|
|
2421
|
+
* const filter = hwPresets.blur('avg');
|
|
2422
|
+
* ```
|
|
562
2423
|
*/
|
|
563
2424
|
blur(type = 'avg', radius) {
|
|
564
2425
|
if (!this.support.blur) {
|
|
@@ -576,8 +2437,26 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
576
2437
|
}
|
|
577
2438
|
}
|
|
578
2439
|
/**
|
|
579
|
-
*
|
|
580
|
-
*
|
|
2440
|
+
* Creates a hardware-accelerated sharpen filter.
|
|
2441
|
+
*
|
|
2442
|
+
* Hardware sharpening support:
|
|
2443
|
+
* - VAAPI: sharpness_vaapi
|
|
2444
|
+
* - OpenCL: unsharp_opencl
|
|
2445
|
+
* - CUDA: sharpen_npp (NPP-based)
|
|
2446
|
+
*
|
|
2447
|
+
* @param amount - Sharpening amount (optional)
|
|
2448
|
+
*
|
|
2449
|
+
* @returns Hardware sharpen filter string or null if not supported
|
|
2450
|
+
*
|
|
2451
|
+
* @example
|
|
2452
|
+
* ```typescript
|
|
2453
|
+
* const filter = hwPresets.sharpen(1.5);
|
|
2454
|
+
* ```
|
|
2455
|
+
*
|
|
2456
|
+
* @example
|
|
2457
|
+
* ```typescript
|
|
2458
|
+
* const filter = hwPresets.sharpen();
|
|
2459
|
+
* ```
|
|
581
2460
|
*/
|
|
582
2461
|
sharpen(amount) {
|
|
583
2462
|
if (!this.support.sharpen) {
|
|
@@ -596,20 +2475,45 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
596
2475
|
}
|
|
597
2476
|
}
|
|
598
2477
|
/**
|
|
599
|
-
*
|
|
600
|
-
*
|
|
2478
|
+
* Creates a hardware-accelerated stack filter.
|
|
2479
|
+
* Only VAAPI and QSV support hardware stacking.
|
|
2480
|
+
*
|
|
2481
|
+
* @param type - Stack type ('h' for horizontal, 'v' for vertical, 'x' for grid)
|
|
2482
|
+
* @param inputs - Number of inputs to stack (default: 2)
|
|
2483
|
+
*
|
|
2484
|
+
* @returns Hardware stack filter string or null if not supported
|
|
2485
|
+
*
|
|
2486
|
+
* @example
|
|
2487
|
+
* ```typescript
|
|
2488
|
+
* const filter = hwPresets.stack('h', 2);
|
|
2489
|
+
* ```
|
|
2490
|
+
*
|
|
2491
|
+
* @example
|
|
2492
|
+
* ```typescript
|
|
2493
|
+
* const filter = hwPresets.stack('x', 4);
|
|
2494
|
+
* ```
|
|
601
2495
|
*/
|
|
602
2496
|
stack(type, inputs = 2) {
|
|
603
2497
|
if (!this.support.stack) {
|
|
604
2498
|
return null;
|
|
605
2499
|
}
|
|
606
2500
|
if (this.deviceType === AV_HWDEVICE_TYPE_VAAPI || this.deviceType === AV_HWDEVICE_TYPE_QSV) {
|
|
607
|
-
return `${type}stack_${this.
|
|
2501
|
+
return `${type}stack_${this.deviceTypeName}=inputs=${inputs}`;
|
|
608
2502
|
}
|
|
609
2503
|
return null;
|
|
610
2504
|
}
|
|
611
2505
|
/**
|
|
612
|
-
*
|
|
2506
|
+
* Creates a hwupload filter to upload frames to hardware memory.
|
|
2507
|
+
* CUDA uses hwupload_cuda, others use generic hwupload.
|
|
2508
|
+
*
|
|
2509
|
+
* @returns Hardware upload filter string
|
|
2510
|
+
*
|
|
2511
|
+
* @example
|
|
2512
|
+
* ```typescript
|
|
2513
|
+
* const filter = hwPresets.hwupload();
|
|
2514
|
+
* ```
|
|
2515
|
+
*
|
|
2516
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#hwupload | FFmpeg hwupload filter}
|
|
613
2517
|
*/
|
|
614
2518
|
hwupload() {
|
|
615
2519
|
if (this.deviceType === AV_HWDEVICE_TYPE_CUDA) {
|
|
@@ -618,25 +2522,64 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
618
2522
|
return 'hwupload';
|
|
619
2523
|
}
|
|
620
2524
|
/**
|
|
621
|
-
*
|
|
2525
|
+
* Creates a hwdownload filter to download frames from hardware memory.
|
|
2526
|
+
*
|
|
2527
|
+
* @returns Hardware download filter string
|
|
2528
|
+
*
|
|
2529
|
+
* @example
|
|
2530
|
+
* ```typescript
|
|
2531
|
+
* const filter = hwPresets.hwdownload();
|
|
2532
|
+
* ```
|
|
2533
|
+
*
|
|
2534
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#hwdownload | FFmpeg hwdownload filter}
|
|
622
2535
|
*/
|
|
623
2536
|
hwdownload() {
|
|
624
2537
|
return 'hwdownload';
|
|
625
2538
|
}
|
|
626
2539
|
/**
|
|
627
|
-
*
|
|
2540
|
+
* Creates a hwmap filter to map frames between hardware devices.
|
|
2541
|
+
*
|
|
2542
|
+
* @param derive - Device to derive from (optional)
|
|
2543
|
+
*
|
|
2544
|
+
* @returns Hardware map filter string
|
|
2545
|
+
*
|
|
2546
|
+
* @example
|
|
2547
|
+
* ```typescript
|
|
2548
|
+
* const filter = hwPresets.hwmap('cuda');
|
|
2549
|
+
* ```
|
|
2550
|
+
*
|
|
2551
|
+
* @example
|
|
2552
|
+
* ```typescript
|
|
2553
|
+
* const filter = hwPresets.hwmap();
|
|
2554
|
+
* ```
|
|
2555
|
+
*
|
|
2556
|
+
* @see {@link https://ffmpeg.org/ffmpeg-filters.html#hwmap | FFmpeg hwmap filter}
|
|
628
2557
|
*/
|
|
629
2558
|
hwmap(derive) {
|
|
630
2559
|
return derive ? `hwmap=derive_device=${derive}` : 'hwmap';
|
|
631
2560
|
}
|
|
632
2561
|
/**
|
|
633
|
-
*
|
|
2562
|
+
* Gets the filter capabilities for this hardware type.
|
|
2563
|
+
*
|
|
2564
|
+
* @returns Object describing which filters are supported
|
|
2565
|
+
*
|
|
2566
|
+
* @example
|
|
2567
|
+
* ```typescript
|
|
2568
|
+
* const caps = hw.getCapabilities();
|
|
2569
|
+
* if (caps.scale && caps.overlay) {
|
|
2570
|
+
* console.log('Hardware supports scaling and overlay');
|
|
2571
|
+
* }
|
|
2572
|
+
* ```
|
|
634
2573
|
*/
|
|
635
2574
|
getCapabilities() {
|
|
636
2575
|
return this.support;
|
|
637
2576
|
}
|
|
638
2577
|
/**
|
|
639
|
-
*
|
|
2578
|
+
* Determines filter support for the hardware type.
|
|
2579
|
+
*
|
|
2580
|
+
* @returns Hardware filter support configuration
|
|
2581
|
+
*
|
|
2582
|
+
* @internal
|
|
640
2583
|
*/
|
|
641
2584
|
getSupport() {
|
|
642
2585
|
switch (this.deviceType) {
|
|
@@ -816,7 +2759,18 @@ export class HardwareFilterPresets extends FilterPresetBase {
|
|
|
816
2759
|
}
|
|
817
2760
|
/**
|
|
818
2761
|
* Hardware filter chain builder with fluent API.
|
|
819
|
-
* Automatically skips unsupported filters (returns null).
|
|
2762
|
+
* Automatically skips unsupported filters (returns null) allowing graceful fallback.
|
|
2763
|
+
*
|
|
2764
|
+
* @example
|
|
2765
|
+
* ```typescript
|
|
2766
|
+
* const hw = new HardwareFilterPresets(AV_HWDEVICE_TYPE_CUDA, 'cuda');
|
|
2767
|
+
* const chain = hw.chain()
|
|
2768
|
+
* .hwupload()
|
|
2769
|
+
* .scale(1920, 1080)
|
|
2770
|
+
* .tonemap() // Skipped if not supported
|
|
2771
|
+
* .hwdownload()
|
|
2772
|
+
* .build();
|
|
2773
|
+
* ```
|
|
820
2774
|
*/
|
|
821
2775
|
export class HardwareFilterChainBuilder extends ChainBuilderBase {
|
|
822
2776
|
}
|