| 1234567891011121314151617181920212223242526272829303132333435363738 |
- import { parseMedia } from "@remotion/media-parser";
- import { nodeReader } from "@remotion/media-parser/node";
- import { execSync } from "node:child_process";
- export async function measureAudioDuration(
- filePath: string
- ): Promise<number> {
- // Primary: parse audio container headers via @remotion/media-parser (fast, no full decode)
- try {
- const result = await parseMedia({
- src: filePath,
- reader: nodeReader,
- fields: { durationInSeconds: true },
- });
- if (result.durationInSeconds != null && result.durationInSeconds > 0) {
- return result.durationInSeconds;
- }
- } catch {
- // Fall through to ffprobe
- }
- // Fallback: ffprobe (available on system)
- try {
- const output = execSync(
- `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${filePath}"`,
- { encoding: "utf-8", timeout: 5000 }
- ).trim();
- const dur = parseFloat(output);
- if (Number.isFinite(dur) && dur > 0) return dur;
- } catch {
- // Fall through to bitrate estimate
- }
- // Last resort: estimate from file size (mp3 @ 128kbps)
- const { statSync } = await import("node:fs");
- const size = statSync(filePath).size;
- return (size * 8) / 128000;
- }
|