wiki:Scaling

FFmpeg has got a very powerful scale filter, which can be used to accomplish various tasks. Some of them are listed here. More can be found in the official documentation.

Warning:

  • When using -filter_complex/-lavfi, the default scaling flags are not applied, so the default algorithm is not bicubic, but bilinear. To achieve the same results for complex filter chains, you have to explicitly set the scaling algorithm via the flags=bicubic option. That was fixed in 9f14396a5103ec80893db801035ece5d14c0d3c5.
  • In some cases, FFmpeg will set the Sample Aspect Ratio to compensate for the ratio change. You have to manually set the SAR value to 1:1 to make the players display it in the way you want. For example:
    ffmpeg -i input.mp4 -vf scale=320:240,setsar=1:1 output.mp4
    
    The above example is highly misleading because setsar=1:1 is equivalent to setsar=r=1:max=1. In this special case it accidentally gives the correct result SAR=1:1, but for example setsar=2:3 would give the wrong result SAR=2:1. The correct syntax for SAR=2:3 is setsar=2/3, or setsar=1 for the above example.
  • When going from BGR (not RGB) to yuv420p the conversion is broken (off-by-one). Use -vf scale=flags=accurate_rnd to fix that.
  • yuvjxxxp pixel formats are deprecated. Yet for x265 the workaround was implemented, but not for jpeg2000 and AV1. For those -vf scale=out_range=pc should be used.
  • Conversion from YCbCr limited to RGB 16 bit is broken, use zscale instead of swscale
  • Limited range RGB is not supported at all.
  • Dither can be turned off using -vf scale=sws_dither=none
  • One should always remember that YCbCr 4:4:4 8 bit is not enough to preserve RGB 8 bit, YCbCr 4:4:4 10 bit is required.
  • The default for matrix in untagged input and output is always limited BT.601

In all the examples, the starting image (input.jpg) will be this one (535×346 pixels):

Simple Rescaling

If you need to simply resize your video to a specific size (e.g 320×240), you can use the scale filter in its most basic form:

ffmpeg -i input.avi -vf scale=320:240 output.avi

Same works for images too:

ffmpeg -i input.jpg -vf scale=320:240 output_320x240.png

The resulting image will look like this:

As you can see, the aspect ratio is not the same as in the original image, so the image appears stretched.

Keeping the Aspect Ratio

If we'd like to keep the aspect ratio, we need to specify only one component, either width or height, and set the other component to -1. For example, this command line:

ffmpeg -i input.jpg -vf scale=320:-1 output_320.png

will set the width of the output image to 320 pixels and will calculate the height of the output image according to the aspect ratio of the input image. The resulting image will have a dimension of 320×207 pixels.

Some codecs require the size of width and height to be a multiple of n. You can achieve this by setting the width or height to -n:

ffmpeg -i input.jpg -vf scale=320:-2 output_320.png

The output will now be 320×206 pixels.

Using Variables

There are also some useful variables which can be used instead of numbers, to specify width and height of the output image.

For example, if you want to stretch the image in such a way to only double the width of the input image, you can use something like this (iw = input width, ih = input height):

ffmpeg -i input.jpg -vf "scale=iw*2:ih" input_double_width.png

The output image will look like this:

If you want to half the size of the picture, just multiply by .5 or divide by 2:

ffmpeg -i input.jpg -vf "scale=iw*.5:ih*.5" input_half_size.png
ffmpeg -i input.jpg -vf "scale=iw/2:ih/2" input_half_size.png

Alternatively, you can scale only one component and keep the aspect ratio by setting the other component to -1:

ffmpeg -i input.jpg -vf "scale=iw*.5:-1" input_half_size.png

Avoiding Upscaling

Sometimes you want to scale an image, but avoid upscaling it if its dimensions are too low. This can be done using min expressions:

ffmpeg -i input.jpg -vf "scale='min(320,iw)':'min(240,ih)'" input_not_upscaled.png

