Files
agent/packages/harness/tests/image-video-duration.test.ts
T

38 lines
2.7 KiB
TypeScript

import { expect, it } from "vitest";
import { mkdtemp, readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import * as media from "../src/image-video/media.js";
import { mediaRuntime, runMedia } from "../src/media/media-worker.js";
it("trims H3's small frame overrun to the requested duration at original speed, preserving the source and rejecting short or excessive output", async () => {
const directory = await mkdtemp(join(tmpdir(), "i2v-duration-"));
const { ffmpeg, ffprobe } = await mediaRuntime();
const signal = new AbortController().signal;
const make = async (name: string, seconds: string) => {
const path = join(directory, name);
await runMedia(ffmpeg, ["-v", "error", "-f", "lavfi", "-i", "testsrc2=size=90x160:rate=24", "-f", "lavfi", "-i", "sine=frequency=440:sample_rate=32000", "-t", seconds, "-c:v", "libx264", "-preset", "ultrafast", "-c:a", "aac", "-n", path], directory, signal);
return path;
};
const source = await make("original.mp4", "1.125");
const original = await readFile(source);
const output = await media.conformImageVideoDuration(source, directory, 1);
const probe = JSON.parse(await runMedia(ffprobe, ["-v", "error", "-show_streams", "-of", "json", output], directory, signal)) as { streams: { codec_type: string; duration: string; nb_frames: string; avg_frame_rate: string }[] };
const video = probe.streams.find(s => s.codec_type === "video")!;
expect(Number(video.duration)).toBe(1);
expect(video.nb_frames).toBe("24");
expect(video.avg_frame_rate).toBe("24/1");
expect(Number(probe.streams.find(s => s.codec_type === "audio")!.duration)).toBeCloseTo(1, 2);
expect(await readFile(source)).toEqual(original);
// Actual H3 2-second response is 56 frames (17k+5), not 48 frames.
const gridSource = await make("h3-2s.mp4", "2.333333");
const gridOriginal = await readFile(gridSource);
const gridOutput = await media.conformImageVideoDuration(gridSource, directory, 2);
const gridProbe = JSON.parse(await runMedia(ffprobe, ["-v", "error", "-select_streams", "v:0", "-show_entries", "stream=duration,nb_frames,avg_frame_rate", "-of", "json", gridOutput], directory, signal)) as { streams: { duration: string; nb_frames: string; avg_frame_rate: string }[] };
expect(gridProbe.streams[0]).toMatchObject({ duration: "2.000000", nb_frames: "48", avg_frame_rate: "24/1" });
expect(await readFile(gridSource)).toEqual(gridOriginal);
await expect(media.conformImageVideoDuration(output, directory, 1)).resolves.toBe(output);
await expect(media.conformImageVideoDuration(await make("short.mp4", "0.875"), directory, 1)).rejects.toBeDefined();
await expect(media.conformImageVideoDuration(await make("long.mp4", "1.5"), directory, 1)).rejects.toBeDefined();
}, 30_000);