>FFmpegLab
FFmpeg Guide

ROI Encoding – Region of Interest Encoding

Allocate more bitrate to faces, text, and critical regions while saving bandwidth on backgrounds. Master the addroi filter and qoffset parameter.

You've probably seen it before: a video where the subject's face is sharp and detailed, but the background is a blocky, pixelated mess. This isn't an accident—it's ROI encoding, one of the most powerful and least‑understood features in modern video compression.

ROI (Region of Interest) encoding lets you tell the encoder: "This part of the frame matters more than the rest". The encoder then allocates more bitrate to that region, delivering higher quality where it counts, while saving bits on the background. The result? Better visual quality at the same bitrate—or the same quality at a lower bitrate.[reference:0]

Yet the command‑line documentation is sparse. The addroi filter was added in 2019[reference:1], but most users don't know it exists, and those who do struggle to make it work. This guide changes that.

Key takeaways

The Gap: A Powerful Feature, Almost No Command‑Line Guide

The FFmpeg ROI API was introduced in 2019[reference:2], adding support for ROI-based encoding in libx264, libx265, and libvpx[reference:3]. The addroi filter followed shortly after[reference:4], providing a command‑line interface for attaching ROI metadata to video frames.

Yet the documentation is sparse. The filter's qoffset parameter is explained in technical terms that assume you already understand quantization[reference:5]. Online resources are scattered—a mailing list post here, a code comment there[reference:6]. There's no cohesive guide that walks you through the why and how of ROI encoding from the command line.

This guide fills that gap.

The Symptom: "Why Is My Face Blurry?"

You've encoded a video at a reasonable bitrate. The background looks fine—but the subject's face is a blocky, pixelated mess. You increase the bitrate, and the face improves—but now the file is twice as large.

The problem is that traditional encoding treats every pixel equally. A face and a plain wall get the same bitrate allocation. ROI encoding fixes this by telling the encoder: "This face is important. Give it more bits."

This is especially critical for:

Core Concepts: What Is ROI Encoding?

ROI encoding is a video coding technique that allocates more bitrate to regions of interest and less to background areas[reference:8]. It works by adjusting the quantization parameter (QP) on a per‑region basis[reference:9]:

ROI encoding doesn't require changing the encoder's core behavior. Instead, it provides a unified interface that translates your ROI specifications into the API calls required by each encoder[reference:10].

The key data structure is AVRegionOfInterest[reference:11], which defines a rectangular region and a quality offset. In the command line, this structure is populated by the addroi filter.

The addroi Filter – Your Command‑Line Tool

The addroi filter attaches ROI metadata to video frames[reference:12]. It doesn't change the pixels—it just tells the encoder which regions should get special treatment.

Syntax:

addroi=x:y:w:h:qoffset[:clear]

If you need to define multiple ROIs on the same frame, use multiple addroi filters chained together—they'll accumulate[reference:19].

Understanding qoffset – The Quality Knob

qoffset is the most important—and most misunderstood—parameter in ROI encoding[reference:20].

The range is calibrated so that extreme values indicate the largest possible offset[reference:24]:

In practice, a value of qoffset = -0.1 to -0.3 is often sufficient to make a visible difference[reference:27]. For a 10‑bit H.264 stream where most of the frame is encoded at QP ≈ 30, a qoffset of -0.1 would lower the QP by about 6.3, resulting in noticeably better quality[reference:28].

Practical Example 1: Face Priority Encoding

Let's encode a video where the subject's face (centered in the frame) gets higher quality than the background.

ShareRenders { } Code Config
Generated Code Logs Customize
# Encode with face region at 1080p, center 600x600 area gets better quality
ffmpeg -i input.mp4 -vf "addroi=420:240:600:600:-0.2" -c:v libx264 -crf 23 -b:v 2M -c:a copy output_face_roi.mp4

Breaking it down:

The result? The face is sharper and more detailed, while the background uses fewer bits. At the same overall bitrate, the subjective quality is higher[reference:29].

