Files
webadderall eaf87be95b Recordly 2.0 local review stack 2/6
Dependency-ordered review preparation. Not pushed or remotely reviewed.
2026-11-06 05:24:21 +11:00

70 lines
1.8 KiB
TypeScript

import type { NativeVideoAudioMuxProgress } from "./types";
export function parseFfmpegProgressClockSeconds(value: string) {
const match = value.match(/^(\d+):(\d+):(\d+(?:\.\d+)?)$/);
if (!match) {
return null;
}
const hours = Number(match[1]);
const minutes = Number(match[2]);
const seconds = Number(match[3]);
if (![hours, minutes, seconds].every(Number.isFinite)) {
return null;
}
return hours * 3600 + minutes * 60 + seconds;
}
export function parseFfmpegProgressLineSeconds(line: string) {
const separatorIndex = line.indexOf("=");
if (separatorIndex <= 0) {
return null;
}
const key = line.slice(0, separatorIndex).trim();
const value = line.slice(separatorIndex + 1).trim();
if (key === "out_time_us" || key === "out_time_ms") {
const microseconds = Number(value);
return Number.isFinite(microseconds) && microseconds >= 0 ? microseconds / 1_000_000 : null;
}
if (key === "out_time") {
return parseFfmpegProgressClockSeconds(value);
}
return null;
}
export function createFfmpegMuxProgressHandler(
totalSec: number | undefined,
onProgress?: (progress: NativeVideoAudioMuxProgress) => void,
) {
if (!onProgress || !Number.isFinite(totalSec) || !totalSec || totalSec <= 0) {
return () => undefined;
}
let lineBuffer = "";
let lastRatio = 0;
return (chunk: Buffer | string) => {
lineBuffer += chunk.toString();
const lines = lineBuffer.split(/\r?\n/);
lineBuffer = lines.pop() ?? "";
for (const line of lines) {
const processedSec = parseFfmpegProgressLineSeconds(line);
if (processedSec === null) {
continue;
}
const ratio = Math.max(0, Math.min(1, processedSec / totalSec));
if (ratio < lastRatio + 0.0025 && ratio < 1) {
continue;
}
lastRatio = Math.max(lastRatio, ratio);
onProgress({
ratio: lastRatio,
processedSec,
totalSec,
});
}
};
}