mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
Add transcode module
This commit is contained in:
parent
5fc874b768
commit
82f16e0cfe
3 changed files with 70 additions and 0 deletions
BIN
packages/ditto/utils/buckbunny.mp4
Normal file
BIN
packages/ditto/utils/buckbunny.mp4
Normal file
Binary file not shown.
8
packages/ditto/utils/transcode.test.ts
Normal file
8
packages/ditto/utils/transcode.test.ts
Normal 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);
|
||||||
|
});
|
||||||
62
packages/ditto/utils/transcode.ts
Normal file
62
packages/ditto/utils/transcode.ts
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue