import * as plugins from './plugins.js'; import { Readable, Writable } from 'stream'; /** * Modern fluent builder API for ffmpeg commands * * @example * ```typescript * // File to file * await ffmpeg.create() * .input('/path/to/input.mp4') * .videoCodec('libx264') * .audioBitrate('128k') * .output('/path/to/output.mp4') * .run(); * * // Buffer to buffer * const outputBuffer = await ffmpeg.create() * .input(inputBuffer, { format: 'mp4' }) * .videoCodec('libx264') * .toBuffer('webm'); * * // With progress * await ffmpeg.create() * .input('/path/to/input.mp4') * .videoCodec('libx264') * .onProgress(p => console.log(`${p.percent}%`)) * .output('/path/to/output.mp4') * .run(); * ``` */ export class FfmpegCommand { ffmpegPath; ffprobePath; // Input configuration inputSource = null; inputOpts = {}; customInputArgs = []; // Output configuration outputDest = null; outputFormat = null; customOutputArgs = []; // Video settings _videoCodec = null; _videoBitrate = null; _width = null; _height = null; _fps = null; _crf = null; _preset = null; _noVideo = false; // Audio settings _audioCodec = null; _audioBitrate = null; _sampleRate = null; _audioChannels = null; _noAudio = false; // Timing _startTime = null; _duration = null; // Video filters videoFilters = []; // Audio filters audioFilters = []; // Complex filter _complexFilter = null; // Extra arguments extraInputArgs = []; extraOutputArgs = []; // Callbacks progressCallback = null; // Options _overwrite = true; constructor(ffmpegPath, ffprobePath) { this.ffmpegPath = ffmpegPath; this.ffprobePath = ffprobePath; } // ==================== INPUT METHODS ==================== /** * Set the input source * @param source - File path, Buffer, or Readable stream * @param options - Input options (format required for buffer/stream) */ input(source, options = {}) { this.inputSource = source; this.inputOpts = options; return this; } /** * Seek to position before input (fast seek) * @param time - Time in seconds or timecode string */ seekInput(time) { this._startTime = time; return this; } /** * Add custom input arguments */ inputArgs(...args) { this.extraInputArgs.push(...args); return this; } // ==================== VIDEO METHODS ==================== /** * Set video codec */ videoCodec(codec) { this._videoCodec = codec; return this; } /** * Set video bitrate * @param bitrate - e.g., '1M', '2000k' */ videoBitrate(bitrate) { this._videoBitrate = bitrate; return this; } /** * Set output dimensions * @param width - Width in pixels (-1 for auto) * @param height - Height in pixels (-1 for auto) */ size(width, height) { this._width = width; this._height = height ?? null; return this; } /** * Set frame rate */ fps(rate) { this._fps = rate; return this; } /** * Set Constant Rate Factor (quality) * @param value - 0-51, lower is better quality */ crf(value) { this._crf = value; return this; } /** * Set encoding preset */ preset(value) { this._preset = value; return this; } /** * Remove video stream */ noVideo() { this._noVideo = true; return this; } /** * Add a video filter * @param filter - Filter string (e.g., 'scale=1920:1080', 'hflip') */ videoFilter(filter) { this.videoFilters.push(filter); return this; } /** * Scale video * @param width - Width (-1 or -2 for auto) * @param height - Height (-1 or -2 for auto) */ scale(width, height) { // Use -2 to ensure even dimensions const w = width === -1 ? '-2' : String(width); const h = height === -1 ? '-2' : String(height); this.videoFilters.push(`scale=${w}:${h}`); return this; } /** * Crop video */ crop(width, height, x = 0, y = 0) { this.videoFilters.push(`crop=${width}:${height}:${x}:${y}`); return this; } /** * Rotate video * @param angle - Rotation in radians or 'PI/2', 'PI', etc. */ rotate(angle) { this.videoFilters.push(`rotate=${angle}`); return this; } /** * Flip video horizontally */ flipHorizontal() { this.videoFilters.push('hflip'); return this; } /** * Flip video vertically */ flipVertical() { this.videoFilters.push('vflip'); return this; } /** * Add padding to video */ pad(width, height, x = 0, y = 0, color = 'black') { this.videoFilters.push(`pad=${width}:${height}:${x}:${y}:${color}`); return this; } // ==================== AUDIO METHODS ==================== /** * Set audio codec */ audioCodec(codec) { this._audioCodec = codec; return this; } /** * Set audio bitrate * @param bitrate - e.g., '128k', '320k' */ audioBitrate(bitrate) { this._audioBitrate = bitrate; return this; } /** * Set audio sample rate * @param rate - Sample rate in Hz (e.g., 44100, 48000) */ sampleRate(rate) { this._sampleRate = rate; return this; } /** * Set number of audio channels * @param channels - 1 for mono, 2 for stereo */ audioChannels(channels) { this._audioChannels = channels; return this; } /** * Remove audio stream */ noAudio() { this._noAudio = true; return this; } /** * Add an audio filter * @param filter - Filter string (e.g., 'volume=2', 'aecho=0.8:0.88:60:0.4') */ audioFilter(filter) { this.audioFilters.push(filter); return this; } /** * Set audio volume * @param level - Volume multiplier (e.g., 2 for double, 0.5 for half) */ volume(level) { this.audioFilters.push(`volume=${level}`); return this; } /** * Normalize audio */ normalize() { this.audioFilters.push('loudnorm'); return this; } // ==================== TIMING METHODS ==================== /** * Set start time (seek) * @param time - Time in seconds or timecode string */ seek(time) { this._startTime = time; return this; } /** * Set output duration * @param time - Duration in seconds or timecode string */ duration(time) { this._duration = time; return this; } /** * Set both start and end time */ trim(start, end) { this._startTime = start; // Calculate duration from end - start if (typeof start === 'number' && typeof end === 'number') { this._duration = end - start; } else { // For string timestamps, set end time as duration (approximate) this._duration = end; } return this; } // ==================== FILTER METHODS ==================== /** * Set a complex filter graph * @param filterGraph - Complex filter string */ complexFilter(filterGraph) { this._complexFilter = filterGraph; return this; } // ==================== OUTPUT METHODS ==================== /** * Set output format */ format(fmt) { this.outputFormat = fmt; return this; } /** * Set output destination (file path) */ output(dest) { this.outputDest = dest; return this; } /** * Add custom output arguments */ outputArgs(...args) { this.extraOutputArgs.push(...args); return this; } /** * Set overwrite flag */ overwrite(value = true) { this._overwrite = value; return this; } // ==================== CALLBACK METHODS ==================== /** * Set progress callback */ onProgress(callback) { this.progressCallback = callback; return this; } // ==================== EXECUTION METHODS ==================== /** * Run the command and output to file */ async run() { if (!this.outputDest || typeof this.outputDest !== 'string') { throw new Error('Output path must be set. Use .output() or .toBuffer()/.toStream()'); } const startTime = Date.now(); const args = this.buildArgs(this.outputDest); await this.execute(args); return { outputPath: this.outputDest, processingTime: Date.now() - startTime, }; } /** * Run the command and return output as Buffer * @param format - Output format */ async toBuffer(format) { if (format) { this.outputFormat = format; } if (!this.outputFormat) { throw new Error('Output format must be specified when outputting to buffer. Use .format() or pass format to .toBuffer()'); } const args = this.buildArgs('pipe:1'); return this.executeToBuffer(args); } /** * Run the command and return output as Web ReadableStream * @param format - Output format */ toStream(format) { if (format) { this.outputFormat = format; } if (!this.outputFormat) { throw new Error('Output format must be specified when outputting to stream. Use .format() or pass format to .toStream()'); } const args = this.buildArgs('pipe:1'); const nodeStream = this.executeToNodeStream(args); // Convert Node.js Readable to Web ReadableStream return Readable.toWeb(nodeStream); } /** * Pipe output to a Web WritableStream * @param writable - Web WritableStream * @param format - Output format */ async pipe(writable, format) { if (format) { this.outputFormat = format; } if (!this.outputFormat) { throw new Error('Output format must be specified when piping. Use .format() or pass format to .pipe()'); } const args = this.buildArgs('pipe:1'); const nodeReadable = this.executeToNodeStream(args); // Convert Node.js Readable to Web ReadableStream and pipe to WritableStream const webReadable = Readable.toWeb(nodeReadable); await webReadable.pipeTo(writable); } /** * Get the ffmpeg arguments that would be used (for debugging) */ getArgs(outputPath = 'output') { return this.buildArgs(outputPath); } // ==================== PRIVATE METHODS ==================== buildArgs(outputPath) { const args = []; // Overwrite flag if (this._overwrite) { args.push('-y'); } // Seek before input (fast seek) if (this._startTime !== null) { args.push('-ss', this.formatTime(this._startTime)); } // Extra input args args.push(...this.extraInputArgs); // Input format (for buffer/stream input) if (this.inputOpts.format && this.isMemoryInput()) { args.push('-f', this.inputOpts.format); } // Input source if (typeof this.inputSource === 'string') { args.push('-i', this.inputSource); } else { // Buffer or stream - read from stdin args.push('-i', 'pipe:0'); } // Duration (after input) if (this._duration !== null) { args.push('-t', this.formatTime(this._duration)); } // Video options if (this._noVideo) { args.push('-vn'); } else { if (this._videoCodec) { args.push('-c:v', this._videoCodec); } if (this._videoBitrate) { args.push('-b:v', this._videoBitrate); } if (this._crf !== null) { args.push('-crf', String(this._crf)); } if (this._preset) { args.push('-preset', this._preset); } if (this._fps) { args.push('-r', String(this._fps)); } // Size (via scale filter or direct) if (this._width !== null || this._height !== null) { const w = this._width !== null ? String(this._width) : '-2'; const h = this._height !== null ? String(this._height) : '-2'; this.videoFilters.unshift(`scale=${w}:${h}`); } } // Audio options if (this._noAudio) { args.push('-an'); } else { if (this._audioCodec) { args.push('-c:a', this._audioCodec); } if (this._audioBitrate) { args.push('-b:a', this._audioBitrate); } if (this._sampleRate) { args.push('-ar', String(this._sampleRate)); } if (this._audioChannels) { args.push('-ac', String(this._audioChannels)); } } // Complex filter if (this._complexFilter) { args.push('-filter_complex', this._complexFilter); } else { // Video filters if (this.videoFilters.length > 0) { args.push('-vf', this.videoFilters.join(',')); } // Audio filters if (this.audioFilters.length > 0) { args.push('-af', this.audioFilters.join(',')); } } // Output format if (this.outputFormat) { args.push('-f', this.outputFormat); } // Extra output args args.push(...this.extraOutputArgs); // Output args.push(outputPath); return args; } async execute(args) { const inputDuration = await this.getInputDuration(); // Add progress output if callback is set if (this.progressCallback) { args.unshift('-progress', 'pipe:2'); } return new Promise((resolve, reject) => { const proc = plugins.child_process.spawn(this.ffmpegPath, args, { stdio: ['pipe', 'pipe', 'pipe'], }); // Handle input this.pipeInputToProcess(proc); // Handle progress if (this.progressCallback && proc.stderr) { this.parseProgress(proc.stderr, inputDuration); } let stderr = ''; proc.stderr?.on('data', (data) => { stderr += data.toString(); }); proc.on('close', (code) => { if (code === 0) { resolve(); } else { reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`)); } }); proc.on('error', reject); }); } executeToBuffer(args) { const inputDuration = this.inputOpts.duration; return new Promise((resolve, reject) => { const proc = plugins.child_process.spawn(this.ffmpegPath, args, { stdio: ['pipe', 'pipe', 'pipe'], }); // Handle input this.pipeInputToProcess(proc); const chunks = []; proc.stdout?.on('data', (chunk) => { chunks.push(chunk); }); // Handle progress on stderr if (this.progressCallback && proc.stderr) { this.parseProgress(proc.stderr, inputDuration); } let stderr = ''; proc.stderr?.on('data', (data) => { stderr += data.toString(); }); proc.on('close', (code) => { if (code === 0) { resolve(Buffer.concat(chunks)); } else { reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`)); } }); proc.on('error', reject); }); } executeToNodeStream(args) { const proc = plugins.child_process.spawn(this.ffmpegPath, args, { stdio: ['pipe', 'pipe', 'pipe'], }); // Handle input this.pipeInputToProcess(proc); // Handle progress on stderr if (this.progressCallback && proc.stderr) { this.parseProgress(proc.stderr, this.inputOpts.duration); } proc.on('error', (err) => { proc.stdout?.destroy(err); }); return proc.stdout; } parseProgress(stderr, duration) { let progressData = {}; stderr.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 (duration && progressData.time) { progressData.percent = Math.min(100, (progressData.time / duration) * 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') && this.progressCallback && progressData.frame !== undefined) { this.progressCallback(progressData); } break; } } }); } async getInputDuration() { if (this.inputOpts.duration) { return this.inputOpts.duration; } if (typeof this.inputSource !== 'string') { return undefined; } try { const result = await this.runProbe([ '-v', 'quiet', '-print_format', 'json', '-show_format', this.inputSource, ]); const data = JSON.parse(result); return parseFloat(data.format?.duration) || undefined; } catch { return undefined; } } runProbe(args) { return new Promise((resolve, reject) => { const proc = plugins.child_process.spawn(this.ffprobePath, args); let stdout = ''; let stderr = ''; proc.stdout?.on('data', (data) => { stdout += data.toString(); }); proc.stderr?.on('data', (data) => { stderr += data.toString(); }); proc.on('close', (code) => { if (code === 0) { resolve(stdout); } else { reject(new Error(`FFprobe exited with code ${code}: ${stderr}`)); } }); proc.on('error', reject); }); } formatTime(time) { if (typeof time === 'string') { return time; } 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')}`; } isNodeStream(value) { return value !== null && typeof value === 'object' && typeof value.pipe === 'function' && !(value instanceof ReadableStream); } isWebReadableStream(value) { return value instanceof ReadableStream; } isMemoryInput() { return Buffer.isBuffer(this.inputSource) || this.inputSource instanceof Uint8Array || this.isNodeStream(this.inputSource) || this.isWebReadableStream(this.inputSource); } pipeInputToProcess(proc) { if (Buffer.isBuffer(this.inputSource)) { proc.stdin?.write(this.inputSource); proc.stdin?.end(); } else if (this.inputSource instanceof Uint8Array) { // Convert Uint8Array to Buffer proc.stdin?.write(Buffer.from(this.inputSource)); proc.stdin?.end(); } else if (this.isWebReadableStream(this.inputSource)) { // Convert Web ReadableStream to Node.js Readable and pipe // Cast to any to handle type mismatch between global ReadableStream and node:stream/web types const nodeReadable = Readable.fromWeb(this.inputSource); nodeReadable.pipe(proc.stdin); } else if (this.isNodeStream(this.inputSource)) { this.inputSource.pipe(proc.stdin); } else if (typeof this.inputSource === 'string') { proc.stdin?.end(); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5mZm1wZWdjb21tYW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5mZm1wZWdjb21tYW5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBa0Q1Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFDaEIsVUFBVSxDQUFTO0lBQ25CLFdBQVcsQ0FBUztJQUU1QixzQkFBc0I7SUFDZCxXQUFXLEdBQXdCLElBQUksQ0FBQztJQUN4QyxTQUFTLEdBQWtCLEVBQUUsQ0FBQztJQUM5QixlQUFlLEdBQWEsRUFBRSxDQUFDO0lBRXZDLHVCQUF1QjtJQUNmLFVBQVUsR0FBeUIsSUFBSSxDQUFDO0lBQ3hDLFlBQVksR0FBb0MsSUFBSSxDQUFDO0lBQ3JELGdCQUFnQixHQUFhLEVBQUUsQ0FBQztJQUV4QyxpQkFBaUI7SUFDVCxXQUFXLEdBQWtDLElBQUksQ0FBQztJQUNsRCxhQUFhLEdBQWtCLElBQUksQ0FBQztJQUNwQyxNQUFNLEdBQWtCLElBQUksQ0FBQztJQUM3QixPQUFPLEdBQWtCLElBQUksQ0FBQztJQUM5QixJQUFJLEdBQWtCLElBQUksQ0FBQztJQUMzQixJQUFJLEdBQWtCLElBQUksQ0FBQztJQUMzQixPQUFPLEdBQThCLElBQUksQ0FBQztJQUMxQyxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBRXpCLGlCQUFpQjtJQUNULFdBQVcsR0FBa0MsSUFBSSxDQUFDO0lBQ2xELGFBQWEsR0FBa0IsSUFBSSxDQUFDO0lBQ3BDLFdBQVcsR0FBa0IsSUFBSSxDQUFDO0lBQ2xDLGNBQWMsR0FBa0IsSUFBSSxDQUFDO0lBQ3JDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFFekIsU0FBUztJQUNELFVBQVUsR0FBMkIsSUFBSSxD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