mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
video was too bigs
This commit is contained in:
@@ -298,13 +298,60 @@ async function buildReplayVideo({ cameraId = null } = {}) {
|
|||||||
}
|
}
|
||||||
const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'rover-replay-'));
|
const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'rover-replay-'));
|
||||||
try {
|
try {
|
||||||
|
const firstFrameByCamera = new Map();
|
||||||
for (let i = 0; i < frames.length; i += 1) {
|
for (let i = 0; i < frames.length; i += 1) {
|
||||||
const filename = `frame-${String(i + 1).padStart(4, '0')}.jpg`;
|
const filename = `frame-${String(i + 1).padStart(4, '0')}.jpg`;
|
||||||
await fsp.writeFile(path.join(tmpDir, filename), frames[i].buffer);
|
await fsp.writeFile(path.join(tmpDir, filename), frames[i].buffer);
|
||||||
|
const cameraId = frames[i].camera?.id;
|
||||||
|
if (cameraId && !firstFrameByCamera.has(cameraId)) {
|
||||||
|
firstFrameByCamera.set(cameraId, filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const outPath = path.join(tmpDir, 'replay.mp4');
|
const outPath = path.join(tmpDir, 'replay.mp4');
|
||||||
const delayMs = getRoomCameraReplayDelayMs();
|
const delayMs = getRoomCameraReplayDelayMs();
|
||||||
const fps = (1000 / delayMs).toFixed(3);
|
const fpsValue = 1000 / delayMs;
|
||||||
|
const fps = fpsValue.toFixed(3);
|
||||||
|
let maxWidth = 0;
|
||||||
|
let maxHeight = 0;
|
||||||
|
for (const filename of firstFrameByCamera.values()) {
|
||||||
|
try {
|
||||||
|
const { stdout } = await execFileAsync('ffprobe', [
|
||||||
|
'-v',
|
||||||
|
'error',
|
||||||
|
'-select_streams',
|
||||||
|
'v:0',
|
||||||
|
'-show_entries',
|
||||||
|
'stream=width,height',
|
||||||
|
'-of',
|
||||||
|
'csv=p=0',
|
||||||
|
path.join(tmpDir, filename),
|
||||||
|
]);
|
||||||
|
const [widthRaw, heightRaw] = stdout.trim().split(',');
|
||||||
|
const width = Number(widthRaw);
|
||||||
|
const height = Number(heightRaw);
|
||||||
|
if (Number.isFinite(width) && Number.isFinite(height)) {
|
||||||
|
maxWidth = Math.max(maxWidth, width);
|
||||||
|
maxHeight = Math.max(maxHeight, height);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn('Failed to probe replay frame size', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const MAX_REPLAY_WIDTH = 1280;
|
||||||
|
const MAX_REPLAY_HEIGHT = 720;
|
||||||
|
let targetWidth = maxWidth || MAX_REPLAY_WIDTH;
|
||||||
|
let targetHeight = maxHeight || MAX_REPLAY_HEIGHT;
|
||||||
|
if (targetWidth > MAX_REPLAY_WIDTH || targetHeight > MAX_REPLAY_HEIGHT) {
|
||||||
|
const scale = Math.min(MAX_REPLAY_WIDTH / targetWidth, MAX_REPLAY_HEIGHT / targetHeight);
|
||||||
|
targetWidth = Math.max(2, Math.floor((targetWidth * scale) / 2) * 2);
|
||||||
|
targetHeight = Math.max(2, Math.floor((targetHeight * scale) / 2) * 2);
|
||||||
|
}
|
||||||
|
const sizeFilter = `scale=${targetWidth}:${targetHeight}:force_original_aspect_ratio=decrease:flags=lanczos,pad=${targetWidth}:${targetHeight}:(ow-iw)/2:(oh-ih)/2:color=black,setsar=1`;
|
||||||
|
const maxBytes = Math.floor(9.5 * 1024 * 1024);
|
||||||
|
const durationSec = Math.max(1, frames.length / fpsValue);
|
||||||
|
const targetBitrateKbps = Math.max(300, Math.floor((maxBytes * 8) / durationSec / 1000));
|
||||||
|
const maxrateKbps = Math.floor(targetBitrateKbps * 1.1);
|
||||||
|
const bufsizeKbps = Math.floor(targetBitrateKbps * 2);
|
||||||
await execFileAsync('ffmpeg', [
|
await execFileAsync('ffmpeg', [
|
||||||
'-y',
|
'-y',
|
||||||
'-hide_banner',
|
'-hide_banner',
|
||||||
@@ -314,8 +361,16 @@ async function buildReplayVideo({ cameraId = null } = {}) {
|
|||||||
fps,
|
fps,
|
||||||
'-i',
|
'-i',
|
||||||
'frame-%04d.jpg',
|
'frame-%04d.jpg',
|
||||||
|
'-vf',
|
||||||
|
sizeFilter,
|
||||||
'-c:v',
|
'-c:v',
|
||||||
'libx264',
|
'libx264',
|
||||||
|
'-b:v',
|
||||||
|
`${targetBitrateKbps}k`,
|
||||||
|
'-maxrate',
|
||||||
|
`${maxrateKbps}k`,
|
||||||
|
'-bufsize',
|
||||||
|
`${bufsizeKbps}k`,
|
||||||
'-pix_fmt',
|
'-pix_fmt',
|
||||||
'yuv420p',
|
'yuv420p',
|
||||||
outPath,
|
outPath,
|
||||||
|
|||||||
Reference in New Issue
Block a user