Node.js FFmpeg Integration via Standard I/O
This article explains how to build a Node.js application that
interfaces directly with the FFmpeg binary using standard input (stdin)
and standard output (stdout) streams. By leveraging Node.js’s native
child_process module, you can pipe media data into FFmpeg
for processing and receive the output stream in real-time, eliminating
the need to write temporary files to disk.
Prerequisites
To follow this guide, you must have Node.js installed on your system, along with the FFmpeg binary. Ensure that FFmpeg is added to your system’s PATH environmental variable so it can be executed from the command line.
Spawning the FFmpeg Process
Node.js provides the child_process module to run system
commands. To redirect standard I/O, you use the spawn
function.
When configuring FFmpeg for standard I/O: * Use pipe:0
(or just -) to tell FFmpeg to read input data from the
stdin stream. * Use pipe:1 (or just -) at the
end of the argument list to tell FFmpeg to write the output data to the
stdout stream. * Specify the output container format explicitly using
the -f flag, as FFmpeg cannot auto-detect the format from a
stream pipe.
Implementation Example
The following code demonstrates how to stream an input video file
(input.mp4), pipe it into FFmpeg to extract the audio,
convert it to MP3 format, and write the resulting audio stream directly
to an output file (output.mp3).
const { spawn } = require('child_process');
const fs = require('fs');
// Create readable and writable file streams
const inputStream = fs.createReadStream('input.mp4');
const outputStream = fs.createWriteStream('output.mp3');
// Spawn the FFmpeg process
const ffmpeg = spawn('ffmpeg', [
'-i', 'pipe:0', // Read input from stdin
'-f', 'mp3', // Force output format to MP3
'-ab', '192k', // Set audio bitrate
'pipe:1' // Write output to stdout
]);
// Pipe the input stream into FFmpeg's stdin
inputStream.pipe(ffmpeg.stdin);
// Pipe FFmpeg's stdout into the output file stream
ffmpeg.stdout.pipe(outputStream);
// FFmpeg writes logs, progress, and errors to stderr
ffmpeg.stderr.on('data', (data) => {
console.log(`FFmpeg progress/log: ${data.toString()}`);
});
// Handle stream errors
ffmpeg.stdin.on('error', (err) => {
console.error('FFmpeg stdin error:', err.message);
});
ffmpeg.stdout.on('error', (err) => {
console.error('FFmpeg stdout error:', err.message);
});
// Handle process completion
ffmpeg.on('close', (code) => {
if (code === 0) {
console.log('FFmpeg processing completed successfully.');
} else {
console.error(`FFmpeg process exited with code ${code}`);
}
});Key Considerations
- Stderr Handling: FFmpeg sends all diagnostic
information, progress updates, and warnings to the
stderrstream instead ofstdout. You must handle thestderrstream to monitor processing progress or debug errors, otherwise the process could hang. - Buffer Overflow: Ensure that you pipe the streams
(
pipe()) rather than writing data manually. Node.js streams manage backpressure automatically, preventing memory issues when the data transfer rates between Node.js and the FFmpeg binary differ. - Format Limitations: Some media formats (such as
MP4) require “seekability” to write header metadata at the end of the
file. Because standard output streams are non-seekable, formats
requiring seeking cannot be streamed over stdout. Use streaming-friendly
formats like fragmented MP4
(
-f mp4 -movflags frag_keyframe+empty_moov), MPEG-TS, WebM, or raw audio formats (like MP3 or FLAC).