FFmpeg recipe
FFmpeg: Rotate a Video 90° (Lossless Metadata)
Two approaches: change container rotation metadata (lossless, instant, but some players ignore it), or re-encode with the transpose filter (slower, universal).
Command
# Lossless metadata rotation (instant, but some players ignore):
ffmpeg -i input.mp4 -metadata:s:v rotate=90 -c copy -y output_rotated.mp4
# Re-encode (universal):
ffmpeg -i input.mp4 -vf "transpose=1" -c:v libx264 -crf 23 -c:a copy -y output_rotated.mp4Prefer no terminal?
Use the Video Rotator in your browser
What each flag does
| -i | Input file. Can be a video, audio, or image. Repeat for multiple inputs. |
|---|---|
| -c copy | Stream-copy: no re-encoding. Output is bit-identical between cut points. Fastest possible. |
| -c:v | Video codec for output. e.g. libx264, libx265, libvpx-vp9. |
| -crf | Constant Rate Factor — quality target (lower = better, larger file). 23 is visually lossless for libx264. |
| -c:a | Audio codec for output. e.g. aac, libmp3lame, copy. |
| transpose=1 | 0 = 90° counterclockwise + flip, 1 = 90° clockwise, 2 = 90° counterclockwise, 3 = 90° clockwise + flip. |
Notes & gotchas
- For 180°, use -vf "transpose=1,transpose=1" or hflip,vflip.
- iPhone videos sometimes already have rotation metadata that flips them — check with ffprobe before assuming orientation.
Check it worked
ffprobe -v error -show_entries stream=width,height -of csv=p=0 output.mp4Width and height swapped relative to the source.
What to change
| The metadata version is instant and fragile | It sets a flag and copies the streams. Players that honour the flag rotate; the rest show the original orientation. |
|---|---|
| transpose bakes it in | 0 is 90 counter-clockwise, 1 is 90 clockwise, 2 is 90 counter-clockwise with vertical flip, 3 is 90 clockwise with flip. |
| Clear the old flag | If you rotate with transpose on a file that already has a rotation flag, add -metadata:s:v rotate=0 or it will be rotated twice. |
If it fails
The video still appears the original way up.
Why: The file carries a rotation flag in its metadata and the player is applying it on top of your rotation.
Fix: Clear the flag with -metadata:s:v rotate=0 after rotating the pixels.
Rotation had no effect at all with -c copy.
Why: Stream copy cannot change pixels, so only metadata could have changed.
Fix: Re-encode with the transpose filter, or set only the rotation metadata if a flag is all you need.