A fluent API to FFMPEG for audio and video manipulation with chainable methods
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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
}