|
| 1 | +import { run } from "../run.js"; |
| 2 | +import { outputName } from "../utils.js"; |
| 3 | + |
| 4 | +export function register(program) { |
| 5 | + program |
| 6 | + .command("oscilloscope") |
| 7 | + .description("Add oscilloscope overlay to video (audio visualization on video)") |
| 8 | + .argument("<input>", "Input video file with audio") |
| 9 | + .option("--size <n>", "Oscilloscope size (0.0-1.0)", "0.5") |
| 10 | + .option("--pos <position>", "Position: top-left, top-right, bottom-left, bottom-right, center", "bottom-right") |
| 11 | + .option("-o, --output <path>", "Output file path") |
| 12 | + .option("--dry-run", "Print the FFmpeg command without running it") |
| 13 | + .option("-y", "Overwrite output without asking") |
| 14 | + .action((input, opts) => { |
| 15 | + const posMap = { |
| 16 | + "top-left": "x=0:y=0", |
| 17 | + "top-right": "x=1:y=0", |
| 18 | + "bottom-left": "x=0:y=1", |
| 19 | + "bottom-right": "x=1:y=1", |
| 20 | + "center": "x=0.5:y=0.5", |
| 21 | + }; |
| 22 | + |
| 23 | + const pos = posMap[opts.pos]; |
| 24 | + if (!pos) { |
| 25 | + console.error(`Error: --pos must be one of: ${Object.keys(posMap).join(", ")}`); |
| 26 | + process.exit(1); |
| 27 | + } |
| 28 | + |
| 29 | + const filter = `avectorscope=s=320x320:zoom=1.5:draw=line,format=yuva420p[osc];[0:v][osc]overlay=W*0.7:H*0.7`; |
| 30 | + const out = opts.output || outputName(input, "oscilloscope"); |
| 31 | + const args = ["-i", input, "-filter_complex", filter, "-c:a", "copy"]; |
| 32 | + |
| 33 | + if (opts.y) args.push("-y"); |
| 34 | + args.push(out); |
| 35 | + run(args, { dryRun: opts.dryRun }); |
| 36 | + }); |
| 37 | +} |
0 commit comments