From 1f010daf520794f4cb2d131957b1c95c0fd8c3b3 Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Mon, 20 Sep 2021 16:31:17 +0200 Subject: [PATCH] New version using (a)trim + concat As suggested here: https://trac.ffmpeg.org/ticket/9430#comment:2 --- dziurkacz-fast.mjs | 93 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 12 deletions(-) diff --git a/dziurkacz-fast.mjs b/dziurkacz-fast.mjs index e2642bb..acf967c 100755 --- a/dziurkacz-fast.mjs +++ b/dziurkacz-fast.mjs @@ -73,19 +73,19 @@ current_piece.end = all_frames[all_frames.length - 1]; pieces.push(current_piece); // this approach is using a filter, so it requires reencoding the entire video, but lets us be very precise: -const filter = pieces - .map( - ({ start, end }) => - `between(t,${(start / FRAMERATE).toFixed(5)},${(end / FRAMERATE).toFixed( - 5 - )})` - ) - .join("+"); +// 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"}`; +// 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 = []; @@ -114,3 +114,72 @@ await $`ffmpeg -i ${video} \ // await $`ffmpeg -f concat -safe 0 -i /tmp/vdlist.txt -c copy -y ${ // video + "final.mp4" // } `; + +function range(n) { + return [...Array(n).keys()]; +} + +for (let piece of pieces) { + console.log(piece); +} + +const ns = range(pieces.length); + +const sample_rate = parseInt( + ( + await $`ffprobe odc25proxy.mp4 2>&1 | grep 'Audio:' | grep --only-matching --extended-regexp '[0-9]+ Hz' | sed 's/ Hz//'` + ).stdout +); // in Hz + +const samples_per_frame = sample_rate / FRAMERATE; + +function generateSplit(pieces, prefix = "") { + return `[0] ${prefix}split=${pieces.length} ${ns + .map((n) => `[copy${n}${prefix}]`) + .join("")}`; +} + +function generateFilter(pieces, prefix = "") { + return pieces + .map( + (piece, n) => + `[copy${n}${prefix}]${prefix}trim=start_frame=${piece.start}:end_frame=${piece.end},setpts=PTS-STARTPTS [copy${n}t${prefix}]` + ) + .join("; "); +} + +function generateAudioFilter(pieces) { + return pieces + .map( + (piece, n) => + `[copy${n}a]atrim=start_sample=${ + piece.start * samples_per_frame + }:end_sample=${ + (piece.end + 1) * samples_per_frame + },asetpts=PTS-STARTPTS [copy${n}ta]` + ) + .join("; "); +} + +// version with audio, that doesn't work yet: +// const filter = `${generateSplit(pieces)}; ${generateSplit( +// pieces, +// "a" +// )}; ${generateFilter(pieces)}; ${generateAudioFilter(pieces)}; ${ns +// .map((n) => `[copy${n}t]`) +// .join("")} concat=n=${pieces.length} [out_video]; ${ns +// .map((n) => `[copy${n}ta]`) +// .join("")} concat=n=${pieces.length} [out_audio]`; + +// video-only version +const audio_filter = `${generateSplit(pieces, "a")}; ${generateAudioFilter( + pieces +)};`; + +const filter = `${generateSplit(pieces)}; +${generateFilter(pieces)}; +${audio_filter} +${ns.map((n) => `[copy${n}t][copy${n}ta]`).join(" ")} +concat=n=${pieces.length}:v=1:a=1 [out_video] [out_audio]`; + +await $`ffmpeg -i ${video} -filter_complex ${filter} -map '[out_video]' -map '[out_audio]' ${`${video}.cut-complex.mp4`}`;