Fixed frame counting optimization, resolving issue #17. Also added a Siemens Star focusing screen, a middle gray metering screen and a field guide screen for use with the filmout feature. TODO: actually change monitors when selected.

This commit is contained in:
mmcwilliams 2019-06-25 12:13:15 -04:00
parent 872b46d4a5
commit f239f862e8
21 changed files with 324 additions and 78 deletions

View File

@ -739,7 +739,7 @@ button:focus {
background: black; background: black;
color: #fff; color: #fff;
} }
#video input[type=text], #video input,
#video select { #video select {
display: block; display: block;
border-radius: 5px; border-radius: 5px;
@ -755,25 +755,25 @@ button:focus {
font-size: 21px; font-size: 21px;
min-width: 300px; min-width: 300px;
} }
#video input[type=text] span, #video input span,
#video select span { #video select span {
display: block; display: block;
font-size: 16px; font-size: 16px;
font-weight: 200; font-weight: 200;
} }
#video input[type=text]:active, #video input:active,
#video select:active, #video select:active,
#video input[type=text] .active, #video input .active,
#video select .active { #video select .active {
background: #fff; background: #fff;
color: #272b30; color: #272b30;
outline: none; outline: none;
} }
#video input[type=text]:focus, #video input:focus,
#video select:focus { #video select:focus {
outline: none; outline: none;
} }
#video input[type=text].active, #video input.active,
#video select.active { #video select.active {
border-color: #DAE035; border-color: #DAE035;
color: #DAE035; color: #DAE035;
@ -805,6 +805,7 @@ button:focus {
box-sizing: border-box; box-sizing: border-box;
height: 360px; height: 360px;
margin: 0 auto; margin: 0 auto;
position: relative;
} }
#filmout_monitor.on { #filmout_monitor.on {
display: block; display: block;
@ -815,14 +816,18 @@ button:focus {
height: 360px; height: 360px;
} }
#filmout { #filmout {
height: 360px; position: absolute;
min-height: 360px; background-repeat: no-repeat;
width: auto; background-size: contain;
margin: 0 auto; background-position: center;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block; display: block;
opacity: 0; opacity: 0;
} }
#filmout .on { #filmout.on {
opacity: 1; opacity: 1;
} }
#filmout_position_wrap { #filmout_position_wrap {

View File

