281

How do I resize a video to make it smaller with FFmpeg? (e.g. from 1024x576 to 720x480.)

Mateen Ulhaq
  • 3,558
Alan
  • 2,911
  • 2
  • 11
  • 6

3 Answers3

432

The most basic example is this:

ffmpeg -i input.avi -s 720x480 -c:a copy output.mkv

Using the scale filter will provide more flexibility:

ffmpeg -i input.avi -filter:v scale=720:-1 -c:a copy output.mkv

The -1 will tell ffmpeg to automatically choose the correct height in relation to the provided width to preserve the aspect ratio. -1 can also be used for width if you provide a given height.


One downside of scale when using libx264 is that this encoder requires even values and scale may automatically choose an odd value resulting in an error: width or height not divisible by 2. You can tell scale to choose an even value for a given height (720 in this example):

scale="trunc(oh*a/2)*2:720"

...or a given width (1280 in this example):

scale="1280:trunc(ow/a/2)*2"

Note that your ffmpeg build could complain about not recognizing -c or -filter options. It also may not support scale. In that case you should use a newer ffmpeg, which you can download as a static build, or compile yourself.

slhck
  • 228,104
jimhark
  • 4,466
  • 1
    I tried ffmpeg -i output.mkv -filter:v scale=720:-1 -acodec copy -threads 12 output_shrink.mkv (in ffmpeg version 0.8.6-6:0.8.6-0ubuntu0.12.10.1) but got the error Unrecognized option 'filter:v' – doug65536 Apr 26 '13 at 15:41
  • 11
    After digging through the man page for ffmpeg several times I found that instead of -filter:v, the option appears to have been changed to -vf. – doug65536 Apr 26 '13 at 15:51
  • 6
    @doug65536 -filter:v and -vf are both fine. The Ubuntu version you were using is broken and outdated—it's not really FFmpeg's ffmpeg, but the binary supplied by Libav (the FFmpeg fork) under the same name. – slhck Jul 26 '13 at 06:41
  • This answer seems to be outdated, -filter:v doesn't work for me at all. – MightyPork Dec 24 '14 at 12:07
  • 1
    @MightyPork probably your ffmpeg build is outdated - what problems happen?. Anyway, this really helped me (with ffmpeg version 2.4.10) to reduce the size of some massive videos to free up some space - thanks! – Wilf Jun 24 '15 at 21:32
  • ffmpeg may be deprecated, see here and here – nutty about natty Jun 29 '15 at 09:57
  • I have to use "-c copy", but in other side I want to resize screen. How can I achieve this? – Dr.jacky Dec 14 '15 at 12:48
  • 1
    What does the -c:a copy flag do? I can't seem to find it in the documentation. – Brian Feb 05 '16 at 20:53
  • 5
    '-c' is short for -codec, ':a' specifies audio stream(s), 'copy' specifies the copy codec, which copies the stream(s) (in this case audio) without reencoding. Basically the audio streams will pass through. This is common when you are only manipulating the video stream. – jimhark Feb 05 '16 at 23:27
  • I was 1-pixel too large after scaling so I added a 1-pixel crop as described in this answer to a similar question: https://unix.stackexchange.com/questions/190431/convert-a-video-to-a-fixed-screen-size-by-cropping-and-resizing – Nick Jan 22 '18 at 00:22
  • 22
    You can tell scale to provide even value by using scale=720:-2 – Barafu Albino May 30 '18 at 17:38
  • Not working with syntax 720x480 but works with 720:480 as in answer below but it also hangs at a place – Rushi M Thakker Aug 29 '19 at 05:19
  • 1
    if by "smaller size" one also means file size, then using H.265 will typically give better (smaller) results than H.264, e.g., ffmpeg ... -c:v libx265 -vtag hvc1 ... and optionally setting -crf and/or a -preset value (see https://trac.ffmpeg.org/wiki/Encode/H.265 ) – michael Mar 01 '21 at 07:31
  • 2
    The syntax of scale with a negative size (which asks a divisibility and keep ratio approximately) may seem practical, but i prefer the scale options force_original_aspect_ratio=decrease and force_divisible_by=2 along with one or two dimensions, because it is much more obvious than relying on the negative arbitrary convention. I have no idea of which option belongs to which ffmpeg version so i do not know how relevant it is. – Link-akro Sep 16 '21 at 23:23
83

I use following commands to do rescaling for videos and images. For fixed width and height -

ffmpeg -i input.avi -vf scale="720:480" output.avi

and if you want to retain aspect ratio just give height as -1 and it will automatically resize based on the width -

ffmpeg -i input.avi -vf scale="720:-1" output.avi

If you want to scale based on input size e.g. lets say reduce the width/height to half you can do -

ffmpeg -i input.avi -vf scale="iw/2:ih/2" output.avi

NOTE :

iw : input width
ih : input height

Static build can be downloaded from - https://johnvansickle.com/ffmpeg/

Documentation : https://ffmpeg.org/ffmpeg.html#filter_005foption

0

Using your GPU instead of CPU:

ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i "input_file.mp4"
-c:a copy -vf "scale_cuda=-2:480" -c:v h264_nvenc "output_file.mp4"

You'll need an NVIDIA graphics card that supports CUDA hardware acceleration.

This worked for me (in Feb. 2024) using FFmpeg v6.0-essentials (from gyan.dev) on Windows 10 Pro with a NVIDIA GeForce GTX 960.


Details:

  1. From the NVIDIA FFmpeg Transcoding Guide:
  • -hwaccel cuda chooses appropriate hw accelerator
  • -hwaccel_output_format cuda keeps the decoded frames in GPU memory
  • -c:v h264_nvenc selects the NVIDIA hardware accelerated H.264 encoder

Without the -hwaccel cuda -hwaccel_output_format cuda option, the decoded raw frames would be copied back to system memory via the PCIe bus, shown in figure 3. Later, the same image would be copied back to GPU memory via PCIe to encode on the GPU. These two additional transfers create latency due to the transfer time and will increase PCIe bandwidth occupancy.

See also:

  1. -vf "scale_cuda=-2:480" scales to a 480px height and a width calculated to keep the aspect ratio. The 2 in -2 makes sure the width is divisible by 2 - see FFmpeg's scale options:

width, w

height, h

Set the output video dimension expression. Default value is the input dimension.

If the width or w value is 0, the input width is used for the output. If the height or h value is 0, the input height is used for the output.

If one and only one of the values is -n with n >= 1, the scale filter will use a value that maintains the aspect ratio of the input image, calculated from the other specified dimension. After that it will, however, make sure that the calculated dimension is divisible by n and adjust the value if necessary.

If both values are -n with n >= 1, the behavior will be identical to both values being set to 0 as previously detailed.

  1. ⚠️ Some formats or filters are not supported by the GPU, so you may need to use both GPU + CPU. See "Mixing CPU and GPU processing" in the NVIDIA FFmpeg Transcoding Guide:

Sometimes it might be necessary to mix CPU and GPU processing. For example you may need to decode on the CPU, because the format is unsupported on the GPU decoder, or because a filter is not available on the GPU. In those cases, you can’t use the -hwaccel cuvid or -hwaccel cuda flag. Instead, you need to manage uploading the data from system to GPU memory using the hwupload_cuda filter.

In the example below, an H.264 stream is decoded on the GPU and downloaded to system memory since -hwaccel cuvid is not set. The fade filter is applied in system memory and the processed image uploaded to GPU memory using the hwupload_cuda filter. Finally, the image is scaled using scale_npp and encoded on the GPU.

ffmpeg -vsync 0 -c:v h264_cuvid -i input.264 -vf "fade,hwupload_cuda,scale_npp=1280:720" -c:v h264_nvenc output.264

Read this to learn more about scale_npp vs. scale_cuda.


Credits: this post, this one, and this one pointed me in the right direction to figure out the proper syntax for hardware acceleration with CUDA.

Narvarth
  • 164
  • 1
  • 5