diff --git a/packages/transcode/analyze.ts b/packages/transcode/analyze.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/transcode/ffmpeg.test.ts b/packages/transcode/ffmpeg.test.ts new file mode 100644 index 00000000..106efb48 --- /dev/null +++ b/packages/transcode/ffmpeg.test.ts @@ -0,0 +1,20 @@ +import { ffmpeg } from './ffmpeg.ts'; + +Deno.test('ffmpeg', async () => { + await using file = await Deno.open(new URL('./buckbunny.mp4', import.meta.url)); + + const output = ffmpeg(file.readable, { + 'i': 'pipe:0', + 'c:v': 'libx264', + 'preset': 'veryfast', + 'loglevel': 'fatal', + 'crf': '23', + 'c:a': 'aac', + 'b:a': '128k', + 'movflags': 'frag_keyframe+empty_moov', + 'f': 'mp4', + }); + + await Deno.mkdir(new URL('./tmp', import.meta.url), { recursive: true }); + await Deno.writeFile(new URL('./tmp/buckbunny-transcoded.mp4', import.meta.url), output); +}); diff --git a/packages/transcode/ffmpeg.ts b/packages/transcode/ffmpeg.ts new file mode 100644 index 00000000..c33b68b0 --- /dev/null +++ b/packages/transcode/ffmpeg.ts @@ -0,0 +1,31 @@ +export type FFmpegFlags = { + 'i': string; + 'c:v': string; + 'preset': string; + 'loglevel': string; + 'crf': string; + 'c:a': string; + 'b:a': string; + 'movflags': string; + 'f': string; + [key: string]: string; +}; + +export function ffmpeg(input: BodyInit, flags: FFmpegFlags): ReadableStream { + const command = new Deno.Command('ffmpeg', { + args: [ + ...Object.entries(flags).flatMap(([k, v]) => [`-${k}`, v]), + 'pipe:1', // Output to stdout + ], + stdin: 'piped', + stdout: 'piped', + }); + + // Spawn the FFmpeg process + const child = command.spawn(); + + // Pipe the input stream into FFmpeg stdin and ensure completion + new Response(input).body!.pipeTo(child.stdin); + + return child.stdout; +}