Extract frames from a video and compose them into a single mosaic image.
Project description
video-mosaic
Extract frames from a video and arrange them into a single mosaic image.
What it does
video-mosaic takes a video file (or URL), extracts frames, and composes them into a grid — like a contact sheet or storyboard. It includes a header with video metadata and optional timestamps on each frame. Supports YouTube, Twitter/X, TikTok, Instagram, and any site supported by yt-dlp.
┌─────────────────────────────────────────┐
│ filename.mp4 │
│ 1920×1080 • 30.2s • 30.00 fps │
├──────┬──────┬──────┬──────┬──────┬──────┤
│ #1 │ #2 │ #3 │ #4 │ #5 │ #6 │
│00:00 │00:05 │00:10 │00:15 │00:20 │00:25 │
├──────┼──────┼──────┼──────┼──────┼──────┤
│ #7 │ #8 │ #9 │ #10 │ #11 │ #12 │
│00:30 │00:35 │00:40 │00:45 │00:50 │00:55 │
└──────┴──────┴──────┴──────┴──────┴──────┘
Installation
pip install video-mosaic
From source
git clone https://github.com/GonzaloFuentes28/video-mosaic.git
cd video-mosaic
pip install .
Prerequisites
ffmpeg must be installed and available in your $PATH.
# macOS
brew install ffmpeg
# Ubuntu / Debian
sudo apt install ffmpeg
# Arch
sudo pacman -S ffmpeg
Quick start
# 48 evenly-spaced frames with timestamps
video-mosaic video.mp4 --frames 48 --labels
# One frame every 5 seconds
video-mosaic video.mp4 --every 5s -o contact-sheet.jpg
# Every single frame of a short clip
video-mosaic clip.mp4 --all -o all-frames.png
# From a URL (requires yt-dlp)
video-mosaic "https://youtube.com/watch?v=abc" --frames 48 --quality 720
video-mosaic "https://x.com/user/status/123" --frames 24
Usage
video-mosaic INPUT [options]
Frame selection (pick one)
| Flag | Description |
|---|---|
--frames N |
Extract exactly N frames, evenly distributed |
--every INTERVAL |
One frame per interval (5s, 500ms, 0.5) |
--all |
Every single frame (careful with long videos) |
Trimming
| Flag | Description |
|---|---|
--from TIME |
Start time (1:30, 90, 0:05.5) |
--to TIME |
End time (2:30, 150) |
# Frames only from the first minute
video-mosaic video.mp4 --frames 24 --from 0:00 --to 1:00
Filtering
| Flag | Description |
|---|---|
--skip-black |
Exclude mostly-black frames |
--skip-dupes |
Exclude near-duplicate consecutive frames |
# Clean up a screencast with lots of static frames
video-mosaic screencast.mp4 --every 1s --skip-dupes --skip-black
Layout
| Flag | Default | Description |
|---|---|---|
--cols N |
auto (√n) | Number of columns |
--thumb-width PX |
native | Thumbnail width in pixels |
--padding PX |
2 | Gap between frames |
--bg COLOR |
#1a1a1a | Background color (hex) |
--labels |
off | Show frame number + timestamp |
--no-header |
— | Hide video info header |
--reverse |
— | Reverse frame order |
# Custom layout: 10 columns, smaller thumbnails, white background
video-mosaic video.mp4 --frames 100 --cols 10 --thumb-width 200 --bg "#ffffff"
Output
| Flag | Default | Description |
|---|---|---|
-o PATH |
mosaic.jpg | Output image (.jpg, .png, .webp) |
--pdf PATH |
— | Also export as multi-page PDF storyboard |
# Image + PDF storyboard
video-mosaic video.mp4 --frames 48 --labels --pdf storyboard.pdf
URL downloads
| Flag | Description |
|---|---|
--quality PX |
Max video height for URL downloads (e.g. 720, 1080) |
Requires yt-dlp: pip install yt-dlp or brew install yt-dlp.
Other
| Flag | Description |
|---|---|
--open |
Open the output image after saving |
--no-progress |
Disable progress bar |
Examples
# Quick overview of a movie trailer
video-mosaic trailer.mp4 -o overview.jpg --frames 36 --cols 6 --labels
# Frame-by-frame analysis of a 2-second clip
video-mosaic clip.mp4 -o analysis.png --all --labels
# Every 10 seconds of a long lecture, skip static slides
video-mosaic lecture.mp4 -o sheet.webp --every 10s --skip-dupes --thumb-width 400
# Just the intro of a video, reversed, as PDF
video-mosaic video.mp4 --frames 20 --from 0:00 --to 0:30 --reverse --pdf intro.pdf
Project structure
src/video_mosaic/
├── __init__.py # Package root, version, VideoMosaicError
├── cli.py # CLI argument parsing and orchestration
├── download.py # URL video downloading via yt-dlp
├── probe.py # Video metadata via ffprobe
├── extract.py # Frame extraction strategies
├── filters.py # Black frame / duplicate detection
├── mosaic.py # Grid composition
├── pdf.py # PDF storyboard export
└── utils.py # Timestamp parsing, font loading
Contributing
git clone https://github.com/GonzaloFuentes28/video-mosaic.git
cd video-mosaic
pip install -e ".[dev]"
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file video_mosaic-0.1.1.tar.gz.
File metadata
- Download URL: video_mosaic-0.1.1.tar.gz
- Upload date:
- Size: 15.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecbd0e5555ea30428044ba2f21b91ef76c2e93d26f5e2865a51cbbe34a4a1843
|
|
| MD5 |
197a52af881b4ef41d097b68c3976e0b
|
|
| BLAKE2b-256 |
62cd0dd4e16048129d656165a4aed05615953b702387ab345dd57bdfefa21786
|
Provenance
The following attestation bundles were made for video_mosaic-0.1.1.tar.gz:
Publisher:
publish.yml on GonzaloFuentes28/video-mosaic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
video_mosaic-0.1.1.tar.gz -
Subject digest:
ecbd0e5555ea30428044ba2f21b91ef76c2e93d26f5e2865a51cbbe34a4a1843 - Sigstore transparency entry: 1192192005
- Sigstore integration time:
-
Permalink:
GonzaloFuentes28/video-mosaic@de6085aa73d90b4290a78cc4f4f490992b0bb6ae -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/GonzaloFuentes28
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@de6085aa73d90b4290a78cc4f4f490992b0bb6ae -
Trigger Event:
push
-
Statement type:
File details
Details for the file video_mosaic-0.1.1-py3-none-any.whl.
File metadata
- Download URL: video_mosaic-0.1.1-py3-none-any.whl
- Upload date:
- Size: 18.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dad7cc4a11efd746f79ed73a2144fbaaad173f7fcad1938c7db850d85d458b52
|
|
| MD5 |
8636c6b736153b1428d42cf1d9d19776
|
|
| BLAKE2b-256 |
92e778ce65cb6a226731ae99890ae1c3b22969829007bb1baf2876c451e0fbc8
|
Provenance
The following attestation bundles were made for video_mosaic-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on GonzaloFuentes28/video-mosaic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
video_mosaic-0.1.1-py3-none-any.whl -
Subject digest:
dad7cc4a11efd746f79ed73a2144fbaaad173f7fcad1938c7db850d85d458b52 - Sigstore transparency entry: 1192192031
- Sigstore integration time:
-
Permalink:
GonzaloFuentes28/video-mosaic@de6085aa73d90b4290a78cc4f4f490992b0bb6ae -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/GonzaloFuentes28
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@de6085aa73d90b4290a78cc4f4f490992b0bb6ae -
Trigger Event:
push
-
Statement type: