2024-02-20 04:57:49 +00:00
|
|
|
const m = require('mithril')
|
|
|
|
const client = require('./api/client')
|
|
|
|
|
|
|
|
const Encoder = {
|
|
|
|
oninit: function(vnode) {
|
|
|
|
this.list_devices = {
|
2024-02-20 05:43:07 +00:00
|
|
|
command: 'ffmpeg.exe',
|
2024-02-20 04:57:49 +00:00
|
|
|
arguments: '-hide_banner -sources decklink',
|
|
|
|
}
|
|
|
|
this.list_formats = {
|
|
|
|
command: '',
|
|
|
|
arguments: '<missing decklink device>',
|
|
|
|
}
|
|
|
|
this.resetStatus()
|
|
|
|
client.registerComponent(this)
|
|
|
|
},
|
|
|
|
|
|
|
|
resetStatus() {
|
|
|
|
this.settingsChanged = false
|
|
|
|
this.settings = {
|
|
|
|
device: '',
|
|
|
|
format_code: '',
|
|
|
|
command: '',
|
|
|
|
}
|
|
|
|
this.encoderStats= null
|
|
|
|
this.encoderStatus = {
|
|
|
|
starting: false,
|
|
|
|
running: false,
|
|
|
|
log: '...',
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onremove: function(vnode) {
|
|
|
|
client.unregisterComponent(this)
|
|
|
|
},
|
|
|
|
|
|
|
|
ioInit: function() {
|
|
|
|
client.on(this, 'encoder.status', status => {
|
|
|
|
this.encoderStatus = status
|
|
|
|
if (!this.settingsChanged) {
|
|
|
|
this.settings = status.settings
|
|
|
|
}
|
|
|
|
this.updateListFormatsHelper()
|
|
|
|
})
|
|
|
|
client.on(this, 'encoder.stats', stats => {
|
|
|
|
this.encoderStats = stats
|
|
|
|
})
|
|
|
|
client.emit('encoder.status')
|
|
|
|
},
|
|
|
|
|
|
|
|
ioConnectionChanged(connected) {
|
|
|
|
if (!connected) {
|
|
|
|
this.resetStatus()
|
|
|
|
} else {
|
|
|
|
client.emit('encoder.status')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
listDecklinkDevices() {
|
|
|
|
client.emit('encoder.run', this.list_devices)
|
|
|
|
},
|
|
|
|
|
|
|
|
listDecklinkFormats() {
|
|
|
|
if (!this.settings.device) return
|
|
|
|
|
|
|
|
client.emit('encoder.run', this.list_formats)
|
|
|
|
},
|
|
|
|
|
|
|
|
startClicked() {
|
|
|
|
client.emit('encoder.start')
|
|
|
|
},
|
|
|
|
|
|
|
|
stopClicked() {
|
|
|
|
client.emit('encoder.stop')
|
|
|
|
},
|
|
|
|
|
|
|
|
saveClicked() {
|
|
|
|
this.settingsChanged = false
|
|
|
|
client.emit('encoder.settings', this.settings)
|
|
|
|
},
|
|
|
|
|
|
|
|
updateListFormatsHelper() {
|
|
|
|
if (this.settings.device) {
|
|
|
|
this.list_formats.command = this.list_devices.command
|
|
|
|
this.list_formats.arguments = `-hide_banner -f decklink -list_formats 1 ${this.settings.device}`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
updateSettings(key, vnode) {
|
|
|
|
this.settingsChanged = true
|
|
|
|
this.settings[key] = vnode.target.value
|
|
|
|
|
|
|
|
this.updateListFormatsHelper()
|
|
|
|
},
|
|
|
|
|
|
|
|
view: function(vnode) {
|
|
|
|
let stats = this.encoderStats
|
|
|
|
return [
|
|
|
|
m('div.column.settings', [
|
|
|
|
m('h2', 'Encoder status'),
|
|
|
|
m('p', 'Status'),
|
|
|
|
m('input', {
|
|
|
|
type: 'text',
|
|
|
|
readonly: true,
|
|
|
|
class: this.encoderStatus.running ? 'red'
|
|
|
|
: this.encoderStatus.starting ? 'green' : '',
|
|
|
|
value: (!client.isConnected
|
|
|
|
? '<Unknown>'
|
|
|
|
: this.encoderStatus.stopError ? `Forcefully stopped: ${this.encoderStatus.stopError}`
|
|
|
|
: stats?.errors ? `Streaming: ${stats.errors} Errors`
|
|
|
|
: stats?.showSlowSpeed ? `Streaming (Slow speed)`
|
|
|
|
: this.encoderStatus.running ? 'Streaming'
|
|
|
|
: this.encoderStatus.starting ? 'Starting'
|
|
|
|
: 'Not streaming'
|
|
|
|
)
|
|
|
|
+ ' '
|
|
|
|
+ (stats ? `(fps=${stats.fps} bitrate=${stats.bitrate}kbps speed=${stats.speed % 1 === 0 ? stats.speed : stats.speed.toFixed(3)}x)` : ''),
|
|
|
|
}),
|
|
|
|
m('.row', [
|
|
|
|
m('button.button', {
|
|
|
|
hidden: this.encoderStatus.running || this.encoderStatus.starting,
|
|
|
|
onclick: this.startClicked.bind(this),
|
|
|
|
}, 'Start'),
|
|
|
|
m('button.button', {
|
|
|
|
hidden: !this.encoderStatus.running && !this.encoderStatus.starting,
|
|
|
|
onclick: this.stopClicked.bind(this),
|
|
|
|
}, 'Stop'),
|
|
|
|
]),
|
|
|
|
// Decklink device section
|
|
|
|
m('h2', 'Settings'),
|
|
|
|
m('p', [
|
|
|
|
'Decklink device, example: ',
|
|
|
|
m('span.pre', '-i "DeckLink Mini Recorder"'),
|
|
|
|
]),
|
|
|
|
m('div.row', [
|
|
|
|
m('input', {
|
|
|
|
oncreate: (vnode) => {vnode.dom.setAttribute('spellcheck', 'false')},
|
|
|
|
type: 'text',
|
|
|
|
autocomplete: 'off',
|
|
|
|
value: this.settings.device,
|
|
|
|
oninput: this.updateSettings.bind(this, 'device'),
|
|
|
|
}),
|
|
|
|
m('button.button', {
|
|
|
|
onclick: this.listDecklinkDevices.bind(this),
|
|
|
|
}, 'List devices'),
|
|
|
|
]),
|
|
|
|
m('.row.meta', [
|
|
|
|
'Clicking List devices runs ',
|
|
|
|
m('.pre', `${this.list_devices.command} ${this.list_devices.arguments}`)
|
|
|
|
]),
|
|
|
|
// Decklink format section
|
|
|
|
m('p', [
|
|
|
|
'Input code, example: ',
|
|
|
|
m('span.pre', '-format_code Hi50'),
|
|
|
|
]),
|
|
|
|
m('div.row', [
|
|
|
|
m('input', {
|
|
|
|
oncreate: (vnode) => {vnode.dom.setAttribute('spellcheck', 'false')},
|
|
|
|
type: 'text',
|
|
|
|
autocomplete: 'off',
|
|
|
|
value: this.settings.format_code,
|
|
|
|
oninput: this.updateSettings.bind(this, 'format_code'),
|
|
|
|
}),
|
|
|
|
m('button.button', {
|
|
|
|
disabled: !Boolean(this.settings.device),
|
|
|
|
onclick: this.listDecklinkFormats.bind(this),
|
|
|
|
}, 'List format'),
|
|
|
|
]),
|
|
|
|
m('.row.meta', [
|
|
|
|
'Clicking List format runs ',
|
|
|
|
m('.pre', `${this.list_formats.command} ${this.list_formats.arguments}`)
|
|
|
|
]),
|
|
|
|
// Encoding options
|
|
|
|
m('p', 'Full encode command'),
|
|
|
|
m('textarea', {
|
|
|
|
oncreate: (vnode) => {vnode.dom.setAttribute('spellcheck', 'false')},
|
|
|
|
value: this.settings.command,
|
|
|
|
autocomplete: 'off',
|
|
|
|
oninput: this.updateSettings.bind(this, 'command'),
|
|
|
|
}),
|
|
|
|
m('.row.meta', [
|
|
|
|
'Any ',
|
|
|
|
m('.pre', 'ffmpeg.exe ... -f decklink ...'),
|
|
|
|
'will be replaced with ',
|
|
|
|
m('.pre', `ffmpeg.exe ... ${this.settings.format_code} -f decklink ${this.settings.device} ...`),
|
|
|
|
]),
|
|
|
|
// Controls
|
|
|
|
m('.row', [
|
|
|
|
m('button.button', {
|
|
|
|
hidden: !this.settingsChanged,
|
|
|
|
onclick: this.saveClicked.bind(this),
|
|
|
|
}, 'Save'),
|
|
|
|
]),
|
|
|
|
m('p', 'Log'),
|
|
|
|
m('pre', this.encoderStatus.log || '...'),
|
|
|
|
]),
|
|
|
|
]
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Encoder
|