Ahosting Logo
Knowledge Base

How to Resize, Crop and Rotate Video with FFmpeg

Three filter habits that avoid the common failuresScaling, cropping, rotating, paddingUse minus two, not minus oneso the calculated dimensionstays divisible by twoAny filter means re-encodingthere is no such thing as acopied resizeCrop before scalecheaper, and the numbers meanwhat you expectRotation metadatasometimes the file is fine andonly the flag is wrongPaddingto fit a target frame withoutdistorting the pictureCheck the resultffprobe the output, not just thecommand exit codeOdd dimensions are rejected by most encoders, which is why minus two exists and minus one causes the error peoplereport.

Resizing, cropping and rotating are FFmpeg's video filters, and they follow one grammar. Learn how a filter chain is written and all three become the same operation with different names.

Resizing

ffmpeg -i input.mp4 -vf scale=1280:720 output.mp4

Fixed dimensions distort the picture if the aspect ratio differs. Use -1 for one side and FFmpeg calculates it:

ffmpeg -i input.mp4 -vf scale=1280:-1 output.mp4

That is right most of the time, and it produces the error described next often enough to be worth knowing about.

"Height not divisible by 2"

H.264 requires even dimensions. A source of 1920×1080 scaled to width 1280 calculates a height of 720, which is fine, but an unusual source can produce an odd number, and the encode fails.

Use -2 instead of -1. It does the same calculation and rounds to an even number:

ffmpeg -i input.mp4 -vf scale=1280:-2 output.mp4

Make this your default. It behaves identically when the maths works out and it does not fail when it does not.

Scaling down, not up

Enlarging a video does not add detail. It produces a larger file containing the same information, softer.

To cap the size without enlarging small inputs:

-vf "scale='min(1280,iw)':-2"

Anything wider than 1280 is reduced; anything smaller is left alone. In a batch pipeline processing files you did not create, this matters: without it, a 640-pixel clip gets upscaled to 1280 and costs bandwidth for nothing.

Cropping

ffmpeg -i input.mp4 -vf crop=1280:720:100:50 output.mp4

Width, height, then the x and y of the top-left corner. Omit the offsets and FFmpeg centres the crop, which is usually what you want:

ffmpeg -i input.mp4 -vf crop=1280:720 output.mp4

You can express it relative to the input using iw and ih. Removing 100 pixels from every edge:

-vf crop=iw-200:ih-200

That works on any input size, which a fixed number does not, and in a batch job the inputs vary.

Finding black bars automatically

To remove letterboxing without measuring it by hand, let FFmpeg detect it:

ffmpeg -i input.mp4 -vf cropdetect -f null -

It prints a suggested crop for each frame it examines. Take the value it settles on and use it in a real command.

Sample from the middle of the file in place of the start. Opening titles are often on black, and detection there suggests cropping most of the picture away.

Rotating

Two ways, and they are not equivalent.

Actually rotate the pixels, which re-encodes:

ffmpeg -i input.mp4 -vf "transpose=1" output.mp4

Values: 0 counter-clockwise with flip, 1 clockwise, 2 counter-clockwise, 3 clockwise with flip. For 180 degrees, apply transpose twice, or use -vf "hflip,vflip".

Change the rotation flag only, which is instant:

ffmpeg -i input.mp4 -c copy -metadata:s:v:0 rotate=90 output.mp4

No re-encoding, no quality loss, and it relies on the player honouring the flag. Most do; some web players and some editing software do not.

For anything going to the web, rotate the pixels. The flag approach is right when the file stays in a controlled environment.

Sideways phone video

A phone video that plays upright and converts sideways had a rotation flag that the conversion dropped.

Modern FFmpeg usually applies it automatically. When it does not, check for the flag first, using ffprobe goes over reading it, then rotate explicitly, and clear the flag so a player does not rotate it a second time.

Combining filters

Separate them with commas, and they run left to right:

-vf "crop=iw-200:ih-200,scale=1280:-2"

Order changes both the result and the cost. Cropping before scaling means the scaler works on fewer pixels, which is faster; scaling before cropping means your crop coordinates apply to the scaled size, not the original.

Decide which coordinate system you are working in and write the chain to match.

Padding instead of cropping

When you need a fixed output size without cutting anything off, scale to fit and pad the rest:

-vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2"

The picture is scaled to fit inside the target, then centred on a background. This is how you produce a consistent output size from mixed sources without distorting anything, useful when a player expects one dimension.

Any filter means re-encoding

Worth stating plainly: -vf and -c copy cannot be used together. Filtering requires decoding the video, so a filter always costs an encode.

The rotation-flag method above is the exception, and it is an exception precisely because it changes metadata rather than filtering.

So do all your filtering in one command rather than chaining several. Each pass is another generation of quality loss, and combining filters costs nothing extra. There is more on the rest of the encode settings in FFmpeg performance tips.

These are all filter chains, and the same syntax extends to watermarks, multiple outputs and audio. Understanding FFmpeg Filters: -vf and -filter_complex sets out the rules behind it.

One ordering mistake here cannot be undone: scaling interlaced source before deinterlacing it bakes the combing in permanently. How to Deinterlace and Change Frame Rate with FFmpeg goes into spotting it first.

Handheld footage needs one more step before any of this, and it must come first because it changes the framing. How to Stabilize Shaky Video with FFmpeg explains the crop it costs.

Read the source dimensions before writing the command

Filters are written against assumptions about the input, and the assumption is frequently wrong for material from a phone.

ffprobe -v error -select_streams v:0 \
  -show_entries stream=width,height,sample_aspect_ratio,display_aspect_ratio:stream_tags=rotate \
  -of default=nw=1 input.mp4

The rotation tag is the one that causes confusion. A file recorded sideways carries a tag telling players to rotate it, so it appears correct while its stored dimensions are the other way round.

A crop or scale expressed in the displayed orientation then applies to the stored one, which produces a result nobody expects. Reading the tag first is what explains it.

Scale with the right algorithm for the direction

Reducing and enlarging are different problems and the default handles one of them well.

ffmpeg -i in.mp4 -vf "scale=1280:-2:flags=lanczos" -c:a copy small.mp4
ffmpeg -i in.mp4 -vf "scale=1280:-2:flags=bicubic" -c:a copy alt.mp4

For reduction, a sharper algorithm preserves detail that the default softens. For enlargement, no algorithm adds information that is not there, and a sharper one mostly emphasises the artefacts.

The expression producing an even height matters regardless. An odd number is rejected by the encoder, which is the single most common failure when scaling to a fixed width.

Combine filters into one pass

Running a crop and then a scale as separate commands encodes the material twice.

ffmpeg -i in.mp4 -vf "crop=1280:720:0:100,scale=854:-2" -c:a copy out.mp4
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 out.mp4

Chaining them applies both in a single pass, at one generation of quality loss instead of two, in roughly half the time.

Order matters within the chain. Cropping before scaling means the scale operates on fewer pixels and is faster; scaling first and cropping after discards work that was just done.