586 lines
42 KiB
JavaScript
586 lines
42 KiB
JavaScript
import * as plugins from './plugins.js';
|
|
import { FfmpegCommand } from './classes.ffmpegcommand.js';
|
|
/**
|
|
* SmartFfmpeg - A fast Node.js module for media file conversion using ffmpeg
|
|
*
|
|
* @example Modern Builder API
|
|
* ```typescript
|
|
* const ffmpeg = new SmartFfmpeg();
|
|
*
|
|
* // File to file with fluent API
|
|
* await ffmpeg.create()
|
|
* .input('/path/to/input.mp4')
|
|
* .videoCodec('libx264')
|
|
* .audioBitrate('128k')
|
|
* .size(1920, 1080)
|
|
* .output('/path/to/output.mp4')
|
|
* .run();
|
|
*
|
|
* // Buffer to buffer
|
|
* const outputBuffer = await ffmpeg.create()
|
|
* .input(inputBuffer, { format: 'mp4' })
|
|
* .videoCodec('libx264')
|
|
* .toBuffer('webm');
|
|
*
|
|
* // With progress tracking
|
|
* await ffmpeg.create()
|
|
* .input('/path/to/input.mp4')
|
|
* .videoCodec('libx264')
|
|
* .onProgress(p => console.log(`${p.percent?.toFixed(1)}%`))
|
|
* .output('/path/to/output.mp4')
|
|
* .run();
|
|
*
|
|
* // Stream output
|
|
* const stream = ffmpeg.create()
|
|
* .input('/path/to/input.mp4')
|
|
* .videoCodec('libx264')
|
|
* .toStream('mp4');
|
|
* ```
|
|
*
|
|
* @example Legacy API (still supported)
|
|
* ```typescript
|
|
* await ffmpeg.convert('input.mp4', 'output.webm', {
|
|
* videoCodec: 'libvpx-vp9',
|
|
* audioBitrate: '128k'
|
|
* });
|
|
* ```
|
|
*/
|
|
export class SmartFfmpeg {
|
|
ffmpegPath;
|
|
ffprobePath;
|
|
constructor() {
|
|
this.ffmpegPath = plugins.ffmpegBinaryPath;
|
|
this.ffprobePath = plugins.ffprobeBinaryPath;
|
|
}
|
|
// ==================== BUILDER API ====================
|
|
/**
|
|
* Create a new FfmpegCommand builder for fluent API usage
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* await ffmpeg.create()
|
|
* .input('/path/to/input.mp4')
|
|
* .videoCodec('libx264')
|
|
* .crf(23)
|
|
* .output('/path/to/output.mp4')
|
|
* .run();
|
|
* ```
|
|
*/
|
|
create() {
|
|
return new FfmpegCommand(this.ffmpegPath, this.ffprobePath);
|
|
}
|
|
/**
|
|
* Shorthand to create a command with input already set
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // File input
|
|
* await ffmpeg.input('/path/to/input.mp4')
|
|
* .videoCodec('libx264')
|
|
* .output('/path/to/output.mp4')
|
|
* .run();
|
|
*
|
|
* // Buffer input
|
|
* const output = await ffmpeg.input(buffer, { format: 'mp4' })
|
|
* .videoCodec('libx264')
|
|
* .toBuffer('webm');
|
|
* ```
|
|
*/
|
|
input(source, options) {
|
|
return this.create().input(source, options);
|
|
}
|
|
// ==================== LEGACY API ====================
|
|
/**
|
|
* Get media file information using ffprobe
|
|
*/
|
|
async getMediaInfo(inputPath) {
|
|
const args = [
|
|
'-v', 'quiet',
|
|
'-print_format', 'json',
|
|
'-show_format',
|
|
'-show_streams',
|
|
inputPath
|
|
];
|
|
const result = await this.runProcess(this.ffprobePath, args);
|
|
const data = JSON.parse(result.stdout);
|
|
return {
|
|
format: {
|
|
filename: data.format.filename,
|
|
formatName: data.format.format_name,
|
|
formatLongName: data.format.format_long_name,
|
|
duration: parseFloat(data.format.duration) || 0,
|
|
size: parseInt(data.format.size, 10) || 0,
|
|
bitrate: parseInt(data.format.bit_rate, 10) || 0,
|
|
},
|
|
streams: (data.streams || []).map((stream) => this.parseStreamInfo(stream)),
|
|
};
|
|
}
|
|
/**
|
|
* Convert media file with specified options
|
|
*/
|
|
async convert(inputPath, outputPath, options = {}) {
|
|
const args = this.buildConversionArgs(inputPath, outputPath, options);
|
|
await this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
/**
|
|
* Convert media file with progress reporting
|
|
*/
|
|
async convertWithProgress(inputPath, outputPath, options = {}, onProgress) {
|
|
// Get duration for progress percentage calculation
|
|
let totalDuration;
|
|
try {
|
|
const info = await this.getMediaInfo(inputPath);
|
|
totalDuration = info.format.duration;
|
|
}
|
|
catch {
|
|
// Continue without duration info
|
|
}
|
|
const args = ['-progress', 'pipe:1', ...this.buildConversionArgs(inputPath, outputPath, options)];
|
|
return new Promise((resolve, reject) => {
|
|
const process = plugins.child_process.spawn(this.ffmpegPath, args);
|
|
let progressData = {};
|
|
process.stdout?.on('data', (data) => {
|
|
const lines = data.toString().split('\n');
|
|
for (const line of lines) {
|
|
const [key, value] = line.split('=');
|
|
if (!key || !value)
|
|
continue;
|
|
switch (key.trim()) {
|
|
case 'frame':
|
|
progressData.frame = parseInt(value, 10);
|
|
break;
|
|
case 'fps':
|
|
progressData.fps = parseFloat(value);
|
|
break;
|
|
case 'total_size':
|
|
progressData.size = parseInt(value, 10);
|
|
break;
|
|
case 'out_time_ms':
|
|
progressData.time = parseInt(value, 10) / 1000000;
|
|
if (totalDuration && progressData.time) {
|
|
progressData.percent = Math.min(100, (progressData.time / totalDuration) * 100);
|
|
}
|
|
break;
|
|
case 'bitrate':
|
|
progressData.bitrate = value.trim();
|
|
break;
|
|
case 'speed':
|
|
progressData.speed = value.trim();
|
|
break;
|
|
case 'progress':
|
|
if (value.trim() === 'continue' || value.trim() === 'end') {
|
|
if (onProgress && progressData.frame !== undefined) {
|
|
onProgress(progressData);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
let stderr = '';
|
|
process.stderr?.on('data', (data) => {
|
|
stderr += data.toString();
|
|
});
|
|
process.on('close', (code) => {
|
|
if (code === 0) {
|
|
resolve();
|
|
}
|
|
else {
|
|
reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`));
|
|
}
|
|
});
|
|
process.on('error', (err) => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* Extract audio from video file
|
|
*/
|
|
async extractAudio(inputPath, outputPath, options = {}) {
|
|
const conversionOptions = {
|
|
...options,
|
|
noVideo: true,
|
|
};
|
|
await this.convert(inputPath, outputPath, conversionOptions);
|
|
}
|
|
/**
|
|
* Remove audio from video file
|
|
*/
|
|
async removeAudio(inputPath, outputPath, options = {}) {
|
|
const conversionOptions = {
|
|
...options,
|
|
noAudio: true,
|
|
};
|
|
await this.convert(inputPath, outputPath, conversionOptions);
|
|
}
|
|
/**
|
|
* Take a screenshot at a specific time
|
|
*/
|
|
async screenshot(inputPath, outputPath, options) {
|
|
const args = [
|
|
'-y',
|
|
'-ss', this.formatTime(options.time),
|
|
'-i', inputPath,
|
|
'-vframes', '1',
|
|
];
|
|
if (options.width || options.height) {
|
|
const scale = this.buildScaleFilter(options.width, options.height);
|
|
args.push('-vf', scale);
|
|
}
|
|
if (options.format === 'jpg' && options.quality) {
|
|
args.push('-q:v', String(Math.round((100 - options.quality) / 100 * 31)));
|
|
}
|
|
else if (options.format === 'webp' && options.quality) {
|
|
args.push('-quality', String(options.quality));
|
|
}
|
|
args.push(outputPath);
|
|
await this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
/**
|
|
* Generate multiple thumbnails from video
|
|
*/
|
|
async generateThumbnails(inputPath, outputDir, options) {
|
|
const info = await this.getMediaInfo(inputPath);
|
|
const duration = info.format.duration;
|
|
const interval = duration / (options.count + 1);
|
|
const pattern = options.filenamePattern || 'thumb_%d';
|
|
const ext = options.format || 'png';
|
|
const outputPaths = [];
|
|
for (let i = 1; i <= options.count; i++) {
|
|
const time = interval * i;
|
|
const filename = pattern.replace('%d', String(i).padStart(3, '0')) + '.' + ext;
|
|
const outputPath = plugins.path.join(outputDir, filename);
|
|
await this.screenshot(inputPath, outputPath, {
|
|
time,
|
|
width: options.width,
|
|
height: options.height,
|
|
format: options.format,
|
|
});
|
|
outputPaths.push(outputPath);
|
|
}
|
|
return outputPaths;
|
|
}
|
|
/**
|
|
* Resize video
|
|
*/
|
|
async resize(inputPath, outputPath, width, height, options = {}) {
|
|
await this.convert(inputPath, outputPath, { ...options, width, height });
|
|
}
|
|
/**
|
|
* Change video frame rate
|
|
*/
|
|
async changeFrameRate(inputPath, outputPath, fps, options = {}) {
|
|
await this.convert(inputPath, outputPath, { ...options, fps });
|
|
}
|
|
/**
|
|
* Trim media file
|
|
*/
|
|
async trim(inputPath, outputPath, startTime, duration, options = {}) {
|
|
await this.convert(inputPath, outputPath, { ...options, startTime, duration });
|
|
}
|
|
/**
|
|
* Convert to GIF
|
|
*/
|
|
async toGif(inputPath, outputPath, options = {}) {
|
|
const args = ['-y'];
|
|
if (options.startTime !== undefined) {
|
|
args.push('-ss', this.formatTime(options.startTime));
|
|
}
|
|
args.push('-i', inputPath);
|
|
if (options.duration !== undefined) {
|
|
args.push('-t', this.formatTime(options.duration));
|
|
}
|
|
// Build filter for GIF optimization
|
|
const filters = [];
|
|
if (options.fps) {
|
|
filters.push(`fps=${options.fps}`);
|
|
}
|
|
if (options.width || options.height) {
|
|
filters.push(this.buildScaleFilter(options.width, options.height));
|
|
}
|
|
// Split filter for palette generation (better GIF quality)
|
|
filters.push('split[s0][s1]');
|
|
filters.push('[s0]palettegen[p]');
|
|
filters.push('[s1][p]paletteuse');
|
|
args.push('-filter_complex', filters.join(','));
|
|
args.push(outputPath);
|
|
await this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
/**
|
|
* Concatenate multiple media files
|
|
*/
|
|
async concat(inputPaths, outputPath, options = {}) {
|
|
// Create concat file content
|
|
const concatContent = inputPaths
|
|
.map(p => `file '${p.replace(/'/g, "'\\''")}'`)
|
|
.join('\n');
|
|
// Write to temp file
|
|
const tempFile = plugins.path.join(plugins.path.dirname(outputPath), `.concat_${Date.now()}.txt`);
|
|
// Write concat file using SmartFs
|
|
const fs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
|
|
await fs.file(tempFile).write(concatContent);
|
|
try {
|
|
const args = [
|
|
'-y',
|
|
'-f', 'concat',
|
|
'-safe', '0',
|
|
'-i', tempFile,
|
|
];
|
|
if (options.videoCodec) {
|
|
args.push('-c:v', options.videoCodec);
|
|
}
|
|
else {
|
|
args.push('-c', 'copy');
|
|
}
|
|
if (options.audioCodec) {
|
|
args.push('-c:a', options.audioCodec);
|
|
}
|
|
args.push(outputPath);
|
|
await this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
finally {
|
|
// Clean up temp file
|
|
await fs.file(tempFile).delete();
|
|
}
|
|
}
|
|
/**
|
|
* Add audio to video
|
|
*/
|
|
async addAudio(videoPath, audioPath, outputPath, options = {}) {
|
|
const args = [
|
|
'-y',
|
|
'-i', videoPath,
|
|
'-i', audioPath,
|
|
'-c:v', options.videoCodec || 'copy',
|
|
'-c:a', options.audioCodec || 'aac',
|
|
];
|
|
if (options.audioBitrate) {
|
|
args.push('-b:a', options.audioBitrate);
|
|
}
|
|
if (options.shortest) {
|
|
args.push('-shortest');
|
|
}
|
|
args.push('-map', '0:v:0', '-map', '1:a:0');
|
|
args.push(outputPath);
|
|
await this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
/**
|
|
* Get available encoders
|
|
*/
|
|
async getEncoders() {
|
|
const result = await this.runProcess(this.ffmpegPath, ['-encoders', '-hide_banner']);
|
|
const lines = result.stdout.split('\n');
|
|
const encoders = [];
|
|
let started = false;
|
|
for (const line of lines) {
|
|
if (line.includes('------')) {
|
|
started = true;
|
|
continue;
|
|
}
|
|
if (started && line.trim()) {
|
|
const match = line.match(/^\s*[A-Z.]+\s+(\S+)/);
|
|
if (match) {
|
|
encoders.push(match[1]);
|
|
}
|
|
}
|
|
}
|
|
return encoders;
|
|
}
|
|
/**
|
|
* Get available decoders
|
|
*/
|
|
async getDecoders() {
|
|
const result = await this.runProcess(this.ffmpegPath, ['-decoders', '-hide_banner']);
|
|
const lines = result.stdout.split('\n');
|
|
const decoders = [];
|
|
let started = false;
|
|
for (const line of lines) {
|
|
if (line.includes('------')) {
|
|
started = true;
|
|
continue;
|
|
}
|
|
if (started && line.trim()) {
|
|
const match = line.match(/^\s*[A-Z.]+\s+(\S+)/);
|
|
if (match) {
|
|
decoders.push(match[1]);
|
|
}
|
|
}
|
|
}
|
|
return decoders;
|
|
}
|
|
/**
|
|
* Get available formats
|
|
*/
|
|
async getFormats() {
|
|
const result = await this.runProcess(this.ffmpegPath, ['-formats', '-hide_banner']);
|
|
const lines = result.stdout.split('\n');
|
|
const formats = [];
|
|
let started = false;
|
|
for (const line of lines) {
|
|
if (line.includes('--')) {
|
|
started = true;
|
|
continue;
|
|
}
|
|
if (started && line.trim()) {
|
|
const match = line.match(/^\s*[DE ]+\s+(\S+)/);
|
|
if (match) {
|
|
formats.push(match[1]);
|
|
}
|
|
}
|
|
}
|
|
return formats;
|
|
}
|
|
/**
|
|
* Run ffmpeg with raw arguments
|
|
*/
|
|
async runRaw(args) {
|
|
return this.runProcess(this.ffmpegPath, args);
|
|
}
|
|
/**
|
|
* Run ffprobe with raw arguments
|
|
*/
|
|
async runProbeRaw(args) {
|
|
return this.runProcess(this.ffprobePath, args);
|
|
}
|
|
// ============ Private Methods ============
|
|
buildConversionArgs(inputPath, outputPath, options) {
|
|
const args = [];
|
|
// Overwrite flag
|
|
if (options.overwrite !== false) {
|
|
args.push('-y');
|
|
}
|
|
// Input seeking (before -i for fast seeking)
|
|
if (options.startTime !== undefined) {
|
|
args.push('-ss', this.formatTime(options.startTime));
|
|
}
|
|
args.push('-i', inputPath);
|
|
// Duration (after -i)
|
|
if (options.duration !== undefined) {
|
|
args.push('-t', this.formatTime(options.duration));
|
|
}
|
|
// Video options
|
|
if (options.noVideo) {
|
|
args.push('-vn');
|
|
}
|
|
else {
|
|
if (options.videoCodec) {
|
|
args.push('-c:v', options.videoCodec);
|
|
}
|
|
if (options.videoBitrate) {
|
|
args.push('-b:v', options.videoBitrate);
|
|
}
|
|
if (options.crf !== undefined) {
|
|
args.push('-crf', String(options.crf));
|
|
}
|
|
if (options.preset) {
|
|
args.push('-preset', options.preset);
|
|
}
|
|
if (options.fps) {
|
|
args.push('-r', String(options.fps));
|
|
}
|
|
if (options.width || options.height) {
|
|
args.push('-vf', this.buildScaleFilter(options.width, options.height));
|
|
}
|
|
}
|
|
// Audio options
|
|
if (options.noAudio) {
|
|
args.push('-an');
|
|
}
|
|
else {
|
|
if (options.audioCodec) {
|
|
args.push('-c:a', options.audioCodec);
|
|
}
|
|
if (options.audioBitrate) {
|
|
args.push('-b:a', options.audioBitrate);
|
|
}
|
|
if (options.sampleRate) {
|
|
args.push('-ar', String(options.sampleRate));
|
|
}
|
|
if (options.audioChannels) {
|
|
args.push('-ac', String(options.audioChannels));
|
|
}
|
|
}
|
|
// Output format
|
|
if (options.format) {
|
|
args.push('-f', options.format);
|
|
}
|
|
// Extra arguments
|
|
if (options.extraArgs) {
|
|
args.push(...options.extraArgs);
|
|
}
|
|
args.push(outputPath);
|
|
return args;
|
|
}
|
|
buildScaleFilter(width, height) {
|
|
const w = width ? String(width) : '-1';
|
|
const h = height ? String(height) : '-1';
|
|
// Use -2 instead of -1 to ensure even dimensions (required for some codecs)
|
|
return `scale=${w === '-1' ? '-2' : w}:${h === '-1' ? '-2' : h}`;
|
|
}
|
|
formatTime(time) {
|
|
if (typeof time === 'string') {
|
|
return time;
|
|
}
|
|
// Convert seconds to HH:MM:SS.mmm format
|
|
const hours = Math.floor(time / 3600);
|
|
const minutes = Math.floor((time % 3600) / 60);
|
|
const seconds = time % 60;
|
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toFixed(3).padStart(6, '0')}`;
|
|
}
|
|
parseStreamInfo(stream) {
|
|
const info = {
|
|
index: stream.index,
|
|
codecName: stream.codec_name,
|
|
codecLongName: stream.codec_long_name,
|
|
codecType: stream.codec_type,
|
|
};
|
|
if (stream.codec_type === 'video') {
|
|
info.width = stream.width;
|
|
info.height = stream.height;
|
|
if (stream.r_frame_rate) {
|
|
const [num, den] = stream.r_frame_rate.split('/').map(Number);
|
|
info.frameRate = den ? num / den : num;
|
|
}
|
|
if (stream.bit_rate) {
|
|
info.bitrate = parseInt(stream.bit_rate, 10);
|
|
}
|
|
}
|
|
if (stream.codec_type === 'audio') {
|
|
info.sampleRate = parseInt(stream.sample_rate, 10);
|
|
info.channels = stream.channels;
|
|
if (stream.bit_rate) {
|
|
info.bitrate = parseInt(stream.bit_rate, 10);
|
|
}
|
|
}
|
|
if (stream.duration) {
|
|
info.duration = parseFloat(stream.duration);
|
|
}
|
|
return info;
|
|
}
|
|
runProcess(command, args) {
|
|
return new Promise((resolve, reject) => {
|
|
const process = plugins.child_process.spawn(command, args);
|
|
let stdout = '';
|
|
let stderr = '';
|
|
process.stdout?.on('data', (data) => {
|
|
stdout += data.toString();
|
|
});
|
|
process.stderr?.on('data', (data) => {
|
|
stderr += data.toString();
|
|
});
|
|
process.on('close', (code) => {
|
|
if (code === 0) {
|
|
resolve({ stdout, stderr });
|
|
}
|
|
else {
|
|
reject(new Error(`Process exited with code ${code}: ${stderr}`));
|
|
}
|
|
});
|
|
process.on('error', (err) => {
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zbWFydGZmbXBlZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuc21hcnRmZm1wZWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFFeEMsT0FBTyxFQUFFLGFBQWEsRUFBeUMsTUFBTSw0QkFBNEIsQ0FBQztBQVNsRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Q0c7QUFDSCxNQUFNLE9BQU8sV0FBVztJQUNkLFVBQVUsQ0FBUztJQUNuQixXQUFXLENBQVM7SUFFNUI7UUFDRSxJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztRQUMzQyxJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztJQUMvQyxDQUFDO0lBRUQsd0RBQXdEO0lBRXhEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILE1BQU07UUFDSixPQUFPLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7OztPQWdCRztJQUNILEtBQUssQ0FBQyxNQUFvQixFQUFFLE9BQXVCO1FBQ2pELE9BQU8sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVELHVEQUF1RDtJQUV2RDs7T0FFRztJQUNJLEtBQUssQ0FBQyxZQUFZLENBQUMsU0FBaUI7UUFDekMsTUFBTSxJQUFJLEdBQUc7WUFDWCxJQUFJLEVBQUUsT0FBTztZQUNiLGVBQWUsRUFBRSxNQUFNO1lBQ3ZCLGNBQWM7WUFDZCxlQUFlO1lBQ2YsU0FBUztTQUNWLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFD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
|