Add transcode module

This commit is contained in:
Alex Gleason 2025-02-27 19:59:13 -06:00
parent 5fc874b768
commit 82f16e0cfe
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
3 changed files with 70 additions and 0 deletions

Binary file not shown.

View file

@ -0,0 +1,8 @@
import { transcodeVideoStream } from './transcode.ts';
Deno.test('transcodeVideoStream', async () => {
await using file = await Deno.open(new URL('./buckbunny.mp4', import.meta.url));
const output = await transcodeVideoStream(file.readable);
await Deno.writeFile(new URL('./buckbunny-transcoded.mp4', import.meta.url), output);
});

View file

@ -0,0 +1,62 @@
export async function transcodeVideoStream(
inputStream: ReadableStream<Uint8Array>,
): Promise<ReadableStream<Uint8Array>> {
const command = new Deno.Command('ffmpeg', {
args: [
'-i',
'pipe:0', // Read input from stdin
'-c:v',
'libx264', // Convert to H.264
'-preset',
'veryfast', // Encoding speed
'-loglevel',
'fatal', // Suppress logs
'-crf',
'23', // Compression level (lower = better quality)
'-c:a',
'aac', // Convert to AAC audio
'-b:a',
'128k', // Audio bitrate
'-movflags',
'frag_keyframe+empty_moov', // Ensures MP4 streaming compatibility
'-f',
'mp4', // Force MP4 format
'pipe:1', // Output to stdout
],
stdin: 'piped',
stdout: 'piped',
stderr: 'piped',
});
// Spawn the FFmpeg process
const process = command.spawn();
// Capture stderr for debugging
const stderrPromise = new Response(process.stderr).text().then((text) => {
if (text.trim()) console.error('FFmpeg stderr:', text);
});
// Pipe the input stream into FFmpeg stdin and ensure completion
const writer = process.stdin.getWriter();
const reader = inputStream.getReader();
async function pumpInput() {
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
await writer.write(value);
}
} finally {
writer.close(); // Close stdin to signal FFmpeg that input is done
}
}
// Start pumping input asynchronously
pumpInput();
// Ensure stderr logs are captured
stderrPromise.catch(console.error);
return process.stdout;
}