generated from ztimson/template
Update services/camera.mjs
This commit is contained in:
+27
-11
@@ -1,4 +1,3 @@
|
||||
|
||||
// Camera service (rpicam-apps wrapper)
|
||||
//
|
||||
// libcamera lets only ONE process own the camera, so everything here goes through a single
|
||||
@@ -401,11 +400,21 @@ export class CameraService extends EventEmitter {
|
||||
}, this.#cfg.streamIdleStopMs);
|
||||
}
|
||||
|
||||
// Resolve exposure and frame timing once so preview and recording don't silently
|
||||
// choose different shutter speeds or incompatible frame rates.
|
||||
#cameraPlan(settings, requestedFps) {
|
||||
const shutterUs = settings.shutterUs > 0 ? settings.shutterUs : 0;
|
||||
const fps = shutterUs > 0
|
||||
? Math.min(Number(requestedFps), 1_000_000 / shutterUs)
|
||||
: Number(requestedFps);
|
||||
|
||||
return { settings, shutterUs, fps: Math.max(0.001, fps) };
|
||||
}
|
||||
|
||||
#streamArgs() {
|
||||
const c = this.#cfg;
|
||||
const s = this.#settings;
|
||||
const shutter = s.shutterUs > 0 ? Math.min(s.shutterUs, c.streamMaxShutterUs) : 0;
|
||||
const fps = shutter > 0 ? Math.min(c.fps, 1_000_000 / shutter) : c.fps;
|
||||
const plan = this.#cameraPlan(this.#settings, c.fps);
|
||||
const { settings, shutterUs, fps } = plan;
|
||||
|
||||
return {
|
||||
fps,
|
||||
@@ -415,8 +424,8 @@ export class CameraService extends EventEmitter {
|
||||
'--height', String(c.height),
|
||||
'--framerate', fps.toFixed(3),
|
||||
'--codec', 'mjpeg',
|
||||
'-q', String(s.quality),
|
||||
...this.#controlArgs(s, { shutterUs: shutter }),
|
||||
'-q', String(settings.quality),
|
||||
...this.#controlArgs(settings, { shutterUs }),
|
||||
'-o', '-',
|
||||
],
|
||||
};
|
||||
@@ -424,7 +433,7 @@ export class CameraService extends EventEmitter {
|
||||
|
||||
#startStream() {
|
||||
const { fps, args } = this.#streamArgs();
|
||||
this.#log.info(`starting live view ${this.#cfg.width}x${this.#cfg.height} @ ${fps.toFixed(1)} fps`);
|
||||
this.#log.info(`starting live view ${this.#cfg.width}x${this.#cfg.height} @ ${fps.toFixed(3)} fps`);
|
||||
|
||||
const proc = spawn(this.#cfg.vidBin, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
||||
const stream = { proc, fps, expected: false, startedAt: Date.now(), frames: 0, exited: null };
|
||||
@@ -584,7 +593,8 @@ export class CameraService extends EventEmitter {
|
||||
|
||||
#stillArgs(file, settings, { raw = false } = {}) {
|
||||
const c = this.#cfg;
|
||||
const manual = settings.shutterUs > 0 && settings.gain > 0;
|
||||
const { shutterUs } = this.#cameraPlan(settings, 1);
|
||||
const manual = shutterUs > 0 && settings.gain > 0;
|
||||
|
||||
return [
|
||||
'-n',
|
||||
@@ -681,7 +691,9 @@ export class CameraService extends EventEmitter {
|
||||
|
||||
const w = width || c.videoWidth;
|
||||
const h = height || c.videoHeight;
|
||||
const f = fps || c.videoFps;
|
||||
const requestedFps = Number(fps || c.videoFps);
|
||||
const plan = this.#cameraPlan(settings, requestedFps);
|
||||
const f = plan.fps;
|
||||
const base = `video_${stamp()}`;
|
||||
const rawFile = path.join(this.#dirs.videos, `${base}.h264`);
|
||||
|
||||
@@ -696,7 +708,7 @@ export class CameraService extends EventEmitter {
|
||||
'--framerate', String(f),
|
||||
'--codec', 'h264',
|
||||
'--inline',
|
||||
...this.#controlArgs(settings),
|
||||
...this.#controlArgs(plan.settings, { shutterUs: plan.shutterUs }),
|
||||
'-o', rawFile,
|
||||
];
|
||||
|
||||
@@ -750,7 +762,11 @@ export class CameraService extends EventEmitter {
|
||||
proc.once('close', (code, signal) => finish(code, signal));
|
||||
});
|
||||
|
||||
this.#log.info(`video recording started (${w}x${h} @ ${f} fps${durationSec ? `, ${durationSec}s` : ''})`);
|
||||
this.#log.info(
|
||||
`video recording started (${w}x${h} @ ${f.toFixed(3)} fps` +
|
||||
`${f < requestedFps ? `, limited from ${requestedFps} fps by ${plan.shutterUs}µs shutter` : ''}` +
|
||||
`${durationSec ? `, ${durationSec}s` : ''})`,
|
||||
);
|
||||
return this.#jobSummary();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user