Video Mosaic in python ffmpeg : success!

I have been working on a way to take a bunch of videos and tile them to play side by side, and the end result is below:

How do we do it? Well, ffmpeg seems like the most powerful and common tool to do editing link this. But the syntax, at least for a python plebian like myself, is completely impenetrable. For example, here is a stack overflow answer:

ffmpeg -i lead_1.mp4 -i lead_2.mp4 -i lead_3.mp4 -i lead_4.mp4 
-filter_complex 
"color=s=1280x720:c=black [base]; 
[0:v] setpts=PTS-STARTPTS, scale= 640x360 [upperleft1]; 
[1:v] setpts=PTS+35/TB, scale=640x360 [lowerright1]; 
[2:v] setpts=PTS+87/TB, scale=640x360 [upperleft2]; 
[3:v] setpts=PTS+183/TB, scale=640x360 [lowerright2]; 
[base][upperleft1] overlay=1 [tmp1]; 
[tmp1][lowerright1] overlay=1:x=640:y=360 [tmp2]; 
[tmp2] [upperleft2] overlay=1 [tmp3]; 
[tmp3][lowerright2] overlay=1:x=640:y=360" 

-c:v libx264 lead_1_2_3_4.mp4

There is an explanation of what is going on above on this page, but even copying and pasting as hard as I could… I was unable to get answers like this to work. So Instead I turned to python-ffmpeg which you can download with conda-forge. This allowed me to write a short function that would do the job I needed, while also being relatively readable. See below for my function:

import os, ffmpeg
import numpy as np

def video_tile(vid_list, row_length, save_name='out.mp4'):
    '''
    takes in a list of same sized videos and tiles them into a single video at 'save_name'.
    important: will overwrite anything that has the file name of the output file
    only nonstandard dependency is python ffmpeg
    
    Parameters
    ----------
    vid_list: list of video files
        the tiled videos are made from this list, 
        will probably act weird if their sizes are not the same
    row_length: int
        number of videos in each row
    save_name: str
        where the video will be saved and what format
    
    Returns
    -------
    None: there are no returns, it just saves the video to 'save_name'

    '''
    N = len(vid_list)
    column_length = int(np.ceil(N/row_length))

    videoprobe = ffmpeg.probe(vid_list[0]) #get info on video
    vwidth, vheight = videoprobe["streams"][0]["width"], videoprobe["streams"][0]["height"] # get dims of fiirst video

    videowidth = vwidth*row_length
    videoheight = vheight*column_length
        
    video_list = [ffmpeg.input(item) for item in vid_list] #import all videos into ffmpeg
    videostr = ffmpeg.filter(video_list[0], "pad", videowidth, videoheight) #sets the first video in large frame
    
    #now we just loop over the list, placing the videos onto the main video stream as we go
    for i,item in enumerate(video_list):
        if i>0:
            j = i//row_length
            k = i - row_length*j
            videostr = ffmpeg.overlay(videostr, item, x=k*vwidth, y=j*vheight) #overlay image
    
    #this is to avoid an error when the target file for the save already exists
    try: os.remove(save_name)
    except: pass
    
    videostr = ffmpeg.output(videostr, save_name)
    ffmpeg.run(videostr)

The video in the post was generated by video_tile(video_list, 3, ‘video_test.mp4’)