diff --git a/app/index.html b/app/index.html
index 87da465..b7e120c 100644
--- a/app/index.html
+++ b/app/index.html
@@ -259,11 +259,11 @@
-
+
-
-
+
+
Camera
diff --git a/app/lib/display/index.js b/app/lib/display/index.js
index 1a7ef61..592bd07 100644
--- a/app/lib/display/index.js
+++ b/app/lib/display/index.js
@@ -88,7 +88,7 @@ async function end () {
if (system.platform !== 'nix') {
await wv.close();
} else {
- cp.kill()
+ if (cp) cp.kill()
}
}
diff --git a/app/lib/ffmpeg/index.js b/app/lib/ffmpeg/index.js
index 33a5b49..dfa7d30 100644
--- a/app/lib/ffmpeg/index.js
+++ b/app/lib/ffmpeg/index.js
@@ -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();
diff --git a/app/lib/ffprobe/index.js b/app/lib/ffprobe/index.js
index cea2514..21684ed 100644
--- a/app/lib/ffprobe/index.js
+++ b/app/lib/ffprobe/index.js
@@ -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;
diff --git a/app/lib/ui/devices.js b/app/lib/ui/devices.js
index bc14195..4302e29 100644
--- a/app/lib/ui/devices.js
+++ b/app/lib/ui/devices.js
@@ -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;
\ No newline at end of file
diff --git a/app/lib/ui/seq.js b/app/lib/ui/seq.js
index 88b7734..d86be8e 100644
--- a/app/lib/ui/seq.js
+++ b/app/lib/ui/seq.js
@@ -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 () {
diff --git a/app/main.js b/app/main.js
index 63935b7..14bb34f 100644
--- a/app/main.js
+++ b/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