Last active
July 25, 2020 21:40
-
-
Save stephenhandley/3bcf4d6ea8450d7281a2626aaa3130f6 to your computer and use it in GitHub Desktop.
hacky script for generating ffmpeg command to tile videos
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ffmpeg -i 0.mp4 -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -i 5.mp4 -i 6.mp4 -i 7.mp4 -i 8.mp4 -i 9.mp4 -i 10.mp4 -i 11.mp4 -i 12.mp4 -i 13.mp4 -i 14.mp4 -i 15.mp4 -i 16.mp4 -i 17.mp4 -i 18.mp4 -i 19.mp4 -i 20.mp4 -i 21.mp4 -i 22.mp4 -i 23.mp4 -i 24.mp4 -t 00:12:16 -filter_complex "amix=inputs=25:duration=longest; [0:v] setpts=PTS-STARTPTS, scale=768x432 [_00]; [1:v] setpts=PTS-STARTPTS, scale=768x432 [_01]; [2:v] setpts=PTS-STARTPTS, scale=768x432 [_02]; [3:v] setpts=PTS-STARTPTS, scale=768x432 [_03]; [4:v] setpts=PTS-STARTPTS, scale=768x432 [_04]; [5:v] setpts=PTS-STARTPTS, scale=768x432 [_10]; [6:v] setpts=PTS-STARTPTS, scale=768x432 [_11]; [7:v] setpts=PTS-STARTPTS, scale=768x432 [_12]; [8:v] setpts=PTS-STARTPTS, scale=768x432 [_13]; [9:v] setpts=PTS-STARTPTS, scale=768x432 [_14]; [10:v] setpts=PTS-STARTPTS, scale=768x432 [_20]; [11:v] setpts=PTS-STARTPTS, scale=768x432 [_21]; [12:v] setpts=PTS-STARTPTS, scale=768x432 [_22]; [13:v] setpts=PTS-STARTPTS, scale=768x432 [_23]; [14:v] setpts=PTS-STARTPTS, scale=768x432 [_24]; [15:v] setpts=PTS-STARTPTS, scale=768x432 [_30]; [16:v] setpts=PTS-STARTPTS, scale=768x432 [_31]; [17:v] setpts=PTS-STARTPTS, scale=768x432 [_32]; [18:v] setpts=PTS-STARTPTS, scale=768x432 [_33]; [19:v] setpts=PTS-STARTPTS, scale=768x432 [_34]; [20:v] setpts=PTS-STARTPTS, scale=768x432 [_40]; [21:v] setpts=PTS-STARTPTS, scale=768x432 [_41]; [22:v] setpts=PTS-STARTPTS, scale=768x432 [_42]; [23:v] setpts=PTS-STARTPTS, scale=768x432 [_43]; [24:v] setpts=PTS-STARTPTS, scale=768x432 [_44]; nullsrc=size=3840x2160 [tmp0]; [tmp0][_00] overlay=x=0:y=0 [tmp1]; [tmp1][_01] overlay=x=0:y=432 [tmp2]; [tmp2][_02] overlay=x=0:y=864 [tmp3]; [tmp3][_03] overlay=x=0:y=1296 [tmp4]; [tmp4][_04] overlay=x=0:y=1728 [tmp5]; [tmp5][_10] overlay=x=768:y=0 [tmp6]; [tmp6][_11] overlay=x=768:y=432 [tmp7]; [tmp7][_12] overlay=x=768:y=864 [tmp8]; [tmp8][_13] overlay=x=768:y=1296 [tmp9]; [tmp9][_14] overlay=x=768:y=1728 [tmp10]; [tmp10][_20] overlay=x=1536:y=0 [tmp11]; [tmp11][_21] overlay=x=1536:y=432 [tmp12]; [tmp12][_22] overlay=x=1536:y=864 [tmp13]; [tmp13][_23] overlay=x=1536:y=1296 [tmp14]; [tmp14][_24] overlay=x=1536:y=1728 [tmp15]; [tmp15][_30] overlay=x=2304:y=0 [tmp16]; [tmp16][_31] overlay=x=2304:y=432 [tmp17]; [tmp17][_32] overlay=x=2304:y=864 [tmp18]; [tmp18][_33] overlay=x=2304:y=1296 [tmp19]; [tmp19][_34] overlay=x=2304:y=1728 [tmp20]; [tmp20][_40] overlay=x=3072:y=0 [tmp21]; [tmp21][_41] overlay=x=3072:y=432 [tmp22]; [tmp22][_42] overlay=x=3072:y=864 [tmp23]; [tmp23][_43] overlay=x=3072:y=1296 [tmp24]; [tmp24][_44] overlay=x=3072:y=1728 " -c:v libx264 ./output.mp4 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// putting this here until i cmdargs it and make it easier to use | |
const Fs = require('fs'); | |
function aspect (dims) { | |
return (dims[0] / dims[1]); | |
} | |
function size (dims) { | |
return dims.join('x') | |
} | |
// TODO: convert to be inputs | |
const count = 25; | |
const input_dims = [1920, 1080]; | |
const ext = '.mp4'; | |
const max_time = '00:12:16'; | |
const output_dims = [3840, 2160]; | |
const dim = Math.sqrt(count); | |
const square = ((count % dim) === 0); | |
if (!square) { | |
throw new Error('Not square'); | |
} | |
const input_aspect = aspect(input_dims); | |
const output_aspect = aspect(output_dims); | |
if (input_aspect !== output_aspect) { | |
throw new Error(`Aspect ratio mismatch. ${input_aspect}}=>${output_aspect}`); | |
} | |
function xy (i) { | |
return [Math.floor(i / dim), i % dim]; | |
} | |
// 1. Build input section | |
let inputs = []; | |
for (let i = 0; i < count; i++) { | |
inputs.push(`-i ${i}${ext}`); | |
} | |
inputs = inputs.join(' '); | |
// 2. time | |
const time = `-t ${max_time}`; | |
// 3. filter | |
let filter = []; | |
// 3a. audio | |
const amix = `amix=inputs=${count}:duration=longest`; | |
filter.push(amix); | |
// 3b. scaling | |
const scaled_dims = output_dims.map((d)=> d / dim); | |
for (let i = 0; i < count; i++) { | |
const [x, y] = xy(i); | |
const scale = `[${i}:v] setpts=PTS-STARTPTS, scale=${size(scaled_dims)} [_${x}${y}]`; | |
filter.push(scale); | |
} | |
// 3c. sections | |
const [scaled_x, scaled_y] = scaled_dims; | |
for (let i = 0; i < count; i++) { | |
const first = (i === 0); | |
const last = (i === (count - 1)); | |
if (first) { | |
filter.push(`nullsrc=size=${size(output_dims)} [tmp0]`); | |
} | |
const [x, y] = xy(i); | |
const start_x = x * scaled_x; | |
const start_y = y * scaled_y; | |
let tmp_out = ''; | |
if (!last) { | |
tmp_out = `[tmp${i + 1}]`; | |
} | |
filter.push(`[tmp${i}][_${x}${y}] overlay=x=${start_x}:y=${start_y} ${tmp_out}`); | |
} | |
console.log(filter); | |
filter = `-filter_complex "${filter.join('; ')}"`; | |
const output = `-c:v libx264 ./output.mp4`; | |
const command = [ | |
'ffmpeg', | |
inputs, | |
time, | |
filter, | |
output | |
].join(' '); | |
console.log(command); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment