New version using (a)trim + concat

As suggested here: https://trac.ffmpeg.org/ticket/9430#comment:2
This commit is contained in:
Kuba Orlik 2021-09-20 16:31:17 +02:00
parent 6028f203e1
commit 1f010daf52

View File

@ -73,19 +73,19 @@ current_piece.end = all_frames[all_frames.length - 1];
pieces.push(current_piece); pieces.push(current_piece);
// this approach is using a filter, so it requires reencoding the entire video, but lets us be very precise: // this approach is using a filter, so it requires reencoding the entire video, but lets us be very precise:
const filter = pieces // const filter = pieces
.map( // .map(
({ start, end }) => // ({ start, end }) =>
`between(t,${(start / FRAMERATE).toFixed(5)},${(end / FRAMERATE).toFixed( // `between(t,${(start / FRAMERATE).toFixed(5)},${(end / FRAMERATE).toFixed(
5 // 5
)})` // )})`
) // )
.join("+"); // .join("+");
await $`ffmpeg -i ${video} \ // await $`ffmpeg -i ${video} \
-vf ${`select='${filter}',setpts=N/FRAME_RATE/TB`} \ // -vf ${`select='${filter}',setpts=N/FRAME_RATE/TB`} \
-af ${`aselect='${filter}',asetpts=N/SR/TB`} \ // -af ${`aselect='${filter}',asetpts=N/SR/TB`} \
${video + ".cut.mp4"}`; // ${video + ".cut.mp4"}`;
// let ffmpeg_args = []; // let ffmpeg_args = [];
// const parts = []; // const parts = [];
@ -114,3 +114,72 @@ await $`ffmpeg -i ${video} \
// await $`ffmpeg -f concat -safe 0 -i /tmp/vdlist.txt -c copy -y ${ // await $`ffmpeg -f concat -safe 0 -i /tmp/vdlist.txt -c copy -y ${
// video + "final.mp4" // 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`}`;