Changes to encoding, UI fixes
This commit is contained in:
parent
de08788b4f
commit
f9bf73f6d7
5 changed files with 80 additions and 155 deletions
|
@ -28,3 +28,6 @@ How to install(Windows, Linux, MacOS):
|
||||||
>2. Add ffmpeg to PATH: `[Win BTN] + R`, type `SystemPropertiesAdvanced`, click `Environment Variables`, under "User variables for (user)" find variable Path, click on it and edit, in the now open window click `new`, and paste `C:\Program Files\DMC\`.
|
>2. Add ffmpeg to PATH: `[Win BTN] + R`, type `SystemPropertiesAdvanced`, click `Environment Variables`, under "User variables for (user)" find variable Path, click on it and edit, in the now open window click `new`, and paste `C:\Program Files\DMC\`.
|
||||||
>3. If the command `ffmpeg` in cmd works, you can now drag and drop files onto the binary and have it work!
|
>3. If the command `ffmpeg` in cmd works, you can now drag and drop files onto the binary and have it work!
|
||||||
>4. to set performance preset, doubleclick the binary
|
>4. to set performance preset, doubleclick the binary
|
||||||
|
|
||||||
|
|
||||||
|
For an amazing read on how to optimize vp9 for file sizes I reccomend this read: https://codeberg.org/deterenkelt/Nadeshiko/wiki/Researches%E2%80%89%E2%80%93%E2%80%89VP9-and-overshooting
|
|
@ -67,10 +67,11 @@ async function main(menu = false) {
|
||||||
await checkFF()
|
await checkFF()
|
||||||
const ui = new UI(settings.settings, settings.currentSetting, settings.settingsFile, filePaths?.length)
|
const ui = new UI(settings.settings, settings.currentSetting, settings.settingsFile, filePaths?.length)
|
||||||
|
|
||||||
if (menu) savesettings = await ui.startMenu()
|
|
||||||
|
|
||||||
//file checks
|
//file checks
|
||||||
let isListEncodable = true
|
let isListEncodable = true
|
||||||
|
|
||||||
|
if (menu) { savesettings = await ui.startMenu(); isListEncodable = false }
|
||||||
|
|
||||||
//check if all files exist
|
//check if all files exist
|
||||||
for (let i = 0; i < filePaths.length; i++) {
|
for (let i = 0; i < filePaths.length; i++) {
|
||||||
if (!fs.existsSync(filePaths[i])) {
|
if (!fs.existsSync(filePaths[i])) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const { exec } = require('child_process')
|
const { exec } = require('child_process')
|
||||||
|
const termkit = require('terminal-kit')
|
||||||
|
|
||||||
class Encoder {
|
class Encoder {
|
||||||
currentSetting
|
currentSetting
|
||||||
|
@ -50,9 +51,9 @@ class Encoder {
|
||||||
async #constructVideoCommand(path, out) {
|
async #constructVideoCommand(path, out) {
|
||||||
let [duration, resolutionHeight] = await this.#getDurationAndResolution(path)
|
let [duration, resolutionHeight] = await this.#getDurationAndResolution(path)
|
||||||
|
|
||||||
//Calculates video bitrate to fit right under 8mb 2:6 audio:video
|
//Calculates video bitrate to fit right under 8mb 2:6 audio:video. 8Mb * 8 = 64000 - 1000 for overhead, *0.97 to leave space for container.
|
||||||
const audioBitRate = Math.round(62000 / 8 * 2 / duration)
|
const audioBitRate = Math.round((63000 / 8 * 2 / duration) * 0.97)
|
||||||
const videoBitRate = Math.round(62000 / 8 * 6 / duration)
|
const videoBitRate = Math.round((63000 / 8 * 6 / duration) * 0.97)
|
||||||
|
|
||||||
//if command had argument of anotehr quality setting change to use that setting
|
//if command had argument of anotehr quality setting change to use that setting
|
||||||
if (this.encodePresetIndexArg) {
|
if (this.encodePresetIndexArg) {
|
||||||
|
@ -60,8 +61,9 @@ class Encoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let command = ""
|
let command = ""
|
||||||
let crfIndex = 0
|
|
||||||
let isTwoPass = true
|
let isTwoPass = true
|
||||||
|
/* REMOVING CRF AS ITS NO LONGER USED -- REPLACE WITH -qmin equivalent
|
||||||
|
|
||||||
//Compares current video height to CRFMAP to determine optimal CRF
|
//Compares current video height to CRFMAP to determine optimal CRF
|
||||||
while (resolutionHeight > this.currentSetting.crfMap[crfIndex].resolution) {
|
while (resolutionHeight > this.currentSetting.crfMap[crfIndex].resolution) {
|
||||||
crfIndex++
|
crfIndex++
|
||||||
|
@ -71,29 +73,58 @@ class Encoder {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
for (let pass = 1; pass <= 2; pass++) {
|
//realtime doesnt support two pass, so just use real time settings
|
||||||
command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libvorbis `
|
|
||||||
command += `-deadline ${this.currentSetting.deadline} `
|
|
||||||
command += `-cpu-used ${this.currentSetting.cpuUsed} `
|
|
||||||
if (this.currentSetting?.bitrateError) {
|
|
||||||
command += `-b:v ${Math.round(videoBitRate / 100 * this.currentSetting.bitrateError)}k `
|
|
||||||
command += `-minrate ${Math.round(videoBitRate)}k `
|
|
||||||
command += `-maxrate ${videoBitRate}k `
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
command += `-b:v ${videoBitRate}k `
|
|
||||||
command += `-b:a ${audioBitRate}k `
|
|
||||||
command += `-crf ${this.currentSetting.crfMap[crfIndex].crf} `
|
|
||||||
}
|
|
||||||
//realtime doesnt support two pass
|
|
||||||
if (this.currentSetting.deadline == "realtime") {
|
if (this.currentSetting.deadline == "realtime") {
|
||||||
command += `-row-mt 1 "${out}.webm"`
|
command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libopus `
|
||||||
isTwoPass = false
|
command += `-deadline ${this.currentSetting.deadline} `
|
||||||
break
|
command += `-quality ${this.currentSetting.deadline} `
|
||||||
}
|
command += `-cpu-used ${this.currentSetting.cpuUsed} `
|
||||||
pass == 1 ? command += `-pass 1 -row-mt 1 -f webm NUL && ` : command += `-pass 2 -row-mt 1 "${out}.webm" `
|
command += `-undershoot-pct 0 -overshoot-pct 0 `
|
||||||
|
command += `-b:v ${Math.round(videoBitRate / 100 * this.currentSetting.bitrateError)}k `
|
||||||
|
command += `-minrate ${Math.round(videoBitRate * 0.5)}k `
|
||||||
|
command += `-maxrate ${Math.floor(videoBitRate * 1.4)}k `
|
||||||
|
command += `-b:a ${audioBitRate}k `
|
||||||
|
command += `-tile-columns 2 -threads 6 `
|
||||||
|
command += `-qmax 60`
|
||||||
|
command += `-g 240 `
|
||||||
|
command += `-row-mt 1 "${out}.webm" `
|
||||||
|
return [command, duration, false]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Pass 1 force to have good deadline and cpu-used 1
|
||||||
|
command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libopus `
|
||||||
|
command += `-deadline good `
|
||||||
|
command += `-quality good `
|
||||||
|
command += `-cpu-used 1 `
|
||||||
|
command += `-undershoot-pct 0 -overshoot-pct 0 `
|
||||||
|
command += `-b:v ${Math.round(videoBitRate / 100 * this.currentSetting.bitrateError)}k `
|
||||||
|
command += `-minrate ${Math.round(videoBitRate * 0.5)}k `
|
||||||
|
command += `-maxrate ${Math.floor(videoBitRate * 1.2)}k `
|
||||||
|
command += `-b:a ${audioBitRate}k `
|
||||||
|
command += `-auto-alt-ref 6 `
|
||||||
|
command += `-qmax 60`
|
||||||
|
command += `-g 240 `
|
||||||
|
|
||||||
|
command += `-row-mt 1 -pass 1 -f webm NUL && `
|
||||||
|
|
||||||
|
//Pass 2 take in settings
|
||||||
|
command += `ffmpeg -y -i "${path}" -vcodec libvpx-vp9 -acodec libopus `
|
||||||
|
command += `-deadline ${this.currentSetting.deadline} `
|
||||||
|
command += `-quality ${this.currentSetting.deadline} `
|
||||||
|
command += `-cpu-used ${this.currentSetting.cpuUsed} `
|
||||||
|
command += `-undershoot-pct 0 -overshoot-pct 0 `
|
||||||
|
command += `-b:v ${Math.round(videoBitRate / 100 * this.currentSetting.bitrateError)}k `
|
||||||
|
command += `-minrate ${Math.round(videoBitRate * 0.5)}k `
|
||||||
|
command += `-maxrate ${Math.floor(videoBitRate * 1.4)}k `
|
||||||
|
command += `-b:a ${audioBitRate}k `
|
||||||
|
command += `-tile-columns 2 -threads 6 `
|
||||||
|
command += `-auto-alt-ref 6 `
|
||||||
|
command += `-qmax 60`
|
||||||
|
command += `-g 240 `
|
||||||
|
|
||||||
|
command += `-row-mt 1 -pass 2 "${out}.webm" `
|
||||||
|
|
||||||
return [command, duration, isTwoPass]
|
return [command, duration, isTwoPass]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,143 +34,33 @@ class SettingsManager {
|
||||||
}
|
}
|
||||||
async #makeNewSettingsFile() {
|
async #makeNewSettingsFile() {
|
||||||
const settings = `
|
const settings = `
|
||||||
{
|
{
|
||||||
"currentSetting": 3,
|
"currentSetting": 2,
|
||||||
"presets": [{
|
"presets": [{
|
||||||
"name": "Most efficient 8 megabytes of your life",
|
"name": "Most efficient 8 megabytes of your life",
|
||||||
"cpuUsed": 0,
|
"cpuUsed": 0,
|
||||||
"deadline": "best",
|
"deadline": "good",
|
||||||
"bitrateError": 90,
|
"bitrateError": 95
|
||||||
"crfMap": [{
|
|
||||||
"resolution": 240,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 360,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 480,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 720,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 1080,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 1440,
|
|
||||||
"crf": 1
|
|
||||||
}, {
|
|
||||||
"resolution": 2160,
|
|
||||||
"crf": 1
|
|
||||||
}]
|
|
||||||
}, {
|
}, {
|
||||||
"name": "I have some time to kill",
|
"name": "I have some time to kill",
|
||||||
"cpuUsed": 1,
|
"cpuUsed": 1,
|
||||||
"deadline": "good",
|
"deadline": "good",
|
||||||
"bitrateError": 90,
|
"bitrateError": 95
|
||||||
"crfMap": [{
|
|
||||||
"resolution": 240,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 360,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 480,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 720,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 1080,
|
|
||||||
"crf": 17
|
|
||||||
}, {
|
|
||||||
"resolution": 1440,
|
|
||||||
"crf": 15
|
|
||||||
}, {
|
|
||||||
"resolution": 2160,
|
|
||||||
"crf": 10
|
|
||||||
}]
|
|
||||||
}, {
|
}, {
|
||||||
"name": "Mid",
|
"name": "Mid",
|
||||||
"cpuUsed": 3,
|
"cpuUsed": 3,
|
||||||
"deadline": "good",
|
"deadline": "realtime",
|
||||||
"bitrateError": 80,
|
"bitrateError": 90
|
||||||
"crfMap": [{
|
|
||||||
"resolution": 240,
|
|
||||||
"crf": 30
|
|
||||||
}, {
|
|
||||||
"resolution": 360,
|
|
||||||
"crf": 30
|
|
||||||
}, {
|
|
||||||
"resolution": 480,
|
|
||||||
"crf": 30
|
|
||||||
}, {
|
|
||||||
"resolution": 720,
|
|
||||||
"crf": 25
|
|
||||||
}, {
|
|
||||||
"resolution": 1080,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 1440,
|
|
||||||
"crf": 15
|
|
||||||
}, {
|
|
||||||
"resolution": 2160,
|
|
||||||
"crf": 10
|
|
||||||
}]
|
|
||||||
}, {
|
}, {
|
||||||
"name": "I don't like waiting",
|
"name": "I don't like waiting",
|
||||||
"cpuUsed": 4,
|
"cpuUsed": 5,
|
||||||
"deadline": 100,
|
"deadline": "realtime",
|
||||||
"bitrateError": 70,
|
"bitrateError": 80
|
||||||
"crfMap": [{
|
|
||||||
"resolution": 240,
|
|
||||||
"crf": 45
|
|
||||||
}, {
|
|
||||||
"resolution": 360,
|
|
||||||
"crf": 42
|
|
||||||
}, {
|
|
||||||
"resolution": 480,
|
|
||||||
"crf": 40
|
|
||||||
}, {
|
|
||||||
"resolution": 720,
|
|
||||||
"crf": 35
|
|
||||||
}, {
|
|
||||||
"resolution": 1080,
|
|
||||||
"crf": 30
|
|
||||||
}, {
|
|
||||||
"resolution": 1440,
|
|
||||||
"crf": 25
|
|
||||||
}, {
|
|
||||||
"resolution": 2160,
|
|
||||||
"crf": 20
|
|
||||||
}]
|
|
||||||
}, {
|
}, {
|
||||||
"name": "I want it, NOW!",
|
"name": "I want it, NOW!",
|
||||||
"cpuUsed": 3,
|
"cpuUsed": 6,
|
||||||
"deadline": "realtime",
|
"deadline": "realtime",
|
||||||
"bitrateError": 50,
|
"bitrateError": 70
|
||||||
"crfMap": [{
|
|
||||||
"resolution": 240,
|
|
||||||
"crf": 40
|
|
||||||
}, {
|
|
||||||
"resolution": 360,
|
|
||||||
"crf": 35
|
|
||||||
}, {
|
|
||||||
"resolution": 480,
|
|
||||||
"crf": 30
|
|
||||||
}, {
|
|
||||||
"resolution": 720,
|
|
||||||
"crf": 25
|
|
||||||
}, {
|
|
||||||
"resolution": 1080,
|
|
||||||
"crf": 20
|
|
||||||
}, {
|
|
||||||
"resolution": 1440,
|
|
||||||
"crf": 15
|
|
||||||
}, {
|
|
||||||
"resolution": 2160,
|
|
||||||
"crf": 10
|
|
||||||
}]
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
14
lib/ui.js
14
lib/ui.js
|
@ -13,7 +13,7 @@ class UI {
|
||||||
this.term = termkit.terminal
|
this.term = termkit.terminal
|
||||||
|
|
||||||
this.multibar = new cliProgress.MultiBar({
|
this.multibar = new cliProgress.MultiBar({
|
||||||
format: '[{bar}] {percentage}% | output: "{filename}" | ETA: {eta_formatted}s | {duration_formatted} | {value}s/{total}s ',
|
format: '[{bar}] {percentage}% | output: "{filename}" | ETA: {eta_formatted} | Elapsed: {duration_formatted} | {value}s/{total}s ',
|
||||||
align: "left",
|
align: "left",
|
||||||
hideCursor: true,
|
hideCursor: true,
|
||||||
autopadding: true,
|
autopadding: true,
|
||||||
|
@ -100,17 +100,17 @@ class UI {
|
||||||
async startMenu() {
|
async startMenu() {
|
||||||
await this.#menu()
|
await this.#menu()
|
||||||
}
|
}
|
||||||
async #menu(settingsFile) {
|
async #menu() {
|
||||||
let menu = []
|
let menu = []
|
||||||
for (let i = 0; i < this.settings.presets.length; i++) {
|
for (let i = 0; i < this.settings.presets.length; i++) {
|
||||||
menu.push(`${i}. ${this.settings.presets[i].name}`)
|
menu.push(`${i}. ${this.settings.presets[i].name}`)
|
||||||
}
|
}
|
||||||
this.term("How to convert: 8mb [optional: -preset {Index}] [filename.extension(s)]\n")
|
this.term.grey("How to convert: 8mb [optional: -preset {Index}] [filename.extension(s)]\n")
|
||||||
this.term("examples: \n")
|
this.term.grey("examples: \n")
|
||||||
this.term.italic(" 8mb -preset 0 file.mp3 file4.mov img.jpg\n")
|
this.term.italic.grey(" 8mb -preset 0 file.mp3 file4.mov img.jpg\n")
|
||||||
this.term.italic(" 8mb.exe file34.wav file2.mp3\n\n")
|
this.term.italic.grey(" 8mb file34.wav file2.mp3\n\n")
|
||||||
this.term.yellow("Hello! This menu is for selecting performance/speed preset.\n")
|
this.term.yellow("Hello! This menu is for selecting performance/speed preset.\n")
|
||||||
this.term.yellow("Currently using ").bgMagenta(`"${this.settings.presets[this.settings.currentSetting].name}"`).yellow(" preset")
|
this.term.yellow("Currently using ").bgMagenta(`"${this.settings.presets[this.settings.currentSetting].name}"`).yellow(" preset\n")
|
||||||
this.term.singleColumnMenu(menu, (error, response) => {
|
this.term.singleColumnMenu(menu, (error, response) => {
|
||||||
this.settings.currentSetting = response.selectedIndex
|
this.settings.currentSetting = response.selectedIndex
|
||||||
this.term.green("\n Using").green.bold(` ${this.settings.presets[this.settings.currentSetting].name} `).green("setting\n")
|
this.term.green("\n Using").green.bold(` ${this.settings.presets[this.settings.currentSetting].name} `).green("setting\n")
|
||||||
|
|
Loading…
Reference in a new issue