@ -57,30 +57,75 @@
} }
img.style.backgroundImage = `url('${src}')`; img.style.backgroundImage = `url('${src}')`;
//img.onload = () => { });
//document.body.appendChild(img)
//return resolve(img)
//}
//img.onerror = reject
//img.src = src
})
} }
async function onMeter () { async function onMeter () {
console.log('meter')
const body = document.querySelector('body') const body = document.querySelector('body')
if (!body.classList.contains('meter')) { if (!body.classList.contains('meter')) {
body.classList.add('meter') body.classList.add('meter')
} }
} }
async function onField () { async function onFocus () {
console.log('focus')
const can = document.getElementById('can') const can = document.getElementById('can')
const ctx = can.getContext('2d') const dpr = window.devicePixelRatio || 1
let ctx;
if (!can.classList.contains('show')) { if (!can.classList.contains('show')) {
can.classList.add('show') can.classList.add('show')
} }
can.width = window.innerWidth can.width = window.innerWidth * dpr
can.height = window.innerHeight can.height = window.innerHeight * dpr
can.style.width = `${window.innerWidth}px` can.style.width = `${window.innerWidth}px`
can.style.height = `${window.innerHeight}px` can.style.height = `${window.innerHeight}px`
ctx = can.getContext('2d')
ctx.scale(dpr, dpr)
try{
await drawFocus(can, ctx)
} catch (err) {
alert(JSON.stringify(err))
}
}
async function drawFocus (can, ctx) {
const count = 20
const half = Math.round(count / 2)
const dpr = window.devicePixelRatio || 1
const w = can.width / dpr
const h = can.height / dpr
const opp = (Math.tan(360 / count) * ((h / 2) + h - w) / 1.5)
console.log(opp)
for (let i = 0; i < count; i++) {
ctx.beginPath()
ctx.moveTo(w / 2, h / 2)
ctx.lineTo((w / 2) + opp, h - w)
ctx.lineTo((w / 2) - opp, h - w)
ctx.fill()
ctx.translate(w / 2, h / 2);
ctx.rotate((360 / count) * Math.PI / 180)
ctx.translate(- w / 2, -h / 2)
}
}
async function onField () {
console.log('field guide')
const can = document.getElementById('can')
const dpr = window.devicePixelRatio || 1
let ctx;
if (!can.classList.contains('show')) {
can.classList.add('show')
}
can.width = window.innerWidth * dpr
can.height = window.innerHeight * dpr
can.style.width = `${window.innerWidth}px`
can.style.height = `${window.innerHeight}px`
ctx = can.getContext('2d')
ctx.scale(dpr, dpr)
try{ try{
await drawField(can, ctx) await drawField(can, ctx)
} catch (err) { } catch (err) {
@ -91,10 +136,13 @@
async function drawField (can, ctx) { async function drawField (can, ctx) {
const count = 20 const count = 20
const half = Math.round(count / 2) const half = Math.round(count / 2)
const w = can.width const dpr = window.devicePixelRatio || 1
const h = can.height const w = can.width / dpr
const h = can.height / dpr
const wsec = w / count const wsec = w / count
const hsec= h / count const hsec = h / count
const spacer = 12
const fontSize = 18;
ctx.moveTo(w / 2, 0) ctx.moveTo(w / 2, 0)
ctx.lineTo(w / 2, h) ctx.lineTo(w / 2, h)
@ -111,34 +159,21 @@
ctx.lineTo(w - (wsec * i), hsec * i) ctx.lineTo(w - (wsec * i), hsec * i)
ctx.stroke() ctx.stroke()
} }
ctx.font = '30px Arial' ctx.font = `${fontSize}px Arial`
for (let i = 0; i < half; i++) { for (let i = 0; i < half; i++) {
ctx.fillText(`${(half - i)}`, (wsec * i) + 15, (h / 2) - 15) ctx.fillText(`${(half - i)}`, (wsec * i) + spacer, (h / 2) - spacer)
ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - 25, (h / 2) - 15) //ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - spacer, (h / 2) - spacer)
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (hsec * i) + 25 ) ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (hsec * i) + spacer + (fontSize / 2) )
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (h - (hsec * i)) - 15) //ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (h - (hsec * i)) - spacer)
} }
} }
async function onDigital (event, arg) { async function onDigital (event, arg) {
console.log('called')
if (arg.src) { if (arg.src) {
try { try {
await setImage(arg.src) await setImage(arg.src)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
} else if (arg.meter) {
try {
await setMeter()
} catch (err) {
console.error(err)
}
} else if (arg.grid) {
try {
await setGrid()
} catch (err) {
console.error(err)
}
} }
return event.returnValue = true return event.returnValue = true
} }
@ -160,6 +195,7 @@
ipcRenderer.on('display', onDigital) ipcRenderer.on('display', onDigital)
ipcRenderer.on('field', onField) ipcRenderer.on('field', onField)
ipcRenderer.on('meter', onMeter) ipcRenderer.on('meter', onMeter)
ipcRenderer.on('focus', onFocus)
document.onkeydown = onEscape document.onkeydown = onEscape
</script> </script>
</body> </body>

View File

@ -353,7 +353,7 @@
<div id="filmout_preview_wrap"> <div id="filmout_preview_wrap">
<div id="filmout_monitor"> <div id="filmout_monitor">
<img src="#" id="filmout"> <div id="filmout"></div>
</div> </div>
</div> </div>
<div id="filmout_stats"> <div id="filmout_stats">
@ -372,17 +372,17 @@
</div> </div>
<div id="filmout_position_wrap"> <div id="filmout_position_wrap">
<div> <div>
<button id="filmout_rewind" title="Rewind 1 Frame"><</button> <button id="filmout_rewind" title="Rewind 1 Frame" onclick="filmout.rewind();"><</button>
<input id="filmout_position" class="count" type="text" value="00000"/> <input id="filmout_position" class="count" type="number" value="00000" onchange="gui.counterFormat(this, this.value);" />
<button id="filmout_advance" title="Advance 1 Frame">></button> <button id="filmout_advance" title="Advance 1 Frame" onclick="filmout.advance();">></button>
</div> </div>
</div> </div>
<div id="filmout_functions"> <div id="filmout_functions">
<div> <div>
<button id="filmout_preview">PREVIEW</button> <button id="filmout_preview">PREVIEW</button>
<button id="filmout_meter">METER</button> <button id="filmout_meter" onclick="filmout.meter();">METER</button>
<button id="filmout_focus">FOCUS</button> <button id="filmout_focus" onclick="filmout.focus();">FOCUS</button>
<button id="filmout_field">FIELD GUIDE</button> <button id="filmout_field" onclick="filmout.field();">FIELD GUIDE</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
#video{ #video{
input[type=text],select{ input,select{
.button(); .button();
display: inline-block; display: inline-block;
padding: 6px 12px; padding: 6px 12px;
@ -41,6 +41,7 @@
box-sizing: border-box; box-sizing: border-box;
height: 360px; height: 360px;
margin: 0 auto; margin: 0 auto;
position: relative;
&.on{ &.on{
display: block; display: block;
} }
@ -51,13 +52,17 @@
height: 360px; height: 360px;
} }
#filmout { #filmout {
height: 360px; position: absolute;
min-height: 360px; background-repeat:no-repeat;
width: auto; background-size: contain;
margin: 0 auto; background-position: center;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block; display: block;
opacity: 0; opacity: 0;
& .on { &.on {
opacity: 1.0; opacity: 1.0;
} }
} }

