-2

I have 36 video files with same dimensions and want to concatenate them into a one single video with 6x6 grid.

Ideally is non-square number of videos are given for example 12, a 4x3 grid as the most square it can be would be great.

I tried with matplotlib's animation library but failed to concatenate videos in both directions first as row then as columns.

Any help is appriciated!

  • I found this [link](https://trac.ffmpeg.org/wiki/Create%20a%20mosaic%20out%20of%20several%20input%20videos) in less than 10 seconds and it answers your question... – Jao Sep 21 '20 at 14:08
  • 1
    I found it too but unfortunately if i have 256 videos to merge this method quickly becomes really hard to achieve :/ I am open for any other solutions – Kayra Uckilinc Sep 21 '20 at 14:14
  • Have you tried `imutils`? It has a `build_montages` [function](https://github.com/jrosebr1/imutils/blob/master/imutils/convenience.py) that may suit your needs. – Basil Sep 21 '20 at 14:46
  • See [Vertically or horizontally stack (mosaic) several videos using ffmpeg?](https://stackoverflow.com/a/33764934/) – llogan May 14 '21 at 15:54

1 Answers1

3

OP talks about a scaling problem with 256 videos. For that matter I'd recommend automation, for example with Python. You should generate a command such as the one used at this link but with your videos and the right amount. We can see that this part is the one that'll change with the number of videos :

Say you have a list of all videos in python (you could do that by hand but i'd recommand using os.listdir like this)

In the same way you'll have to generate the input for the overlay filters, this will depend on you output resolution. Let's say it's defined by width and height variables. Also, in my example the number of videos of the grid (grid_width and grid_width) are set by hand. Here is a sample of code I don't have the resource or time to test but this should be a good basis for your work :

###list_videos contains the path the the videos
width = 1920
height = 1080
input_videos = ""
input_setpts = "nullsrc=size={}x{} [base];".format(width, height)
input_overlays = "[base][video0] overlay=shortest=1 [tmp0];"
grid_width = 16
grid_height = 16
for index, path_video in enumerate(list_video):
        input_videos += " -i " + path_video
        input_setpts += "[{}:v] setpts=PTS-STARTPTS, scale={}x{} [video{}];".format(index, width//grid_width, height//grid_height, index)
        if index > 0 and index < len(list_video) - 1:
            input_overlays += "[tmp{}][video{}] overlay=shortest=1:x={}:y={} [tmp{}];".format(index-1, index, width//grid_width * (index%grid_width), height//grid_height * (index//grid_width), index)
        if index == len(list_video) - 1:
            input_overlays += "[tmp{}][video{}] overlay=shortest=1:x={}:y={}".format(index-1, index, width//grid_width * (index%grid_width), height//grid_height * (index//grid_width))

complete_command = "ffmpeg" + input_videos + " -filter_complex \"" + input_setpts + input_overlays + "\" -c:v libx264 output.mp4"

print(complete_command) 

In the end you can run complete_command with os.system, information there.

Gerhard Burger
  • 1,379
  • 1
  • 16
  • 25
Jao
  • 558
  • 2
  • 12
  • 1
    I am not sure why I got downvoted I searched really hard and had no solutions then created my own post, have a nice day that works great! – Kayra Uckilinc Sep 21 '20 at 20:50
  • I actually intended to update that blog with something like this but never got around to it. Very cool. – Michael Oct 17 '20 at 02:34
  • 1
    Thanks for your basis, after fixing some issues I got it to work! I put my changes in an edit – Gerhard Burger May 13 '21 at 13:12
  • A more efficient method is to use the hstack, vstack, or xstack filters. See [Vertically or horizontally stack (mosaic) several videos using ffmpeg?](https://stackoverflow.com/a/33764934/) – llogan May 14 '21 at 15:55