· 4 min read
Rotate a video with FFmpeg, no re-encoding
Using -display_rotation with -c copy to write MP4 rotation metadata, and why the older -metadata:s:v rotate=N recipe silently does nothing now.
ffmpeg -display_rotation:v:0 90 -i bbb5.mp4 -c copy rotated.mp4
Requires FFmpeg 6.0 or newer (February 2023). Stream copy, no re-encoding — finishes in milliseconds regardless of file length. Throughout, bbb5.mp4 is shorthand for big_buck_bunny_720p_5sec.mp4; substitute your own file.
The angle is in counter-clockwise degrees. For 90° clockwise (the usual “phone video plays on its side” fix), use -90 or 270 in place of 90.

Left: original. Middle: -display_rotation:v:0 90 (90° counter-clockwise). Right: -display_rotation:v:0 -90 (90° clockwise).
Why this works, and why the old recipe doesn’t
-c copy doesn’t decode frames. Rotation lives in display-matrix side data attached to the video stream; the muxer writes that side-data into the container header and packets pass through untouched. Martin Storsjö set the carve-out in 2015: “such side data isn’t copied into the output stream (except when doing stream copy).”
The old recipe still circulating online:
ffmpeg -i bbb5.mp4 -c copy -metadata:s:v:0 rotate=90 rotated.mp4
Silently broken on MP4/MOV in current FFmpeg. Exit 0, file written, no rotation flag. The history:
-
2017 — wm4 deprecates the metadata route (Tested-by Michael Niedermayer), with the rationale that the metadata API was unsafe: “user tags could ‘leak’ into it, creating unintended features or bugs.”
-
2021 — Andreas Rheinhardt stops the MOV/MP4 muxer from exporting the rotate tag.
-
2024 — confirmed on ffmpeg-user when a user reports
-metadata:s:v rotate=180 -c copydoes nothing: “That is deprecated and does not work.”
The replacement, -display_rotation, was added by Jan Ekström in October 2022 and shipped with FFmpeg 6.0. From the official ffmpeg manual:
When the video is being transcoded (rather than copied) and -autorotate is enabled, the video will be rotated at the filtering stage. Otherwise, the metadata will be written into the output file if the muxer supports it.
Container coverage
| Container | Behavior |
|---|---|
| MP4, MOV | Display matrix in the tkhd track header; -display_rotation writes it |
| MKV | TAG:ROTATE tag (Matroska has no display matrix); both -display_rotation and the legacy -metadata:s:v:0 rotate=N still work |
| WebM, AVI | No rotation field; both syntaxes silently do nothing — re-encode required |
The flag isn’t universally honored downstream either. YouTube ignores it on upload, VLC’s trim/convert can strip it, and a videohelp thread catalogs editors that display the file as if no rotation existed: VirtualDub 2, Magix, AviDemux, plus DaVinci Resolve’s proxy generator.
For mirror-image fixes, -display_hflip and -display_vflip are the companion booleans (no value, same input-per-stream syntax):
ffmpeg -display_hflip -i bbb5.mp4 -c copy mirrored.mp4
When you have to re-encode
Three cases push you back to decoding: the downstream player ignores rotation metadata, the container has no rotation field (WebM, AVI), or you’re on FFmpeg 5.x or older. All three end at transpose:
ffmpeg -i bbb5.mp4 -vf transpose=1 -c:a copy rotated.mp4
Modes:
- 0 — counter-clockwise + vertical flip
- 1 — clockwise
- 2 — counter-clockwise
- 3 — clockwise + vertical flip
If -display_rotation “does nothing” on a file that already has rotation metadata, you’re on FFmpeg 6.0 or 6.1 — upgrade. James Almer’s August 2025 fix made the option actually override existing rotation; before that, on already-rotated files it could be silently ignored.