Execute FFmpeg commands with full control over the process lifecycle, including execution methods, streaming, progress monitoring, and process management.
Execute the configured FFmpeg command.
/**
* Execute the FFmpeg command
* @returns FfmpegCommand instance (for event handling)
* @emits 'start', 'progress', 'stderr', 'codecData', 'error', 'end'
*/
run() // → FfmpegCommand
// Aliases: exec, executeUsage Examples:
// Basic execution with events
ffmpeg('input.avi')
.videoCodec('libx264')
.save('output.mp4')
.on('start', (commandLine) => {
console.log('Spawned FFmpeg with command: ' + commandLine);
})
.on('progress', (progress) => {
console.log('Processing: ' + progress.percent + '% done');
})
.on('end', () => {
console.log('Processing finished successfully');
})
.on('error', (err, stdout, stderr) => {
console.error('Error occurred: ' + err.message);
});
// Promise-based execution
const processVideo = () => {
return new Promise((resolve, reject) => {
ffmpeg('input.mp4')
.videoCodec('libx264')
.save('output.mp4')
.on('end', resolve)
.on('error', reject);
});
};Execute command and save output to a specific file.
/**
* Execute command and save to file
* @param output - Output file path
* @returns FfmpegCommand instance (for event handling)
*/
save(output) // → FfmpegCommand
// Aliases: saveToFileUsage Examples:
// Simple save operation
ffmpeg('input.avi').save('output.mp4');
// Save with configuration
ffmpeg('input.mov')
.videoCodec('libx264')
.audioBitrate('128k')
.save('converted.mp4')
.on('progress', (progress) => {
console.log(`Progress: ${progress.percent}%`);
});
// Multiple saves (different outputs)
ffmpeg('source.avi')
.save('copy1.mp4')
.save('copy2.avi');Execute command and pipe output to streams.
/**
* Execute command and pipe to stream
* @param stream - Optional target writable stream
* @param options - Optional pipe options
* @returns WritableStream (the output stream)
*/
pipe(stream?, options?) // → WritableStream
// Aliases: stream, writeToStreamUsage Examples:
const fs = require('fs');
const express = require('express');
// Pipe to file stream
const outputStream = fs.createWriteStream('output.mp4');
ffmpeg('input.avi')
.videoCodec('libx264')
.format('mp4')
.pipe(outputStream);
// Pipe to HTTP response (streaming video)
app.get('/video', (req, res) => {
res.contentType('video/mp4');
ffmpeg('source.mkv')
.videoCodec('libx264')
.format('mp4')
.outputOptions('-movflags', 'frag_keyframe+empty_moov') // Streaming-friendly
.pipe(res);
});
// Get output stream for custom handling
const outputStream = ffmpeg('input.avi')
.videoCodec('libx264')
.format('mp4')
.pipe();
outputStream.on('data', (chunk) => {
// Handle video data chunks
console.log(`Received ${chunk.length} bytes`);
});
// Pipe with options
ffmpeg('input.mp4')
.format('webm')
.pipe(outputStream, { end: false }); // Don't end stream when doneControl the FFmpeg process during execution.
/**
* Kill the FFmpeg process
* @param signal - Optional kill signal (default: 'SIGKILL')
* @returns FfmpegCommand instance
*/
kill(signal?) // → FfmpegCommand
/**
* Change process niceness (priority)
* @param niceness - New niceness value (-20 to 20)
* @returns FfmpegCommand instance
*/
renice(niceness) // → FfmpegCommandUsage Examples:
// Graceful termination
const command = ffmpeg('long_video.mp4')
.save('output.mp4')
.on('progress', (progress) => {
if (progress.percent > 50) {
command.kill('SIGINT'); // Graceful stop
}
});
// Force kill on timeout
const command = ffmpeg('input.avi').save('output.mp4');
setTimeout(() => {
command.kill(); // Force kill (SIGKILL)
}, 30000); // 30 second timeout
// Adjust process priority
ffmpeg('input.mp4')
.renice(10) // Lower priority (higher niceness)
.save('background_conversion.mp4');Create identical copies of configured commands.
/**
* Create identical command copy
* @returns New FfmpegCommand with same configuration
*/
clone() // → FfmpegCommandUsage Example:
// Base configuration
const baseCommand = ffmpeg('input.avi')
.videoCodec('libx264')
.audioCodec('aac');
// Create variations
const hdCommand = baseCommand.clone().size('1920x1080').save('hd.mp4');
const sdCommand = baseCommand.clone().size('854x480').save('sd.mp4');
const audioCommand = baseCommand.clone().noVideo().save('audio.mp3');
// Run all conversions
hdCommand.run();
sdCommand.run();
audioCommand.run();Monitor processing progress and statistics.
/**
* Progress event data
*/
interface ProgressInfo {
frames: number; // Number of frames transcoded
currentFps: number; // Current processing FPS
currentKbps: number; // Current processing speed (kbps)
targetSize: number; // Target output size in KB
timemark: string; // Current processing time (HH:MM:SS.mmm)
percent: number; // Progress percentage (0-100)
}Usage Examples:
ffmpeg('input.mp4')
.save('output.mp4')
.on('progress', (progress) => {
console.log(`
Progress: ${progress.percent.toFixed(1)}%
Frames: ${progress.frames}
FPS: ${progress.currentFps}
Speed: ${progress.currentKbps} kbps
Time: ${progress.timemark}
Size: ${progress.targetSize} KB
`);
});
// Progress bar implementation
ffmpeg('long_video.mp4')
.save('output.mp4')
.on('progress', (progress) => {
const bar = '='.repeat(Math.floor(progress.percent / 2));
const spaces = ' '.repeat(50 - bar.length);
process.stdout.write(`\r[${bar}${spaces}] ${progress.percent.toFixed(1)}%`);
})
.on('end', () => {
console.log('\nProcessing complete!');
});Handle processing errors and diagnostics.
/**
* Error event handler
* @param error - Error object with message
* @param stdout - FFmpeg stdout output
* @param stderr - FFmpeg stderr output
*/
.on('error', (error, stdout, stderr) => void)Usage Examples:
ffmpeg('input.mp4')
.save('output.mp4')
.on('error', (err, stdout, stderr) => {
console.error('FFmpeg error occurred:');
console.error('Error message:', err.message);
console.error('FFmpeg stdout:', stdout);
console.error('FFmpeg stderr:', stderr);
// Handle specific error types
if (err.message.includes('No such file')) {
console.error('Input file not found');
} else if (err.message.includes('Permission denied')) {
console.error('Permission error - check file access');
}
});
// Retry on error
const processWithRetry = (input, output, retries = 3) => {
return new Promise((resolve, reject) => {
const attempt = (retriesLeft) => {
ffmpeg(input)
.save(output)
.on('end', resolve)
.on('error', (err) => {
if (retriesLeft > 0) {
console.log(`Retry ${3 - retriesLeft + 1}/${3}`);
setTimeout(() => attempt(retriesLeft - 1), 1000);
} else {
reject(err);
}
});
};
attempt(retries);
});
};Handle all available events for comprehensive monitoring.
/**
* All available events
*/
.on('start', (commandLine) => void) // Process started
.on('codecData', (data) => void) // Input codec info
.on('progress', (progress) => void) // Progress update
.on('stderr', (stderrLine) => void) // Raw stderr line
.on('error', (err, stdout, stderr) => void) // Error occurred
.on('end', (stdout, stderr) => void) // Processing completeUsage Example:
ffmpeg('input.mp4')
.save('output.mp4')
.on('start', (commandLine) => {
console.log('Started:', commandLine);
})
.on('codecData', (data) => {
console.log('Input codec info:', data);
})
.on('progress', (progress) => {
console.log(`Progress: ${progress.percent}%`);
})
.on('stderr', (stderrLine) => {
console.log('FFmpeg stderr:', stderrLine);
})
.on('error', (err, stdout, stderr) => {
console.error('Processing failed:', err.message);
})
.on('end', (stdout, stderr) => {
console.log('Processing completed successfully');
console.log('Final stdout:', stdout);
});/**
* Kill signals for process termination
*/
type KillSignal =
| 'SIGTERM' // Graceful termination (default for most systems)
| 'SIGINT' // Interrupt (Ctrl+C equivalent)
| 'SIGKILL' // Force kill (cannot be caught)
| 'SIGUSR1' // User-defined signal 1
| string; // Any valid system signal
/**
* Process niceness range
*/
type Niceness = number; // -20 (highest priority) to 20 (lowest priority)
/**
* Pipe options for streaming
*/
interface PipeOptions {
end?: boolean; // End target stream when FFmpeg finishes (default: true)
allowHalfOpen?: boolean; // Keep stream open for writing after reading ends
objectMode?: boolean; // Object mode for streams
}
/**
* Codec data structure from codecData event
*/
interface CodecData {
format: string; // Input format name
duration: string; // Input duration
audio?: AudioCodecInfo; // Audio stream information
video?: VideoCodecInfo; // Video stream information
}
/**
* Audio codec information
*/
interface AudioCodecInfo {
codec: string; // Audio codec name
sample_fmt: string; // Sample format
sample_rate: string; // Sample rate
channels: number; // Channel count
channel_layout: string; // Channel layout description
}
/**
* Video codec information
*/
interface VideoCodecInfo {
codec: string; // Video codec name
pix_fmt: string; // Pixel format
resolution: string; // Video resolution (WxH)
fps: number; // Frame rate
}