Quite often, when using a smartphone, we shoot videos in portrait mode, also known as vertical video, or even rotated 180 degrees. Depending on the software or app you're using to edit, preview or share, the videos might appear rotated or even upside down.
This might also happen if you start recording in one orientation and then rotate the smartphone before the device has a chance to update it's orientation settings. Video rotation is one tricky, but simple issue to overcome and in this guide we will show you how to fix rotated videos using FFMpeg.
Videos and images created by mobile devices including iPhones and Android phones contain a lot of metadata like GPS position, device make and model, fps, rotation and many others.
In this article we'll focus on the rotation - it represents the orientation of the device. It has 4 possible values (0, 90, 180 and 270) and it stores how the device was held when starting the recording:
portrait | vertical | portrait | vertical |
0° | 90° | 180° | 270° |
However, it's not only the rotation that needs to be fixed, it's also the width and height of the video that needs to be adjusted as these can also be he wrong way round.
This tutorial will show you how to use FFmpeg to rotate videos and get the right orientation, width and height with just a couple of commands.
This guide covers Windows, Mac and Linux distributions - the apps we'll use are platform independent.
FFmpeg is the leading multimedia framework used to manipulate and transform video files easily. ExifTool is a free and open-source program for reading and modifying metadata and exif information.
We prepared a few sample videos if you want to experiment using different video rotations - please check the Test Media repository for free to use samples.
For this article we used the h1920_w1080_f30_a9-16_r90.mp4 video, which was shot using a Samsung S9 Android device in vertical, portrait orientation.
First let's take a look at the metadata of the video we want to fix. We can use ExifTool, ffprobe or ffmpeg.
exiftool h1920_w1080_f30_a9-16_r90.mp4
This command will return all metadata from the video file. We only need to retrieve the rotation and the dimensions, so we can pass the -Rotation
, -ImageWidth
and -ImageHeight
options.
You can pass them individually:
exiftool -Rotation h1920_w1080_f30_a9-16_r90.mp4
or all at once:
exiftool -Rotation -ImageWidth -ImageHeight h1920_w1080_f30_a9-16_r90.mp4
The output confirms what we described - the rotation is 90 and the width and height are switched:
Rotation : 90
Image Width : 1920
Image Height : 1080
Because the video is shot in vertical mode, we would expect the width to be 1080 and the height, 1920 pixels.
FFprobe is an utility that comes bundled with FFmpeg. It analyzes the video metadata and prints the information in human readable format
ffprobe -i h1920_w1080_f30_a9-16_r90.mp4
or
ffmpeg -i h1920_w1080_f30_a9-16_r90.mp4
We can see in the output that rotate
is set to 90
:
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709/bt709/smpte170m), 1920x1080, 14067 kb/s,
SAR 1:1 DAR 16:9, 30.01 fps, 30 tbr, 90k tbn, 180k tbc (default)
Metadata:
rotate : 90
creation_time : 2020-04-18T05:27:06.000000Z
handler_name : VideoHandle
Side data:
displaymatrix: rotation of -90.00 degrees
To filter the FFprobe info we can use different commands:
To retrieve just the rotation:
ffprobe -v error -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1:nk=1 -i h1920_w1080_f30_a9-16_r90.mp4
To retrieve the width:
ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=nw=1:nk=1 -i h1920_w1080_f30_a9-16_r90.mp4
We'll get rotation = 90 and width = 1920
To fix the video rotation so it is compatible with the widest range of software and viewing applications we will need to reset the rotation and then swap around the width and height.
First we need to reset the rotation to 0:
ffmpeg -i h1920_w1080_f30_a9-16_r90.mp4 -c copy -metadata:s:v:0 rotate=0 temp.mp4
This will create a copy of the video and reset the rotation metadata to 0. However, the width and height are still the wrong way round. You might notice the thumbnail of the newly generated video is rotated.
Let's check the metadata just to make sure we got the rotation right:
exiftool -Rotation -ImageWidth -ImageHeight temp.mp4
Rotation : 0
Image Width : 1920
Image Height : 1080
The rotation is correct but the width should be 1080 and height 1920.
Try it again with ffprobe:
ffprobe -i temp.mp4
We'll see the Rotation info was dropped - so it is now set to 0:
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709/bt709/smpte170m), 1920x1080, 14067 kb/s,
SAR 1:1 DAR 16:9, 30.01 fps, 30 tbr, 90k tbn, 180k tbc (default)
Metadata:
handler_name : VideoHandler
We now need to re-encode the video to ensure the width and height will be flipped so that the dimensions are correct:
ffmpeg -i temp.mp4 -vf "transpose=1" -crf 23 -c:a copy rotated.mp4
The -crf (Constant Rate Factor) value is a quality setting used for mp4 video compression. For our example we used 23 which gives a file size close to the original.
The transpose feature uses static values; you can use either the integer or the string value:
Integer | String | Value |
---|---|---|
0 | cclock_flip | 90° counterclockwise and vertical flip (default) |
1 | clock | 90° clockwise |
2 | cclock | 90° counterclockwise |
3 | clock_flip | 90° clockwise and vertical flip |
The same command can be run, passing the corresponding string to the transpose parameter:
ffmpeg -i temp.mp4 -vf "transpose=clock" -crf 23 -c:a copy rotated.mp4
To rotate videos by 180 degrees counter clockwise, you to need to add the transpose parameter twice like below.
ffmpeg -i temp.mp4 -vf "transpose=2,transpose=2" -crf 23 -c:a copy rotated.mp4
or
ffmpeg -i temp.mp4 -vf "transpose=cclock,transpose=cclock" -crf 23 -c:a copy rotated.mp4
One last step, to confirm the width and height are correct:
exiftool -Rotation -ImageWidth -ImageHeight rotated.mp4
There it is:
Rotation : 0
Image Width : 1080
Image Height : 1920
If we need one more confirmation:
ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=nw=1:nk=1 -i rotated.mp4
the width is confirmed at 1080.
ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=nw=1:nk=1 -i rotated.mp4
will confirm the height is 1920.
Once you have resolved any rotation issues with your video it is now ready to be used in an edit and rendered by the Shotstack video editing API.
Here is the JSON we post to the API to render a vertical video. In this example we are using a fixed version of our original h1920_w1080_f30_a9-16_r90.mp4
file. The aspect ratio and the fit parameters ensure we render a vertical video:
{
"timeline": {
"background": "#000000",
"soundtrack": {
"src": "https://shotstack-assets.s3-ap-southeast-2.amazonaws.com/music/unminus/palmtrees.mp3",
"effect": "fadeOut"
},
"tracks": [
{
"clips": [
{
"asset": {
"type": "video",
"src": "https://shotstack-video-hosting.s3-ap-southeast-2.amazonaws.com/h1920_w1080_f30_a9-16_r90-fixed.mp4"
},
"start": 0,
"length": 10,
"fit": "contain"
}
]
}
]
},
"output": {
"format": "mp4",
"resolution": "sd",
"aspectRatio": "9:16"
}
}
Which creates the video below:
Icons made by prettycons from Flaticon
curl --request POST 'https://api.shotstack.io/v1/render' \
--header 'x-api-key: YOUR_API_KEY' \
--data-raw '{
"timeline": {
"tracks": [
{
"clips": [
{
"asset": {
"type": "video",
"src": "https://shotstack-assets.s3.amazonaws.com/footage/beach-overhead.mp4"
},
"start": 0,
"length": "auto"
}
]
}
]
},
"output": {
"format": "mp4",
"size": {
"width": 1280,
"height": 720
}
}
}'