add drawtext, filter param overrides, and refactor preview rendering

This commit is contained in:
Sam Lavigne 2023-08-29 16:45:17 -04:00
parent a7da696e51
commit 519ebf67cb
9 changed files with 518 additions and 473 deletions

View File

@ -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

BIN
public/arial.ttf Normal file

Binary file not shown.

BIN
public/comic.ttf Normal file

Binary file not shown.

BIN
public/courier.ttf Normal file

Binary file not shown.

BIN
public/times.ttf Normal file

Binary file not shown.

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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) => {

View File

@ -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`
); );
}); });