DEV Community

Preecha
Preecha

Posted on

How to upscale and enhance video quality with FFmpeg: scaling, denoising, stabilization

TL;DR

FFmpeg can upscale video with -vf "scale=1920:1080:flags=lanczos". Lanczos is the best built-in scaling algorithm for upscaling. Use hqdn3d to reduce grain while preserving edges, and use vidstab for camera shake stabilization with a two-pass workflow. For a full enhancement pipeline, chain denoising, scaling, and stabilization in one FFmpeg filter graph.

Try Apidog today

Introduction

Video quality enhancement with FFmpeg is more than changing resolution. A practical enhancement workflow usually targets three separate problems:

  • Low resolution or pixelation: upscale with scale
  • Noise or grain: denoise with hqdn3d
  • Camera shake: stabilize with vidstab

This guide shows each step independently, then combines them into one implementation-focused pipeline.

Scaling algorithms

When FFmpeg upscales video, it has to create new pixels. The scaling algorithm controls how those pixels are estimated.

Algorithm Speed Quality Best for
neighbor Fastest Lowest Pixel art
bilinear Fast Low Speed-critical jobs
bicubic Medium Good General downscaling
lanczos Slower Best Upscaling

For most video upscaling tasks, start with lanczos.

Upscale 720p to 1080p

ffmpeg -i input_720p.mp4 \
  -vf "scale=1920:1080:flags=lanczos" \
  -c:v libx264 -crf 20 \
  output_1080p.mp4
Enter fullscreen mode Exit fullscreen mode

Maintain aspect ratio

Use -2 for the height so FFmpeg calculates it automatically while keeping the value divisible by 2.

ffmpeg -i input.mp4 \
  -vf "scale=1920:-2:flags=lanczos" \
  -c:v libx264 -crf 20 \
  output.mp4
Enter fullscreen mode Exit fullscreen mode

Scale to 4K

ffmpeg -i input.mp4 \
  -vf "scale=3840:-2:flags=lanczos" \
  -c:v libx264 -crf 18 -preset slow \
  output_4k.mp4
Enter fullscreen mode Exit fullscreen mode

-preset slow tells x264 to spend more time optimizing compression. This is useful for higher-resolution output where file size and quality matter more.

Denoising with hqdn3d

The hqdn3d filter performs high-quality 3D denoising. It reduces grain and noise while preserving edge detail better than simple blur filters.

ffmpeg -i noisy_video.mp4 \
  -vf "hqdn3d=4:3:6:4.5" \
  -c:v libx264 -crf 20 \
  denoised.mp4
Enter fullscreen mode Exit fullscreen mode

The parameter format is:

hqdn3d=luma_spatial:chroma_spatial:luma_temporal:chroma_temporal
Enter fullscreen mode Exit fullscreen mode
Parameter Range Purpose Default
luma_spatial 0-16 Spatial noise in brightness channel 4
chroma_spatial 0-16 Spatial noise in color channels 3
luma_temporal 0-16 Temporal smoothing in brightness 6
chroma_temporal 0-16 Temporal smoothing in color 4.5

Stronger denoising

Use stronger values for visibly grainy footage:

ffmpeg -i grainy.mp4 \
  -vf "hqdn3d=10:8:15:10" \
  -c:v libx264 -crf 20 \
  clean.mp4
Enter fullscreen mode Exit fullscreen mode

Higher values remove more noise, but they can blur fine detail. Test on a short clip before processing a full video.

Light denoising

Use lighter values when you want to preserve detail:

ffmpeg -i video.mp4 \
  -vf "hqdn3d=2:1.5:3:2.5" \
  -c:v libx264 -crf 20 \
  output.mp4
Enter fullscreen mode Exit fullscreen mode

Stabilization with vidstab

The vidstab filter uses a two-pass workflow:

  1. Analyze motion and write transform data.
  2. Apply stabilization using that transform data.

Check whether your FFmpeg build includes vidstab:

ffmpeg -filters | grep vidstab
Enter fullscreen mode Exit fullscreen mode

On macOS, the Homebrew FFmpeg package includes it:

brew install ffmpeg
Enter fullscreen mode Exit fullscreen mode

Pass 1: Analyze motion

ffmpeg -i shaky_video.mp4 \
  -vf "vidstabdetect=stepsize=6:shakiness=8:accuracy=9:result=transform.trf" \
  -f null -
Enter fullscreen mode Exit fullscreen mode

Key options:

  • shakiness=8: expected camera shake from 1-10
  • accuracy=9: motion detection accuracy from 1-15
  • result=transform.trf: output transform file
  • -f null -: discard video output because this pass only creates the transform file

Pass 2: Apply stabilization

ffmpeg -i shaky_video.mp4 \
  -vf "vidstabtransform=input=transform.trf:zoom=1:smoothing=10" \
  -c:v libx264 -crf 20 \
  stabilized.mp4
Enter fullscreen mode Exit fullscreen mode

Key options:

  • zoom=1: adds 1% zoom to compensate for edge cropping
  • smoothing=10: controls how smooth the camera path becomes