Practical Example 2: Text Overlay Quality

If your video has important text overlays (subtitles, lower thirds, game HUD), you can prioritize those regions.

ShareRenders { } Code Config
Generated Code Logs Customize
# Prioritize the bottom third of the frame where subtitles appear
ffmpeg -i input.mp4 -vf "addroi=0:720:1920:360:-0.15" -c:v libx264 -crf 23 -b:v 2M -c:a copy output_subtitle_roi.mp4

This ensures that subtitles and lower‑third graphics remain crisp and readable, even at lower bitrates.

Practical Example 3: Multiple ROIs

You can define multiple regions by chaining addroi filters. Each region can have a different qoffset value[reference:30].

ShareRenders { } Code Config
Generated Code Logs Customize
# Two ROIs: face (high priority) and subtitles (medium priority)
ffmpeg -i input.mp4 -vf "addroi=420:240:600:600:-0.3,addroi=0:720:1920:360:-0.1" -c:v libx264 -crf 23 -b:v 2M -c:a copy output_multi_roi.mp4

Important ordering rules: When multiple regions overlap, the first region in the chain takes priority[reference:31]. Regions should be ordered from most to least important, as some encoders have a limited number of region slots[reference:32][reference:33].

The clear parameter removes existing ROIs before adding new ones—use it if you're building a complex filtergraph and need to start fresh[reference:34].

Practical Example 4: Dynamic ROI with zmq

One of the most exciting features of ROI encoding is the ability to move the region in real time during live streaming[reference:35].

ShareRenders { } Code Config
Generated Code Logs Customize
# Start encoding with a dynamic ROI filter listening for zmq commands
ffmpeg -i input.mp4 -vf "addroi=iw-200:ih-200:iw/2:ih/2:-1,zmq" -c:v libx264 -crf 23 -f mpegts udp://127.0.0.1:1234

# In another terminal, move the ROI to a new position
echo "Parsed_addroi_0 reinit x=200:y=200:w=300:h=300" | ./zmqsend

This is incredibly powerful for live streaming[reference:36]. Imagine a security camera that follows a moving subject, always keeping the face in the high‑quality ROI[reference:37]. Or a sports broadcast that tracks the ball. The zmq filter makes this possible.

Encoder Support – What Works Where

ROI encoding is not supported by all encoders. Here's what works[reference:38]:

EncoderROI SupportNotes
libx264✅ Full supportSupports different QP offsets for different macroblocks[reference:39]
libx265✅ Full supportSimilar to libx264, with CTU‑level control[reference:40]
libvpx (VP8/VP9)✅ Full supportRequires aq_mode=0, cpu_used>=5, and deadline=realtime[reference:41]
h264_vaapi / hevc_vaapi✅ Partial supportHardware‑accelerated, but may have region count limits[reference:42]
nvenc (NVIDIA)⚠️ LimitedSome support via NVENC API, but not fully integrated
libaom-av1❌ Not yetROI API support is still in development
Software encoders (e.g., mpeg4)❌ NoOnly modern encoders with ROI APIs support this

Important: The FFmpeg ROI API was introduced in version 4.2.1[reference:43]. Ensure you're using a recent build.

Debugging Common ROI Issues

Here are the most frequent problems and their solutions.

ProblemLikely CauseFix
No visible quality difference qoffset is too small or encoder doesn't support ROI Try qoffset=-0.5; check encoder support; use -c:v libx264
Encoder ignores ROI Using an unsupported encoder or older FFmpeg Use libx264, libx265, or libvpx with FFmpeg ≥ 4.2.1
Region is misaligned Encoder requires region alignment (e.g., 16‑pixel boundaries for H.264) Align x, y, w, h to multiples of 16 (or 32 for H.265)[reference:44]
Multiple regions not working Encoder has a limited number of region slots Order regions from most to least important; truncate the list if needed[reference:45]
VP8/VP9 ROI not working Missing required encoder parameters Set aq_mode=0, cpu_used>=5, and deadline=realtime[reference:46]
Dynamic ROI with zmq not responding zmq filter not built or filter name mismatch Check that FFmpeg was built with --enable-libzmq; use the correct filter name in the command

