You've got a perfectly good 16:9 video and now every platform wants 9:16 vertical. Manually re-exporting from a GUI editor for each platform is tedious — especially when the specs are almost identical across the board. If you've been searching for "ffmpeg reels format" or "ffmpeg convert to tiktok," you're in the right place.
The good news: all major short-form platforms accept the same base format — 1080×1920, H.264, AAC, MP4. One FFmpeg command covers YouTube Shorts, Instagram Reels, TikTok, X, and Facebook Reels. The differences are in duration limits and bitrate sweet spots, not the container or codec.
This guide shows you how to convert any video to vertical format, add text and subtitles, and batch-process an entire folder — all from the command line.
What you'll learn
- Platform specs for Shorts, Reels, TikTok, X, and Facebook Reels
- A single FFmpeg command that works for all platforms
- Three methods to convert 16:9 to 9:16 (crop, pad, blur background)
- How to add text overlays and burn in subtitles
- Platform-specific encoding tweaks
- Batch processing with shell scripts
Platform Video Specs at a Glance
Every platform has its own help page, but the core requirements are remarkably similar. Here's the condensed version:
| Platform | Aspect Ratio | Max Resolution | Codec | Max Duration | File Size Limit |
|---|---|---|---|---|---|
| YouTube Shorts | 9:16 | 1080×1920 | H.264 + AAC | 3 min | 256 GB |
| Instagram Reels | 9:16 | 1080×1920 | H.264 + AAC | 20 min (90s recommended) | 4 GB |
| TikTok | 9:16 | 1080×1920 | H.264 + AAC | Recording 10 min / Upload 60 min | 72–500 MB |
| X (Twitter) | 9:16, 16:9, 1:1 | 1920×1080 | H.264 + AAC | 2 min 20s (free) / 4 hr (Premium) | 512 MB (free) / 16 GB (Premium) |
| Facebook Reels | 9:16 | 1080×1920 | H.264 + AAC | No limit (≤90s recommended) | 4 GB |
The pattern: 1080×1920, H.264, AAC, MP4. That's your target for everything. Platform specs change frequently — always check the linked official pages for the latest limits before a major upload run.
Recommended bitrates
Bitrate determines quality vs. file size. Higher isn't always better — platforms re-encode your upload anyway, so going beyond their processing ceiling wastes bandwidth.
| Platform | Video Bitrate | Audio Bitrate | Notes |
|---|---|---|---|
| YouTube Shorts | 5–10 Mbps | 128 kbps | YouTube recommends 8+ Mbps for 1080p |
| Instagram Reels | 3.5–5 Mbps | 128 kbps | Lower bitrate is fine — Meta re-encodes aggressively |
| TikTok | 2–4 Mbps | 128 kbps | Optimal file size for fast upload |
| X | 2.5–5 Mbps | 128 kbps | 5 Mbps for 1080p, 2.5 Mbps for 720p |
| Facebook Reels | 4–6 Mbps | 128 kbps | Higher bitrate for text-heavy content |
The Universal FFmpeg Preset
This single command produces a file that works on every platform listed above:
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 20 -preset slow -profile:v high -level 4.2 \
-pix_fmt yuv420p -r 30 \
-c:a aac -b:a 128k -ar 44100 -ac 2 \
-movflags +faststart \
-y output_vertical.mp4
What each part does:
| Flag | Purpose |
|---|---|
scale=1080:1920:force_original_aspect_ratio=decrease | Scales to fit within 1080×1920, keeping aspect ratio |
pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black | Adds black bars to fill the remaining space |
setsar=1 | Ensures square pixels (prevents stretching) |
-crf 20 | Quality level — lower = better quality, larger file. 18–23 is the sweet spot |
-preset slow | Better compression at the cost of encoding time |
-profile:v high -level 4.2 | Maximum H.264 compatibility across devices |
-pix_fmt yuv420p | Required for broad player compatibility |
-movflags +faststart | Moves the moov atom to the beginning — crucial for web playback |
Adjusting CRF for specific platforms
The -crf value controls the quality-size tradeoff. Here's a quick reference:
# YouTube Shorts — higher quality (YouTube re-encodes, so start clean)
-crf 18
# Instagram Reels / TikTok — balanced (platforms compress anyway)
-crf 22
# X — keep file size small for the 512 MB limit
-crf 23
Three Ways to Convert 16:9 to 9:16
The universal preset uses padding (black bars). But that's not always what you want — sometimes you'd rather crop into the action, or add a blurred background for a polished look. Here are the three main approaches.
Method 1: Pad (black bars)
Best for: tutorials, screencasts, and talking-head videos where all content matters.
ffmpeg -i input_16x9.mp4 \
-vf "scale=1080:-2:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
output_padded.mp4
The video sits in the center with black bars above and below. Clean and simple, but it wastes 43% of the screen real estate on a 16:9 source.
Method 2: Crop (center cut)
Best for: action-focused content, landscapes, or when the subject is centered.
ffmpeg -i input_16x9.mp4 \
-vf "scale=-2:1920,crop=1080:1920" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
output_cropped.mp4
This scales the height to 1920, then crops the width to 1080 from the center. You lose the left and right edges — about 43% of the original frame.
To crop from a specific position instead of center:
# Crop from the left third (for subjects on the left side)
-vf "scale=-2:1920,crop=1080:1920:0:0"
# Crop from the right third
-vf "scale=-2:1920,crop=1080:1920:iw-1080:0"
Method 3: Blur background (the professional look)
Best for: repurposing YouTube videos into Shorts/Reels. This is what most content creators use — the original video plays in the center while a blurred, zoomed version fills the background.
ffmpeg -i input_16x9.mp4 -filter_complex \
"[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20:5[bg]; \
[0:v]scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=0x00000000[fg]; \
[bg][fg]overlay=0:0,format=yuv420p" \
-c:v libx264 -crf 20 -preset slow \
-c:a aac -b:a 128k -movflags +faststart \
output_blur_bg.mp4
How the filter chain works:
[bg]: Scales the input to cover 1080×1920, crops to fit, then applies a 20-pixel box blur[fg]: Scales the input to fit within 1080×1920, pads with transparent pixelsoverlay: Stacks the sharp foreground on top of the blurred background
Which method to choose?
| Method | Pros | Cons | Best for |
|---|---|---|---|
| Pad | No content loss, fast encode | Wasted screen space, looks basic | Tutorials, screencasts |
| Crop | Fills the frame, high impact | Loses side content | Action, centered subjects |
| Blur background | Professional look, no content loss | Slower encode, larger file | Repurposed YouTube content |
Adding Text Overlays and Burned-In Subtitles
Vertical videos for social media almost always benefit from text — whether it's a title, a call-to-action, or full captions. FFmpeg handles both static text overlays and subtitle burn-in.
Static text overlay with drawtext
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black, \
drawtext=text='Subscribe for more':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=h-100: \
box=1:boxcolor=black@0.6:boxborderw=10" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
output_text.mp4
Key parameters for drawtext:
| Parameter | Description |
|---|---|
text | The text string to display |
fontsize | Font size in pixels (48–72 works well for 1080p vertical) |
fontcolor | Text color (white, yellow, #FF5733) |
x, y | Position — (w-text_w)/2 centers horizontally |
box=1 | Enable background box |
boxcolor=black@0.6 | Semi-transparent black background |
fontfile | Path to a .ttf font file for custom fonts |
enable='between(t,2,8)' | Show text only between seconds 2 and 8 |
Burning in SRT subtitles
Burned-in (hardcoded) subtitles are standard for social media — most viewers watch on mute, and platform auto-captions are often inaccurate.
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black, \
subtitles=captions.srt:force_style='FontSize=20,FontName=Arial,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,MarginV=60'" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
output_subtitled.mp4
The force_style parameter uses ASS subtitle styling syntax. Key style options:
FontSize=20— size in the ASS coordinate system (different from drawtext's pixel-based size)PrimaryColour=&H00FFFFFF— white text (format:&HAABBGGRR)OutlineColour=&H00000000— black outlineOutline=2— outline thicknessMarginV=60— vertical margin from the bottom (keeps subtitles above platform UI elements)
ASS subtitles for advanced styling
For word-by-word highlighting (karaoke style) or precise positioning, use ASS format:
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black, \
ass=styled_captions.ass" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
output_ass.mp4
To generate SRT from audio automatically, see FFmpeg + Whisper: Auto-Generate Subtitles.
Platform-Specific Tweaks
The universal preset covers 90% of cases, but sometimes you need to optimize for a specific platform.
YouTube Shorts
YouTube keeps your original quality longer when you upload at higher bitrate, since it stores multiple quality tiers.
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 18 -preset slow -profile:v high -level 4.2 \
-pix_fmt yuv420p -r 60 \
-c:a aac -b:a 192k -ar 48000 -ac 2 \
-movflags +faststart \
-t 180 \
output_shorts.mp4
Differences from the universal preset:
-crf 18— higher quality, since YouTube re-encodes-r 60— 60 fps for smoother playback-b:a 192k -ar 48000— higher audio quality-t 180— hard limit at 3 minutes (Shorts max duration)
Instagram Reels
Meta's servers re-encode aggressively, so there's no point uploading a massive file. Optimize for a smaller, cleaner source.
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 22 -preset slow -profile:v high -level 4.0 \
-pix_fmt yuv420p -r 30 \
-c:a aac -b:a 128k -ar 44100 -ac 2 \
-movflags +faststart \
-t 90 \
output_reels.mp4
-crf 22— slightly more compression (Meta re-encodes anyway)-t 90— Instagram recommends keeping Reels under 90 seconds for reach
TikTok
TikTok's algorithm favors videos in the 21–34 second sweet spot. Keep file sizes small for faster upload processing.
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 23 -preset slow -profile:v high -level 4.0 \
-maxrate 4M -bufsize 8M \
-pix_fmt yuv420p -r 30 \
-c:a aac -b:a 128k -ar 44100 -ac 2 \
-movflags +faststart \
output_tiktok.mp4
-maxrate 4M -bufsize 8M— caps bitrate to keep file size under TikTok's limits-crf 23— good enough quality at a smaller size
X (Twitter)
X has the strictest file size limits for free users (512 MB) and duration limits (2 min 20s).
ffmpeg -i input.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 23 -preset slow -profile:v high -level 4.0 \
-maxrate 5M -bufsize 10M \
-pix_fmt yuv420p -r 30 \
-c:a aac -b:a 128k -ar 44100 -ac 2 \
-movflags +faststart \
-t 140 \
output_x.mp4
-t 140— hard limit at 2 minutes 20 seconds-maxrate 5M— prevents bitrate spikes that could push the file over 512 MB
Batch Processing
When you have dozens of videos to convert, a shell script saves hours.
Convert all videos in a folder
#!/bin/bash
# batch-vertical.sh — Convert all MP4s to 9:16 vertical format
INPUT_DIR="$1"
OUTPUT_DIR="$2"
METHOD="${3:-pad}" # pad, crop, or blur
mkdir -p "$OUTPUT_DIR"
for f in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$f" .mp4)
echo "Processing: $filename"
case "$METHOD" in
pad)
VF="scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1"
;;
crop)
VF="scale=-2:1920,crop=1080:1920,setsar=1"
;;
blur)
# Blur background requires filter_complex — handled separately
ffmpeg -i "$f" -filter_complex \
"[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20:5[bg]; \
[0:v]scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=0x00000000[fg]; \
[bg][fg]overlay=0:0,format=yuv420p" \
-c:v libx264 -crf 20 -preset slow \
-c:a aac -b:a 128k -movflags +faststart \
-y "$OUTPUT_DIR/${filename}_vertical.mp4"
continue
;;
esac
ffmpeg -i "$f" \
-vf "$VF" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
-y "$OUTPUT_DIR/${filename}_vertical.mp4"
done
echo "Done. Output files in $OUTPUT_DIR"
Usage:
chmod +x batch-vertical.sh
./batch-vertical.sh ./raw_videos ./vertical_output pad
./batch-vertical.sh ./raw_videos ./vertical_output blur
Parallel processing for speed
The script above processes one video at a time. For large batches, use GNU Parallel or xargs to encode multiple files simultaneously:
# Process 4 videos in parallel using xargs
ls raw_videos/*.mp4 | xargs -P 4 -I {} bash -c '
filename=$(basename "{}" .mp4)
ffmpeg -i "{}" \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black,setsar=1" \
-c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 128k -movflags +faststart \
-y "vertical_output/${filename}_vertical.mp4"
'
For more advanced automation (Python-based, progress tracking, error handling), see Automating FFmpeg with Python.
FAQ
What's the best aspect ratio for Shorts, Reels, and TikTok?
9:16 (1080×1920) for all of them. Square (1:1) also works but gets less screen real estate and lower engagement on platforms that prioritize full-screen vertical content.
Can I upload 4K (2160×3840) vertical video?
YouTube Shorts supports up to 4K. Instagram and TikTok will re-encode to 1080p regardless, so uploading 4K to those platforms just wastes upload time and bandwidth. Stick with 1080×1920.
How do I convert a square (1:1) video to 9:16?
Same approach as 16:9 — pad, crop, or blur background:
# Pad a 1:1 video to 9:16
ffmpeg -i square.mp4 \
-vf "scale=1080:-2:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" \
-c:v libx264 -crf 20 -pix_fmt yuv420p -c:a copy \
output_vertical.mp4
Should I use H.265 (HEVC) instead of H.264?
No, at least not for social media uploads. Every platform re-encodes your upload to their own format (often VP9 or AV1 internally). H.264 has universal upload compatibility, while HEVC may cause processing errors on some platforms. For archiving your masters, H.265 or AV1 gives better compression — see AV1 vs H.265 vs H.264 comparison.
How do I trim a video to a specific duration before converting?
Use -ss (start time) and -t (duration) or -to (end time):
# Extract 30 seconds starting at 1:15
ffmpeg -ss 01:15 -i input.mp4 -t 30 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" \
-c:v libx264 -crf 20 -pix_fmt yuv420p -c:a aac -b:a 128k \
-movflags +faststart output_clip.mp4
Place -ss before -i for fast seeking (input seeking), or after -i for frame-accurate seeking (slower). For more details, see FFmpeg Usage Guide — trimming and cutting.
How can I speed up encoding with GPU?
Replace libx264 with a hardware encoder:
# NVIDIA NVENC
-c:v h264_nvenc -preset p4 -cq 22
# Intel Quick Sync
-c:v h264_qsv -global_quality 22
# Apple VideoToolbox (macOS)
-c:v h264_videotoolbox -q:v 60
GPU encoding is 3–10× faster but produces slightly larger files at the same visual quality. See FFmpeg GPU Encoding Guide for setup instructions.
Do I need to normalize audio before uploading to social media?
It's strongly recommended. Platforms apply their own loudness normalization (typically around -14 LUFS), and if your audio is too quiet or too loud, the result may sound compressed or distorted. Pre-normalizing gives you control over the final sound. See FFmpeg Audio Normalization Guide for details.
What's the ideal video length for each platform?
There's no single answer — it depends on content type and audience. But here's what the algorithms tend to favor:
| Platform | Sweet Spot | Max Length |
|---|---|---|
| YouTube Shorts | 30–60s | 3 min |
| Instagram Reels | 15–30s | 20 min |
| TikTok | 21–34s | 60 min (upload) |
| X | 15–45s | 2 min 20s (free) / 4 hr (Premium) |
| Facebook Reels | 15–30s | No limit (≤90s recommended) |
Wrapping Up
Converting video for social media with FFmpeg comes down to three things: the right resolution (1080×1920), the right codec (H.264 + AAC in MP4), and the right conversion method for your content (crop, pad, or blur background).
The universal preset at the top of this article handles most cases. If you need to process a backlog, the batch script scales to hundreds of files. And if your workflow includes audio normalization or subtitle generation, chain it with the tools from the loudnorm guide and Whisper subtitle guide.
For a full reference of FFmpeg commands beyond social media conversion, see the FFmpeg Usage Guide.