Digital projector feature added. Select a video and it will be displayed on the main monitor (TODO: address this) and the camera will advance in sync, as with a regular optical printer.
This commit is contained in:
parent
fafb313f7d
commit
40b5ecfe69
|
@ -259,11 +259,11 @@
|
|||
<select id="projector_device">
|
||||
<option>Not Set</option>
|
||||
</select>
|
||||
<input type="radio" id="digital_type_arduino" name="digital_type" value="arduino" checked="checked" />
|
||||
<input type="radio" id="projector_type_arduino" name="projector_type" value="arduino" checked="checked" />
|
||||
</div>
|
||||
<div class="spacer">
|
||||
<input type="text" id="digital" name="digital" placeholder="Digital file" onclick="devices.digitalSelect();" readonly />
|
||||
<input type="radio" id="digital_type" name="digital_type" value="video" onclick="devices.digital();" />
|
||||
<input type="text" id="digital" name="digital" placeholder="Digital file" onclick="devices.digitalSelect();" data-file="" readonly />
|
||||
<input type="radio" id="projector_type" name="projector_type" value="video" onclick="devices.digital();" />
|
||||
</div>
|
||||
<div>
|
||||
<h4>Camera</h4>
|
||||
|
|
|
@ -88,7 +88,7 @@ async function end () {
|
|||
if (system.platform !== 'nix') {
|
||||
await wv.close();
|
||||
} else {
|
||||
cp.kill()
|
||||
if (cp) cp.kill()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ async function frame (video, frame, obj) {
|
|||
//-vf "select=gte(n\,${frame})" -compression_algo raw -pix_fmt rgb24 "export-${padded}.png"
|
||||
|
||||
try {
|
||||
output = await exec(cmd);
|
||||
console.log(cmd);
|
||||
output = await exec(cmd);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ async function checkDir () {
|
|||
|
||||
module.exports = (sys) => {
|
||||
system = sys;
|
||||
TMPDIR = path.join(system.tmp, 'intval_go_node');
|
||||
TMPDIR = path.join(system.tmp, 'mcopy_digital');
|
||||
|
||||
checkDir();
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ const fs = require('fs-extra');
|
|||
|
||||
const exec = require('exec');
|
||||
//const spawn = require('spawn');
|
||||
const exit = require('exit');
|
||||
//const exit = require('exit');
|
||||
|
||||
let system = {};
|
||||
|
||||
|
@ -21,17 +21,24 @@ async function info (video) {
|
|||
return exit(err, 5);
|
||||
}
|
||||
if (!exists) {
|
||||
return exit(`File ${video} does not exist`, 6);
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await exec(cmd);
|
||||
} catch (err) {
|
||||
return exit(err, 7);
|
||||
//return exit(err, 7);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(raw);
|
||||
json = JSON.parse(raw.stdout);
|
||||
} catch (err) {
|
||||
return raw;
|
||||
return raw.stdout;
|
||||
}
|
||||
|
||||
if (json && json.streams) {
|
||||
|
@ -57,22 +64,28 @@ async function frames (video) {
|
|||
try {
|
||||
exists = await fs.exists(video);
|
||||
} catch (err) {
|
||||
return exit(err, 5);
|
||||
//return exit(err, 5);
|
||||
console.error(err);
|
||||
return false
|
||||
}
|
||||
if (!exists) {
|
||||
return exit(`File ${video} does not exist`, 6);
|
||||
//return exit(`File ${video} does not exist`, 6);
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
console.log(cmd);
|
||||
raw = await exec(cmd);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
frames = parseInt(raw)
|
||||
frames = parseInt(raw.stdout)
|
||||
} catch (err) {
|
||||
return raw;
|
||||
return raw.stdout;
|
||||
}
|
||||
|
||||
return frames;
|
||||
|
|
|
@ -37,6 +37,7 @@ devices.listen = function () {
|
|||
'use strict';
|
||||
ipcRenderer.on('ready', devices.ready);
|
||||
ipcRenderer.on('intval', devices.intvalCb);
|
||||
ipcRenderer.on('digital', devices.digitalCb);
|
||||
};
|
||||
devices.ready = function (event, arg) {
|
||||
'use strict';
|
||||
|
@ -104,44 +105,6 @@ devices.intval = function () {
|
|||
}
|
||||
};
|
||||
|
||||
devices.digitalSelect = function () {
|
||||
const elem = $('#digital');
|
||||
dialog.showOpenDialog({
|
||||
properties: [
|
||||
'openFile',
|
||||
'openDirectory'
|
||||
],
|
||||
filters: [
|
||||
{ name: 'Movies', extensions: ['mkv', 'avi', 'mp4', 'mpeg', 'mov'] },
|
||||
{ name: 'All Files', extensions: ['*'] }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
devices.digital = function () {
|
||||
'use strict';
|
||||
const elem = $('#digital');
|
||||
let proceed = false;
|
||||
let obj = {
|
||||
connect: true,
|
||||
url : url
|
||||
};
|
||||
if ( url !== '' && typeof url !== 'undefined') {
|
||||
proceed = confirm(`Are you sure you want to`);
|
||||
} else {
|
||||
alert('Cannot connect')
|
||||
}
|
||||
|
||||
if (proceed) {
|
||||
//gui.overlay(true);
|
||||
//gui.spinner(true, `Connecting to`);
|
||||
ipcRenderer.send('video', obj)
|
||||
} else {
|
||||
$('#camera_type_arduino').prop('checked', 'checked');
|
||||
$('#intval').removeClass('active');
|
||||
}
|
||||
};
|
||||
|
||||
devices.intvalCb = function (evt, args) {
|
||||
'use strict';
|
||||
let state;
|
||||
|
@ -163,4 +126,89 @@ devices.intvalCb = function (evt, args) {
|
|||
}
|
||||
};
|
||||
|
||||
devices.digitalSelect = function () {
|
||||
'use strict';
|
||||
const elem = $('#digital');
|
||||
const extensions = ['mpg', 'mpeg', 'mov', 'mkv', 'avi'];
|
||||
dialog.showOpenDialog({
|
||||
title : `Select video or image sequence`,
|
||||
properties : [`openFile`], // openDirectory, multiSelection, openFile
|
||||
defaultPath: 'c:/',
|
||||
filters :
|
||||
[
|
||||
{
|
||||
name: 'Videos',
|
||||
extensions
|
||||
},
|
||||
{
|
||||
name: 'All Files',
|
||||
extensions: ['*']
|
||||
},
|
||||
]
|
||||
}, (files) => {
|
||||
let valid = false;
|
||||
console.dir(files)
|
||||
let path = files[0]
|
||||
if (path && path !== '') {
|
||||
for (let ext of extensions) {
|
||||
if (path.toLowerCase().indexOf(`.${ext}`) !== -1) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
if (!valid) return false;
|
||||
log.info(`Selected video ${path.split('/').pop()}`, 'DIGITAL', true);
|
||||
elem.attr('data-file', path);
|
||||
elem.val(path.split('/').pop());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
devices.digital = function () {
|
||||
'use strict';
|
||||
const elem = $('#digital');
|
||||
const path = elem.attr('data-file');
|
||||
const fileName = elem.val();
|
||||
let proceed = false;
|
||||
let obj = {
|
||||
path,
|
||||
fileName
|
||||
}
|
||||
|
||||
if (path && path !== '') {
|
||||
proceed = confirm(`Are you sure you want to use ${fileName}?`);
|
||||
}
|
||||
|
||||
if (proceed) {
|
||||
gui.overlay(true);
|
||||
gui.spinner(true, `Getting info about ${fileName}`);
|
||||
ipcRenderer.send('digital', obj)
|
||||
} else {
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
$('#digital').removeClass('active');
|
||||
}
|
||||
};
|
||||
|
||||
devices.digitalCb = function (evt, args) {
|
||||
'use strict';
|
||||
let state;
|
||||
gui.spinner(false);
|
||||
gui.overlay(false);
|
||||
if (args.valid && args.valid === true) {
|
||||
//success state
|
||||
state = JSON.parse(args.state);
|
||||
$('#digital').addClass('active');
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
gui.notify('DEVICES', `Using video ${state.fileName}`);
|
||||
|
||||
mcopy.state.sequence.arr = ['PF', 'CF'];
|
||||
gui.grid.state(0);
|
||||
gui.grid.state(1);
|
||||
|
||||
gui.updateState();
|
||||
} else {
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
$('#digital').removeClass('active');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = devices;
|
|
@ -26,6 +26,7 @@ seq.run = function () {
|
|||
}
|
||||
if (seq.i == 0) {
|
||||
$('#loop_current').text(gui.fmtZero(mcopy.loopCount + 1, 6));
|
||||
ipcRenderer.send('seq', { action : 'loop' });
|
||||
}
|
||||
if (seq.stop()) {
|
||||
$('.row input').removeClass('h');
|
||||
|
@ -73,7 +74,7 @@ seq.run = function () {
|
|||
} else {
|
||||
log.info('Sequence completed in ' + humanizeDuration(timeEnd), 'SEQUENCE', true);
|
||||
}
|
||||
|
||||
ipcRenderer.send('seq', { action : 'stop' });
|
||||
//capture.report = ipcRenderer.sendSync('transfer', { action: 'end'});
|
||||
//if (capture.active) {
|
||||
//alert(capture.report);
|
||||
|
@ -90,6 +91,9 @@ seq.run = function () {
|
|||
seq.stop = function (state) {
|
||||
'use strict';
|
||||
if (typeof state === 'undefined') {
|
||||
if (seq.stopState === true) {
|
||||
ipcRenderer.send('seq', { action : 'stop' });
|
||||
}
|
||||
return seq.stopState;
|
||||
} else {
|
||||
seq.stopState = state;
|
||||
|
@ -97,7 +101,10 @@ seq.stop = function (state) {
|
|||
if (state === false) {
|
||||
mcopy.loopCount = 0
|
||||
$('#loop_current').text('');
|
||||
} else {
|
||||
ipcRenderer.send('seq', { action : 'stop' });
|
||||
}
|
||||
return state
|
||||
};
|
||||
seq.init = function (start) {
|
||||
'use strict';
|
||||
|
@ -108,7 +115,9 @@ seq.init = function (start) {
|
|||
}
|
||||
seq.stop(false);
|
||||
seq.i = start;
|
||||
|
||||
//ipcRenderer.sendSync('transfer', { action: 'start'});
|
||||
ipcRenderer.send('seq', { action : 'start' });
|
||||
seq.run();
|
||||
};
|
||||
seq.stats = function () {
|
||||
|
|
147
app/main.js
147
app/main.js
|
@ -405,7 +405,8 @@ light.end = async function (rgb, id, ms) {
|
|||
}
|
||||
|
||||
proj.state = {
|
||||
dir : true //default dir
|
||||
dir : true, //default dir
|
||||
digital : false
|
||||
}
|
||||
proj.init = function () {
|
||||
proj.listen()
|
||||
|
@ -419,20 +420,32 @@ proj.set = async function (dir, id) {
|
|||
cmd = mcopy.cfg.arduino.cmd.proj_backward
|
||||
}
|
||||
proj.state.dir = dir
|
||||
try {
|
||||
ms = await arduino.send('projector', cmd)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
if (proj.digital) {
|
||||
dig.set(dir)
|
||||
} else {
|
||||
try {
|
||||
ms = await arduino.send('projector', cmd)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
return await proj.end(cmd, id, ms)
|
||||
}
|
||||
proj.move = async function (frame, id) {
|
||||
const cmd = mcopy.cfg.arduino.cmd.projector
|
||||
let ms
|
||||
try {
|
||||
ms = await arduino.send('projector', cmd)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
if (proj.digital) {
|
||||
try {
|
||||
ms = await dig.move()
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
ms = await arduino.send('projector', cmd)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
return await proj.end(mcopy.cfg.arduino.cmd.projector, id, ms)
|
||||
}
|
||||
|
@ -453,6 +466,7 @@ proj.listen = function () {
|
|||
}
|
||||
event.returnValue = true
|
||||
})
|
||||
ipcMain.on('digital', proj.connectDigital)
|
||||
}
|
||||
proj.end = async function (cmd, id, ms) {
|
||||
let message = ''
|
||||
|
@ -473,6 +487,94 @@ proj.end = async function (cmd, id, ms) {
|
|||
return await mainWindow.webContents.send('proj', {cmd: cmd, id : id, ms: ms})
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a file as the "digital" source on "projector"
|
||||
*
|
||||
**/
|
||||
proj.connectDigital = async function (evt, arg) {
|
||||
let info;
|
||||
let frames = 0;
|
||||
|
||||
try {
|
||||
info = await ffprobe.info(arg.path);
|
||||
} catch (err) {
|
||||
log.error(err, 'DIGITAL', true, true);
|
||||
proj.digital = false;
|
||||
await mainWindow.webContents.send('digital', { valid : false });
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
frames = await ffprobe.frames(arg.path);
|
||||
} catch (err) {
|
||||
log.error(err, 'DIGITAL', true, true);
|
||||
proj.digital = false;
|
||||
await mainWindow.webContents.send('digital', { valid : false });
|
||||
return false;
|
||||
}
|
||||
|
||||
dig.state.frame = 0;
|
||||
dig.state.path = arg.path;
|
||||
dig.state.fileName = arg.fileName;
|
||||
dig.state.frames = frames;
|
||||
dig.state.info = info;
|
||||
|
||||
console.dir(dig.state);
|
||||
|
||||
log.info(`Opened ${dig.state.fileName}`, 'DIGITAL', true, true);
|
||||
log.info(`Frames : ${frames}`, 'DIGITAL', true, true);
|
||||
proj.digital = true;
|
||||
return await mainWindow.webContents.send('digital', { valid : true, state : JSON.stringify(dig.state) });
|
||||
}
|
||||
|
||||
const dig = {};
|
||||
dig.state = {
|
||||
frame : 0,
|
||||
frames : 0,
|
||||
path : null,
|
||||
fileName : null,
|
||||
info : {},
|
||||
dir : true
|
||||
};
|
||||
|
||||
dig.set = function (dir) {
|
||||
dig.state.dir = dir;
|
||||
}
|
||||
|
||||
dig.move = async function () {
|
||||
let start = +new Date()
|
||||
let last = dig.state.dir + 0;
|
||||
if (dig.state.dir) {
|
||||
dig.state.frame++
|
||||
} else {
|
||||
dig.state.frame--
|
||||
}
|
||||
if (dig.state.frame < 1) {
|
||||
dig.state.frame = 1
|
||||
}
|
||||
|
||||
if (last > 0) {
|
||||
display.end()
|
||||
//wipe last frame
|
||||
try {
|
||||
await ffmpeg.clear(last)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await ffmpeg.frame(dig.state.path, dig.state.frame)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
display.start(dig.state.frame)
|
||||
|
||||
await delay(100)
|
||||
|
||||
return (+new Date()) - start
|
||||
}
|
||||
|
||||
cam.intval = null
|
||||
cam.state = {
|
||||
dir : true //default dir
|
||||
|
@ -510,10 +612,17 @@ cam.move = async function (frame, id) {
|
|||
const cmd = mcopy.cfg.arduino.cmd.camera
|
||||
let ms
|
||||
if (cam.intval) {
|
||||
|
||||
ms = await cam.intval.move()
|
||||
try {
|
||||
ms = await cam.intval.move()
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
} else {
|
||||
ms = await arduino.send('camera', cmd)
|
||||
try {
|
||||
ms = await arduino.send('camera', cmd)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
log.info('Camera move time', { ms })
|
||||
return cam.end(cmd, id, ms)
|
||||
|
@ -591,6 +700,19 @@ cam.end = async function (cmd, id, ms) {
|
|||
mainWindow.webContents.send('cam', {cmd: cmd, id : id, ms: ms})
|
||||
};
|
||||
|
||||
const seq = {};
|
||||
seq.init = function () {
|
||||
seq.listen();
|
||||
}
|
||||
|
||||
seq.listen = function () {
|
||||
ipcMain.on('seq', async (evt, arg) => {
|
||||
if (arg.action === 'stop' && proj.digital) {
|
||||
display.end()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
log.file = function () {
|
||||
let logPath = path.join(os.homedir(), `/.config/mcopy/`)
|
||||
if (process.platform === 'darwin') {
|
||||
|
@ -675,6 +797,7 @@ var init = async function () {
|
|||
proj.init()
|
||||
cam.init()
|
||||
dev.init()
|
||||
seq.init()
|
||||
|
||||
|
||||
//capture = require('capture')(SYSTEM); //redundant
|
||||
|
|
Loading…
Reference in New Issue