Visualize ROI with the FFmpegLab IDE

ROI encoding is much easier to debug with visual feedback. The FFmpegLab IDE lets you:

Here's how ROI visualization looks in the FFmpegLab IDE.

ShareRenders { } Code Config
Generated Code Logs Customize
# Visual ROI configuration
# Drag rectangles on the preview to define regions; adjust qoffset with sliders

The IDE shows you exactly what's happening—which regions are defined, what qoffset values are applied, and how the encoder will prioritize quality. You can drag rectangles to define regions, adjust qoffset with sliders, and see the visual feedback in real time.

Frequently Asked Questions (FAQ)

What is ROI encoding and why would I use it?

ROI (Region of Interest) encoding allocates more bitrate to important regions of a frame (like faces or text) and less to backgrounds[reference:47]. This improves visual quality where it matters most without increasing the overall bitrate—perfect for surveillance, video conferencing, and live streaming[reference:48].

How do I use ROI encoding from the command line?

Use the addroi filter: -vf "addroi=x:y:w:h:qoffset"[reference:49]. For example, -vf "addroi=420:240:600:600:-0.2" gives better quality to a 600×600 region centered in a 1080p frame. Chain multiple addroi filters for multiple regions.

What does qoffset mean?

qoffset controls the quality offset, ranging from -1.0 to +1.0[reference:50]. Negative values give better quality (lower QP, more bits). Positive values give worse quality (higher QP, fewer bits)[reference:51]. A value of -0.2 is often enough to make a visible difference[reference:52].

Which encoders support ROI encoding?

libx264, libx265, and libvpx (VP8/VP9) have full support[reference:53]. Hardware encoders like h264_vaapi and hevc_vaapi have partial support[reference:54]. libaom-av1 and older encoders do not yet support ROI. Ensure you're using FFmpeg ≥ 4.2.1[reference:55].

Can I move the ROI during encoding?

Yes—using the zmq filter with addroi[reference:56]. You can send commands to update the ROI position in real time. This is ideal for live streaming where the subject moves[reference:57]. Example: echo "Parsed_addroi_0 reinit x=200:y=200:w=300:h=300" | ./zmqsend[reference:58].

Why isn't my ROI encoding working?

Common reasons: (1) Using an unsupported encoder—use libx264, libx265, or libvpx; (2) qoffset is too small—try -0.5; (3) Region coordinates need alignment—align x, y, w, h to multiples of 16 for H.264[reference:59]; (4) For VP8/VP9, ensure aq_mode=0 and cpu_used>=5[reference:60].

Final Word

ROI encoding is one of the most powerful—and least‑understood—features in modern FFmpeg. By telling the encoder which parts of the frame matter most, you can deliver better visual quality at the same bitrate, or the same quality at a lower bitrate.

The addroi filter makes this accessible from the command line[reference:61]. With qoffset values ranging from -1.0 to +1.0, you have fine‑grained control over quality allocation[reference:62]. Multiple regions can be defined[reference:63], and dynamic ROI with zmq opens the door to real‑time applications like live streaming and surveillance[reference:64].

With the FFmpegLab IDE's visual feedback, you can experiment, debug, and perfect your ROI settings without the guesswork. Drag rectangles, adjust qoffset with sliders, and see the results in real time.

Next time you're encoding a video where some parts matter more than others, reach for ROI encoding. Your viewers—and your bandwidth budget—will thank you.

✦  Fresh from the render queue

Better FFmpeg workflows, delivered.

Get practical commands, new templates, and deep-dive guides for the edits that are usually hardest to get right.

✓  Copy-pasteable commands    ✓  Editor templates    ✓  No noise
One useful email at a time.