Originally published at ffmpeg-micro.com
You have a set of product screenshots, event photos, or AI-generated images. You need them stitched into a video. Maybe it's for a social media post, a product demo, or an automated content pipeline that cranks out faceless YouTube videos. FFmpeg can do this, but the syntax is unintuitive and the gotchas will cost you hours if you don't know them upfront.
Turn a Single Image into a Video with FFmpeg
The simplest slideshow is one image displayed for a set duration. FFmpeg needs three things: loop the image, set a frame rate, and define the duration.
ffmpeg -loop 1 -framerate 30 -i slide.jpg -t 5 -c:v libx264 -pix_fmt yuv420p output.mp4
What each flag does:
-
-loop 1keeps reading the image repeatedly. Without this, you get a single-frame video. -
-framerate 30sets 30 frames per second for smooth playback. -
-t 5limits the output to 5 seconds. -
-pix_fmt yuv420pforces a pixel format that works on every player. Skip this and some devices will show a black screen.
That gives you a 5-second MP4 of your image. This is the building block for everything else.
Create a Multi-Image Slideshow
For multiple images, create a video clip from each image, then concatenate them with FFmpeg's concat demuxer.
First, make individual clips:
ffmpeg -loop 1 -framerate 30 -i slide1.jpg -t 3 -c:v libx264 -pix_fmt yuv420p clip1.mp4
ffmpeg -loop 1 -framerate 30 -i slide2.jpg -t 3 -c:v libx264 -pix_fmt yuv420p clip2.mp4
ffmpeg -loop 1 -framerate 30 -i slide3.jpg -t 3 -c:v libx264 -pix_fmt yuv420p clip3.mp4
Create a file list (slides.txt):
file 'clip1.mp4'
file 'clip2.mp4'
file 'clip3.mp4'
Concatenate:
ffmpeg -f concat -safe 0 -i slides.txt -c copy slideshow.mp4
Result: a 9-second slideshow with 3 seconds per image, hard cuts between slides.
Add Fade Transitions Between Slides
Hard cuts work, but fade transitions look more polished. FFmpeg's xfade filter handles this. The tricky part is calculating the offset for each transition.
Two images with a 1-second crossfade:
ffmpeg -loop 1 -framerate 30 -t 4 -i slide1.jpg \
-loop 1 -framerate 30 -t 4 -i slide2.jpg \
-filter_complex "[0:v][1:v]xfade=transition=fade:duration=1:offset=3[v]" \
-map "[v]" -c:v libx264 -pix_fmt yuv420p slideshow.mp4
The offset=3 means the fade starts 3 seconds in (each clip is 4 seconds, fade duration is 1 second, so 4 - 1 = 3). Total output is 7 seconds.
For three images, chain the filters:
ffmpeg -loop 1 -framerate 30 -t 4 -i slide1.jpg \
-loop 1 -framerate 30 -t 4 -i slide2.jpg \
-loop 1 -framerate 30 -t 4 -i slide3.jpg \
-filter_complex "[0:v][1:v]xfade=transition=fade:duration=1:offset=3[out1];[out1][2:v]xfade=transition=fade:duration=1:offset=6[v]" \
-map "[v]" -c:v libx264 -pix_fmt yuv420p slideshow.mp4
The offset formula is simple: for transition number N (starting from 1), offset = N * (clip_duration - fade_duration). So with 4-second clips and 1-second fades, offsets are 3, 6, 9, and so on.
FFmpeg's xfade filter supports over 40 transition styles beyond fade: fadeblack, fadewhite, wipeleft, slideright, circlecrop, dissolve, pixelize, radial, and more. Swap transition=fade for any of these.
Add Background Audio
ffmpeg -loop 1 -framerate 30 -t 4 -i slide1.jpg \
-loop 1 -framerate 30 -t 4 -i slide2.jpg \
-i background-music.mp3 \
-filter_complex "[0:v][1:v]xfade=transition=fade:duration=1:offset=3[v]" \
-map "[v]" -map 2:a -c:v libx264 -c:a aac -shortest -pix_fmt yuv420p slideshow.mp4
The -shortest flag stops the output when the video track ends. Without it, a 3-minute song produces a 3-minute video with the last slide frozen for the remaining duration.
Create Slideshows with the FFmpeg Micro API
CLI commands work on your machine. But if you're building this into an app or running it at scale, you don't want to manage FFmpeg installations, temp files, and server infrastructure.
FFmpeg Micro is a cloud API that lets you create slideshows with a single HTTP request. No binary management, no scaling headaches. The API accepts up to 10 image inputs per request with per-image duration control and full filter support.
Two-image slideshow with a fade transition:
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": [
{
"url": "https://example.com/slide1.jpg",
"options": [
{"option": "-loop", "argument": "1"},
{"option": "-framerate", "argument": "30"},
{"option": "-t", "argument": "4"}
]
},
{
"url": "https://example.com/slide2.jpg",
"options": [
{"option": "-loop", "argument": "1"},
{"option": "-framerate", "argument": "30"},
{"option": "-t", "argument": "4"}
]
}
],
"outputFormat": "mp4",
"options": [
{"option": "-c:v", "argument": "libx264"},
{"option": "-pix_fmt", "argument": "yuv420p"},
{"option": "-crf", "argument": "23"}
],
"filters": [
{"filter": "[0:v][1:v]xfade=transition=fade:duration=1:offset=3[v]"}
]
}'
Poll for completion, then download:
curl https://api.ffmpeg-micro.com/v1/transcodes/JOB_ID \
-H "Authorization: Bearer YOUR_API_KEY"
curl https://api.ffmpeg-micro.com/v1/transcodes/JOB_ID/download \
-H "Authorization: Bearer YOUR_API_KEY"
If your images aren't at public URLs, upload them first using the three-step upload flow. The API supports JPEG, PNG, GIF, and WebP as image inputs.
For a deeper dive on video transcoding with FFmpeg, see the Learn FFmpeg course.
Common Pitfalls
Mixed image dimensions. Images with different sizes will produce garbled output or errors. Scale and pad every image to a consistent resolution:
-vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2"
This scales to fit within 1920x1080 while preserving aspect ratio, then adds black bars to fill the frame.
Missing -pix_fmt yuv420p. FFmpeg sometimes defaults to yuv444p, which most mobile players and browsers can't decode. Always set this explicitly for MP4 output.
Wrong xfade offset math. Offset = transition_number * (clip_duration - fade_duration). Get this wrong and transitions overlap or leave gaps between slides.
Forgetting -loop 1. Without it, FFmpeg reads the image once and creates a single-frame video regardless of the -t value.
Mismatched frame rates. Different frame rates across inputs cause jittery xfade transitions. Keep all inputs at the same frame rate.
FAQ
Can I set different durations per slide in an FFmpeg slideshow?
Yes. Use a different -t value for each input. Recalculate your xfade offsets accordingly. If slide 1 is 5 seconds and slide 2 is 3 seconds with a 1-second fade, the offset is 4 (5 minus 1).
What transition effects does FFmpeg support for slideshows?
The xfade filter includes over 40 options: fade, fadeblack, fadewhite, wipeleft, wiperight, slideleft, slideright, circlecrop, dissolve, pixelize, radial, zoomin, and many more. Replace transition=fade with any of these in your filter string.
How do I add a Ken Burns zoom effect to slideshow images?
Use the zoompan filter. For a slow zoom-in over 5 seconds at 30fps: zoompan=z='min(zoom+0.0015,1.5)':d=150:s=1920x1080. This gradually increases zoom from 1x to 1.5x over 150 frames.
What image formats work for FFmpeg slideshows?
JPEG, PNG, WebP, BMP, and TIFF all work as inputs. JPEG gives the best balance of quality and processing speed. FFmpeg Micro's API accepts JPEG, PNG, GIF, and WebP.
Can I create slideshows programmatically without installing FFmpeg?
FFmpeg Micro is a cloud API that handles slideshow creation via HTTP requests. Send your image URLs, define transitions and timing, and download the finished video. No local FFmpeg installation needed. Get a free API key to try it.









