homebridge-plugin-utils 1.15.2 → 1.16.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 +4 -1
- package/build/eslint-rules.mjs +1 -0
- package/dist/featureoptions.d.ts +83 -5
- package/dist/featureoptions.js +65 -6
- package/dist/featureoptions.js.map +1 -1
- package/dist/ffmpeg/codecs.d.ts +172 -0
- package/dist/ffmpeg/codecs.js +374 -0
- package/dist/ffmpeg/codecs.js.map +1 -0
- package/dist/ffmpeg/exec.d.ts +108 -0
- package/dist/ffmpeg/exec.js +122 -0
- package/dist/ffmpeg/exec.js.map +1 -0
- package/dist/ffmpeg/index.d.ts +8 -0
- package/dist/ffmpeg/index.js +13 -0
- package/dist/ffmpeg/index.js.map +1 -0
- package/dist/ffmpeg/options.d.ts +345 -0
- package/dist/ffmpeg/options.js +750 -0
- package/dist/ffmpeg/options.js.map +1 -0
- package/dist/ffmpeg/process.d.ts +155 -0
- package/dist/ffmpeg/process.js +344 -0
- package/dist/ffmpeg/process.js.map +1 -0
- package/dist/ffmpeg/record.d.ts +230 -0
- package/dist/ffmpeg/record.js +504 -0
- package/dist/ffmpeg/record.js.map +1 -0
- package/dist/ffmpeg/rtp.d.ts +205 -0
- package/dist/ffmpeg/rtp.js +335 -0
- package/dist/ffmpeg/rtp.js.map +1 -0
- package/dist/ffmpeg/settings.d.ts +6 -0
- package/dist/ffmpeg/settings.js +17 -0
- package/dist/ffmpeg/settings.js.map +1 -0
- package/dist/ffmpeg/stream.d.ts +143 -0
- package/dist/ffmpeg/stream.js +186 -0
- package/dist/ffmpeg/stream.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mqttclient.d.ts +161 -1
- package/dist/mqttclient.js +161 -9
- package/dist/mqttclient.js.map +1 -1
- package/dist/service.d.ts +9 -2
- package/dist/service.js +6 -0
- package/dist/service.js.map +1 -1
- package/dist/ui/featureoptions.js +65 -6
- package/dist/ui/featureoptions.js.map +1 -1
- package/dist/ui/webUi-featureoptions.mjs +5 -4
- package/dist/util.d.ts +203 -12
- package/dist/util.js +95 -12
- package/dist/util.js.map +1 -1
- package/package.json +13 -9
- package/dist/rtp.d.ts +0 -32
- package/dist/rtp.js +0 -178
- package/dist/rtp.js.map +0 -1
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/* Copyright(C) 2023-2025, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* ffmpeg/codecs.ts: Probe FFmpeg capabilities and codecs.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Probe FFmpeg capabilities and codecs on the host system.
|
|
7
|
+
*
|
|
8
|
+
* Utilities for dynamically probing FFmpeg capabilities on the host system, including codec and hardware acceleration support.
|
|
9
|
+
*
|
|
10
|
+
* This module provides classes and interfaces to detect which FFmpeg encoders, decoders, and hardware acceleration methods are available, as well as host platform
|
|
11
|
+
* detection (such as macOS or Raspberry Pi specifics) that directly impact transcoding or livestreaming use cases. It enables advanced plugin development by allowing
|
|
12
|
+
* dynamic adaptation to the host's video processing features, helping ensure compatibility and optimal performance when working with camera-related Homebridge plugins
|
|
13
|
+
* that leverage FFmpeg.
|
|
14
|
+
*
|
|
15
|
+
* Key features include:
|
|
16
|
+
*
|
|
17
|
+
* - Querying the FFmpeg version, available codecs, and hardware acceleration methods.
|
|
18
|
+
* - Detecting host hardware platform details that are relevant to transcoding in FFmpeg.
|
|
19
|
+
* - Checking for the presence of specific encoders/decoders and validating hardware acceleration support.
|
|
20
|
+
*
|
|
21
|
+
* This module is intended for use by plugin developers or advanced users who need to introspect and adapt to system-level FFmpeg capabilities programmatically.
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import { EOL, cpus } from "node:os";
|
|
26
|
+
import { env, platform } from "node:process";
|
|
27
|
+
import { execFile } from "node:child_process";
|
|
28
|
+
import { readFileSync } from "node:fs";
|
|
29
|
+
import util from "node:util";
|
|
30
|
+
/**
|
|
31
|
+
* Probe FFmpeg capabilities and codecs on the host system.
|
|
32
|
+
*
|
|
33
|
+
* This class provides methods to check available FFmpeg decoders, encoders, and hardware acceleration methods, as well as to determine system-specific resources such as
|
|
34
|
+
* GPU memory (on Raspberry Pi). Intended for plugin authors or advanced users needing to assess FFmpeg capabilities dynamically.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* const codecs = new FfmpegCodecs({
|
|
40
|
+
*
|
|
41
|
+
* ffmpegExec: "ffmpeg",
|
|
42
|
+
* log: console,
|
|
43
|
+
* verbose: true
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Probe system and FFmpeg capabilities.
|
|
47
|
+
* const ready = await codecs.probe();
|
|
48
|
+
*
|
|
49
|
+
* if(ready) {
|
|
50
|
+
*
|
|
51
|
+
* console.log("Available FFmpeg version:", codecs.ffmpegVersion);
|
|
52
|
+
*
|
|
53
|
+
* if(codecs.hasDecoder("h264", "h264_v4l2m2m")) {
|
|
54
|
+
*
|
|
55
|
+
* console.log("Hardware H.264 decoder is available.");
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @category FFmpeg
|
|
61
|
+
*/
|
|
62
|
+
export class FfmpegCodecs {
|
|
63
|
+
/**
|
|
64
|
+
* The path or command name to invoke FFmpeg.
|
|
65
|
+
*/
|
|
66
|
+
ffmpegExec;
|
|
67
|
+
_ffmpegVersion;
|
|
68
|
+
_gpuMem;
|
|
69
|
+
_hostSystem;
|
|
70
|
+
log;
|
|
71
|
+
ffmpegCodecs;
|
|
72
|
+
ffmpegHwAccels;
|
|
73
|
+
/**
|
|
74
|
+
* Indicates whether verbose logging is enabled for FFmpeg probing.
|
|
75
|
+
*/
|
|
76
|
+
verbose;
|
|
77
|
+
/**
|
|
78
|
+
* Creates an instance of `FfmpegCodecs`.
|
|
79
|
+
*
|
|
80
|
+
* @param options - Options used to configure FFmpeg probing.
|
|
81
|
+
*/
|
|
82
|
+
constructor(options) {
|
|
83
|
+
this._gpuMem = 0;
|
|
84
|
+
this._ffmpegVersion = "";
|
|
85
|
+
this._hostSystem = "";
|
|
86
|
+
this.ffmpegExec = options.ffmpegExec ?? "ffmpeg";
|
|
87
|
+
this.ffmpegCodecs = {};
|
|
88
|
+
this.ffmpegHwAccels = {};
|
|
89
|
+
this.log = options.log;
|
|
90
|
+
this.verbose ??= options.verbose ?? false;
|
|
91
|
+
// Detect our host system type.
|
|
92
|
+
this.probeHwOs();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Probes the host system and FFmpeg executable for capabilities, version, codecs, and hardware acceleration support.
|
|
96
|
+
*
|
|
97
|
+
* Returns `true` if probing succeeded, otherwise `false`.
|
|
98
|
+
*
|
|
99
|
+
* @returns A promise that resolves to `true` if probing is successful, or `false` on failure.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
*
|
|
103
|
+
* ```ts
|
|
104
|
+
*
|
|
105
|
+
* const ready = await codecs.probe();
|
|
106
|
+
*
|
|
107
|
+
* if(!ready) {
|
|
108
|
+
*
|
|
109
|
+
* console.log("FFmpeg probing failed.");
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
async probe() {
|
|
114
|
+
// Let's conduct our system-specific capability probes.
|
|
115
|
+
switch (this.hostSystem) {
|
|
116
|
+
case "raspbian":
|
|
117
|
+
// If we're on a Raspberry Pi, let's verify that we have enough GPU memory for hardware-based decoding and encoding.
|
|
118
|
+
await this.probeRpiGpuMem();
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
// Capture the version information of FFmpeg.
|
|
124
|
+
if (!(await this.probeFfmpegVersion())) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
// Ensure we've got a working video processor before we do anything else.
|
|
128
|
+
if (!(await this.probeFfmpegCodecs()) || !(await this.probeFfmpegHwAccel())) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Checks whether a specific decoder is available for a given codec.
|
|
135
|
+
*
|
|
136
|
+
* @param codec - The codec name, e.g., "h264".
|
|
137
|
+
* @param decoder - The decoder name to check for, e.g., "h264_qsv".
|
|
138
|
+
*
|
|
139
|
+
* @returns `true` if the decoder is available for the codec, `false` otherwise.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
*
|
|
143
|
+
* ```ts
|
|
144
|
+
*
|
|
145
|
+
* if(codecs.hasDecoder("h264", "h264_qsv")) {
|
|
146
|
+
*
|
|
147
|
+
* // Use hardware decoding.
|
|
148
|
+
* }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
hasDecoder(codec, decoder) {
|
|
152
|
+
// Normalize our lookups.
|
|
153
|
+
codec = codec.toLowerCase();
|
|
154
|
+
decoder = decoder.toLowerCase();
|
|
155
|
+
return this.ffmpegCodecs[codec]?.decoders.some(x => x === decoder);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Checks whether a specific encoder is available for a given codec.
|
|
159
|
+
*
|
|
160
|
+
* @param codec - The codec name, e.g., "h264".
|
|
161
|
+
* @param encoder - The encoder name to check for, e.g., "h264_videotoolbox".
|
|
162
|
+
*
|
|
163
|
+
* @returns `true` if the encoder is available for the codec, `false` otherwise.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
*
|
|
167
|
+
* ```ts
|
|
168
|
+
*
|
|
169
|
+
* if(codecs.hasEncoder("h264", "h264_videotoolbox")) {
|
|
170
|
+
*
|
|
171
|
+
* // Use hardware encoding.
|
|
172
|
+
* }
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
hasEncoder(codec, encoder) {
|
|
176
|
+
// Normalize our lookups.
|
|
177
|
+
codec = codec.toLowerCase();
|
|
178
|
+
encoder = encoder.toLowerCase();
|
|
179
|
+
return this.ffmpegCodecs[codec]?.encoders.some(x => x === encoder);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Checks whether a given hardware acceleration method is available and validated on the host.
|
|
183
|
+
*
|
|
184
|
+
* @param accel - The hardware acceleration method name, e.g., "videotoolbox".
|
|
185
|
+
*
|
|
186
|
+
* @returns `true` if the hardware acceleration method is available, `false` otherwise.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
*
|
|
190
|
+
* ```ts
|
|
191
|
+
* if(codecs.hasHwAccel("videotoolbox")) {
|
|
192
|
+
*
|
|
193
|
+
* // Hardware acceleration is supported.
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
hasHwAccel(accel) {
|
|
198
|
+
return this.ffmpegHwAccels[accel.toLowerCase()] ? true : false;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Returns the amount of GPU memory available on the host system, in megabytes.
|
|
202
|
+
*
|
|
203
|
+
* @remarks Always returns `0` on non-Raspberry Pi systems.
|
|
204
|
+
*/
|
|
205
|
+
get gpuMem() {
|
|
206
|
+
return this._gpuMem;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Returns the detected FFmpeg version string, or "unknown" if detection failed.
|
|
210
|
+
*/
|
|
211
|
+
get ffmpegVersion() {
|
|
212
|
+
return this._ffmpegVersion;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Returns the host system type we are running on as one of "generic", "macOS.Apple", "macOS.Intel", or "raspbian".
|
|
216
|
+
*
|
|
217
|
+
* @remarks We are only trying to detect host capabilities to the extent they impact which FFmpeg options we are going to use.
|
|
218
|
+
*/
|
|
219
|
+
get hostSystem() {
|
|
220
|
+
return this._hostSystem;
|
|
221
|
+
}
|
|
222
|
+
// Probe our video processor's version.
|
|
223
|
+
async probeFfmpegVersion() {
|
|
224
|
+
return this.probeCmd(this.ffmpegExec, ["-hide_banner", "-version"], (stdout) => {
|
|
225
|
+
// A regular expression to parse out the version.
|
|
226
|
+
const versionRegex = /^ffmpeg version (.*) Copyright.*$/m;
|
|
227
|
+
// Parse out the version string.
|
|
228
|
+
const versionMatch = versionRegex.exec(stdout);
|
|
229
|
+
// If we have a version string, let's save it. Otherwise, we're blind.
|
|
230
|
+
this._ffmpegVersion = versionMatch ? versionMatch[1] : "unknown";
|
|
231
|
+
this.log.info("Using FFmpeg version: %s.", this.ffmpegVersion);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
// Probe our video processor's hardware acceleration capabilities.
|
|
235
|
+
async probeFfmpegHwAccel() {
|
|
236
|
+
if (!(await this.probeCmd(this.ffmpegExec, ["-hide_banner", "-hwaccels"], (stdout) => {
|
|
237
|
+
// Iterate through each line, and a build a list of encoders.
|
|
238
|
+
for (const accel of stdout.split(EOL)) {
|
|
239
|
+
// Skip blank lines.
|
|
240
|
+
if (!accel.length) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
// Skip the first line.
|
|
244
|
+
if (accel === "Hardware acceleration methods:") {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// We've found a hardware acceleration method, let's add it.
|
|
248
|
+
this.ffmpegHwAccels[accel.toLowerCase()] = true;
|
|
249
|
+
}
|
|
250
|
+
}))) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
// Let's test to ensure that just because we have a codec or capability available to us, it doesn't necessarily mean that the user has the hardware capabilities
|
|
254
|
+
// needed to use it, resulting in an FFmpeg error. We catch that here and prevent those capabilities from being exposed unless both software and hardware capabilities
|
|
255
|
+
// enable it. This simple test, generates a one-second video that is processed by the requested codec. If it fails, we discard the codec.
|
|
256
|
+
for (const accel of Object.keys(this.ffmpegHwAccels)) {
|
|
257
|
+
// eslint-disable-next-line no-await-in-loop
|
|
258
|
+
if (!(await this.probeCmd(this.ffmpegExec, [
|
|
259
|
+
"-hide_banner", "-hwaccel", accel, "-v", "quiet", "-t", "1", "-f", "lavfi", "-i", "color=black:1920x1080", "-c:v", "libx264", "-f", "null", "-"
|
|
260
|
+
], () => { }, true))) {
|
|
261
|
+
delete this.ffmpegHwAccels[accel];
|
|
262
|
+
if (this.verbose) {
|
|
263
|
+
this.log.error("Hardware-accelerated decoding and encoding using %s will be unavailable: unable to successfully validate capabilities.", accel);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
// Probe our video processor's encoding and decoding capabilities.
|
|
270
|
+
async probeFfmpegCodecs() {
|
|
271
|
+
return this.probeCmd(this.ffmpegExec, ["-hide_banner", "-codecs"], (stdout) => {
|
|
272
|
+
// A regular expression to parse out the codec and it's supported decoders.
|
|
273
|
+
const decodersRegex = /\S+\s+(\S+).+\(decoders: (.*?)\s*\)/;
|
|
274
|
+
// A regular expression to parse out the codec and it's supported encoders.
|
|
275
|
+
const encodersRegex = /\S+\s+(\S+).+\(encoders: (.*?)\s*\)/;
|
|
276
|
+
// Iterate through each line, and a build a list of encoders.
|
|
277
|
+
for (const codecLine of stdout.split(EOL)) {
|
|
278
|
+
// Let's see if we have decoders.
|
|
279
|
+
const decodersMatch = decodersRegex.exec(codecLine);
|
|
280
|
+
// Let's see if we have encoders.
|
|
281
|
+
const encodersMatch = encodersRegex.exec(codecLine);
|
|
282
|
+
// If we found decoders, add them to our list of supported decoders for this format.
|
|
283
|
+
if (decodersMatch) {
|
|
284
|
+
this.ffmpegCodecs[decodersMatch[1]] = { decoders: [], encoders: [] };
|
|
285
|
+
this.ffmpegCodecs[decodersMatch[1]].decoders = decodersMatch[2].split(" ").map(x => x.toLowerCase());
|
|
286
|
+
}
|
|
287
|
+
// If we found decoders, add them to our list of supported decoders for this format.
|
|
288
|
+
if (encodersMatch) {
|
|
289
|
+
if (!this.ffmpegCodecs[encodersMatch[1]]) {
|
|
290
|
+
this.ffmpegCodecs[encodersMatch[1]] = { decoders: [], encoders: [] };
|
|
291
|
+
}
|
|
292
|
+
this.ffmpegCodecs[encodersMatch[1]].encoders = encodersMatch[2].split(" ").map(x => x.toLowerCase());
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
// Identify what hardware and operating system environment we're actually running on.
|
|
298
|
+
probeHwOs() {
|
|
299
|
+
// Start off with a generic identifier.
|
|
300
|
+
this._hostSystem = "generic";
|
|
301
|
+
// Take a look at the platform we're on for an initial hint of what we are.
|
|
302
|
+
switch (platform) {
|
|
303
|
+
// The beloved macOS.
|
|
304
|
+
case "darwin":
|
|
305
|
+
this._hostSystem = "macOS." + (cpus()[0].model.includes("Apple") ? "Apple" : "Intel");
|
|
306
|
+
break;
|
|
307
|
+
// The indomitable Linux.
|
|
308
|
+
case "linux":
|
|
309
|
+
// Let's further see if we're a small, but scrappy, Raspberry Pi.
|
|
310
|
+
try {
|
|
311
|
+
// As of the 4.9 kernel, Raspberry Pi prefers to be identified using this method and has deprecated cpuinfo.
|
|
312
|
+
const systemId = readFileSync("/sys/firmware/devicetree/base/model", { encoding: "utf8" });
|
|
313
|
+
// Is it a Pi 4?
|
|
314
|
+
if (/Raspberry Pi (Compute Module )?4/.test(systemId)) {
|
|
315
|
+
this._hostSystem = "raspbian";
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
// We aren't especially concerned with errors here, given we're just trying to ascertain the system information through hints.
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
default:
|
|
323
|
+
// We aren't trying to solve for every system type.
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// Probe Raspberry Pi GPU capabilities.
|
|
328
|
+
async probeRpiGpuMem() {
|
|
329
|
+
return this.probeCmd("vcgencmd", ["get_mem", "gpu"], (stdout) => {
|
|
330
|
+
// A regular expression to parse out the configured GPU memory on the Raspberry Pi.
|
|
331
|
+
const gpuRegex = /^gpu=(.*)M\n$/;
|
|
332
|
+
// Let's see what we've got.
|
|
333
|
+
const gpuMatch = gpuRegex.exec(stdout);
|
|
334
|
+
// We matched what we're looking for.
|
|
335
|
+
if (gpuMatch) {
|
|
336
|
+
// Parse the result and retrieve our allocated GPU memory.
|
|
337
|
+
this._gpuMem = parseInt(gpuMatch[1]);
|
|
338
|
+
// Something went wrong.
|
|
339
|
+
if (isNaN(this._gpuMem)) {
|
|
340
|
+
this._gpuMem = 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
// Utility to probe the capabilities of FFmpeg and the host platform.
|
|
346
|
+
async probeCmd(command, commandLineArgs, processOutput, quietRunErrors = false) {
|
|
347
|
+
try {
|
|
348
|
+
// Promisify exec to allow us to wait for it asynchronously.
|
|
349
|
+
const execAsync = util.promisify(execFile);
|
|
350
|
+
// Check for the codecs in our video processor.
|
|
351
|
+
const { stdout } = await execAsync(command, commandLineArgs);
|
|
352
|
+
processOutput(stdout);
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
// It's really a SystemError, but Node hides that type from us for esoteric reasons.
|
|
357
|
+
if (error instanceof Error) {
|
|
358
|
+
const execError = error;
|
|
359
|
+
if (execError.code === "ENOENT") {
|
|
360
|
+
this.log.error("Unable to find '%s' in path: '%s'.", command, env.PATH);
|
|
361
|
+
}
|
|
362
|
+
else if (quietRunErrors) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
this.log.error("Error running %s: %s", command, error.message);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
this.log.error("Unable to probe the capabilities of your Homebridge host without access to '%s'. Ensure that it is available in your path and correctly working.", command);
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=codecs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codecs.js","sourceRoot":"","sources":["../../src/ffmpeg/codecs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executes arbitrary FFmpeg commands and returns the results.
|
|
3
|
+
*
|
|
4
|
+
* This module exposes the `FfmpegExec` class, which extends the core process handling of FFmpeg to support running custom command-line operations. It enables developers
|
|
5
|
+
* to run FFmpeg commands from Node.js, capture both standard output and error streams, handle process exit codes, and optionally supply input via stdin.
|
|
6
|
+
*
|
|
7
|
+
* Intended for plugin developers and advanced users, this module is ideal for scenarios where you need direct control over FFmpeg execution—such as probing media,
|
|
8
|
+
* transcoding, or automation tasks—while still benefiting from structured result handling and robust error logging.
|
|
9
|
+
*
|
|
10
|
+
* Key features:
|
|
11
|
+
*
|
|
12
|
+
* - Execute any FFmpeg command with custom arguments.
|
|
13
|
+
* - Capture stdout, stderr, and exit codes as structured results.
|
|
14
|
+
* - Optional stdin data injection.
|
|
15
|
+
* - Configurable error logging.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import type { FfmpegOptions } from "./options.js";
|
|
20
|
+
import { FfmpegProcess } from "./process.js";
|
|
21
|
+
import type { Nullable } from "../util.js";
|
|
22
|
+
/**
|
|
23
|
+
* Describes the result of executing an FFmpeg process.
|
|
24
|
+
*
|
|
25
|
+
* @property exitCode - The process exit code, or `null` if not available.
|
|
26
|
+
* @property stderr - The standard error output as a Buffer.
|
|
27
|
+
* @property stdout - The standard output as a Buffer.
|
|
28
|
+
*
|
|
29
|
+
* @category FFmpeg
|
|
30
|
+
*/
|
|
31
|
+
export type ProcessResult = {
|
|
32
|
+
exitCode: Nullable<number>;
|
|
33
|
+
stderr: Buffer;
|
|
34
|
+
stdout: Buffer;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Executes arbitrary FFmpeg commands and returns the results.
|
|
38
|
+
*
|
|
39
|
+
* This class extends `FfmpegProcess` to provide a simple interface for running FFmpeg with custom command-line arguments, capturing both standard output and standard
|
|
40
|
+
* error, and returning process results in a structured format. Intended for plugin authors and advanced users who need to programmatically execute FFmpeg commands and
|
|
41
|
+
* capture their results.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const exec = new FfmpegExec(options, ["-version"]);
|
|
47
|
+
* const result = await exec.exec();
|
|
48
|
+
*
|
|
49
|
+
* if(result && result.exitCode === 0) {
|
|
50
|
+
*
|
|
51
|
+
* console.log(result.stdout.toString());
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @see FfmpegProcess
|
|
56
|
+
* @see {@link https://ffmpeg.org/documentation.html | FFmpeg Documentation}
|
|
57
|
+
*
|
|
58
|
+
* @category FFmpeg
|
|
59
|
+
*/
|
|
60
|
+
export declare class FfmpegExec extends FfmpegProcess {
|
|
61
|
+
private isLoggingErrors;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a new instance of `FfmpegExec`.
|
|
64
|
+
*
|
|
65
|
+
* @param options - The options used to configure FFmpeg execution.
|
|
66
|
+
* @param commandLineArgs - Optional. Command-line arguments to pass to the FFmpeg process.
|
|
67
|
+
* @param logErrors - Optional. If `true`, errors will be logged; otherwise, they will be suppressed. Defaults to `true`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* const exec = new FfmpegExec(options, ["-i", "input.mp4", "-f", "null", "-"]);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
constructor(options: FfmpegOptions, commandLineArgs?: string[], logErrors?: boolean);
|
|
76
|
+
/**
|
|
77
|
+
* Runs the FFmpeg process and returns the result, including exit code, stdout, and stderr.
|
|
78
|
+
*
|
|
79
|
+
* If `stdinData` is provided, it will be written to the process's standard input before execution. Returns `null` if the process fails to start.
|
|
80
|
+
*
|
|
81
|
+
* @param stdinData - Optional. Data to write to FFmpeg's standard input.
|
|
82
|
+
*
|
|
83
|
+
* @returns A promise that resolves to a `ProcessResult` object containing the exit code, stdout, and stderr, or `null` if the process could not be started.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
*
|
|
87
|
+
* ```ts
|
|
88
|
+
* const exec = new FfmpegExec(options, ["-i", "input.wav", "output.mp3"]);
|
|
89
|
+
* const result = await exec.exec();
|
|
90
|
+
*
|
|
91
|
+
* if(result) {
|
|
92
|
+
*
|
|
93
|
+
* console.log("Exit code:", result.exitCode);
|
|
94
|
+
* console.log("FFmpeg output:", result.stdout.toString());
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
exec(stdinData?: Buffer): Promise<Nullable<ProcessResult>>;
|
|
99
|
+
/**
|
|
100
|
+
* Logs errors encountered during FFmpeg execution.
|
|
101
|
+
*
|
|
102
|
+
* If error logging is disabled, this method will do nothing. Otherwise, it calls the parent implementation for standard logging behavior.
|
|
103
|
+
*
|
|
104
|
+
* @param exitCode - The exit code returned by the FFmpeg process.
|
|
105
|
+
* @param signal - The signal used to terminate the process, if any.
|
|
106
|
+
*/
|
|
107
|
+
protected logFfmpegError(exitCode: number, signal: NodeJS.Signals): void;
|
|
108
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* ffmpeg/exec.ts: Execute arbitrary FFmpeg commands and return the results.
|
|
4
|
+
*/
|
|
5
|
+
import { FfmpegProcess } from "./process.js";
|
|
6
|
+
/**
|
|
7
|
+
* Executes arbitrary FFmpeg commands and returns the results.
|
|
8
|
+
*
|
|
9
|
+
* This class extends `FfmpegProcess` to provide a simple interface for running FFmpeg with custom command-line arguments, capturing both standard output and standard
|
|
10
|
+
* error, and returning process results in a structured format. Intended for plugin authors and advanced users who need to programmatically execute FFmpeg commands and
|
|
11
|
+
* capture their results.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const exec = new FfmpegExec(options, ["-version"]);
|
|
17
|
+
* const result = await exec.exec();
|
|
18
|
+
*
|
|
19
|
+
* if(result && result.exitCode === 0) {
|
|
20
|
+
*
|
|
21
|
+
* console.log(result.stdout.toString());
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @see FfmpegProcess
|
|
26
|
+
* @see {@link https://ffmpeg.org/documentation.html | FFmpeg Documentation}
|
|
27
|
+
*
|
|
28
|
+
* @category FFmpeg
|
|
29
|
+
*/
|
|
30
|
+
export class FfmpegExec extends FfmpegProcess {
|
|
31
|
+
isLoggingErrors;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new instance of `FfmpegExec`.
|
|
34
|
+
*
|
|
35
|
+
* @param options - The options used to configure FFmpeg execution.
|
|
36
|
+
* @param commandLineArgs - Optional. Command-line arguments to pass to the FFmpeg process.
|
|
37
|
+
* @param logErrors - Optional. If `true`, errors will be logged; otherwise, they will be suppressed. Defaults to `true`.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const exec = new FfmpegExec(options, ["-i", "input.mp4", "-f", "null", "-"]);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
constructor(options, commandLineArgs, logErrors = true) {
|
|
46
|
+
// Initialize our parent.
|
|
47
|
+
super(options, commandLineArgs);
|
|
48
|
+
// We want to log errors when they occur.
|
|
49
|
+
this.isLoggingErrors = logErrors;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Runs the FFmpeg process and returns the result, including exit code, stdout, and stderr.
|
|
53
|
+
*
|
|
54
|
+
* If `stdinData` is provided, it will be written to the process's standard input before execution. Returns `null` if the process fails to start.
|
|
55
|
+
*
|
|
56
|
+
* @param stdinData - Optional. Data to write to FFmpeg's standard input.
|
|
57
|
+
*
|
|
58
|
+
* @returns A promise that resolves to a `ProcessResult` object containing the exit code, stdout, and stderr, or `null` if the process could not be started.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* const exec = new FfmpegExec(options, ["-i", "input.wav", "output.mp3"]);
|
|
64
|
+
* const result = await exec.exec();
|
|
65
|
+
*
|
|
66
|
+
* if(result) {
|
|
67
|
+
*
|
|
68
|
+
* console.log("Exit code:", result.exitCode);
|
|
69
|
+
* console.log("FFmpeg output:", result.stdout.toString());
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
async exec(stdinData) {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
this.start();
|
|
76
|
+
if (this.process === null) {
|
|
77
|
+
this.log.error("Unable to execute command.");
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Write data to stdin and close
|
|
81
|
+
if (stdinData) {
|
|
82
|
+
this.process.stdin.end(stdinData);
|
|
83
|
+
}
|
|
84
|
+
const stderr = [];
|
|
85
|
+
const stdout = [];
|
|
86
|
+
// Read standard output and standard error into buffers.
|
|
87
|
+
this.process.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
88
|
+
this.process.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
89
|
+
// We prepend this listener to ensure we can properly cleanup after ourselves.
|
|
90
|
+
this.process.prependOnceListener("exit", () => {
|
|
91
|
+
// Trigger our process cleanup activities.
|
|
92
|
+
this.stop();
|
|
93
|
+
});
|
|
94
|
+
// Return when process is done.
|
|
95
|
+
this.process.once("exit", (exitCode) => {
|
|
96
|
+
// Return the output and results.
|
|
97
|
+
resolve({
|
|
98
|
+
exitCode,
|
|
99
|
+
stderr: Buffer.concat(stderr),
|
|
100
|
+
stdout: Buffer.concat(stdout)
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Logs errors encountered during FFmpeg execution.
|
|
107
|
+
*
|
|
108
|
+
* If error logging is disabled, this method will do nothing. Otherwise, it calls the parent implementation for standard logging behavior.
|
|
109
|
+
*
|
|
110
|
+
* @param exitCode - The exit code returned by the FFmpeg process.
|
|
111
|
+
* @param signal - The signal used to terminate the process, if any.
|
|
112
|
+
*/
|
|
113
|
+
logFfmpegError(exitCode, signal) {
|
|
114
|
+
// If we're ignoring errors, we're done.
|
|
115
|
+
if (!this.isLoggingErrors) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Otherwise, revert to our default logging in our parent.
|
|
119
|
+
super.logFfmpegError(exitCode, signal);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/ffmpeg/exec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAmB7C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,UAAW,SAAQ,aAAa;IAEnC,eAAe,CAAU;IAEjC;;;;;;;;;;;;OAYG;IACH,YAAY,OAAsB,EAAE,eAA0B,EAAE,SAAS,GAAG,IAAI;QAE9E,yBAAyB;QACzB,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAEhC,yCAAyC;QACzC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,KAAK,CAAC,IAAI,CAAC,SAAkB;QAElC,OAAO,IAAI,OAAO,CAA0B,CAAC,OAAO,EAAE,EAAE;YAEtD,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,IAAG,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBAEzB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;gBAE7C,OAAO,IAAI,CAAC;YACd,CAAC;YAED,gCAAgC;YAChC,IAAG,SAAS,EAAE,CAAC;gBAEb,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACpC,CAAC;YAED,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;YAE5B,wDAAwD;YACxD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,8EAA8E;YAC9E,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE;gBAE5C,0CAA0C;gBAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,+BAA+B;YAC/B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;gBAErC,iCAAiC;gBACjC,OAAO,CAAC;oBAEN,QAAQ;oBACR,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;oBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;iBAC9B,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACO,cAAc,CAAC,QAAgB,EAAE,MAAsB;QAE/D,wCAAwC;QACxC,IAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAEzB,OAAO;QACT,CAAC;QAED,0DAA0D;QAC1D,KAAK,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;CAEF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* ffmpeg/index.ts: FFmpeg classes.
|
|
4
|
+
*/
|
|
5
|
+
export * from "./codecs.js";
|
|
6
|
+
export * from "./exec.js";
|
|
7
|
+
export * from "./options.js";
|
|
8
|
+
export * from "./process.js";
|
|
9
|
+
export * from "./record.js";
|
|
10
|
+
export * from "./rtp.js";
|
|
11
|
+
export * from "./settings.js";
|
|
12
|
+
export * from "./stream.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ffmpeg/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|