If black borders appear, increase zoom.

More aggressive stabilization

ffmpeg -i video.mp4 \
  -vf "vidstabtransform=input=transform.trf:zoom=3:smoothing=30:optzoom=1" \
  -c:v libx264 -crf 20 \
  stable.mp4
Enter fullscreen mode Exit fullscreen mode

optzoom=1 lets FFmpeg optimize zoom to avoid borders.

Combined quality enhancement pipeline

After running the vidstabdetect pass, combine denoising, scaling, and stabilization in one filter chain:

ffmpeg -i source.mp4 \
  -vf "hqdn3d=4:3:6:4.5,scale=1920:-2:flags=lanczos,vidstabtransform=input=transform.trf:zoom=1:smoothing=10" \
  -c:v libx264 -crf 18 -preset slow \
  -c:a copy \
  enhanced.mp4
Enter fullscreen mode Exit fullscreen mode

Recommended order:

  1. Denoise first to reduce artifacts before scaling.
  2. Scale second so noise is not enlarged.
  3. Stabilize last using the transform file from vidstabdetect.

Before running the combined command, create the transform file:

ffmpeg -i source.mp4 \
  -vf "vidstabdetect=stepsize=6:shakiness=8:accuracy=9:result=transform.trf" \
  -f null -
Enter fullscreen mode Exit fullscreen mode

Sharpening filter

If footage looks soft rather than noisy, use unsharp.

ffmpeg -i video.mp4 \
  -vf "unsharp=5:5:1.5:5:5:0.5" \
  -c:v libx264 -crf 20 \
  sharpened.mp4
Enter fullscreen mode Exit fullscreen mode

Parameter format:

unsharp=lx:ly:la:cx:cy:ca
Enter fullscreen mode Exit fullscreen mode

Where:

  • lx:ly: luma matrix size in pixels
  • la: luma amount, where positive values sharpen and negative values blur
  • cx:cy:ca: chroma matrix size and amount

Light sharpening:

ffmpeg -i video.mp4 \
  -vf "unsharp=3:3:0.5:3:3:0.0" \
  -c:v libx264 -crf 20 \
  output.mp4
Enter fullscreen mode Exit fullscreen mode

Strong sharpening:

ffmpeg -i video.mp4 \
  -vf "unsharp=5:5:2.5:5:5:0.0" \
  -c:v libx264 -crf 20 \
  output.mp4
Enter fullscreen mode Exit fullscreen mode

Performance considerations

Enhancement filters are compute-heavy. Approximate processing times for a 10-minute 1080p video:

Pipeline Estimated time
Scale only 2-5 minutes
Scale + hqdn3d 5-10 minutes
Scale + hqdn3d + vidstab 15-25 minutes

Use -preset to balance encoding speed and file size:

Preset Behavior
ultrafast Fastest encoding, larger files
fast Moderate speed and size
slow Slower encoding, smaller files for a given CRF
veryslow Usually not worth the extra time compared with slow

For batch processing, you can use GNU parallel:

ls *.mp4 | parallel ffmpeg -i {} \
  -vf "scale=1920:-2:flags=lanczos" \
  -c:v libx264 -crf 20 \
  enhanced_{/}
Enter fullscreen mode Exit fullscreen mode

Connecting to AI video upscaling APIs

FFmpeg filters are fast and free, but AI-powered upscaling can produce better results for low-quality or damaged footage. AI upscaling uses neural models instead of algorithmic interpolation.

WaveSpeedAI offers AI upscaling models through an API:

POST https://api.wavespeed.ai/api/v2/wavespeed-ai/video-enhance
Authorization: Bearer {{WAVESPEED_API_KEY}}
Content-Type: application/json

{
  "video_url": "https://storage.example.com/source-video.mp4",
  "scale": 2,
  "enhance": true
}
Enter fullscreen mode Exit fullscreen mode

Test the API request before integrating it into your app.

Add basic assertions:

  • Status code is 200
  • Response body contains an id field

Then poll the status endpoint for completion and compare the AI-upscaled result against FFmpeg’s Lanczos output.

Use FFmpeg for standard enhancement work. Use API-based AI upscaling when output quality matters more than processing cost or runtime.

FAQ

Is Lanczos better than bicubic for all cases?

For upscaling, yes. For downscaling, bicubic is often faster with comparable quality. Lanczos is more computationally expensive.

Does vidstab work on phone footage?

Yes. Phone footage often benefits from stabilization. For handheld phone video, set shakiness high, usually between 8 and 10.

How much zoom is needed to hide stabilization borders?

Typically 3-8%, depending on how shaky the source is. Use optzoom=1 to let FFmpeg calculate it automatically.

Can FFmpeg enhance low-resolution historical footage?

FFmpeg filters can help, but they have limits. AI-based upscaling tools, such as ESRGAN or specialized video enhancement APIs, usually produce better results on severely degraded footage.

Does denoising slow down playback?

No. Denoising happens during conversion. The exported video plays normally.

Top comments (0)