diff --git a/services/worker/src/ffmpeg/executor.js b/services/worker/src/ffmpeg/executor.js new file mode 100644 index 0000000..6465950 --- /dev/null +++ b/services/worker/src/ffmpeg/executor.js @@ -0,0 +1,84 @@ +import { execFile } from 'child_process'; +import { promisify } from 'util'; + +const execFileAsync = promisify(execFile); + +export const runFFmpeg = async (args, options = {}) => { + const { stdio = 'pipe', ...otherOptions } = options; + try { + const { stdout, stderr } = await execFileAsync('ffmpeg', args, { + stdio, + ...otherOptions, + }); + return { stdout, stderr }; + } catch (error) { + throw new Error(`FFmpeg error: ${error.message}\nStderr: ${error.stderr}`); + } +}; + +export const getMediaDuration = async (inputPath) => { + const args = [ + '-v', 'error', + '-show_entries', 'format=duration', + '-of', 'default=noprint_wrappers=1:nokey=1:noinvalidchars=1', + inputPath, + ]; + const { stdout } = await runFFmpeg(args); + return parseFloat(stdout.trim()); +}; + +export const extractFrameAtTime = async (inputPath, outputPath, timeCode) => { + const args = [ + '-i', inputPath, + '-ss', timeCode, + '-vframes', '1', + '-q:v', '2', + outputPath, + ]; + await runFFmpeg(args); +}; + +export const transcodeVideo = async (inputPath, outputPath, options = {}) => { + const { + videoCodec = 'libx264', + videoPreset = 'fast', + videoBitrate = '10M', + audioCodec = 'aac', + audioBitrate = '192k', + } = options; + + const args = [ + '-i', inputPath, + '-c:v', videoCodec, + '-preset', videoPreset, + '-b:v', videoBitrate, + '-c:a', audioCodec, + '-b:a', audioBitrate, + '-movflags', '+faststart', + outputPath, + ]; + + await runFFmpeg(args); +}; + +export const trimSegment = async (inputPath, outputPath, inPoint, outPoint) => { + const args = [ + '-i', inputPath, + '-ss', inPoint, + '-to', outPoint, + '-c', 'copy', + outputPath, + ]; + await runFFmpeg(args); +}; + +export const concatSegments = async (segmentListFile, outputPath) => { + const args = [ + '-f', 'concat', + '-safe', '0', + '-i', segmentListFile, + '-c', 'copy', + outputPath, + ]; + await runFFmpeg(args); +};