“My downloaded video has black bars on the top and bottom.” “A 4:3 source plays with thick black bars on the sides of my widescreen monitor.” Forum answers usually just say -vf crop=W:H:X:Y and stop there — leaving you to figure out how to find the right values, why libx264 rejects odd dimensions, and how to handle bars that aren’t pure black. This guide walks through the full workflow with cropdetect automatic detection, manual calculation, and the reverse pad workflow for letterbox-output platforms.
Tested with: FFmpeg 8.1 (Windows / macOS / Linux)
What You’ll Learn
- How to auto-detect black-bar regions with the
cropdetectfilter - How to apply detected values to the
cropfilter in one paste - The even-dimensions trap for libx264 + yuv420p and how to fix it
- Tuning the
limitthreshold when bars aren’t pure black - Letterbox (top/bottom) vs. pillarbox (left/right) distinctions
- Adding bars instead of removing them with the
padfilter - A batch-processing script for many files at once
Why Black Bars Appear
| Case | Situation | What you see |
|---|---|---|
| Letterbox | 2.35:1 cinema content on a 16:9 display | Bars on top and bottom |
| Pillarbox | 4:3 (1.33:1) source on a 16:9 display | Bars on left and right |
| Windowbox | 4:3 source rendered at 2.35:1 | Bars on all four sides |
| Burned-in bars | Black pixels physically encoded into the file | Real pixel data |
Only the last case — bars that exist as actual pixels in the file — needs crop. Bars that the player adds dynamically to preserve aspect ratio aren’t part of the file and don’t need touching.
Auto-detect with cropdetect
Basic detection command
ffmpeg -i input.mp4 -vf cropdetect -f null -
| Part | Meaning |
|---|---|
-vf cropdetect | Analyze each frame for black-bar regions |
-f null - | Discard the output, only run analysis |
The console fills with per-frame log lines whose tail looks like:
[Parsed_cropdetect_0 @ 0x...] x1:0 x2:1919 y1:140 y2:939 w:1920 h:800 x:0 y:140 crop=1920:800:0:140
The crop=1920:800:0:140 token at the end is the value to paste straight into the next step.
Speed up with a sampled window
Running cropdetect across a feature-length film is slow. If the opening logo fills the frame, the detection on the first few seconds will be wrong anyway. Sample a representative slice from the middle of the video instead:
ffmpeg -ss 60 -i input.mp4 -t 5 -vf cropdetect -f null -
-ss 60 seeks to the 1-minute mark; -t 5 analyzes only 5 seconds. That’s enough to nail the active picture region of most modern content.
Tuning limit, round, and reset
cropdetect takes three useful arguments.
| Argument | Default | Meaning |
|---|---|---|
limit | 24 (8-bit) | Luma upper bound for “black”. Lower = stricter, higher = looser |
round | 16 | Snap detected dimensions to multiples of this. Helps encoder compatibility |
reset | 0 | Reset the running detection every N frames. Useful for scene-by-scene variation |
# Tighter threshold (limit=16), finer rounding (round=2)
ffmpeg -ss 60 -i input.mp4 -t 5 -vf cropdetect=24:16:0 -f null -
Lowering limit too far makes dark scene content look like black bars. Start with the default 24 and tweak only if detection fails.
Apply Detected Values to the crop Filter
Take the cropdetect output (e.g. crop=1920:800:0:140) and pass it directly to -vf. The example below uses resolution-independent expressions so it works on any input — substitute the literal numbers from your detection run when you want exact pixel counts.
ffmpeg -i input.mp4 -vf "crop=in_w:in_h-40:0:20" -c:a copy output.mp4
| Part | Meaning |
|---|---|
crop=W:H:X:Y | Cut a W×H rectangle starting at top-left (X, Y) |
in_w / in_h | Input width / height variables (works without knowing the resolution) |
-c:a copy | Copy audio without re-encoding (fast, lossless) |
The example above shaves 20 pixels off the top and bottom. For a 1920×1080 source with 140-pixel bars you would write crop=1920:800:0:140 instead.
Important:
cropalways re-encodes the video. The output codec is determined by the container if you don’t specify one (mp4 → libx264 by default). For quality control, set-c:v libx264 -crf 18explicitly.
Recommended quality-aware form
ffmpeg -i input.mp4 -vf "crop=in_w:in_h-40:0:20" \
-c:v libx264 -crf 18 -preset slow \
-c:a copy output.mp4
-crf 18 is widely considered visually lossless. -preset slow improves compression efficiency at the cost of encode time — a fair trade for archival output.
Can I crop without re-encoding?
# Wrong
ffmpeg -i input.mp4 -vf "crop=in_w:in_h-40:0:20" -c copy output.mp4
-c copy means stream copy, which is incompatible with -vf filters. Filters mutate pixel data, so re-encoding is mandatory. If you need to avoid re-encoding entirely, the only option is a non-FFmpeg “smart cut” tool that splits on keyframes — and even that won’t actually crop pixels.
Manual Calculation
When cropdetect mis-detects (e.g., very dark scene material) or you want to crop to a specific ratio, calculate by hand.
Letterbox example (top/bottom bars)
For a 1920×1080 source with 140-pixel bars on top and bottom: height = 1080 − 140×2 = 800, Y offset = 140. The general form for “shave N pixels off top and bottom”:
# Shave 20px off top and bottom (same idea as 1920x1080 → 1920x1040)
ffmpeg -i input.mp4 -vf "crop=in_w:in_h-40:0:20" -c:a copy output.mp4
Pillarbox example (left/right bars)
For a 1920×1080 frame with a 4:3 (1440×1080) image inside and 240-pixel bars on each side: width = 1920 − 240×2 = 1440, X offset = 240. General form:
# Shave 40px off left and right
ffmpeg -i input.mp4 -vf "crop=in_w-80:in_h:40:0" -c:a copy output.mp4
Center crop (shorthand)
Omit X and Y for a centered crop:
# Cut a centered 4:3 region from the input (assumes in_h*4/3 <= in_w)
ffmpeg -i input.mp4 -vf "crop=in_h*4/3:in_h" -c:a copy output.mp4
The Even-Dimensions Trap and Fix
H.264 / H.265 with the most-compatible yuv420p pixel format requires both width and height to be multiples of 2. Otherwise:
[libx264 @ 0x...] height not divisible by 2 (1920x801)
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0
cropdetect’s default round=16 avoids this. The trap shows up when you set round=2, manually compute odd numbers, or trust a scene-detected width.
Fix 1: force even with arithmetic
# floor(W/2)*2 forces an even result
ffmpeg -i input.mp4 -vf "crop=floor(in_w/2)*2:floor(in_h/2)*2" -c:a copy output.mp4
in_w / in_h are the input width / height. The floor(x/2)*2 idiom subtracts 1 if the value is odd. Drop this into any reusable script.
Fix 2: relax the yuv420p requirement
yuv444p and yuv422p allow odd dimensions, but playback compatibility drops sharply on TVs, mobile, and embedded players.
# Allow odd dimensions by switching to yuv444p
ffmpeg -i input.mp4 -vf "crop=in_w-1:in_h-1:0:0" \
-c:v libx264 -pix_fmt yuv444p -c:a copy output.mp4
For anything you’ll redistribute, keep yuv420p and even dimensions.
When Bars Aren’t Pure Black
Noisy sources or aggressively compressed video can have “almost black” bars at (16, 16, 16) or (24, 24, 24) instead of pure (0, 0, 0). The default limit=24 may not catch them.
# Loosen the limit to 64
ffmpeg -ss 60 -i input.mp4 -t 5 -vf cropdetect=64:2:0 -f null -
The three positional args are limit:round:reset. Setting limit too high will eat into dark scene content, so always sanity-check the detected rectangle visually:
# Preview the detected crop without re-encoding
ffplay -vf "crop=1920:800:0:140" input.mp4
If ffplay is unavailable, render a 5-second test segment first and watch it before processing the full file.
Adding Black Bars Instead (pad)
YouTube, Instagram Feed, and similar platforms expect a fixed aspect ratio. If you submit a 4:3 or vertical clip, they may auto-crop it. Better to pre-pad with pad:
4:3 → 16:9 with pillarboxes
ffmpeg -i input.mp4 -vf "scale=1080:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black" -c:a copy output.mp4
| Part | Meaning |
|---|---|
scale=...:force_original_aspect_ratio=decrease | Fit content into 1080 height while preserving ratio |
pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black | Center the scaled frame inside a 1920×1080 black canvas |
(ow-iw)/2 is “(output width − input width) divided by 2” — the X offset for a centered placement.
Vertical → 16:9 with pillarboxes
To turn a 1080×1920 phone clip into a 1920×1080 letterbox-style upload:
ffmpeg -i input.mp4 -vf "scale=-2:1080,pad=1920:1080:(ow-iw)/2:0:black" -c:a copy output.mp4
The vertical content is scaled to 1080 height, then padded sideways to reach 1920 width.
Pad with a non-black color
ffmpeg -i input.mp4 -vf "pad=1920:1080:(ow-iw)/2:(oh-ih)/2:white" -c:a copy output.mp4
The last pad argument is the color. Named colors (white, red) and 0xRRGGBB hex literals both work.
Batch Processing Script
To apply the same crop to many files:
for f in *.mp4; do
ffmpeg -nostdin -i "$f" -vf "crop=1920:800:0:140" -c:v libx264 -crf 20 -c:a copy "cropped_${f}" -y
done
To auto-detect per file (each may have a different bar size):
for f in *.mp4; do
CROP=$(ffmpeg -ss 60 -i "$f" -t 3 -vf cropdetect -f null - 2>&1 | \
grep -oE 'crop=[0-9:]+' | tail -1)
ffmpeg -nostdin -i "$f" -vf "$CROP" -c:v libx264 -crf 20 -c:a copy "cropped_${f}" -y
done
grep -oE 'crop=[0-9:]+' | tail -1 keeps only the last detected crop value, which is the most stable result after the running average has settled.
FAQ
Q1. Why does just cropping degrade quality?
A. crop rewrites pixel data, so re-encoding is mandatory. Output quality depends on your codec settings. Specify -c:v libx264 -crf 18 (visually lossless) or lower for archival use. -c copy cannot be combined with -vf filters.
Q2. The video has bars that change size between scenes — what now?
A. Pass reset=N to cropdetect (e.g. cropdetect=24:16:30) so the running detection resets every N frames. Pick the smallest detected rectangle (the most conservative crop) so no scene gets cut. If scenes vary too dramatically, split the file at the boundaries and crop each segment individually.
Q3. I want to pad a vertical phone clip into a 16:9 frame.
A. See the “Vertical → 16:9 with pillarboxes” section. scale=-2:1080,pad=1920:1080:(ow-iw)/2:0:black centers the vertical clip inside a horizontal canvas with black sides.
Q4. Should crop come before or after scale in the filter chain?
A. Generally crop first, then scale. Cropping reduces the pixel count before scaling, which is faster and avoids scaling artifacts in regions that are about to be discarded. Example: -vf "crop=1920:800:0:140,scale=1280:-2".
Q5. I get Width is not divisible by 2 errors.
A. yuv420p won’t accept odd dimensions. Either trim a pixel off the crop value or use crop=floor(in_w/2)*2:floor(in_h/2)*2 to force even sizes. Keeping cropdetect’s default round=16 sidesteps this entirely.
Q6. cropdetect output is jittering between values every frame.
A. Dark or fast-motion scenes can momentarily shift the detection. Use -ss plus -t to sample a representative bright section (e.g. mid-scene daylight) and trust that result for the whole file.
Related Articles
- Resize Video — scale Filter Guide
- Vertical Video to Horizontal — Complete Guide
- Video Format Conversion — MP4 / MOV / WebM
- FFmpeg Command Basic Syntax
Tested with ffmpeg 8.1 / Windows 11 Primary source: ffmpeg.org/ffmpeg-filters.html#crop / ffmpeg.org/ffmpeg-filters.html#cropdetect / ffmpeg.org/ffmpeg-filters.html#pad