DNxHD support, Better screen reader support
Build / build (push) Successful in 1m12s

This commit is contained in:
2025-08-19 13:02:39 +07:00
parent 3921c003bb
commit 4cad43abe1
6 changed files with 102 additions and 11 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ encoders supported by your FFmpeg install will show up.
- [ ] av1_nvenc - [ ] av1_nvenc
- [ ] av1_qsv - [ ] av1_qsv
- [ ] av1_vaapi - [ ] av1_vaapi
- [ ] DNxHD - [x] DNxHD (Does not provide options to deal with its pickiness yet)
- [ ] H.264 - [ ] H.264
- [x] libx264 - [x] libx264
- [x] libx264rgb (Untested, but _should_ work) - [x] libx264rgb (Untested, but _should_ work)
+27 -5
View File
@@ -27,6 +27,7 @@ import { generateRandomString } from "./util/string";
import "./css/icons.css"; import "./css/icons.css";
import BreezeIcon from "./components/BreezeIcon"; import BreezeIcon from "./components/BreezeIcon";
import AV1Options from "./components/AV1Options"; import AV1Options from "./components/AV1Options";
import DNxHDOptions from "./components/DNxHDOptions";
const commonCodecs = new Set(["h264", "hevc", "vp8", "vp9", "av1", "dnxhd"]); const commonCodecs = new Set(["h264", "hevc", "vp8", "vp9", "av1", "dnxhd"]);
@@ -540,7 +541,9 @@ function App() {
0 0
} }
> >
<label>Encoder</label> <label for="videoEncoder">
Encoder
</label>
<select <select
name="videoEncoder" name="videoEncoder"
id="videoEncoder" id="videoEncoder"
@@ -589,14 +592,31 @@ function App() {
onParamChanged={onParametersChanged} onParamChanged={onParametersChanged}
/> />
</Match> </Match>
<Match
when={
selectedCodec()?.shortName ===
"dnxhd"
}
>
<DNxHDOptions
codec={selectedCodec()}
params={ffmpegParams}
onParamChanged={onParametersChanged}
/>
</Match>
</Switch> </Switch>
<div class="row flex-col align-items-center"> <div class="row flex-col align-items-center">
<h3 class="k-form-section-title"> <h3 class="k-form-section-title">
Extra Arguments Extra Arguments
</h3> </h3>
</div> </div>
<form class="k-form"> <form
<label>Global Options</label> class="k-form"
onsubmit={(e) => e.preventDefault()}
>
<label for="globalopts">
Global Options
</label>
<input <input
type="text" type="text"
name="globalopts" name="globalopts"
@@ -608,7 +628,7 @@ function App() {
setGlobalopts(e.target.value); setGlobalopts(e.target.value);
}} }}
/> />
<label>Input Options</label> <label for="inputopts">Input Options</label>
<input <input
type="text" type="text"
name="inputopts" name="inputopts"
@@ -620,7 +640,9 @@ function App() {
setInputopts(e.target.value); setInputopts(e.target.value);
}} }}
/> />
<label>Output Options</label> <label for="outputopts">
Output Options
</label>
<input <input
type="text" type="text"
name="outputopts" name="outputopts"
+55
View File
@@ -0,0 +1,55 @@
import { os } from "@neutralinojs/lib";
import { type CodecInfo, type FFmpegParams } from "../util/ffmpeg";
import BreezeIcon from "./BreezeIcon";
/**
* Options for H.264/H.265 codecs
*/
function DNxHDOptions(props: {
codec: CodecInfo | undefined;
params: FFmpegParams;
onParamChanged: (key: string, value: any) => void;
}) {
return (
<section id="commonLossyOptions">
<div class="row flex-col align-items-center">
<h3 class="k-form-section-title">Encoder Options</h3>
</div>
<div class="k-form">
<label>Help</label>
<div>
<button
class="icon-button"
onclick={() =>
os.open("https://askubuntu.com/a/907515")
}
title="DNxHD is a picky encoder."
>
<BreezeIcon icon="help-about" alt="Help" />
</button>
</div>
<label for="profile">Profile</label>
<select
class="k-dropdown"
name="profile"
id="profile"
value={props.params.outputopts?.profile ?? "dnxhd"}
oninput={(e) => {
props.onParamChanged("outputopts", {
profile: e.target.value,
});
}}
>
<option value="dnxhd">DNxHD</option>
<option value="dnxhr_444">DNxHR 444</option>
<option value="dnxhr_hqx">DNxHR HQX</option>
<option value="dnxhr_hq">DNxHR HQ</option>
<option value="dnxhr_sq">DNxHR SQ</option>
<option value="dnxhr_lb">DNxHR LB</option>
</select>
</div>
</section>
);
}
export default DNxHDOptions;
+1 -1
View File
@@ -63,7 +63,7 @@ function H264Options(props: {
<BreezeIcon icon="help-about" alt="Help" /> <BreezeIcon icon="help-about" alt="Help" />
</button> </button>
</div> </div>
<label>Preset</label> <label for="encodingPreset">Preset</label>
<select <select
class="k-dropdown" class="k-dropdown"
name="encodingPreset" name="encodingPreset"
+7 -4
View File
@@ -64,10 +64,12 @@ function LibaomOptions(props: {
<BreezeIcon icon="help-about" alt="Help" /> <BreezeIcon icon="help-about" alt="Help" />
</button> </button>
</div> </div>
<label>Rate-control modes</label> <label for="rateControlMode">Rate-control modes</label>
<select <select
class="k-dropdown" class="k-dropdown"
onchange={(e) => setRateControlMode(e.target.value)} onchange={(e) => setRateControlMode(e.target.value)}
name="rateControlMode"
id="rateControlMode"
> >
<option value="Constant">Constant Quality</option> <option value="Constant">Constant Quality</option>
<option value="Constrained">Constrained Quality</option> <option value="Constrained">Constrained Quality</option>
@@ -80,7 +82,7 @@ function LibaomOptions(props: {
rateControlMode() === "Constrained" rateControlMode() === "Constrained"
} }
> >
<label>CRF</label> <label for="crf">CRF</label>
<input <input
type="number" type="number"
name="crf" name="crf"
@@ -97,12 +99,13 @@ function LibaomOptions(props: {
/> />
</Show> </Show>
<Show when={rateControlMode() !== "Constant"}> <Show when={rateControlMode() !== "Constant"}>
<label>Bitrate</label> <label for="bitrate">Bitrate</label>
<div class="row gap2"> <div class="row gap2 align-items-center">
<input <input
type="number" type="number"
name="bitrate" name="bitrate"
id="bitrate" id="bitrate"
aria-label="Kbps"
value={props.params.vbitrate ?? DEFAULT_BITRATE} value={props.params.vbitrate ?? DEFAULT_BITRATE}
oninput={(e) => { oninput={(e) => {
props.onParamChanged( props.onParamChanged(
+11
View File
@@ -103,6 +103,10 @@ export interface FFmpegParams {
* Extra parameters defined by users * Extra parameters defined by users
*/ */
useropts: ExtraFFmpegArguments; useropts: ExtraFFmpegArguments;
/**
* Extra output parameters defined by Vencoder
*/
outputopts?: { [key: string]: string };
} }
const NULL_LOCATION = window.NL_OS === "Windows" ? "NUL" : "/dev/null"; const NULL_LOCATION = window.NL_OS === "Windows" ? "NUL" : "/dev/null";
@@ -129,6 +133,13 @@ export function generateOutputCommand(params: FFmpegParams) {
globalopts += " " + params.useropts.global; globalopts += " " + params.useropts.global;
} }
if (params.outputopts !== undefined) {
console.log(params.outputopts);
for (const key of Object.keys(params.outputopts)) {
outputopts += ` -${key} ${params.outputopts[key]}`.trimEnd();
}
}
if (params.twopass) { if (params.twopass) {
const commonOpts = `${globalopts}${inputopts} -i "${params.inputFile ?? "{fileName}"}" -c:v ${params.encoder ?? params.vcodec} -b:v ${ const commonOpts = `${globalopts}${inputopts} -i "${params.inputFile ?? "{fileName}"}" -c:v ${params.encoder ?? params.vcodec} -b:v ${
params.vbitrate ?? DEFAULT_BITRATE params.vbitrate ?? DEFAULT_BITRATE