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:
parent
872b46d4a5
commit
f239f862e8
|
@ -739,7 +739,7 @@ button:focus {
|
|||
background: black;
|
||||
color: #fff;
|
||||
}
|
||||
#video input[type=text],
|
||||
#video input,
|
||||
#video select {
|
||||
display: block;
|
||||
border-radius: 5px;
|
||||
|
@ -755,25 +755,25 @@ button:focus {
|
|||
font-size: 21px;
|
||||
min-width: 300px;
|
||||
}
|
||||
#video input[type=text] span,
|
||||
#video input span,
|
||||
#video select span {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
}
|
||||
#video input[type=text]:active,
|
||||
#video input:active,
|
||||
#video select:active,
|
||||
#video input[type=text] .active,
|
||||
#video input .active,
|
||||
#video select .active {
|
||||
background: #fff;
|
||||
color: #272b30;
|
||||
outline: none;
|
||||
}
|
||||
#video input[type=text]:focus,
|
||||
#video input:focus,
|
||||
#video select:focus {
|
||||
outline: none;
|
||||
}
|
||||
#video input[type=text].active,
|
||||
#video input.active,
|
||||
#video select.active {
|
||||
border-color: #DAE035;
|
||||
color: #DAE035;
|
||||
|
@ -805,6 +805,7 @@ button:focus {
|
|||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
#filmout_monitor.on {
|
||||
display: block;
|
||||
|
@ -815,10 +816,14 @@ button:focus {
|
|||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
height: 360px;
|
||||
min-height: 360px;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
|
|
|
@ -57,30 +57,75 @@
|
|||
}
|
||||
|
||||
img.style.backgroundImage = `url('${src}')`;
|
||||
//img.onload = () => {
|
||||
//document.body.appendChild(img)
|
||||
//return resolve(img)
|
||||
//}
|
||||
//img.onerror = reject
|
||||
//img.src = src
|
||||
})
|
||||
});
|
||||
}
|
||||
async function onMeter () {
|
||||
console.log('meter')
|
||||
const body = document.querySelector('body')
|
||||
if (!body.classList.contains('meter')) {
|
||||
body.classList.add('meter')
|
||||
}
|
||||
}
|
||||
async function onField () {
|
||||
async function onFocus () {
|
||||
console.log('focus')
|
||||
const can = document.getElementById('can')
|
||||
const ctx = can.getContext('2d')
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
let ctx;
|
||||
if (!can.classList.contains('show')) {
|
||||
can.classList.add('show')
|
||||
}
|
||||
can.width = window.innerWidth
|
||||
can.height = window.innerHeight
|
||||
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{
|
||||
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{
|
||||
await drawField(can, ctx)
|
||||
} catch (err) {
|
||||
|
@ -91,10 +136,13 @@
|
|||
async function drawField (can, ctx) {
|
||||
const count = 20
|
||||
const half = Math.round(count / 2)
|
||||
const w = can.width
|
||||
const h = can.height
|
||||
const dpr = window.devicePixelRatio || 1
|
||||
const w = can.width / dpr
|
||||
const h = can.height / dpr
|
||||
const wsec = w / count
|
||||
const hsec = h / count
|
||||
const spacer = 12
|
||||
const fontSize = 18;
|
||||
|
||||
ctx.moveTo(w / 2, 0)
|
||||
ctx.lineTo(w / 2, h)
|
||||
|
@ -111,34 +159,21 @@
|
|||
ctx.lineTo(w - (wsec * i), hsec * i)
|
||||
ctx.stroke()
|
||||
}
|
||||
ctx.font = '30px Arial'
|
||||
ctx.font = `${fontSize}px Arial`
|
||||
for (let i = 0; i < half; i++) {
|
||||
ctx.fillText(`${(half - i)}`, (wsec * i) + 15, (h / 2) - 15)
|
||||
ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - 25, (h / 2) - 15)
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (hsec * i) + 25 )
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + 15, (h - (hsec * i)) - 15)
|
||||
ctx.fillText(`${(half - i)}`, (wsec * i) + spacer, (h / 2) - spacer)
|
||||
//ctx.fillText(`${(half - i)}`, (w - (wsec * i)) - spacer, (h / 2) - spacer)
|
||||
ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (hsec * i) + spacer + (fontSize / 2) )
|
||||
//ctx.fillText(`${(half - i)}`, (w / 2) + spacer, (h - (hsec * i)) - spacer)
|
||||
}
|
||||
}
|
||||
async function onDigital (event, arg) {
|
||||
console.log('called')
|
||||
if (arg.src) {
|
||||
try {
|
||||
await setImage(arg.src)
|
||||
} catch (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
|
||||
}
|
||||
|
@ -160,6 +195,7 @@
|
|||
ipcRenderer.on('display', onDigital)
|
||||
ipcRenderer.on('field', onField)
|
||||
ipcRenderer.on('meter', onMeter)
|
||||
ipcRenderer.on('focus', onFocus)
|
||||
document.onkeydown = onEscape
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -353,7 +353,7 @@
|
|||
|
||||
<div id="filmout_preview_wrap">
|
||||
<div id="filmout_monitor">
|
||||
<img src="#" id="filmout">
|
||||
<div id="filmout"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_stats">
|
||||
|
@ -372,17 +372,17 @@
|
|||
</div>
|
||||
<div id="filmout_position_wrap">
|
||||
<div>
|
||||
<button id="filmout_rewind" title="Rewind 1 Frame"><</button>
|
||||
<input id="filmout_position" class="count" type="text" value="00000"/>
|
||||
<button id="filmout_advance" title="Advance 1 Frame">></button>
|
||||
<button id="filmout_rewind" title="Rewind 1 Frame" onclick="filmout.rewind();"><</button>
|
||||
<input id="filmout_position" class="count" type="number" value="00000" onchange="gui.counterFormat(this, this.value);" />
|
||||
<button id="filmout_advance" title="Advance 1 Frame" onclick="filmout.advance();">></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filmout_functions">
|
||||
<div>
|
||||
<button id="filmout_preview">PREVIEW</button>
|
||||
<button id="filmout_meter">METER</button>
|
||||
<button id="filmout_focus">FOCUS</button>
|
||||
<button id="filmout_field">FIELD GUIDE</button>
|
||||
<button id="filmout_meter" onclick="filmout.meter();">METER</button>
|
||||
<button id="filmout_focus" onclick="filmout.focus();">FOCUS</button>
|
||||
<button id="filmout_field" onclick="filmout.field();">FIELD GUIDE</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#video{
|
||||
input[type=text],select{
|
||||
input,select{
|
||||
.button();
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
|
@ -41,6 +41,7 @@
|
|||
box-sizing: border-box;
|
||||
height: 360px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
&.on{
|
||||
display: block;
|
||||
}
|
||||
|
@ -51,10 +52,14 @@
|
|||
height: 360px;
|
||||
}
|
||||
#filmout {
|
||||
height: 360px;
|
||||
min-height: 360px;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
background-repeat:no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
&.on {
|
||||
|
|
|
@ -60,7 +60,7 @@ class WebView {
|
|||
console.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
await delay_1.delay(100);
|
||||
await delay_1.delay(200);
|
||||
return true;
|
||||
}
|
||||
async focus() {
|
||||
|
@ -68,6 +68,7 @@ class WebView {
|
|||
console.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus: true });
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ class WebView {
|
|||
console.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
//aspect ratio
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field: true });
|
||||
}
|
||||
|
@ -93,6 +94,7 @@ class WebView {
|
|||
console.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter: true });
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -41,6 +41,8 @@ class FilmOut {
|
|||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.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;
|
||||
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) {
|
||||
try {
|
||||
await this.display.open();
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -35,6 +35,9 @@ class FilmOut {
|
|||
constructor() {
|
||||
this.id = 'filmout';
|
||||
this.displays = [];
|
||||
this.state = {
|
||||
frame: 0
|
||||
};
|
||||
}
|
||||
init() {
|
||||
this.listen();
|
||||
|
@ -42,6 +45,7 @@ class FilmOut {
|
|||
listen() {
|
||||
ipcRenderer.on(this.id, this.onFilmout.bind(this));
|
||||
ipcRenderer.on('system', this.onSystem.bind(this));
|
||||
ipcRenderer.on('preview_frame', this.onFrame.bind(this));
|
||||
}
|
||||
onSystem(evt, args) {
|
||||
let option;
|
||||
|
@ -58,6 +62,7 @@ class FilmOut {
|
|||
if (args.displays.length > 1) {
|
||||
$('#filmout_displays').on('change', this.onChange.bind(this));
|
||||
}
|
||||
$('#filmout_position').on('change', this.previewFrame.bind(this));
|
||||
}
|
||||
onChange() {
|
||||
const val = $('#filmout_displays').val();
|
||||
|
@ -89,6 +94,7 @@ class FilmOut {
|
|||
elem.addClass('on');
|
||||
$('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
|
||||
$('#filmout_stats_monitor_aspect').text(`${aspect}`);
|
||||
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
|
||||
console.dir(display);
|
||||
}
|
||||
selectFile() {
|
||||
|
@ -156,8 +162,8 @@ class FilmOut {
|
|||
if (args.valid && args.valid === true) {
|
||||
//success state
|
||||
state = JSON.parse(args.state);
|
||||
console.dir(args);
|
||||
console.dir(state);
|
||||
//console.dir(args)
|
||||
//console.dir(state)
|
||||
$('#digital').addClass('active');
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
gui.notify('DEVICES', `Using video ${state.fileName}`);
|
||||
|
@ -169,17 +175,61 @@ class FilmOut {
|
|||
if (light.disabled) {
|
||||
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');
|
||||
$('#filmout_stats_video_name').text(state.fileName);
|
||||
$('#filmout_stats_video_size').text(`${state.info.width} x ${state.info.height}`);
|
||||
$('#filmout_stats_video_frames').text(`${state.frames} frames`);
|
||||
gui.updateState();
|
||||
this.previewFrame();
|
||||
}
|
||||
else {
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
$('#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();
|
||||
module.exports = filmout;
|
||||
|
|
|
@ -50,6 +50,9 @@ let filmout : FilmOut;
|
|||
class FilmOut {
|
||||
private id : string = 'filmout';
|
||||
private displays : any[] = [];
|
||||
private state : any = {
|
||||
frame : 0
|
||||
}
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
@ -59,9 +62,11 @@ class FilmOut {
|
|||
listen () {
|
||||
ipcRenderer.on(this.id, this.onFilmout.bind(this));
|
||||
ipcRenderer.on('system', this.onSystem.bind(this));
|
||||
ipcRenderer.on('preview_frame', this.onFrame.bind(this));
|
||||
}
|
||||
onSystem (evt : Event, args : any) {
|
||||
let option : any;
|
||||
|
||||
for (let display of args.displays) {
|
||||
this.displays.push(display);
|
||||
option = $('<option>');
|
||||
|
@ -76,6 +81,7 @@ class FilmOut {
|
|||
if (args.displays.length > 1) {
|
||||
$('#filmout_displays').on('change', this.onChange.bind(this));
|
||||
}
|
||||
$('#filmout_position').on('change', this.previewFrame.bind(this));
|
||||
}
|
||||
|
||||
onChange () {
|
||||
|
@ -109,6 +115,7 @@ class FilmOut {
|
|||
elem.addClass('on');
|
||||
$('#filmout_stats_monitor_size').text(`${display.width} x ${display.height}`);
|
||||
$('#filmout_stats_monitor_aspect').text(`${aspect}`);
|
||||
$('#filmout_stats_monitor_scale').text(`${parseFloat(display.scale).toFixed(1)} scale factor`);
|
||||
console.dir(display);
|
||||
}
|
||||
selectFile () {
|
||||
|
@ -170,13 +177,15 @@ class FilmOut {
|
|||
onFilmout (evt : any, args : any) {
|
||||
let state : any;
|
||||
let color : number[] = [255, 255, 255];
|
||||
|
||||
gui.spinner(false);
|
||||
gui.overlay(false);
|
||||
|
||||
if (args.valid && args.valid === true) {
|
||||
//success state
|
||||
state = JSON.parse(args.state);
|
||||
console.dir(args)
|
||||
console.dir(state)
|
||||
//console.dir(args)
|
||||
//console.dir(state)
|
||||
$('#digital').addClass('active');
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
gui.notify('DEVICES', `Using video ${state.fileName}`);
|
||||
|
@ -192,17 +201,65 @@ class FilmOut {
|
|||
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');
|
||||
$('#filmout_stats_video_name').text(state.fileName);
|
||||
$('#filmout_stats_video_size').text(`${state.info.width} x ${state.info.height}`);
|
||||
$('#filmout_stats_video_frames').text(`${state.frames} frames`);
|
||||
|
||||
gui.updateState();
|
||||
this.previewFrame();
|
||||
} else {
|
||||
$('#projector_type_digital').prop('checked', 'checked');
|
||||
$('#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();
|
||||
|
|
|
@ -60,7 +60,7 @@ class WebView {
|
|||
console.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
await delay_1.delay(100);
|
||||
await delay_1.delay(200);
|
||||
return true;
|
||||
}
|
||||
async focus() {
|
||||
|
@ -68,6 +68,7 @@ class WebView {
|
|||
console.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus: true });
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ class WebView {
|
|||
console.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
//aspect ratio
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field: true });
|
||||
}
|
||||
|
@ -93,6 +94,7 @@ class WebView {
|
|||
console.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter: true });
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -41,6 +41,8 @@ class FilmOut {
|
|||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.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;
|
||||
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) {
|
||||
try {
|
||||
await this.display.open();
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -60,7 +60,7 @@ class WebView {
|
|||
console.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
await delay_1.delay(100);
|
||||
await delay_1.delay(200);
|
||||
return true;
|
||||
}
|
||||
async focus() {
|
||||
|
@ -68,6 +68,7 @@ class WebView {
|
|||
console.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus: true });
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ class WebView {
|
|||
console.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
//aspect ratio
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field: true });
|
||||
}
|
||||
|
@ -93,6 +94,7 @@ class WebView {
|
|||
console.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay_1.delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter: true });
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -41,6 +41,8 @@ class FilmOut {
|
|||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.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;
|
||||
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) {
|
||||
try {
|
||||
await this.display.open();
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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.
|
|
@ -65,7 +65,7 @@ class WebView {
|
|||
console.error(err);
|
||||
}
|
||||
this.showing = true;
|
||||
await delay(100);
|
||||
await delay(200);
|
||||
return true;
|
||||
}
|
||||
async focus () {
|
||||
|
@ -73,6 +73,7 @@ class WebView {
|
|||
console.warn(`Cannot show focus screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('focus', { focus : true });
|
||||
} catch (err) {
|
||||
|
@ -84,7 +85,7 @@ class WebView {
|
|||
console.warn(`Cannot show field guide because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
//aspect ratio
|
||||
await delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('field', { field : true });
|
||||
} catch (err) {
|
||||
|
@ -96,6 +97,7 @@ class WebView {
|
|||
console.warn(`Cannot show meter screen because window does not exist`);
|
||||
return false;
|
||||
}
|
||||
await delay(500);
|
||||
try {
|
||||
this.digitalWindow.webContents.send('meter', { meter : true });
|
||||
} catch (err) {
|
||||
|
|
|
@ -49,6 +49,8 @@ class FilmOut {
|
|||
this.ipc.on('field', this.field.bind(this));
|
||||
this.ipc.on('meter', this.meter.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;
|
||||
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) {
|
||||
try {
|
||||
await this.display.open();
|
||||
|
|
Loading…
Reference in New Issue