Create a Video Contact Sheet with FFmpeg Tile Filter

This guide explains how to use the FFmpeg tile video filter to generate a contact sheet or image grid from video frames. By combining the tile filter with frame extraction filters like fps or select, and optional scaling, you can quickly produce thumbnail galleries summarizing an entire video into a single image.

Basic Tile Filter Command

The tile filter takes sequential video frames and arranges them into a grid defined as ColumnsxRows. Because a standard video contains thousands of frames, you must downsample the frame rate before tiling so the resulting sheet covers the desired duration of the video.

The standard command structure is:

ffmpeg -i input.mp4 -vf "fps=1/60,scale=320:-1,tile=4x4" -frames:v 1 contact_sheet.png

Breakdown of the Parameters

  • -i input.mp4: Specifies the input video file.
  • -vf: Defines the video filtergraph containing a chain of three operations:
    • fps=1/60: Samples one frame every 60 seconds. Adjust this interval based on your video length and desired coverage.
    • scale=320:-1: Resizes each extracted thumbnail to a width of 320 pixels while preserving the original aspect ratio (-1). Scaling down is critical to keep memory usage low and output dimensions manageable.
    • tile=4x4: Arranges the thumbnails into a grid of 4 columns and 4 rows (16 frames total).
  • -frames:v 1: Tells FFmpeg to stop processing after outputting one single image frame.
  • contact_sheet.png: The destination image file.

Adding Margins, Padding, and Colors

You can customize the layout of the contact sheet by adding borders between images and setting a background color:

ffmpeg -i input.mp4 -vf "fps=1/30,scale=300:-1,tile=3x3:nb_frames=9:padding=10:margin=20:color=white" -frames:v 1 contact_sheet.jpg
  • nb_frames=9: Explicitly tells the tile filter to finish the grid after rendering 9 frames, ensuring it stops even if the video ends early.
  • padding=10: Inserts a 10-pixel gap between each thumbnail.
  • margin=20: Inserts a 20-pixel outer border around the entire grid.
  • color=white: Sets the background, margin, and padding color (accepts color names or hex codes like 0x000000).

Generating a Contact Sheet for a Specific Video Duration

If you want an evenly spaced contact sheet regardless of the file length, calculate the fps value based on total video duration:

\[\text{fps} = \frac{\text{Total Frames Needed}}{\text{Video Duration in Seconds}}\]

For example, to fit 25 frames (5x5 grid) across a 500-second video:

ffmpeg -i input.mp4 -vf "fps=25/500,scale=320:-1,tile=5x5" -frames:v 1 output.png