add drawtext, filter param overrides, and refactor preview rendering
This commit is contained in:
parent
a7da696e51
commit
519ebf67cb
|
@ -2,6 +2,29 @@ import json
|
||||||
import re
|
import re
|
||||||
from subprocess import run
|
from subprocess import run
|
||||||
|
|
||||||
|
MAXES = ["INT_MAX", "FLT_MAX", "DBL_MAX", "I64_MAX", "UINT32_MAX"]
|
||||||
|
|
||||||
|
MINS = [
|
||||||
|
"INT_MIN",
|
||||||
|
"FLT_MIN",
|
||||||
|
"DBL_MIN",
|
||||||
|
"-DBL_MAX",
|
||||||
|
"I64_MIN",
|
||||||
|
"-FLT_MAX",
|
||||||
|
]
|
||||||
|
|
||||||
|
OPTION_OVERRIDES = {
|
||||||
|
"drawtext": {
|
||||||
|
"fontfile": [
|
||||||
|
{"value": "", "desc": ""},
|
||||||
|
{"value": "times.ttf", "desc": "Times"},
|
||||||
|
{"value": "arial.ttf", "desc": "Arial"},
|
||||||
|
{"value": "courier.ttf", "desc": "Courier"},
|
||||||
|
{"value": "comic.ttf", "desc": "Comic Sans"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_names():
|
def get_names():
|
||||||
filters = []
|
filters = []
|
||||||
|
@ -68,30 +91,17 @@ def get_params(f):
|
||||||
|
|
||||||
params.append(item)
|
params.append(item)
|
||||||
|
|
||||||
if item.get("max", 0) in ["INT_MAX", "FLT_MAX", "DBL_MAX", "I64_MAX"]:
|
if item.get("max", 0) in MAXES:
|
||||||
item["max"] = 2147483647
|
item["max"] = 2000
|
||||||
|
|
||||||
if item.get("min", 0) in [
|
if item.get("min", 0) in MINS:
|
||||||
"INT_MIN",
|
item["min"] = -2000
|
||||||
"FLT_MIN",
|
|
||||||
"DBL_MIN",
|
|
||||||
"-DBL_MAX",
|
|
||||||
"I64_MIN",
|
|
||||||
"-FLT_MAX",
|
|
||||||
]:
|
|
||||||
item["min"] = -2147483648
|
|
||||||
|
|
||||||
if item.get("default", 0) in ["INT_MAX", "FLT_MAX", "DBL_MAX", "I64_MAX"]:
|
if item.get("default", 0) in MAXES:
|
||||||
item["default"] = 2147483647
|
item["default"] = 2000
|
||||||
|
|
||||||
if item.get("default", 0) in [
|
if item.get("default", 0) in MINS:
|
||||||
"INT_MIN",
|
item["default"] = -2000
|
||||||
"FLT_MIN",
|
|
||||||
"DBL_MIN",
|
|
||||||
"-DBL_MAX",
|
|
||||||
"I64_MAX",
|
|
||||||
]:
|
|
||||||
item["default"] = -2147483648
|
|
||||||
|
|
||||||
if item["default"] == "nan":
|
if item["default"] == "nan":
|
||||||
item["default"] = None
|
item["default"] = None
|
||||||
|
@ -102,7 +112,7 @@ def get_params(f):
|
||||||
if item["default"]:
|
if item["default"]:
|
||||||
item["default"] = float(item["default"])
|
item["default"] = float(item["default"])
|
||||||
|
|
||||||
if item["type"] == "int":
|
if item["type"] in ["int", "int64", "int32"]:
|
||||||
try:
|
try:
|
||||||
item["min"] = int(item["min"])
|
item["min"] = int(item["min"])
|
||||||
item["max"] = int(item["max"])
|
item["max"] = int(item["max"])
|
||||||
|
@ -122,6 +132,13 @@ def get_params(f):
|
||||||
|
|
||||||
f["params"] = params
|
f["params"] = params
|
||||||
|
|
||||||
|
if f["name"] in OPTION_OVERRIDES:
|
||||||
|
for key, val in OPTION_OVERRIDES[f["name"]].items():
|
||||||
|
for p in f["params"]:
|
||||||
|
if p["name"] == key:
|
||||||
|
p["options"] = val
|
||||||
|
p["default"] = val[0]["value"]
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -37,15 +37,21 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (log.trim() != "") log += "\n\n";
|
if (log.trim() != "") log += "\n\n";
|
||||||
|
|
||||||
for (let vid of $inputs) {
|
for (let vid of $inputs) {
|
||||||
await ffmpeg.writeFile(vid.name, await fetchFile("/" + vid.name));
|
await ffmpeg.writeFile(vid.name, await fetchFile("/" + vid.name));
|
||||||
}
|
}
|
||||||
const command = "-hide_banner -loglevel error" + $previewCommand;
|
|
||||||
let clist = command
|
const fontNames = [...new Set([...$previewCommand.join(" ").matchAll(/\W([a-z]+\.ttf)/g)].map(f => f[1]))];
|
||||||
.replaceAll('"', "")
|
|
||||||
.replace("ffmpeg", "")
|
for (let f of fontNames) {
|
||||||
.split(" ")
|
await ffmpeg.writeFile(f, await fetchFile("/" + f));
|
||||||
.filter((i) => i.trim() != "");
|
}
|
||||||
|
|
||||||
|
let clist = [...$previewCommand];
|
||||||
|
clist.shift() // remove "ffmpeg" from start of command
|
||||||
|
clist.unshift("-hide_banner", "-loglevel", "error")
|
||||||
|
clist = clist.map(c => c.replaceAll('"', ""));
|
||||||
if (outname.endsWith("mp4")) {
|
if (outname.endsWith("mp4")) {
|
||||||
clist.splice(clist.length - 1, 0, "-pix_fmt");
|
clist.splice(clist.length - 1, 0, "-pix_fmt");
|
||||||
clist.splice(clist.length - 1, 0, "yuv420p");
|
clist.splice(clist.length - 1, 0, "yuv420p");
|
||||||
|
@ -135,7 +141,7 @@
|
||||||
readonly
|
readonly
|
||||||
class="actual-command"
|
class="actual-command"
|
||||||
bind:this={commandRef}
|
bind:this={commandRef}
|
||||||
on:click={() => commandRef.select()}>{$previewCommand}</textarea
|
on:click={() => commandRef.select()}>{$previewCommand.join(" ")}</textarea
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
896
src/filters.json
896
src/filters.json
File diff suppressed because it is too large
Load Diff
|
@ -169,7 +169,7 @@ export const previewCommand = derived([edges, nodes], ([$edges, $nodes]) => {
|
||||||
finalCommand.push(out.data.name);
|
finalCommand.push(out.data.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalCommand.join(" ");
|
return finalCommand;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const inputs = derived(nodes, ($nodes) => {
|
export const inputs = derived(nodes, ($nodes) => {
|
||||||
|
|
|
@ -51,13 +51,13 @@ describe("Filter param builder", () => {
|
||||||
|
|
||||||
describe("Command builder", () => {
|
describe("Command builder", () => {
|
||||||
test("Defaults", () => {
|
test("Defaults", () => {
|
||||||
expect(get(previewCommand)).toBe("ffmpeg -i punch.mp4 out.mp4");
|
expect(get(previewCommand).join(" ")).toBe("ffmpeg -i punch.mp4 out.mp4");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Simple video filter", () => {
|
test("Simple video filter", () => {
|
||||||
resetNodes();
|
resetNodes();
|
||||||
addNode({ name: "filter", type: "V->V" }, "filter");
|
addNode({ name: "filter", type: "V->V" }, "filter");
|
||||||
expect(get(previewCommand)).toBe(
|
expect(get(previewCommand).join(" ")).toBe(
|
||||||
`ffmpeg -i punch.mp4 -filter_complex "[0:v]filter[out_v]" -map "[out_v]" -map 0:a out.mp4`
|
`ffmpeg -i punch.mp4 -filter_complex "[0:v]filter[out_v]" -map "[out_v]" -map 0:a out.mp4`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -65,7 +65,7 @@ describe("Command builder", () => {
|
||||||
test("Simple audio filter", () => {
|
test("Simple audio filter", () => {
|
||||||
resetNodes();
|
resetNodes();
|
||||||
addNode({ name: "filter", type: "A->A" }, "filter");
|
addNode({ name: "filter", type: "A->A" }, "filter");
|
||||||
expect(get(previewCommand)).toBe(
|
expect(get(previewCommand).join(" ")).toBe(
|
||||||
`ffmpeg -i punch.mp4 -filter_complex "[0:a]filter[out_a]" -map "[out_a]" -map 0:v out.mp4`
|
`ffmpeg -i punch.mp4 -filter_complex "[0:a]filter[out_a]" -map "[out_a]" -map 0:v out.mp4`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -74,7 +74,7 @@ describe("Command builder", () => {
|
||||||
resetNodes();
|
resetNodes();
|
||||||
addNode({ name: "afilter", type: "A->A" }, "filter");
|
addNode({ name: "afilter", type: "A->A" }, "filter");
|
||||||
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
||||||
expect(get(previewCommand)).toBe(
|
expect(get(previewCommand).join(" ")).toBe(
|
||||||
`ffmpeg -i punch.mp4 -filter_complex "[0:a]afilter[out_a];[0:v]vfilter[out_v]" -map "[out_a]" -map "[out_v]" out.mp4`
|
`ffmpeg -i punch.mp4 -filter_complex "[0:a]afilter[out_a];[0:v]vfilter[out_v]" -map "[out_a]" -map "[out_v]" out.mp4`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,7 @@ describe("Command builder", () => {
|
||||||
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
||||||
addNode({ name: "vfilter2", type: "V->V" }, "filter");
|
addNode({ name: "vfilter2", type: "V->V" }, "filter");
|
||||||
addNode({ name: "vfilter3", type: "V->V" }, "filter");
|
addNode({ name: "vfilter3", type: "V->V" }, "filter");
|
||||||
expect(get(previewCommand)).toBe(
|
expect(get(previewCommand).join(" ")).toBe(
|
||||||
`ffmpeg -i punch.mp4 -filter_complex "[0:v]vfilter,vfilter2,vfilter3[out_v]" -map "[out_v]" -map 0:a out.mp4`
|
`ffmpeg -i punch.mp4 -filter_complex "[0:v]vfilter,vfilter2,vfilter3[out_v]" -map "[out_v]" -map 0:a out.mp4`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -94,7 +94,7 @@ describe("Command builder", () => {
|
||||||
addNode({ name: "afilter", type: "A->A" }, "filter");
|
addNode({ name: "afilter", type: "A->A" }, "filter");
|
||||||
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
addNode({ name: "vfilter", type: "V->V" }, "filter");
|
||||||
addNode({ name: "vfilter2", type: "V->V" }, "filter");
|
addNode({ name: "vfilter2", type: "V->V" }, "filter");
|
||||||
expect(get(previewCommand)).toBe(
|
expect(get(previewCommand).join(" ")).toBe(
|
||||||
`ffmpeg -i punch.mp4 -filter_complex "[0:v]vfilter[1];[0:a]afilter[out_a];[1]vfilter2[out_v]" -map "[out_a]" -map "[out_v]" out.mp4`
|
`ffmpeg -i punch.mp4 -filter_complex "[0:v]vfilter[1];[0:a]afilter[out_a];[1]vfilter2[out_v]" -map "[out_a]" -map "[out_v]" out.mp4`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue