From dfb23823443fc9065b984f3a9ba4f2a9fbdc8219 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sat, 18 Sep 2021 14:17:40 +0200 Subject: [PATCH] Add newer, faster version --- README.md | 2 +- dziurkacz-fast.mjs | 116 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100755 dziurkacz-fast.mjs diff --git a/README.md b/README.md index ff3fdc8..9a60119 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ ffmpeg -i video.mp4 -vn -acodec copy audio.aac 3. Wyeksportuj wszystkie labelki do pliku tekstowego (export -> labels) -4. Uruchom `zx --quiet dziurkacz.mjs /ścieżka/do/pliku/video.mp4 /ścieżka/do/pliku/z/wyeskportowanymi/labelkami.txt` +4. Uruchom `zx --quiet dziurkacz-fast.mjs /ścieżka/do/pliku/video.mp4 /ścieżka/do/pliku/z/wyeskportowanymi/labelkami.txt` Plik wynikowy znajdziesz w /tmp/dziurkacz/working.mp4 diff --git a/dziurkacz-fast.mjs b/dziurkacz-fast.mjs new file mode 100755 index 0000000..0a77da7 --- /dev/null +++ b/dziurkacz-fast.mjs @@ -0,0 +1,116 @@ +#!/usr/bin/zx + +const { extname } = require("path"); + +const args = process.argv.slice(-2); + +const video = args[0]; +const labels = args[1]; +const ext = extname(video); + +const FREQ = 48000; +const FRAMERATE = parseFloat( + (await $`mediainfo --Output="Video;%FrameRate%" ${video}`).stdout +); + +const labels_contents = (await $`awk '{print $3, $4, $5}' < ${labels}`).stdout; + +const cuts = labels_contents + .split(os.EOL) + .slice(0, -1) + .map((e) => + e + .split(" ") + .slice(1) + .map((x) => parseFloat(x)) + ) + .map(([samples, start]) => ({ + duration: samples / FREQ, + start, + end: start + samples / FREQ, + })); + +console.log(cuts); + +let all_frames = []; + +const frame_count = parseInt( + (await $`mediainfo --Output="Video;%FrameCount%" ${video}`).stdout +); + +for (let i = 0; i < frame_count; i++) { + all_frames.push(i); +} + +console.log(all_frames); + +for (let cut of cuts) { + all_frames = [ + ...all_frames.slice(0, Math.round(cut.start * FRAMERATE)), + ...all_frames.slice(Math.round(cut.end * FRAMERATE)), + ]; +} + +console.log(all_frames); + +const pieces = []; + +let current_piece = { start: all_frames[0] }; + +let predicted_frame_number = 0; + +// skipping the first one, as we're doing lookback +for (let i = 1; i < all_frames.length; i++) { + if (all_frames[i] != all_frames[i - 1] + 1) { + current_piece.end = all_frames[i - 1]; + pieces.push(current_piece); + current_piece = { start: all_frames[i] }; + } +} + +current_piece.end = all_frames[all_frames.length - 1]; + +pieces.push(current_piece); + +// discarding this as using a filter requires reencoding the entire video: +const filter = pieces + .map( + ({ start, end }) => + `between(t,${(start / FRAMERATE).toFixed(5)},${(end / FRAMERATE).toFixed( + 5 + )})` + ) + .join("+"); + +await $`ffmpeg -i ${video} \ + -vf ${`select='${filter}',setpts=N/FRAME_RATE/TB`} \ + -af ${`aselect='${filter}',asetpts=N/SR/TB`} \ + ${video + ".cut.mp4"}`; + +// let ffmpeg_args = []; +// const parts = []; +// for (let i in pieces) { +// const piece = pieces[i]; +// const output_filename = video + "-" + i + ".mp4"; +// ffmpeg_args = [ +// ...ffmpeg_args, +// "-ss", +// (piece.start / FRAMERATE).toFixed(5), +// "-t", +// ((piece.end - piece.start) / FRAMERATE).toFixed(5), +// "-c", +// "copy", +// output_filename, +// ]; +// parts.push(output_filename); +// } + +// console.log(ffmpeg_args); + +// await $`ffmpeg -i ${video} ${ffmpeg_args}`; + +// await $`echo ${parts.map((s) => `file ${s}`).join("\n")} > /tmp/vdlist.txt`; + +// await $`ffmpeg -f concat -safe 0 -i /tmp/vdlist.txt -c copy -y ${ +// video + "final.mp4" +// } `;