The output width will be evaluated to be the minimum of 320 and the input width. If you have an imput image that is only 240 pixels wide, the result of the min function will be 240 – this will be your target value.

Fitting into a Rectangle / Statically-sized Player

Sometimes you need to scale the input image so that it fits into a specified rectangle, e.g. when consolidating material from different sources.

You can achieve this with the force_original_aspect_ratio option. It has two possible values:

  • decrease: The output video dimensions will automatically be decreased if needed.
  • increase: The output video dimensions will automatically be increased if needed.

This allows you to force the image to fit into a 320×240 box, downscaling it with the correct aspect ratio:

ffmpeg -i input.jpg -vf scale=w=320:h=240:force_original_aspect_ratio=decrease output_320.png

This produces our 320×207 image that we had seen before.

You may have additional constraints such as adding black bars (pillar- and letterboxing) to fill up the remaining space when scaling to a certain rectangle. You can additionally add a black border using the pad filter:

ffmpeg -i input.jpg -vf "scale=320:240:force_original_aspect_ratio=decrease,pad=320:240:(ow-iw)/2:(oh-ih)/2" output_320_padding.png

More examples can be found in this Super User answer.

scale2ref

If you need to scale one video to match another without pre-defining the dimensions, see the scale2ref filter.

Two videos are provided for input and output. The 1st input is scaled and the 2nd input is unchanged, but used for reference. For example, to put 2 videos side-by-side and have the 2nd video scale to match the first:

ffmpeg -i vid1.mp4 -i vid2.mp4 -filter_complex "[1:v][0:v]scale2ref=oh*mdar:h=in_h:[v1][v0];[v0][v1]hstack[vo]" -map "[vo]" ./output-video.mp4

Specifying scaling algorithm

You can specify which algorithm is used for resizing with the -sws_flags option. For example, to use bilinear instead of the default bicubic scaling:

ffmpeg -i test.tif -vf scale=504:376 -sws_flags bilinear out.bmp

List of scaling algorithms with their defaults, if any:
fast_bilinear
bilinear
bicubic
experimental
neighbor
area
bicublin, Bicubic scaling algorithm for the luma component, bilinear for chroma components.
gauss
sinc
lanczos, The default width (alpha) is 3 and can be changed by setting param0.
spline

See the scaler documentation for more info.

Setting param0 for lanczos is done via

-vf scale=1920x1080:flags=lanczos:param0=3

To set multiple flags you can combine them with a + sign. For example:

-sws_flags lanczos+full_chroma_inp

You can also specify the options directly in the scale filter, for example:

-vf scale=1920x1080:flags=lanczos

Chroma sample location

FFmpeg does not see the chroma sample location on either limited or full range file, so you should specify it by hand when going to .rgb (or upsampled from 4:2:0 to 4:4:4 .yuv):

ffmpeg -i cosmos.mkv -vf 'scale=in_h_chr_pos=0:in_v_chr_pos=128' -pix_fmt rgb24 qnfvarejwnfe3.rgb //for left
ffmpeg -i cosmos.mkv -vf 'scale=in_h_chr_pos=0:in_v_chr_pos=0' -pix_fmt rgb24 qnfvarejwnfe3.rgb //for top-left

To create BT.2020-NCL matrix with top-left chroma this can be used (if the source image is not using bt.2020 primaries the color managment must be done first on linear data, also correct transfer must be tagged, either SDR or HDR one, again this requires color managment):

-vf scale=out_color_matrix=bt2020nc:out_h_chr_pos=0:out_v_chr_pos=0

To change chroma sample location in VUI in HEVC to 0 (left) with -c copy this can be used (2 would be top-left, -1 will remove any sample location from VUI, all 0, 1, 2, 3, 4, 5 sample locations are possible):

ffmpeg -i file.mp4 -c copy -bsf:v hevc_metadata=chroma_sample_loc_type=0 file1.mp4
Last modified 8 months ago Last modified on Jul 21, 2023, 9:26:13 AM

Attachments (5)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.