Maintaining aspect ratio with FFmpeg

FfmpegVideo ProcessingAspect Ratio

Ffmpeg Problem Overview


I need to convert a bunch of video files using FFmpeg. I run a Bash file that converts all the files nicely, however there is a problem if a file converted is not in 16:9 format.

As I am fixing the size of the screen to -s 720x400, if the aspect ratio of the original is 4:3, FFmpeg creates a 16:9 output file, screwing up the aspect ratio.

Is there a setting that allows setting an aspect ratio as the main parameter, with size being adjusted (for example, by fixing an X or Y dimension only)?

Ffmpeg Solutions


Solution 1 - Ffmpeg

-vf "scale=640:-1"

works great until you will encounter error

[libx264 @ 0x2f08120] height not divisible by 2 (640x853)

So most generic approach is use filter expressions:

scale=640:trunc(ow/a/2)*2

It takes output width (ow), divides it by aspect ratio (a), divides by 2, truncates digits after decimal point and multiplies by 2. It guarantees that resulting height is divisible by 2.

Credits to ffmpeg trac

UPDATE

As comments pointed out simpler way would be to use -vf "scale=640:-2". Credits to @BradWerth for elegant solution

Solution 2 - Ffmpeg

For example:

1920x1080 aspect ratio 16:9 => 640x480 aspect 4:3:

ffmpeg -y -i import.media -aspect 16:9 scale=640x360,pad=640:480:0:60:black output.media

aspect ratio 16:9 , size width 640pixel => height 360pixel:
With final output size 640x480, and pad 60pixel black image (top and bottom):

"-vf scale=640x360,pad=640:480:0:60:black"

Solution 3 - Ffmpeg

I've asked this a long time ago, but I've actually got a solution which was not known to me at the time -- in order to keep the aspect ratio, you should use the video filter scale, which is a very powerful filter.

You can simply use it like this:

-vf "scale=640:-1" 

Which will fix the width and supply the height required to keep the aspect ratio. But you can also use many other options and even mathematical functions, check the documentation here - http://ffmpeg.org/ffmpeg.html#scale

Solution 4 - Ffmpeg

Although most of these answers are great, I was looking for a command that could resize to a target dimension (width or height) while maintaining aspect ratio. I was able to accomplish this using ffmpeg's Expression Evaluation.

Here's the relevant video filter, with a target dimension of 512:

-vf "thumbnail,scale='if(gt(iw,ih),512,trunc(oh*a/2)*2)':'if(gt(iw,ih),trunc(ow/a/2)*2,512)'"


For the output width:

'if(gt(iw,ih),512,trunc(oh*a/2)*2)'

If width is greater than height, return the target, otherwise, return the proportional width.


For the output height:

'if(gt(iw,ih),trunc(ow/a/2)*2,512)'

If width is greater than height, return the proportional height, otherwise, return the target.

Solution 5 - Ffmpeg

Use force_original_aspect_ratio, from the ffmpeg trac:

ffmpeg -i input.mp4 -vf scale=720:400:force_original_aspect_ratio=decrease output.mp4

Solution 6 - Ffmpeg

If you are trying to fit a bounding box, then using force_original_aspect_ratio as per xmedeko's answer is a good starting point.

However, this does not work if your input video has a weird size and you are encoding to a format that requires the dimensions to be divisible by 2, resulting in an error.

In this case, you can use expression evaluation in the scale function, like that used in Charlie's answer.

Assuming an output bounding box of 720x400:

-vf "scale='trunc(min(1,min(720/iw,400/ih))*iw/2)*2':'trunc(min(1,min(720/iw,400/ih))*ih/2)*2'"

To break this down:

  • min(1,min(720/iw,400/ih) finds the scaling factor to fit within the bounding box (from here), constraining it to a maximum of 1 to ensure it only downscales, and
  • trunc(<scaling factor>*iw/2)*2 and trunc(<scaling factor>*iw/2)*2 ensure that the dimensions are divisible by 2 by dividing by 2, making the result an integer, then multiplying it back by 2.

This eliminates the need for finding the dimensions of the input video prior to encoding.

Solution 7 - Ffmpeg

you can use ffmpeg -i to get the dimensions of the original file, and use that in your commands for the encode. What platform are you using ffmpeg on?

Solution 8 - Ffmpeg

If '-aspect x:y' is present and output file format is ISO Media File Format (mp4) then ffmpeg adds pasp-atom (PixelAspectRatioBox) into stsd-box in the video track to indicate to players the expected aspect ratio. Players should scale video frames respectively. Not needed to scale video before encoding or transcoding to fit it to the aspect ratio, it should be performed by a player.

Solution 9 - Ffmpeg

As ffmpeg requires to have width/height dividable by 2, and I suppose you want to specify one of the dimensions, this would be the option:

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

Solution 10 - Ffmpeg

The above answers are great, but most of them assume specific video dimensions and don't operate on a generic aspect ratio.

You can pad the video to fit any aspect ratio, regardless of specific dimensions, using this:

-vf 'pad=x=(ow-iw)/2:y=(oh-ih)/2:aspect=16/9'

I use the ratio 16/9 in my example. The above is a shortcut for just doing something more manual like this:

pad='max(iw,(16/9)*ih)':'max(ih,iw/(16/9))':(ow-iw)/2:(oh-ih)/2

That might output odd-sized (not even) video dimensions, so you can make sure the output is even like this:

pad='trunc(max(iw,(16/9)*ih)/2)*2':'trunc(max(ih,iw/(16/9))/2)*2':(ow-iw)/2:(oh-ih)/2

But really all you need is pad=x=(ow-iw)/2:y=(oh-ih)/2:aspect=16/9

For all of the above examples you'll get an error if the INPUT video has odd-sized dimensions. Even pad=iw:ih gives error if the input is odd-sized. Normally you wouldn't ever have odd-sized input, but if you do you can fix it by first using this filter: pad='mod(iw,2)+iw':'mod(ih,2)+ih'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question0-alphaView Question on Stackoverflow
Solution 1 - FfmpegmenteView Answer on Stackoverflow
Solution 2 - Ffmpegcool2ikouView Answer on Stackoverflow
Solution 3 - Ffmpeg0-alphaView Answer on Stackoverflow
Solution 4 - FfmpegCharlieView Answer on Stackoverflow
Solution 5 - FfmpegxmedekoView Answer on Stackoverflow
Solution 6 - FfmpegtvStaticView Answer on Stackoverflow
Solution 7 - Ffmpegbox86rowhView Answer on Stackoverflow
Solution 8 - FfmpegShevach RiabtsevView Answer on Stackoverflow
Solution 9 - FfmpegrapttorView Answer on Stackoverflow
Solution 10 - FfmpegChrisView Answer on Stackoverflow