mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
Let ffprobe pipe data to stdin
This commit is contained in:
parent
d70a00a8ca
commit
5f10f92d4e
4 changed files with 50 additions and 8 deletions
|
|
@ -4,8 +4,7 @@ import { getVideoDimensions } from './analyze.ts';
|
||||||
|
|
||||||
Deno.test('getVideoDimensions', async () => {
|
Deno.test('getVideoDimensions', async () => {
|
||||||
const uri = new URL('./buckbunny.mp4', import.meta.url);
|
const uri = new URL('./buckbunny.mp4', import.meta.url);
|
||||||
|
const dimensions = await getVideoDimensions(uri);
|
||||||
const dimensions = await getVideoDimensions(uri.href);
|
|
||||||
|
|
||||||
assertEquals(dimensions, { width: 1920, height: 1080 });
|
assertEquals(dimensions, { width: 1920, height: 1080 });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import { ffprobe } from './ffprobe.ts';
|
import { ffprobe } from './ffprobe.ts';
|
||||||
|
|
||||||
export async function getVideoDimensions(path: string): Promise<{ width: number; height: number } | null> {
|
export async function getVideoDimensions(
|
||||||
const stream = ffprobe(path, {
|
input: URL | ReadableStream<Uint8Array>,
|
||||||
|
): Promise<{ width: number; height: number } | null> {
|
||||||
|
const stream = ffprobe(input, {
|
||||||
'v': 'error',
|
'v': 'error',
|
||||||
'select_streams': 'v:0',
|
'select_streams': 'v:0',
|
||||||
'show_entries': 'stream=width,height',
|
'show_entries': 'stream=width,height',
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,21 @@ import { assertEquals } from '@std/assert';
|
||||||
import { ffprobe } from './ffprobe.ts';
|
import { ffprobe } from './ffprobe.ts';
|
||||||
|
|
||||||
Deno.test('ffprobe', async () => {
|
Deno.test('ffprobe', async () => {
|
||||||
|
await using file = await Deno.open(new URL('./buckbunny.mp4', import.meta.url));
|
||||||
|
|
||||||
|
const stream = ffprobe(file.readable, {
|
||||||
|
'v': 'error',
|
||||||
|
'select_streams': 'v:0',
|
||||||
|
'show_entries': 'stream=width,height',
|
||||||
|
'of': 'json',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { streams: [dimensions] } = await new Response(stream).json();
|
||||||
|
|
||||||
|
assertEquals(dimensions, { width: 1920, height: 1080 });
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test('ffprobe from file', async () => {
|
||||||
const uri = new URL('./buckbunny.mp4', import.meta.url);
|
const uri = new URL('./buckbunny.mp4', import.meta.url);
|
||||||
|
|
||||||
const stream = ffprobe(uri, {
|
const stream = ffprobe(uri, {
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,45 @@ export interface FFprobeFlags {
|
||||||
[key: string]: string | undefined;
|
[key: string]: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ffprobe(path: URL | string, flags: FFprobeFlags): ReadableStream<Uint8Array> {
|
export function ffprobe(input: URL | ReadableStream<Uint8Array>, flags: FFprobeFlags): ReadableStream<Uint8Array> {
|
||||||
const args = [];
|
const args = [];
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(flags)) {
|
for (const [key, value] of Object.entries(flags)) {
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
|
if (value) {
|
||||||
args.push(`-${key}`, value);
|
args.push(`-${key}`, value);
|
||||||
|
} else {
|
||||||
|
args.push(`-${key}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push(path instanceof URL ? path.href : path);
|
if (input instanceof URL) {
|
||||||
|
args.push('-i', input.href);
|
||||||
|
} else {
|
||||||
|
args.push('-i', 'pipe:0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn the FFprobe process
|
||||||
|
const command = new Deno.Command('ffprobe', {
|
||||||
|
args,
|
||||||
|
stdin: input instanceof ReadableStream ? 'piped' : 'null',
|
||||||
|
stdout: 'piped',
|
||||||
|
});
|
||||||
|
|
||||||
const command = new Deno.Command('ffprobe', { args, stdout: 'piped' });
|
|
||||||
const child = command.spawn();
|
const child = command.spawn();
|
||||||
|
|
||||||
|
// Pipe the input stream into FFmpeg stdin and ensure completion
|
||||||
|
if (input instanceof ReadableStream) {
|
||||||
|
input.pipeTo(child.stdin).catch((e: unknown) => {
|
||||||
|
if (e instanceof Error && e.name === 'BrokenPipe') {
|
||||||
|
// Ignore. ffprobe closes the pipe once it has read the metadata.
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the FFmpeg stdout stream
|
||||||
return child.stdout;
|
return child.stdout;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue