FFmpeg Zoompan: Camera Movement on High-Res Canvas

This article explains how to use FFmpeg's zoompan filter to execute smooth panning and zooming across a high-resolution canvas without losing image quality. You will learn how the filter operates, how to bypass its default downscaling behavior, and how to construct commands for linear pans, gradual zooms, and combined cinematic camera paths.

The Default Resolution Pitfall

By default, the zoompan filter sets its working viewport and output resolution to 1280x720. If you input an ultra-high-resolution image (such as 4K, 8K, or a wide panorama), FFmpeg will downscale the entire canvas to 720p before cropping and zooming, resulting in blurry, pixelated footage.

To maintain full canvas fidelity, you must explicitly define the output size using the s parameter or process the frame dimensions dynamically within the filter.

Key Zoompan Parameters

The zoompan filter relies on several key variables and options:

  • z: The zoom factor. Evaluated each frame. z=1 displays the base crop window; z=2 zooms in by 2x.
  • x and y: The top-left coordinates of the crop area on the source canvas.
  • d: Duration of the effect in total output frames.
  • s: Output video resolution (e.g., 1920x1080).
  • fps: Frame rate of the generated video (defaults to 25).
  • on: The current output frame count, starting from 0.

Example 1: Horizontal Pan Across a Wide Image

To move the camera smoothly from the left side of a high-resolution image to the right without zooming, set a fixed zoom level and increment the x coordinate on every frame.

ffmpeg -loop 1 -i input.jpg -vf "zoompan=z=1:x='on*(iw-ow)/300':y='(ih-oh)/2':d=300:s=1920x1080:fps=30" -t 10 -c:v libx264 -pix_fmt yuv420p pan_horizontal.mp4
  • d=300 and fps=30 produce a 10-second sequence (300 frames / 30 fps).
  • x='on*(iw-ow)/300' slides the crop window from frame 0 (x = 0) to frame 300 (x = input width minus output width).
  • y='(ih-oh)/2' centers the camera vertically.

Example 2: Smooth Zoom-In on a High-Resolution Canvas

To zoom into a specific point on the canvas, increment z on each frame while updating x and y to keep the target centered.

ffmpeg -loop 1 -i input.jpg -vf "zoompan=z='min(zoom+0.0015,1.5)':x='(iw/2)-(iw/zoom/2)':y='(ih/2)-(ih/zoom/2)':d=300:s=1920x1080:fps=30" -t 10 -c:v libx264 -pix_fmt yuv420p zoom_center.mp4
  • z='min(zoom+0.0015,1.5)' gradually increases the zoom factor from 1.0 to 1.5.
  • x='(iw/2)-(iw/zoom/2)' and y='(ih/2)-(ih/zoom/2)' ensure the zoom centers on the middle of the source canvas by recalculating the visible window relative to the current zoom level.

Example 3: Diagonal Pan with Simultaneous Zoom

To move diagonally while zooming in toward an off-center region:

ffmpeg -loop 1 -i input.jpg -vf "zoompan=z='min(zoom+0.002,1.8)':x='on*2':y='on*1.5':d=300:s=1920x1080:fps=30" -t 10 -c:v libx264 -pix_fmt yuv420p pan_and_zoom.mp4
  • x='on*2' shifts the viewport 2 pixels rightward per frame.
  • y='on*1.5' shifts the viewport 1.5 pixels downward per frame.
  • Ensure that x + (iw/zoom) and y + (ih/zoom) do not exceed the original image boundaries (iw and ih), otherwise the filter will clamp or distort the edge of the frame.

Best Practices for Smooth Output

  1. Coordinate Rounding: If you observe jitter during slow movements, it is often due to pixel rounding in the integer crop coordinates. Upscaling the source image using the scale filter prior to zoompan provides finer sub-pixel movement steps before the final frame is rendered.
  2. Pixel Format: Always append -pix_fmt yuv420p when encoding with libx264 to ensure the generated MP4 file is compatible with web browsers and standard media players.