Added ffprobe functionality. On UI side, enable and disable buttons via class to prevent user error

This commit is contained in:
mmcwilliams 2024-08-09 16:20:07 -04:00
parent 53bf156d10
commit d3f0a27f30
22 changed files with 504 additions and 21 deletions

View File

@ -39,31 +39,47 @@ class Client {
case 'close' :
this.receiveCameraClose();
break;
case 'select' :
this.receiveSelect(msg);
break;
default:
console.warn(`No command ${msg.cmd}`);
console.warn(`No command "${msg.cmd}"`);
break;
}
}
public disableClass (className : string) {
document.querySelectorAll(`.${className}`).forEach((el : HTMLButtonElement) => {
el.disabled = true;
});
}
public enableClass (className : string) {
document.querySelectorAll(`.${className}`).forEach((el : HTMLButtonElement) => {
el.disabled = false;
});
}
public sendCameraOpen () {
console.log('send camera open');
this.disableClass('manualCtrl');
this.client.send(JSON.stringify({ cmd : 'open' }));
}
private receiveCameraOpen () {
console.log('got camera open');
this.enableClass('manualCtrl');
}
public sendCameraClose () {
console.log('send camera close');
this.disableClass('manualCtrl');
this.client.send(JSON.stringify({ cmd : 'close' }));
}
private receiveCameraClose () {
console.log('got camera close');
this.enableClass('manualCtrl');
}
public sendSelect () {
@ -79,7 +95,8 @@ class Client {
}
private receiveSelect (msg : Message) {
console.log('got select');
console.dir(msg)
}
public fullscreen () {

View File

@ -5,6 +5,8 @@ export declare class Display {
private display;
private offset;
constructor(width: number, height: number);
setOffsetX(x: number): void;
setOffsetY(y: number): void;
setSource(width: number, height: number): void;
getDimensions(): fdOutgoingPosition;
}

View File

@ -15,6 +15,12 @@ class Display {
this.screen = new Dimensions(width, height);
this.offset = { x: 0, y: 0 };
}
setOffsetX(x) {
this.offset.x = x;
}
setOffsetY(y) {
this.offset.y = y;
}
setSource(width, height) {
this.source = new Dimensions(width, height);
if (this.source.getRatio() > this.screen.getRatio()) {

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/display/index.ts"],"names":[],"mappings":";;;AAEA,MAAM,UAAU;IAIf,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;CACD;AAOD,MAAa,OAAO;IAQnB,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAE,CAAA;IAC9B,CAAC;IAEM,SAAS,CAAE,KAAc,EAAE,MAAe;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAG,CAAC,EAAG,CAAC,EAAE,CAAA;IAC5D,CAAC;IAEM,aAAa;QACnB,OAAO;YACN,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,KAAK;YACtB,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,MAAM;YACvB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACjB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;SACjB,CAAA;IACF,CAAC;CACD;AA/BD,0BA+BC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/display/index.ts"],"names":[],"mappings":";;;AAEA,MAAM,UAAU;IAIf,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,QAAQ;QACd,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;CACD;AAOD,MAAa,OAAO;IAQnB,YAAa,KAAc,EAAE,MAAe;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAG,CAAC,EAAE,CAAA;IAC9B,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,UAAU,CAAE,CAAU;QAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAEM,SAAS,CAAE,KAAc,EAAE,MAAe;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;YACrD,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAG,CAAC,EAAG,CAAC,EAAE,CAAA;IAC5D,CAAC;IAEM,aAAa;QACnB,OAAO;YACN,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,KAAK;YACtB,CAAC,EAAG,IAAI,CAAC,OAAO,CAAC,MAAM;YACvB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACjB,CAAC,EAAG,IAAI,CAAC,MAAM,CAAC,CAAC;SACjB,CAAA;IACF,CAAC;CACD;AAvCD,0BAuCC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}

33
dist/ffprobe/index.d.ts vendored Normal file
View File

@ -0,0 +1,33 @@
/** @module lib/ffprobe */
/**
* Class representing all ffprobe features.
*/
export declare class FFPROBE {
private bin;
private log;
constructor(bin?: string);
exists(path: string): Promise<boolean>;
/**
* Parse the fps entry into a float representing the fps of a video
**/
private parseFps;
/**
* Get info on a video in json format. Use for filmout.
*
* @param {string} video Path to video
*
* @returns {object} Video info in an object
**/
info(video: string): Promise<any>;
private exec;
/**
* Count the number of frames in the video using one of two methods.
* The first uses -select_streams and is very fast. The second uses
* -count_frames and is VERY slow.
*
* @param {string} video Path to video
*
* @returns {integer} Number of frames in video
**/
frames(video: string): Promise<any>;
}

179
dist/ffprobe/index.js vendored Normal file
View File

@ -0,0 +1,179 @@
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.FFPROBE = void 0;
const promises_1 = require("fs/promises");
const path_1 = require("path");
const shell_1 = require("../shell");
const log_1 = require("../log");
/** @module lib/ffprobe */
/**
* Class representing all ffprobe features.
*/
class FFPROBE {
constructor(bin = 'ffprobe') {
this.bin = bin;
this.log = (0, log_1.createLog)('ffprobe2');
}
async exists(path) {
try {
await (0, promises_1.access)(path);
return true;
}
catch {
return false;
}
}
/**
* Parse the fps entry into a float representing the fps of a video
**/
parseFps(fpsStr) {
let fps = 30.0;
let parts;
if (fpsStr.indexOf('/') !== -1) {
parts = fpsStr.split('/');
fps = parseFloat(parts[0]) / parseFloat(parts[1]);
}
else {
fps = parseFloat(fpsStr);
}
return fps;
}
/**
* Get info on a video in json format. Use for filmout.
*
* @param {string} video Path to video
*
* @returns {object} Video info in an object
**/
async info(video) {
const cmd = [
this.bin,
'-v', 'quiet',
'-print_format', 'json',
'-show_format',
'-show_streams',
video
];
let fileExists;
let raw;
let json;
let vid; //whether video has stream with video data
try {
fileExists = await this.exists(video);
}
catch (err) {
this.log.error(`Error checking if ${video} exists`, err);
}
if (!fileExists) {
this.log.error(new Error(`File ${video} does not exist`));
return false;
}
try {
raw = await this.exec(cmd);
}
catch (err) {
this.log.error('Error getting info', err);
return false;
}
try {
json = JSON.parse(raw);
}
catch (err) {
this.log.error('Error parsing stdout', err);
this.log.error(raw);
return raw;
}
if (json.format && json.format.duration) {
json.seconds = parseFloat(json.format.duration);
}
if (json && json.streams) {
vid = json.streams.find((stream) => {
if (stream.width && stream.height)
return stream;
});
}
if (vid) {
json.width = vid.width;
json.height = vid.height;
json.fps = this.parseFps(vid.r_frame_rate);
}
return json;
}
async exec(cmd) {
return new Promise(async (resolve, reject) => {
function after(lines) {
return resolve(lines);
}
const child = new shell_1.Shell(cmd, null, null, after, true);
await child.execute();
});
}
/**
* Count the number of frames in the video using one of two methods.
* The first uses -select_streams and is very fast. The second uses
* -count_frames and is VERY slow.
*
* @param {string} video Path to video
*
* @returns {integer} Number of frames in video
**/
async frames(video) {
const ext = (0, path_1.extname)(video.toLowerCase());
let cmd = [
this.bin,
'-v', 'error',
'-select_streams', 'v:0',
'-show_entries', 'stream=nb_frames',
'-of', 'default=nokey=1:noprint_wrappers=1',
video
];
let backup_cmd = [
this.bin,
'-v', 'error',
'-count_frames',
'-select_streams', 'v:0',
'-show_entries', 'stream=nb_read_frames',
'-of', 'default=nokey=1:noprint_wrappers=1',
video
];
let fileExists;
let raw;
let frames;
try {
fileExists = await this.exists(video);
}
catch (err) {
this.log.error('Error checking if file exists', err);
return false;
}
if (!fileExists) {
this.log.error(new Error(`File ${video} does not exist`));
return false;
}
if (ext === '.mkv') {
cmd = backup_cmd;
}
try {
raw = await this.exec(cmd);
}
catch (err) {
this.log.error(err);
return false;
}
try {
frames = parseInt(raw.stdout);
}
catch (err) {
return raw.stdout;
}
return frames;
}
}
exports.FFPROBE = FFPROBE;
/*
function map (obj : any) {
console.dir(obj);
}
*/
module.exports = { FFPROBE };
//# sourceMappingURL=index.js.map

1
dist/ffprobe/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ffprobe/index.ts"],"names":[],"mappings":"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"}

6
dist/files/index.js vendored
View File

@ -88,7 +88,7 @@ class Files {
return videos;
}
static async enumerateSequence(path) {
const dirs = [];
const imgs = [];
let all;
let stats;
let filePath;
@ -104,7 +104,7 @@ class Files {
try {
stats = await (0, promises_1.lstat)(filePath);
if (stats.isFile() && imageExtensions.indexOf((0, path_1.extname)((0, path_1.basename)(elem).toLowerCase())) !== -1) {
dirs.push({
imgs.push({
path: filePath,
hash: hash_1.Hashes.stringHash(filePath),
name: (0, path_1.basename)(filePath)
@ -115,7 +115,7 @@ class Files {
//
}
}
return dirs;
return imgs;
}
}
exports.Files = Files;

5
dist/index.js vendored
View File

@ -37,6 +37,7 @@ const log_1 = require("./log");
const files_1 = require("./files");
const display_1 = require("./display");
const ffmpeg_1 = require("./ffmpeg");
const ffprobe_1 = require("./ffprobe");
const camera_1 = require("./camera");
const sequence_1 = require("./sequence");
const log = (0, log_1.createLog)('fm');
@ -45,6 +46,7 @@ let wss;
let fd;
let display;
let ffmpeg;
let ffprobe;
let camera;
let sequence;
let index;
@ -221,10 +223,11 @@ async function main() {
await settings();
index = await createTemplate('./views/index.hbs');
ffmpeg = new ffmpeg_1.FFMPEG(process.env['FFMPEG']);
ffprobe = new ffprobe_1.FFPROBE();
camera = new camera_1.Camera();
display = new display_1.Display(width, height);
//fd = new FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']));
sequence = new sequence_1.Sequence(camera, fd, display);
sequence = new sequence_1.Sequence(camera, fd, display, ffprobe);
app.listen(port, async () => {
log.info(`filmout_manager HTTP server running on port ${port}`);
});

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -2,17 +2,19 @@ import type { SequenceObject } from '../files';
import type { FD } from '../fd';
import type { Camera } from '../camera';
import type { Display } from '../display';
import type { FFPROBE } from '../ffprobe';
export declare class Sequence {
private log;
private current;
private images;
private camera;
private display;
private ffprobe;
private fd;
private running;
private progress;
private frames;
constructor(camera: Camera, fd: FD, display: Display);
constructor(camera: Camera, fd: FD, display: Display, ffprobe: FFPROBE);
start(): void;
stop(): void;
isRunning(): boolean;

View File

@ -4,13 +4,14 @@ exports.Sequence = void 0;
const files_1 = require("../files");
const log_1 = require("../log");
class Sequence {
constructor(camera, fd, display) {
constructor(camera, fd, display, ffprobe) {
this.current = null;
this.images = [];
this.log = (0, log_1.createLog)('seq');
this.camera = camera;
this.fd = fd;
this.display = display;
this.ffprobe = ffprobe;
}
start() {
this.running = true;
@ -38,6 +39,9 @@ class Sequence {
return;
}
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
if (this.images.length > 0) {
console.dir(await this.ffprobe.info(this.images[0].path));
}
}
unload() {
this.current = null;

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":";;;AAAA,oCAAiC;AACjC,gCAAkC;AAOlC,MAAa,QAAQ;IAWpB,YAAa,MAAe,EAAE,EAAO,EAAE,OAAgB;QAT/C,YAAO,GAAoB,IAAI,CAAC;QAChC,WAAM,GAAmB,EAAE,CAAC;QASnC,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAEM,IAAI,CAAE,GAAoB;QAChC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,SAAS,EAAE,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,SAAS;QACtB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAG,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,GAAG,MAAM,aAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yCAAyC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAClF,OAAO;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,MAAM,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3H,CAAC;IAEM,MAAM;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAEM,QAAQ;QACd,OAAO;YACN,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,QAAQ,EAAG,IAAI,CAAC,QAAQ;SACxB,CAAA;IACF,CAAC;CACD;AA/DD,4BA+DC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sequence/index.ts"],"names":[],"mappings":";;;AAAA,oCAAiC;AACjC,gCAAkC;AAQlC,MAAa,QAAQ;IAYpB,YAAa,MAAe,EAAE,EAAO,EAAE,OAAgB,EAAE,OAAiB;QAVlE,YAAO,GAAoB,IAAI,CAAC;QAChC,WAAM,GAAmB,EAAE,CAAC;QAUnC,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAEM,IAAI,CAAE,GAAoB;QAChC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,SAAS,EAAE,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,SAAS;QACtB,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAG,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,GAAG,MAAM,aAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yCAAyC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAClF,OAAO;QACR,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,MAAM,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAE1H,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,CAAC;IACF,CAAC;IAEM,MAAM;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAEM,QAAQ;QACd,OAAO;YACN,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,IAAI,EAAG,IAAI,CAAC,OAAO,CAAC,IAAI;YACxB,QAAQ,EAAG,IAAI,CAAC,QAAQ;SACxB,CAAA;IACF,CAAC;CACD;AArED,4BAqEC"}

View File

@ -32,6 +32,14 @@ export class Display {
this.offset = { x: 0, y : 0 }
}
public setOffsetX (x : number) {
this.offset.x = x;
}
public setOffsetY (y : number) {
this.offset.y = y;
}
public setSource (width : number, height : number) {
this.source = new Dimensions(width, height);
if (this.source.getRatio() > this.screen.getRatio()) {

192
src/ffprobe/index.ts Normal file
View File

@ -0,0 +1,192 @@
'use strict';
import { access } from 'fs/promises';
import { extname } from 'path';
import { Shell } from '../shell';
import { createLog } from '../log';
import type { Logger } from 'winston';
/** @module lib/ffprobe */
/**
* Class representing all ffprobe features.
*/
export class FFPROBE {
private bin : string;
private log : Logger;
constructor (bin : string = 'ffprobe') {
this.bin = bin;
this.log = createLog('ffprobe2');
}
public async exists (path : string) : Promise<boolean> {
try {
await access(path);
return true;
} catch {
return false;
}
}
/**
* Parse the fps entry into a float representing the fps of a video
**/
private parseFps (fpsStr : string) {
let fps : number = 30.0;
let parts : string[];
if (fpsStr.indexOf('/') !== -1) {
parts = fpsStr.split('/');
fps = parseFloat(parts[0]) / parseFloat(parts[1]);
} else {
fps = parseFloat(fpsStr);
}
return fps
}
/**
* Get info on a video in json format. Use for filmout.
*
* @param {string} video Path to video
*
* @returns {object} Video info in an object
**/
public async info (video : string) {
const cmd : string[] = [
this.bin,
'-v', 'quiet',
'-print_format', 'json',
'-show_format',
'-show_streams',
video
];
let fileExists : boolean;
let raw : any;
let json : any;
let vid : any; //whether video has stream with video data
try {
fileExists = await this.exists(video);
} catch (err) {
this.log.error(`Error checking if ${video} exists`, err);
}
if (!fileExists) {
this.log.error(new Error(`File ${video} does not exist`));
return false
}
try {
raw = await this.exec(cmd);
} catch (err) {
this.log.error('Error getting info', err);
return false
}
try {
json = JSON.parse(raw);
} catch (err) {
this.log.error('Error parsing stdout', err);
this.log.error(raw);
return raw;
}
if (json.format && json.format.duration) {
json.seconds = parseFloat(json.format.duration);
}
if (json && json.streams) {
vid = json.streams.find((stream : any) => {
if (stream.width && stream.height) return stream;
});
}
if (vid) {
json.width = vid.width;
json.height = vid.height;
json.fps = this.parseFps(vid.r_frame_rate)
}
return json;
}
private async exec (cmd : string[]) : Promise<string> {
return new Promise(async (resolve : Function, reject : Function) => {
function after (lines : string) {
return resolve(lines);
}
const child : Shell = new Shell(cmd, null, null, after, true);
await child.execute();
});
}
/**
* Count the number of frames in the video using one of two methods.
* The first uses -select_streams and is very fast. The second uses
* -count_frames and is VERY slow.
*
* @param {string} video Path to video
*
* @returns {integer} Number of frames in video
**/
public async frames (video : string) {
const ext : string = extname(video.toLowerCase());
let cmd : string[] = [
this.bin,
'-v', 'error',
'-select_streams', 'v:0',
'-show_entries', 'stream=nb_frames',
'-of', 'default=nokey=1:noprint_wrappers=1',
video
];
let backup_cmd : string[] = [
this.bin,
'-v', 'error',
'-count_frames',
'-select_streams', 'v:0',
'-show_entries', 'stream=nb_read_frames',
'-of', 'default=nokey=1:noprint_wrappers=1',
video
];
let fileExists : boolean;
let raw : any;
let frames : number;
try {
fileExists = await this.exists(video);
} catch (err) {
this.log.error('Error checking if file exists', err);
return false
}
if (!fileExists) {
this.log.error(new Error(`File ${video} does not exist`));
return false;
}
if (ext === '.mkv') {
cmd = backup_cmd;
}
try {
raw = await this.exec(cmd);
} catch (err) {
this.log.error(err);
return false;
}
try {
frames = parseInt(raw.stdout);
} catch (err) {
return raw.stdout;
}
return frames;
}
}
/*
function map (obj : any) {
console.dir(obj);
}
*/
module.exports = { FFPROBE };

View File

@ -113,7 +113,7 @@ export class Files {
}
public static async enumerateSequence (path : string) : Promise<ImageObject[]> {
const dirs : ImageObject[] = [];
const imgs : ImageObject[] = [];
let all : string[];
let stats : Stats;
let filePath : string;
@ -131,7 +131,7 @@ export class Files {
try {
stats = await lstat(filePath);
if (stats.isFile() && imageExtensions.indexOf(extname(basename(elem).toLowerCase())) !== -1) {
dirs.push({
imgs.push({
path : filePath,
hash : Hashes.stringHash(filePath),
name : basename(filePath)
@ -142,7 +142,7 @@ export class Files {
}
}
return dirs;
return imgs;
}
}

View File

@ -24,6 +24,7 @@ import { TestImage } from './testimage';
import { FD } from './fd';
import { Display } from './display';
import { FFMPEG } from './ffmpeg';
import { FFPROBE } from './ffprobe';
import { Camera } from './camera';
import { Sequence } from './sequence';
@ -33,6 +34,7 @@ let wss : Server;
let fd : FD;
let display : Display;
let ffmpeg : FFMPEG;
let ffprobe : FFPROBE;
let camera : Camera;
let sequence : Sequence;
let index : HandlebarsTemplateDelegate<any>;
@ -215,10 +217,11 @@ async function main () {
await settings();
index = await createTemplate('./views/index.hbs');
ffmpeg = new FFMPEG(process.env['FFMPEG']);
ffprobe = new FFPROBE();
camera = new Camera();
display = new Display(width, height);
//fd = new FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']));
sequence = new Sequence(camera, fd, display);
sequence = new Sequence(camera, fd, display, ffprobe);
app.listen(port, async () => {
log.info(`filmout_manager HTTP server running on port ${port}`);

View File

@ -5,6 +5,7 @@ import type { SequenceObject, ImageObject } from '../files';
import type { FD } from '../fd';
import type { Camera } from '../camera';
import type { Display } from '../display';
import type { FFPROBE } from '../ffprobe';
export class Sequence {
private log : Logger;
@ -12,16 +13,18 @@ export class Sequence {
private images : ImageObject[] = [];
private camera : Camera;
private display : Display;
private ffprobe : FFPROBE;
private fd : FD;
private running : boolean;
private progress : number;
private frames : number;
constructor (camera : Camera, fd : FD, display: Display) {
constructor (camera : Camera, fd : FD, display: Display, ffprobe : FFPROBE) {
this.log = createLog('seq');
this.camera = camera;
this.fd = fd;
this.display = display;
this.ffprobe = ffprobe;
}
public start () {
@ -55,6 +58,10 @@ export class Sequence {
}
this.log.info(`Sequence ${this.current.name} contains ${this.images.length} image${this.images.length === 1 ? '' : 's'}`);
if (this.images.length > 0) {
console.dir(await this.ffprobe.info(this.images[0].path));
}
}
public unload () {

View File

@ -7,6 +7,8 @@ declare class Client {
private onOpen;
private setSequence;
private cmd;
disableClass(className: string): void;
enableClass(className: string): void;
sendCameraOpen(): void;
private receiveCameraOpen;
sendCameraClose(): void;

View File

@ -35,24 +35,39 @@ class Client {
break;
case 'select':
this.receiveSelect(msg);
break;
default:
console.warn(`No command ${msg.cmd}`);
console.warn(`No command "${msg.cmd}"`);
break;
}
}
disableClass(className) {
document.querySelectorAll(`.${className}`).forEach((el) => {
el.disabled = true;
});
}
enableClass(className) {
document.querySelectorAll(`.${className}`).forEach((el) => {
el.disabled = false;
});
}
sendCameraOpen() {
console.log('send camera open');
this.disableClass('manualCtrl');
this.client.send(JSON.stringify({ cmd: 'open' }));
}
receiveCameraOpen() {
console.log('got camera open');
this.enableClass('manualCtrl');
}
sendCameraClose() {
console.log('send camera close');
this.disableClass('manualCtrl');
this.client.send(JSON.stringify({ cmd: 'close' }));
}
receiveCameraClose() {
console.log('got camera close');
this.enableClass('manualCtrl');
}
sendSelect() {
const sequence = document.getElementById('sequence').value;
@ -66,6 +81,8 @@ class Client {
this.client.send(JSON.stringify(msg));
}
receiveSelect(msg) {
console.log('got select');
console.dir(msg);
}
fullscreen() {
if (!document.fullscreenElement) {

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../browser/index.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../browser/index.ts"],"names":[],"mappings":"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"}

View File

@ -46,8 +46,15 @@
<button id="select" onclick="client.sendSelect();">Select</button>
</div>
<div>
<button id="open" onclick="client.sendCameraOpen()">Open Gate</button>
<button id="close" onclick="client.sendCameraClose()">Close Gate</button>
<button id="start" class="sequenceCtrl" disabled>Start</button>
<button id="stop" class="sequenceCtrl" disabled>Stop</button>
<button id="pause" class="sequenceCtrl" disabled>Pause</button>
</div>
<div>
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open Gate</button>
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close Gate</button>
<button id="focus" class="manualCtrl" onclick="">Focus</button>
<button id="framing" class="manualCtrl" onclick="">Framing</button>
</div>
<div class="status-bar" id="status">
<p class="status-bar-field">Idle</p>