2024-07-12 13:51:39 +00:00
|
|
|
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
exports.Sequence = void 0;
|
2024-07-31 18:39:21 +00:00
|
|
|
const files_1 = require("../files");
|
|
|
|
const log_1 = require("../log");
|
2024-08-16 04:52:46 +00:00
|
|
|
var SequenceStatus;
|
|
|
|
(function (SequenceStatus) {
|
|
|
|
SequenceStatus[SequenceStatus["IDLE"] = 0] = "IDLE";
|
|
|
|
SequenceStatus[SequenceStatus["RUNNING"] = 1] = "RUNNING";
|
|
|
|
SequenceStatus[SequenceStatus["PAUSED"] = 2] = "PAUSED";
|
|
|
|
})(SequenceStatus || (SequenceStatus = {}));
|
2024-10-19 02:13:52 +00:00
|
|
|
class Statistics {
|
|
|
|
constructor(exposure, frames) {
|
|
|
|
this.exposure = exposure;
|
|
|
|
this.frames = frames;
|
|
|
|
this.frameLoad = [];
|
|
|
|
this.frameOpen = [];
|
|
|
|
this.frameExposureElapsed = [];
|
|
|
|
this.frameExposureReported = [];
|
|
|
|
this.frameClose = [];
|
|
|
|
this.frameTotal = [];
|
|
|
|
}
|
|
|
|
add(load, open, exposureElapsed, exposureReported, close, total) {
|
|
|
|
this.frameLoad.push(load);
|
|
|
|
this.frameOpen.push(open);
|
|
|
|
this.frameExposureElapsed.push(exposureElapsed);
|
|
|
|
this.frameExposureReported.push(exposureReported);
|
|
|
|
this.frameClose.push(close);
|
|
|
|
this.frameTotal.push(total);
|
|
|
|
}
|
|
|
|
average(arr) {
|
|
|
|
return arr.reduce((a, b) => a + b) / arr.length;
|
|
|
|
}
|
|
|
|
elapsed() {
|
|
|
|
return this.frameTotal.reduce((a, b) => a + b);
|
|
|
|
}
|
|
|
|
estimate(frame, avg) {
|
|
|
|
const frames = this.frames - frame;
|
|
|
|
return frames * avg;
|
|
|
|
}
|
|
|
|
margin(target, arr) {
|
|
|
|
const min = Math.min(...arr);
|
|
|
|
const max = Math.max(...arr);
|
|
|
|
const diff = Math.abs(max - min);
|
|
|
|
return (diff / target) / 2;
|
|
|
|
}
|
|
|
|
calculate(frame) {
|
|
|
|
if (this.frameTotal.length === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const totalFrameAvg = this.average(this.frameTotal);
|
|
|
|
const openAvg = this.average(this.frameOpen);
|
|
|
|
const closeAvg = this.average(this.frameClose);
|
|
|
|
const exposureAvg = this.average(this.frameExposureReported);
|
|
|
|
const loadAvg = this.average(this.frameLoad);
|
|
|
|
return {
|
|
|
|
totalFrameLast: this.frameTotal[this.frameTotal.length - 1],
|
|
|
|
totalFrameAvg,
|
|
|
|
totalFrameMargin: this.margin(totalFrameAvg, this.frameTotal) * 100.0,
|
|
|
|
fps: 1000.0 / totalFrameAvg,
|
|
|
|
loadLast: this.frameLoad[this.frameLoad.length - 1],
|
|
|
|
loadAvg,
|
|
|
|
loadMargin: this.margin(loadAvg, this.frameLoad),
|
|
|
|
openLast: this.frameOpen[this.frameOpen.length - 1],
|
|
|
|
openAvg,
|
|
|
|
openMargin: this.margin(openAvg, this.frameOpen) * 100.0,
|
|
|
|
closeLast: this.frameClose[this.frameClose.length - 1],
|
|
|
|
closeAvg,
|
|
|
|
closeMargin: this.margin(closeAvg, this.frameClose) * 100.0,
|
|
|
|
exposureLast: this.frameExposureReported[this.frameExposureReported.length - 1],
|
|
|
|
exposureAvg,
|
|
|
|
exposureMargin: this.margin(exposureAvg, this.frameExposureReported) * 100.0,
|
|
|
|
elapsed: this.elapsed(),
|
|
|
|
estimate: this.estimate(frame, totalFrameAvg)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
class Sequence {
|
2024-08-15 02:43:02 +00:00
|
|
|
constructor(camera, fd, display, ffprobe, send) {
|
2024-07-12 13:51:39 +00:00
|
|
|
this.current = null;
|
2024-08-15 02:43:02 +00:00
|
|
|
this.info = null;
|
2024-07-31 18:39:21 +00:00
|
|
|
this.images = [];
|
2024-10-19 02:13:52 +00:00
|
|
|
this.stats = null;
|
2024-08-16 04:52:46 +00:00
|
|
|
this.running = false;
|
|
|
|
this.paused = false;
|
|
|
|
this.progress = 0;
|
|
|
|
this.frame = 0;
|
|
|
|
this.frames = 0;
|
|
|
|
this.exposure = 1000;
|
2024-07-31 18:39:21 +00:00
|
|
|
this.log = (0, log_1.createLog)('seq');
|
2024-08-05 02:34:03 +00:00
|
|
|
this.camera = camera;
|
|
|
|
this.fd = fd;
|
|
|
|
this.display = display;
|
2024-08-09 20:20:07 +00:00
|
|
|
this.ffprobe = ffprobe;
|
2024-08-15 02:43:02 +00:00
|
|
|
this.send = send;
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
|
|
|
start() {
|
2024-08-24 14:23:15 +00:00
|
|
|
if (this.current !== null) {
|
|
|
|
this.running = true;
|
|
|
|
this.log.info(`Started sequence: ${this.current.name}`);
|
2024-10-19 02:13:52 +00:00
|
|
|
this.stats = new Statistics(this.exposure, this.frames);
|
2024-08-24 14:23:15 +00:00
|
|
|
this.run();
|
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
|
|
|
stop() {
|
2024-08-24 14:23:15 +00:00
|
|
|
if (this.running && this.current !== null) {
|
|
|
|
this.log.info(`Stopped sequence: ${this.current.name}`);
|
|
|
|
this.running = false;
|
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
|
|
|
isRunning() {
|
|
|
|
return this.running;
|
|
|
|
}
|
2024-10-22 03:51:38 +00:00
|
|
|
isLoaded() {
|
|
|
|
return this.current !== null;
|
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
async run() {
|
|
|
|
//update running
|
|
|
|
for (let i = this.frame; i < this.images.length; i++) {
|
|
|
|
if (!this.running) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
await this.frameRecord();
|
|
|
|
}
|
|
|
|
catch (err) {
|
|
|
|
this.log.error(`Error recording frame`, err);
|
|
|
|
}
|
|
|
|
this.frameAdvance();
|
|
|
|
}
|
|
|
|
//complete running
|
2024-10-18 03:06:37 +00:00
|
|
|
this.updateClientsOnState();
|
2024-10-19 02:13:52 +00:00
|
|
|
this.stats = null;
|
2024-08-24 14:23:15 +00:00
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
async load(seq) {
|
2024-07-31 18:39:21 +00:00
|
|
|
this.current = seq;
|
2024-08-16 04:52:46 +00:00
|
|
|
this.frame = 0;
|
|
|
|
this.progress = 0;
|
|
|
|
await this.enumerate();
|
2024-08-24 14:23:15 +00:00
|
|
|
this.updateClientsOnLoad();
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
updateClientsOnLoad() {
|
2024-08-16 04:52:46 +00:00
|
|
|
if (this.current !== null) {
|
|
|
|
this.send({ cmd: 'select', state: this.getState() });
|
|
|
|
}
|
2024-07-31 18:39:21 +00:00
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
updateClientsOnState() {
|
|
|
|
if (this.current !== null) {
|
|
|
|
this.send({ cmd: 'update', state: this.getState() });
|
|
|
|
}
|
|
|
|
}
|
2024-10-22 19:04:25 +00:00
|
|
|
updateClientsOnDisplay() {
|
|
|
|
if (this.current !== null) {
|
|
|
|
this.send({ cmd: 'display', state: this.getState() });
|
|
|
|
}
|
|
|
|
}
|
2024-07-31 18:39:21 +00:00
|
|
|
async enumerate() {
|
2024-08-15 02:43:02 +00:00
|
|
|
let screen;
|
2024-07-31 18:39:21 +00:00
|
|
|
if (this.current === null) {
|
|
|
|
this.log.error('Cannot enumerate sequence because it is not set');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
this.images = await files_1.Files.enumerateSequence(this.current.path);
|
|
|
|
}
|
|
|
|
catch (err) {
|
|
|
|
this.log.error(`Error enumerating images in sequence: ${this.current.name}`, err);
|
|
|
|
return;
|
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
this.frames = this.images.length;
|
2024-07-31 18:39:21 +00:00
|
|
|
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
|
2024-08-16 04:52:46 +00:00
|
|
|
if (this.frames > 0) {
|
2024-08-15 02:43:02 +00:00
|
|
|
this.info = await this.ffprobe.info(this.images[0].path);
|
|
|
|
}
|
|
|
|
if (this.info !== null) {
|
|
|
|
screen = this.display.getScreen();
|
|
|
|
this.display.setSource(this.info.width, this.info.height);
|
2024-08-15 22:55:37 +00:00
|
|
|
this.log.info(`Screen : ${screen.width},${screen.height}`);
|
|
|
|
this.log.info(`Sequence : ${this.info.width},${this.info.height}`);
|
2024-10-22 19:04:25 +00:00
|
|
|
this.log.info(`Display : ${JSON.stringify(this.display.getOutgoingPosition())}`);
|
2024-08-09 20:20:07 +00:00
|
|
|
}
|
2024-07-31 18:39:21 +00:00
|
|
|
}
|
|
|
|
unload() {
|
|
|
|
this.current = null;
|
2024-08-15 02:43:02 +00:00
|
|
|
this.info = null;
|
2024-07-31 18:39:21 +00:00
|
|
|
this.images = [];
|
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
getState() {
|
2024-10-22 19:04:25 +00:00
|
|
|
const dimensions = this.display.getOutgoingPosition();
|
2024-08-16 04:52:46 +00:00
|
|
|
const source = this.display.getSource();
|
|
|
|
const screen = this.display.getScreen();
|
|
|
|
return {
|
|
|
|
display: {
|
|
|
|
width: dimensions.w,
|
|
|
|
height: dimensions.h
|
|
|
|
},
|
|
|
|
offset: {
|
|
|
|
x: dimensions.x,
|
|
|
|
y: dimensions.y
|
|
|
|
},
|
|
|
|
screen,
|
|
|
|
source,
|
|
|
|
sequence: {
|
|
|
|
hash: this.current.hash,
|
|
|
|
name: this.current.name,
|
|
|
|
progress: this.progress,
|
|
|
|
current: this.frame,
|
|
|
|
frames: this.frames,
|
|
|
|
status: this.getStatus()
|
|
|
|
},
|
2024-10-19 02:13:52 +00:00
|
|
|
exposure: this.exposure,
|
|
|
|
statistics: this.stats !== null ? this.stats.calculate(this.frame) : null
|
2024-08-16 04:52:46 +00:00
|
|
|
};
|
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
getUpdateState() {
|
|
|
|
return {
|
|
|
|
sequence: {
|
|
|
|
hash: this.current.hash,
|
|
|
|
name: this.current.name,
|
|
|
|
progress: this.progress,
|
|
|
|
current: this.frame,
|
|
|
|
frames: this.frames,
|
|
|
|
status: this.getStatus()
|
|
|
|
},
|
|
|
|
exposure: this.exposure
|
|
|
|
};
|
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
getSequenceState() {
|
2024-08-18 01:22:17 +00:00
|
|
|
if (this.current === null) {
|
|
|
|
return null;
|
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
return {
|
|
|
|
hash: this.current.hash,
|
|
|
|
name: this.current.name,
|
|
|
|
progress: this.progress
|
|
|
|
};
|
|
|
|
}
|
2024-08-16 04:52:46 +00:00
|
|
|
setExposure(ms) {
|
|
|
|
this.exposure = ms;
|
2024-10-18 03:06:37 +00:00
|
|
|
this.log.info(`Updated exposure: ${ms}ms`);
|
|
|
|
this.updateClientsOnState();
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
|
|
|
getStatus() {
|
|
|
|
if (this.running && this.paused) {
|
|
|
|
return SequenceStatus.PAUSED;
|
|
|
|
}
|
|
|
|
else if (this.running && !this.paused) {
|
|
|
|
return SequenceStatus.RUNNING;
|
|
|
|
}
|
|
|
|
return SequenceStatus.IDLE;
|
|
|
|
}
|
|
|
|
getCurrent() {
|
|
|
|
if (this.current !== null && this.images.length > 0 && typeof this.images[this.frame] !== 'undefined') {
|
2024-08-18 01:22:17 +00:00
|
|
|
return this.images[this.frame];
|
2024-08-16 04:52:46 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
frameAdvance(frames = 1) {
|
|
|
|
if (this.frame + frames >= this.images.length) {
|
|
|
|
this.frame = this.images.length - 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.frame += frames;
|
|
|
|
}
|
|
|
|
this.progress = this.frame / (this.images.length - 1);
|
|
|
|
this.updateClientsOnState();
|
|
|
|
}
|
|
|
|
frameRewind(frames = 1) {
|
2024-08-30 17:49:16 +00:00
|
|
|
if (this.frame - frames < 0) {
|
2024-08-24 14:23:15 +00:00
|
|
|
this.frame = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.frame -= frames;
|
|
|
|
}
|
|
|
|
this.progress = this.frame > 0 ? this.frame / (this.images.length - 1) : 0;
|
|
|
|
this.updateClientsOnState();
|
|
|
|
}
|
|
|
|
frameSet(frame) {
|
|
|
|
if (frame < 0) {
|
|
|
|
frame = 0;
|
|
|
|
}
|
|
|
|
else if (frame > this.images.length - 1) {
|
|
|
|
frame = this.images.length - 1;
|
|
|
|
}
|
2024-08-30 17:49:16 +00:00
|
|
|
this.frame = frame;
|
2024-08-24 14:23:15 +00:00
|
|
|
this.progress = this.frame > 0 ? this.frame / (this.images.length - 1) : 0;
|
|
|
|
this.updateClientsOnState();
|
|
|
|
}
|
2024-10-22 19:04:25 +00:00
|
|
|
updateOffset(x, y) {
|
|
|
|
const current = this.display.getOutgoingPosition();
|
|
|
|
const screen = this.display.getScreen();
|
|
|
|
let totalX;
|
|
|
|
let totalY;
|
|
|
|
if (x !== 0) {
|
|
|
|
if (current.x + x < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
totalX = current.x + current.w + x;
|
|
|
|
if (totalX > screen.width) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.display.setOffsetX(current.x + x);
|
|
|
|
}
|
|
|
|
if (y !== 0) {
|
|
|
|
if (current.y + y < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
totalY = current.y + current.h + y;
|
|
|
|
if (totalY > screen.height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.display.setOffsetY(current.y + y);
|
|
|
|
}
|
2024-10-24 15:41:53 +00:00
|
|
|
this.updateClientsOnDisplay();
|
2024-10-22 19:04:25 +00:00
|
|
|
}
|
|
|
|
updateSize(width, height) {
|
|
|
|
const current = this.display.getOutgoingPosition();
|
|
|
|
const screen = this.display.getScreen();
|
|
|
|
let totalX;
|
|
|
|
let totalY;
|
|
|
|
if (width !== 0) {
|
|
|
|
if (current.w + width < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
totalX = current.x + current.w + width;
|
|
|
|
if (totalX > screen.width) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.display.setWidth(current.w + width);
|
|
|
|
}
|
|
|
|
if (height !== 0) {
|
|
|
|
if (current.h + height < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
totalY = current.y + current.h + height;
|
|
|
|
if (totalY > screen.height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.display.setHeight(current.h + height);
|
|
|
|
}
|
2024-10-24 15:41:53 +00:00
|
|
|
this.updateClientsOnDisplay();
|
2024-10-22 19:04:25 +00:00
|
|
|
}
|
|
|
|
updateScale(scale) {
|
2024-10-24 15:41:53 +00:00
|
|
|
const source = this.display.getSource();
|
2024-10-22 19:04:25 +00:00
|
|
|
const current = this.display.getDimensions();
|
|
|
|
const offset = this.display.getOffset();
|
|
|
|
const screen = this.display.getScreen();
|
2024-10-24 15:41:53 +00:00
|
|
|
let newWidth;
|
|
|
|
let newHeight;
|
|
|
|
let newOffsetX;
|
|
|
|
let newOffsetY;
|
|
|
|
if (source.getRatio() > screen.getRatio()) {
|
|
|
|
if (current.width + scale > screen.width || current.width + scale < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
newWidth = current.width + scale;
|
|
|
|
newHeight = Math.floor(newWidth / source.getRatio());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (current.height + scale > screen.height || current.height + scale < 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
newHeight = current.height + scale;
|
|
|
|
newWidth = Math.floor(source.getRatio() * newHeight);
|
|
|
|
}
|
|
|
|
newOffsetX = Math.round((screen.width - newWidth) / 2);
|
|
|
|
newOffsetY = Math.round((screen.height - newHeight) / 2);
|
|
|
|
this.display.setWidth(newWidth);
|
|
|
|
this.display.setHeight(newHeight);
|
|
|
|
this.display.setOffsetX(newOffsetX);
|
|
|
|
this.display.setOffsetY(newOffsetY);
|
|
|
|
this.updateClientsOnDisplay();
|
2024-10-22 19:04:25 +00:00
|
|
|
}
|
2024-08-24 14:23:15 +00:00
|
|
|
async frameRecord() {
|
2024-10-19 02:13:52 +00:00
|
|
|
const start = Date.now();
|
|
|
|
let load;
|
|
|
|
let open;
|
|
|
|
let exposureElapsed;
|
|
|
|
let exposureReported;
|
|
|
|
let close;
|
|
|
|
let total;
|
|
|
|
let result;
|
2024-08-24 14:23:15 +00:00
|
|
|
const img = this.images[this.frame];
|
2024-10-22 19:04:25 +00:00
|
|
|
const dimensions = this.display.getOutgoingPosition();
|
2024-08-24 14:23:15 +00:00
|
|
|
this.log.info(`Frame: ${this.frame} / ${this.images.length}`);
|
|
|
|
await this.fd.load(img.path, dimensions.x, dimensions.y, dimensions.w, dimensions.h);
|
2024-10-19 02:13:52 +00:00
|
|
|
load = Date.now() - start;
|
2024-08-24 14:23:15 +00:00
|
|
|
await this.camera.open();
|
2024-10-19 02:13:52 +00:00
|
|
|
open = Date.now() - start - load;
|
|
|
|
result = await this.fd.display(img.path, [this.exposure]);
|
|
|
|
exposureReported = result.reported;
|
|
|
|
exposureElapsed = Date.now() - start - load - open;
|
2024-08-24 14:23:15 +00:00
|
|
|
await this.camera.close();
|
2024-10-19 02:13:52 +00:00
|
|
|
close = Date.now() - start - load - open - exposureElapsed;
|
|
|
|
total = Date.now() - start;
|
|
|
|
this.stats.add(load, open, exposureElapsed, exposureReported, close, total);
|
2024-08-24 14:23:15 +00:00
|
|
|
}
|
2024-07-12 13:51:39 +00:00
|
|
|
}
|
|
|
|
exports.Sequence = Sequence;
|
|
|
|
//# sourceMappingURL=index.js.map
|