View File

@ -60,7 +60,7 @@ class WebView {
console.error(err); console.error(err);
} }
this.showing = true; this.showing = true;
await delay_1.delay(100); await delay_1.delay(200);
return true; return true;
} }
async focus() { async focus() {
@ -68,6 +68,7 @@ class WebView {
console.warn(`Cannot show focus screen because window does not exist`); console.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('focus', { focus: true }); this.digitalWindow.webContents.send('focus', { focus: true });
} }
@ -80,7 +81,7 @@ class WebView {
console.warn(`Cannot show field guide because window does not exist`); console.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
//aspect ratio await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('field', { field: true }); this.digitalWindow.webContents.send('field', { field: true });
} }
@ -93,6 +94,7 @@ class WebView {
console.warn(`Cannot show meter screen because window does not exist`); console.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('meter', { meter: true }); this.digitalWindow.webContents.send('meter', { meter: true });
} }

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,8 @@ class FilmOut {
this.ipc.on('field', this.field.bind(this)); this.ipc.on('field', this.field.bind(this));
this.ipc.on('meter', this.meter.bind(this)); this.ipc.on('meter', this.meter.bind(this));
this.ipc.on('filmout_close', this.close.bind(this)); this.ipc.on('filmout_close', this.close.bind(this));
//preview
this.ipc.on('preview_frame', this.previewFrame.bind(this));
} }
/** /**
* *
@ -127,6 +129,21 @@ class FilmOut {
this.state.enabled = true; this.state.enabled = true;
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) }); return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
} }
async previewFrame(evt, arg) {
const state = JSON.parse(JSON.stringify(this.state));
let path;
state.frame = arg.frame;
try {
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
}
catch (err) {
console.error(err);
throw err;
}
this.ui.send('preview_frame', { path, frame: arg.frame });
}
async preview(evt, arg) {
}
async focus(evt, arg) { async focus(evt, arg) {
try { try {
await this.display.open(); await this.display.open();

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,9 @@ class FilmOut {
constructor() { constructor() {
this.id = 'filmout'; this.id = 'filmout';
this.displays = []; this.displays = [];
this.state = {
frame: 0
};
} }
init() { init() {
this.listen(); this.listen();
@ -42,6 +45,7 @@ class FilmOut {
listen() { listen() {
ipcRenderer.on(this.id, this.onFilmout.bind(this)); ipcRenderer.on(this.id, this.onFilmout.bind(this));
ipcRenderer.on('system', this.onSystem.bind(this)); ipcRenderer.on('system', this.onSystem.bind(this));
ipcRenderer.on('preview_frame', this.onFrame.bind(this));
} }
onSystem(evt, args) { onSystem(evt, args) {
let option; let option;
@ -58,6 +62,7 @@ class FilmOut {
if (args.displays.length > 1) { if (args.displays.length > 1) {
$('#filmout_displays').on('change', this.onChange.bind(this)); $('#filmout_displays').on('change', this.onChange.bind(this));
} }
$('#filmout_position').on('change', this.previewFrame.bind(this));
} }
onChange() { onChange() {
const val = $('#filmout_displays').val(); const val = $('#filmout_displays').val();
@ -87,8 +92,9 @@ class FilmOut {
elem.width(w); elem.width(w);
} }
elem.addClass('on'); elem.addClass('on');
$('#filmout_stats_monitor_size').text(`${display.width}x${display.height}`); $('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
$('#filmout_stats_monitor_aspect').text(`${aspect}`); $('#filmout_stats_monitor_aspect').text(`${aspect}`);
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
console.dir(display); console.dir(display);
} }
selectFile() { selectFile() {
@ -156,8 +162,8 @@ class FilmOut {
if (args.valid && args.valid === true) { if (args.valid && args.valid === true) {
//success state //success state
state = JSON.parse(args.state); state = JSON.parse(args.state);
console.dir(args); //console.dir(args)
console.dir(state); //console.dir(state)
$('#digital').addClass('active'); $('#digital').addClass('active');
$('#projector_type_digital').prop('checked', 'checked'); $('#projector_type_digital').prop('checked', 'checked');
gui.notify('DEVICES', `Using video ${state.fileName}`); gui.notify('DEVICES', `Using video ${state.fileName}`);
@ -169,17 +175,61 @@ class FilmOut {
if (light.disabled) { if (light.disabled) {
light.enable(); light.enable();
} }
this.state.frame = 0;
this.state.frames = state.frames;
this.state.width = state.info.width;
this.state.height = state.info.height;
this.state.name = state.fileName;
$('#seq_loop').val(`${state.frames - 1}`).trigger('change'); $('#seq_loop').val(`${state.frames - 1}`).trigger('change');
$('#filmout_stats_video_name').text(state.fileName); $('#filmout_stats_video_name').text(state.fileName);
$('#filmout_stats_video_size').text(`${state.info.width}x${state.info.height}`); $('#filmout_stats_video_size').text(`${state.info.width} x ${state.info.height}`);
$('#filmout_stats_video_frames').text(`${state.frames} frames`); $('#filmout_stats_video_frames').text(`${state.frames} frames`);
gui.updateState(); gui.updateState();
this.previewFrame();
} }
else { else {
$('#projector_type_digital').prop('checked', 'checked'); $('#projector_type_digital').prop('checked', 'checked');
$('#digital').removeClass('active'); $('#digital').removeClass('active');
} }
} }
previewFrame() {
const frameStr = $('#filmout_position').val();
const frame = parseInt(frameStr, 10);
this.state.frame = frame;
ipcRenderer.send('preview_frame', { frame });
}
onFrame(evt, args) {
const elem = $('#filmout');
elem[0].style.backgroundImage = `url('${args.path}')`;
elem.addClass('on');
}
advance() {
this.state.frame++;
if (this.state.frame >= this.state.frames) {
this.state.frame = 0;
}
$('#filmout_position').val(this.state.frame).trigger('change');
}
rewind() {
this.state.frame--;
if (this.state.frame < 0) {
this.state.frame = this.state.frames - 1;
}
$('#filmout_position').val(this.state.frame).trigger('change');
}
preview(evt, arg) {
}
focus() {
ipcRenderer.send('focus', { focus: true });
}
field() {
ipcRenderer.send('field', { field: true });
}
meter() {
ipcRenderer.send('meter', { meter: true });
}
close(evt, arg) {
}
} }
filmout = new FilmOut(); filmout = new FilmOut();
module.exports = filmout; module.exports = filmout;

View File

@ -50,6 +50,9 @@ let filmout : FilmOut;
class FilmOut { class FilmOut {
private id : string = 'filmout'; private id : string = 'filmout';
private displays : any[] = []; private displays : any[] = [];
private state : any = {
frame : 0
}
constructor () { constructor () {
} }
@ -59,9 +62,11 @@ class FilmOut {
listen () { listen () {
ipcRenderer.on(this.id, this.onFilmout.bind(this)); ipcRenderer.on(this.id, this.onFilmout.bind(this));
ipcRenderer.on('system', this.onSystem.bind(this)); ipcRenderer.on('system', this.onSystem.bind(this));
ipcRenderer.on('preview_frame', this.onFrame.bind(this));
} }
onSystem (evt : Event, args : any) { onSystem (evt : Event, args : any) {
let option : any; let option : any;
for (let display of args.displays) { for (let display of args.displays) {
this.displays.push(display); this.displays.push(display);
option = $('<option>'); option = $('<option>');
@ -76,6 +81,7 @@ class FilmOut {
if (args.displays.length > 1) { if (args.displays.length > 1) {
$('#filmout_displays').on('change', this.onChange.bind(this)); $('#filmout_displays').on('change', this.onChange.bind(this));
} }
$('#filmout_position').on('change', this.previewFrame.bind(this));
} }
onChange () { onChange () {
@ -107,8 +113,9 @@ class FilmOut {
} }
elem.addClass('on'); elem.addClass('on');
$('#filmout_stats_monitor_size').text(`${display.width}x${display.height}`); $('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
$('#filmout_stats_monitor_aspect').text(`${aspect}`); $('#filmout_stats_monitor_aspect').text(`${aspect}`);
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
console.dir(display); console.dir(display);
} }
selectFile () { selectFile () {
@ -170,13 +177,15 @@ class FilmOut {
onFilmout (evt : any, args : any) { onFilmout (evt : any, args : any) {
let state : any; let state : any;
let color : number[] = [255, 255, 255]; let color : number[] = [255, 255, 255];
gui.spinner(false); gui.spinner(false);
gui.overlay(false); gui.overlay(false);
if (args.valid && args.valid === true) { if (args.valid && args.valid === true) {
//success state //success state
state = JSON.parse(args.state); state = JSON.parse(args.state);
console.dir(args) //console.dir(args)
console.dir(state) //console.dir(state)
$('#digital').addClass('active'); $('#digital').addClass('active');
$('#projector_type_digital').prop('checked', 'checked'); $('#projector_type_digital').prop('checked', 'checked');
gui.notify('DEVICES', `Using video ${state.fileName}`); gui.notify('DEVICES', `Using video ${state.fileName}`);
@ -192,17 +201,65 @@ class FilmOut {
light.enable(); light.enable();
} }
this.state.frame = 0;
this.state.frames = state.frames;
this.state.width = state.info.width;
this.state.height = state.info.height;
this.state.name = state.fileName;
$('#seq_loop').val(`${state.frames - 1}`).trigger('change'); $('#seq_loop').val(`${state.frames - 1}`).trigger('change');
$('#filmout_stats_video_name').text(state.fileName); $('#filmout_stats_video_name').text(state.fileName);
$('#filmout_stats_video_size').text(`${state.info.width}x${state.info.height}`); $('#filmout_stats_video_size').text(`${state.info.width} x ${state.info.height}`);
$('#filmout_stats_video_frames').text(`${state.frames} frames`); $('#filmout_stats_video_frames').text(`${state.frames} frames`);
gui.updateState(); gui.updateState();
this.previewFrame();
} else { } else {
$('#projector_type_digital').prop('checked', 'checked'); $('#projector_type_digital').prop('checked', 'checked');
$('#digital').removeClass('active'); $('#digital').removeClass('active');
} }
} }
previewFrame () {
const frameStr : string = $('#filmout_position').val() as string;
const frame : number = parseInt(frameStr, 10);
this.state.frame = frame;
ipcRenderer.send('preview_frame', { frame });
}
onFrame (evt : any, args : any) {
const elem : any = $('#filmout');
elem[0].style.backgroundImage = `url('${args.path}')`;
elem.addClass('on');
}
advance () {
this.state.frame++;
if (this.state.frame >= this.state.frames) {
this.state.frame = 0;
}
$('#filmout_position').val(this.state.frame).trigger('change');
}
rewind () {
this.state.frame--;
if (this.state.frame < 0) {
this.state.frame = this.state.frames - 1;
}
$('#filmout_position').val(this.state.frame).trigger('change');
}
preview (evt : any, arg : any) {
}
focus () {
ipcRenderer.send('focus', { focus : true });
}
field () {
ipcRenderer.send('field', { field : true });
}
meter () {
ipcRenderer.send('meter', { meter : true });
}
close (evt : any, arg : any) {
}
} }
filmout = new FilmOut(); filmout = new FilmOut();

View File

@ -60,7 +60,7 @@ class WebView {
console.error(err); console.error(err);
} }
this.showing = true; this.showing = true;
await delay_1.delay(100); await delay_1.delay(200);
return true; return true;
} }
async focus() { async focus() {
@ -68,6 +68,7 @@ class WebView {
console.warn(`Cannot show focus screen because window does not exist`); console.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('focus', { focus: true }); this.digitalWindow.webContents.send('focus', { focus: true });
} }
@ -80,7 +81,7 @@ class WebView {
console.warn(`Cannot show field guide because window does not exist`); console.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
//aspect ratio await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('field', { field: true }); this.digitalWindow.webContents.send('field', { field: true });
} }
@ -93,6 +94,7 @@ class WebView {
console.warn(`Cannot show meter screen because window does not exist`); console.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('meter', { meter: true }); this.digitalWindow.webContents.send('meter', { meter: true });
} }

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,8 @@ class FilmOut {
this.ipc.on('field', this.field.bind(this)); this.ipc.on('field', this.field.bind(this));
this.ipc.on('meter', this.meter.bind(this)); this.ipc.on('meter', this.meter.bind(this));
this.ipc.on('filmout_close', this.close.bind(this)); this.ipc.on('filmout_close', this.close.bind(this));
//preview
this.ipc.on('preview_frame', this.previewFrame.bind(this));
} }
/** /**
* *
@ -127,6 +129,21 @@ class FilmOut {
this.state.enabled = true; this.state.enabled = true;
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) }); return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
} }
async previewFrame(evt, arg) {
const state = JSON.parse(JSON.stringify(this.state));
let path;
state.frame = arg.frame;
try {
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
}
catch (err) {
console.error(err);
throw err;
}
this.ui.send('preview_frame', { path, frame: arg.frame });
}
async preview(evt, arg) {
}
async focus(evt, arg) { async focus(evt, arg) {
try { try {
await this.display.open(); await this.display.open();

File diff suppressed because one or more lines are too long

View File

@ -60,7 +60,7 @@ class WebView {
console.error(err); console.error(err);
} }
this.showing = true; this.showing = true;
await delay_1.delay(100); await delay_1.delay(200);
return true; return true;
} }
async focus() { async focus() {
@ -68,6 +68,7 @@ class WebView {
console.warn(`Cannot show focus screen because window does not exist`); console.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('focus', { focus: true }); this.digitalWindow.webContents.send('focus', { focus: true });
} }
@ -80,7 +81,7 @@ class WebView {
console.warn(`Cannot show field guide because window does not exist`); console.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
//aspect ratio await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('field', { field: true }); this.digitalWindow.webContents.send('field', { field: true });
} }
@ -93,6 +94,7 @@ class WebView {
console.warn(`Cannot show meter screen because window does not exist`); console.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500);
try { try {
this.digitalWindow.webContents.send('meter', { meter: true }); this.digitalWindow.webContents.send('meter', { meter: true });
} }

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,8 @@ class FilmOut {
this.ipc.on('field', this.field.bind(this)); this.ipc.on('field', this.field.bind(this));
this.ipc.on('meter', this.meter.bind(this)); this.ipc.on('meter', this.meter.bind(this));
this.ipc.on('filmout_close', this.close.bind(this)); this.ipc.on('filmout_close', this.close.bind(this));
//preview
this.ipc.on('preview_frame', this.previewFrame.bind(this));
} }
/** /**
* *
@ -127,6 +129,21 @@ class FilmOut {
this.state.enabled = true; this.state.enabled = true;
return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) }); return await this.ui.send(this.id, { valid: true, state: JSON.stringify(this.state) });
} }
async previewFrame(evt, arg) {
const state = JSON.parse(JSON.stringify(this.state));
let path;
state.frame = arg.frame;
try {
path = await this.ffmpeg.frame(state, { color: [255, 255, 255] });
}
catch (err) {
console.error(err);
throw err;
}
this.ui.send('preview_frame', { path, frame: arg.frame });
}
async preview(evt, arg) {
}
async focus(evt, arg) { async focus(evt, arg) {
try { try {
await this.display.open(); await this.display.open();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
ffprobe: Query the container
ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 input.mp4
This is a fast method.
Not all formats (such as Matroska) will report the number of frames resulting in the output of N/A. See the other methods listed below.
ffprobe: Count the number of frames
ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 input.mkv
This is a slow method.
Add the -skip_frame nokey option to only count key frames.
ffmpeg: Count the number of frames
If you do not have ffprobe you can use ffmpeg instead:
ffmpeg -i input.mkv -map 0:v:0 -c copy -f null -
This is a somewhat fast method.
Refer to frame= near the end of the console output.
Add the -discard nokey input option (before -i) to only count key frames.

View File

@ -65,7 +65,7 @@ class WebView {
console.error(err); console.error(err);
} }
this.showing = true; this.showing = true;
await delay(100); await delay(200);
return true; return true;
} }
async focus () { async focus () {
@ -73,6 +73,7 @@ class WebView {
console.warn(`Cannot show focus screen because window does not exist`); console.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay(500);
try { try {
this.digitalWindow.webContents.send('focus', { focus : true }); this.digitalWindow.webContents.send('focus', { focus : true });
} catch (err) { } catch (err) {
@ -84,7 +85,7 @@ class WebView {
console.warn(`Cannot show field guide because window does not exist`); console.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
//aspect ratio await delay(500);
try { try {
this.digitalWindow.webContents.send('field', { field : true }); this.digitalWindow.webContents.send('field', { field : true });
} catch (err) { } catch (err) {
@ -96,6 +97,7 @@ class WebView {
console.warn(`Cannot show meter screen because window does not exist`); console.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay(500);
try { try {
this.digitalWindow.webContents.send('meter', { meter : true }); this.digitalWindow.webContents.send('meter', { meter : true });
} catch (err) { } catch (err) {

View File

@ -49,6 +49,8 @@ class FilmOut {
this.ipc.on('field', this.field.bind(this)); this.ipc.on('field', this.field.bind(this));
this.ipc.on('meter', this.meter.bind(this)); this.ipc.on('meter', this.meter.bind(this));
this.ipc.on('filmout_close', this.close.bind(this)); this.ipc.on('filmout_close', this.close.bind(this));
//preview
this.ipc.on('preview_frame', this.previewFrame.bind(this));
} }
/** /**
* *
@ -134,6 +136,23 @@ class FilmOut {
this.state.enabled = true; this.state.enabled = true;
return await this.ui.send(this.id, { valid : true, state : JSON.stringify(this.state) }); return await this.ui.send(this.id, { valid : true, state : JSON.stringify(this.state) });
} }
async previewFrame (evt : any, arg : any) {
const state : any = JSON.parse(JSON.stringify(this.state));
let path : string;
state.frame = arg.frame;
try {
path = await this.ffmpeg.frame(state, { color : [255, 255, 255] });
} catch (err) {
console.error(err);
throw err;
}
this.ui.send('preview_frame', { path, frame : arg.frame })
}
async preview (evt : any, arg : any) {
}
async focus (evt : any, arg : any) { async focus (evt : any, arg : any) {
try { try {
await this.display.open(); await this.display.open();