birdgen/src/concatenateVideos.js
hazy 0a01583f56 Various improvements
Make CLI arguments use flags, support webm output encoding, allow running from any working directory, add optional profiles, add audio to spliced-in clips, various small fixes
2022-06-28 17:45:21 -05:00

54 lines
2.4 KiB
JavaScript

import fs from 'fs'
import exec from './exec.js'
import getArgument from './getArgument.js'
function getExtension(filename) {
return filename.split('/').pop().split('.').pop()
}
export function getArgs(filename) {
let extension = getExtension(filename)
if (extension=='webm') return `-c:v libvpx-vp9 -crf 30 -cpu-used 5 -deadline realtime -vsync 2`
return `-c:v libx264 -x264-params crf=25 -ar 44100 -vsync 2`
}
export default async function concatenateVideos(filenames, outfile) {
const chunkSize = getArgument('chunk-size')??40
console.log(`Joining every ${chunkSize} clips`)
let chunks = []
for (let i = 0; i < filenames.length; i += chunkSize) {
const ffmpegArgs = getArgs(outfile)
const filenamesSlice = filenames.slice(i, i + chunkSize)
const inputs = filenamesSlice.map(e => `-i "${e}"`).join(' ')
const filter = filenamesSlice.map((e, i) => `[${i}:v:0][${i}:a:0]`).join('')
const chunkFile = `${__dirname}/tmp/chunk-${i}.${getExtension(outfile)}`
const execScript = `ffmpeg -y ${inputs} -filter_complex "${filter}concat=n=${filenamesSlice.length}:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" ${ffmpegArgs} "${chunkFile}"`
process.stdout.clearLine()
process.stdout.cursorTo(0)
process.stdout.write(`Starting chunk ${Math.floor(i/chunkSize)+1} of ${Math.ceil(filenames.length/chunkSize)}`)
process.stdout.cursorTo(0)
await exec(execScript, {
maxBuffer: 5 * 1024 * 1024
})
process.stdout.clearLine()
process.stdout.cursorTo(0)
process.stdout.write(`Completed chunk ${Math.floor(i/chunkSize)+1} of ${Math.ceil(filenames.length/chunkSize)}`)
process.stdout.cursorTo(0)
chunks.push(chunkFile)
}
if (chunks.length>1) {
const ffmpegArgs = getArgs(outfile)
console.log(`\nJoining all ${Math.ceil(filenames.length/chunkSize)} chunks`)
const inputs = chunks.map(e => `-i "${e}"`).join(' ')
const filter = chunks.map((e, i) => `[${i}:v:0][${i}:a:0]`).join('')
const execScript = `ffmpeg -y ${inputs} -filter_complex "${filter}concat=n=${chunks.length}:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" ${ffmpegArgs} "${outfile}"`
console.log(execScript)
await exec(execScript, {
maxBuffer: 5 * 1024 * 1024
})
} else {
fs.promises.rename(chunks[0], outfile)
}
console.log('Complete.')
}