Skip to main content

oximedia_codec/rate_control/
mod.rs

1// Clippy allows for common pedantic lints in rate control math
2#![allow(clippy::cast_lossless)]
3#![allow(clippy::cast_precision_loss)]
4#![allow(clippy::cast_possible_truncation)]
5#![allow(clippy::cast_sign_loss)]
6#![allow(clippy::similar_names)]
7#![allow(clippy::unused_self)]
8
9//! Rate control module for video encoders.
10//!
11//! This module provides comprehensive rate control algorithms for video encoding:
12//!
13//! - **CQP** (Constant QP): Fixed quantization parameter per frame type
14//! - **CBR** (Constant Bitrate): Maintains steady bitrate with buffer model
15//! - **VBR** (Variable Bitrate): Variable bitrate with optional two-pass
16//! - **CRF** (Constant Rate Factor): Quality-based rate control
17//!
18//! # Architecture
19//!
20//! The rate control system consists of several interconnected components:
21//!
22//! ```text
23//! ┌─────────────────────────────────────────────────────────────────┐
24//! │                        Rate Controller                          │
25//! │  ┌─────────────────────────────────────────────────────────────┐ │
26//! │  │                      Lookahead                               │ │
27//! │  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │ │
28//! │  │  │ Scene Change │  │ Complexity   │  │ Mini-GOP         │   │ │
29//! │  │  │ Detection    │  │ Estimation   │  │ Structure        │   │ │
30//! │  │  └──────────────┘  └──────────────┘  └──────────────────┘   │ │
31//! │  └─────────────────────────────────────────────────────────────┘ │
32//! │  ┌─────────────────────────────────────────────────────────────┐ │
33//! │  │                    Rate Controllers                          │ │
34//! │  │  ┌─────┐  ┌─────┐  ┌─────┐  ┌─────┐                         │ │
35//! │  │  │ CQP │  │ CBR │  │ VBR │  │ CRF │                         │ │
36//! │  │  └─────┘  └─────┘  └─────┘  └─────┘                         │ │
37//! │  └─────────────────────────────────────────────────────────────┘ │
38//! │  ┌─────────────────────────────────────────────────────────────┐ │
39//! │  │                    Support Systems                           │ │
40//! │  │  ┌──────────────┐  ┌──────────────┐                         │ │
41//! │  │  │ Rate Buffer  │  │ Adaptive     │                         │ │
42//! │  │  │ (HRD)        │  │ Quantization │                         │ │
43//! │  │  └──────────────┘  └──────────────┘                         │ │
44//! │  └─────────────────────────────────────────────────────────────┘ │
45//! └─────────────────────────────────────────────────────────────────┘
46//! ```
47//!
48//! # Usage
49//!
50//! ## Simple CQP Encoding
51//!
52//! ```ignore
53//! use oximedia_codec::rate_control::{CqpController, RcConfig};
54//!
55//! let config = RcConfig::cqp(28);
56//! let mut controller = CqpController::new(&config);
57//!
58//! // Get QP for each frame
59//! let output = controller.get_qp(FrameType::Key);
60//! encoder.set_qp(output.qp);
61//! ```
62//!
63//! ## CBR Streaming
64//!
65//! ```ignore
66//! use oximedia_codec::rate_control::{CbrController, RcConfig};
67//!
68//! let config = RcConfig::cbr(5_000_000); // 5 Mbps
69//! let mut controller = CbrController::new(&config);
70//!
71//! // For each frame
72//! let output = controller.get_rc(frame_type);
73//! if !output.drop_frame {
74//!     encoder.set_qp(output.qp);
75//!     // ... encode frame ...
76//!     controller.update(&stats);
77//! }
78//! ```
79//!
80//! ## Quality-Based CRF
81//!
82//! ```ignore
83//! use oximedia_codec::rate_control::{CrfController, RcConfig};
84//!
85//! let config = RcConfig::crf(23.0);
86//! let mut controller = CrfController::new(&config);
87//!
88//! // For each frame
89//! let output = controller.get_rc(frame_type, complexity);
90//! encoder.set_qp(output.qp);
91//! encoder.set_lambda(output.lambda);
92//! ```
93//!
94//! ## Two-Pass VBR
95//!
96//! ```ignore
97//! use oximedia_codec::rate_control::{VbrController, RcConfig};
98//!
99//! // First pass
100//! let config = RcConfig::vbr(5_000_000, 10_000_000);
101//! let mut pass1 = VbrController::new(&config);
102//! pass1.set_pass(1);
103//!
104//! // Analyze all frames...
105//! let first_pass_data = pass1.finalize_first_pass()?;
106//!
107//! // Second pass
108//! let mut pass2 = VbrController::new(&config);
109//! pass2.set_pass(2);
110//! pass2.set_first_pass_data(first_pass_data);
111//!
112//! // Encode with optimal bit allocation
113//! ```
114//!
115//! ## Rate Control Tuning Guide
116//!
117//! OxiMedia exposes four rate control modes through [`RcConfig`]. Each mode targets
118//! a different encoding scenario:
119//!
120//! ### CBR (Constant Bit Rate)
121//!
122//! Best for: live streaming, video conferencing, broadcast contribution links.
123//! The encoder fills a virtual decoder buffer at a fixed pace; frame quality fluctuates
124//! to keep the bitrate steady.
125//!
126//! ```ignore
127//! use oximedia_codec::rate_control::{CbrController, RcConfig};
128//!
129//! // 4 Mbps CBR with a 1-second VBV buffer (buffer_size = target_bitrate by default)
130//! let config = RcConfig::cbr(4_000_000);
131//! let mut controller = CbrController::new(&config);
132//! ```
133//!
134//! Key fields in [`RcConfig`] for CBR:
135//!
136//! - `target_bitrate` — bits per second; set by `RcConfig::cbr(bitrate)`.
137//! - `buffer_size` — VBV/HRD buffer size in bits; defaults to 1× `target_bitrate` (1-second buffer).
138//! - `initial_buffer_fullness` — buffer fill at start of encode (0.0–1.0, default 0.75).
139//!
140//! Increase `buffer_size` to allow larger peaks before the encoder is forced to drop quality.
141//! A 2-second buffer (`2 × target_bitrate`) gives more headroom for complex scenes.
142//!
143//! ### VBR (Variable Bit Rate)
144//!
145//! Best for: VOD encoding where average bitrate matters but short-term peaks are allowed.
146//!
147//! ```ignore
148//! use oximedia_codec::rate_control::{VbrController, RcConfig};
149//!
150//! // Target 3 Mbps average, allow up to 6 Mbps peaks on complex scenes
151//! let config = RcConfig::vbr(3_000_000, 6_000_000);
152//! let mut controller = VbrController::new(&config);
153//! ```
154//!
155//! Key fields in [`RcConfig`] for VBR:
156//!
157//! - `target_bitrate` — average target bitrate.
158//! - `max_bitrate` — peak bitrate ceiling (`Some(max)` set by `RcConfig::vbr`).
159//! - `min_bitrate` — minimum bitrate floor (`None` by default; set manually for ABR).
160//!
161//! Two-pass VBR (`pass1.set_pass(1)` → `pass2.set_pass(2)`) gives better bit allocation
162//! across the whole file by analyzing content complexity in the first pass.
163//!
164//! ### CRF (Constant Rate Factor)
165//!
166//! Best for: archival, high-quality mastering, and any use case where file size should
167//! vary with content complexity to maintain consistent perceptual quality.
168//!
169//! ```ignore
170//! use oximedia_codec::rate_control::{CrfController, RcConfig};
171//!
172//! // CRF 23 — good general-purpose quality (0 = lossless, 63 = worst)
173//! let config = RcConfig::crf(23.0);
174//! let mut controller = CrfController::new(&config);
175//!
176//! // Near-lossless archival: lower CRF = higher quality + larger file
177//! let archival_config = RcConfig::crf(12.0);
178//! ```
179//!
180//! CRF scale reference (AV1/VP9):
181//!
182//! | CRF | Typical use |
183//! |-----|-------------|
184//! | 0–10 | Lossless / near-lossless archival |
185//! | 18–23 | High quality (streaming masters) |
186//! | 24–32 | Good quality (distribution, web) |
187//! | 33–50 | Acceptable quality (preview, mobile) |
188//! | 51–63 | Low quality (thumbnails, drafts) |
189//!
190//! ### CQP (Constant Quantization Parameter)
191//!
192//! Best for: per-frame quality control, frame-level quality analysis, and hardware
193//! encoders that operate in fixed-QP mode.
194//!
195//! ```ignore
196//! use oximedia_codec::rate_control::{CqpController, RcConfig};
197//!
198//! // QP 25: balanced quality (0 = lossless, 63 = worst quality)
199//! let config = RcConfig::cqp(25);
200//! let mut controller = CqpController::new(&config);
201//! ```
202//!
203//! The `initial_qp` field in [`RcConfig`] controls the quantization parameter applied
204//! to all frames. Unlike CRF, there is no buffer feedback — the bitrate varies freely
205//! with content complexity.
206//!
207//! ### Mode Selection Summary
208//!
209//! | Use Case | Mode | `RcConfig` factory |
210//! |----------|------|--------------------|
211//! | Live stream (Twitch/YouTube RTMP) | CBR | `RcConfig::cbr(bitrate)` |
212//! | VOD (Netflix, streaming) | VBR | `RcConfig::vbr(target, max)` |
213//! | Archival master | CRF 12–18 | `RcConfig::crf(15.0)` |
214//! | Frame-level QP control | CQP | `RcConfig::cqp(qp)` |
215//! | Adaptive bitrate ladder | ABR/VBR | `RcConfig::vbr` + `AbrController` |
216
217#![forbid(unsafe_code)]
218
219pub mod abr;
220pub mod allocation;
221pub mod analysis;
222pub mod aq;
223pub mod buffer;
224pub mod cbr;
225pub mod complexity;
226pub mod cqp;
227pub mod crf;
228pub mod lookahead;
229pub mod quantizer;
230pub mod scene_adaptive;
231pub mod simple_rc;
232pub mod types;
233pub mod vbr;
234
235// Re-export main types
236pub use abr::{
237    AbrController, FirstPassStats as AbrFirstPassStats, FramePassStats as AbrFramePassStats,
238};
239pub use allocation::{AllocationResult, AllocationStrategy, BitrateAllocator, GopAllocationStatus};
240pub use analysis::{
241    AnalysisResult, ContentAnalyzer, ContentType, SceneChangeThreshold, TextureMetrics,
242};
243pub use aq::{AdaptiveQuantization, AqMode, AqResult, AqStrength};
244pub use buffer::{BufferModel, RateBuffer, VbvParams};
245pub use cbr::CbrController;
246pub use complexity::{ComplexityEstimator, ComplexityResult, MotionAnalyzer, MotionResult};
247pub use cqp::CqpController;
248pub use crf::{CrfController, QualityPreset};
249pub use lookahead::{
250    AdaptiveAllocation, ContentAdaptiveAllocator, ContentMetrics, Lookahead, LookaheadFrame,
251    MiniGopInfo, SceneChangeDetector, SceneContentType,
252};
253pub use quantizer::{BlockQpMap, QpResult, QpSelector, QpStrategy};
254pub use scene_adaptive::{
255    FrameBitTarget, FrameContentMetrics, Scene as AdaptiveScene, SceneAdaptiveAllocator,
256    SceneAdaptiveConfig, SceneContentType as SceneAdaptiveContentType,
257};
258pub use simple_rc::{
259    SimpleRateControlConfig, SimpleRateControlMode, SimpleRateControlStats, SimpleRateController,
260};
261pub use types::{
262    FrameStats, GopStats, RateControlMode, RcConfig, RcConfigError, RcOutput, RcState,
263};
264pub use vbr::{FirstPassData, VbrController};
265
266/// Create a rate controller based on the configuration mode.
267///
268/// This factory function creates the appropriate controller type based on
269/// the `RateControlMode` specified in the configuration.
270///
271/// # Example
272///
273/// ```ignore
274/// use oximedia_codec::rate_control::{create_controller, RcConfig, RateControlMode};
275///
276/// let config = RcConfig::cbr(5_000_000);
277/// let controller = create_controller(&config);
278/// ```
279#[must_use]
280pub fn create_controller(config: &RcConfig) -> Box<dyn RateController> {
281    match config.mode {
282        RateControlMode::Cqp => Box::new(CqpController::new(config)),
283        RateControlMode::Cbr => Box::new(CbrController::new(config)),
284        RateControlMode::Vbr | RateControlMode::Abr => Box::new(VbrController::new(config)),
285        RateControlMode::Crf => Box::new(CrfController::new(config)),
286    }
287}
288
289/// Common trait for all rate controllers.
290pub trait RateController: Send {
291    /// Get rate control output for a frame.
292    fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput;
293
294    /// Update controller with frame encoding results.
295    fn update_stats(&mut self, stats: &FrameStats);
296
297    /// Reset the controller state.
298    fn reset(&mut self);
299
300    /// Get the current QP value.
301    fn current_qp(&self) -> f32;
302
303    /// Get total frames processed.
304    fn frame_count(&self) -> u64;
305
306    /// Get total bits produced.
307    fn total_bits(&self) -> u64;
308}
309
310impl RateController for CqpController {
311    fn get_output(&mut self, frame_type: crate::frame::FrameType, _complexity: f32) -> RcOutput {
312        self.get_qp(frame_type)
313    }
314
315    fn update_stats(&mut self, stats: &FrameStats) {
316        self.update(stats);
317    }
318
319    fn reset(&mut self) {
320        CqpController::reset(self);
321    }
322
323    fn current_qp(&self) -> f32 {
324        self.base_qp() as f32
325    }
326
327    fn frame_count(&self) -> u64 {
328        CqpController::frame_count(self)
329    }
330
331    fn total_bits(&self) -> u64 {
332        CqpController::total_bits(self)
333    }
334}
335
336impl RateController for CbrController {
337    fn get_output(&mut self, frame_type: crate::frame::FrameType, _complexity: f32) -> RcOutput {
338        self.get_rc(frame_type)
339    }
340
341    fn update_stats(&mut self, stats: &FrameStats) {
342        self.update(stats);
343    }
344
345    fn reset(&mut self) {
346        CbrController::reset(self);
347    }
348
349    fn current_qp(&self) -> f32 {
350        CbrController::current_qp(self)
351    }
352
353    fn frame_count(&self) -> u64 {
354        CbrController::frame_count(self)
355    }
356
357    fn total_bits(&self) -> u64 {
358        // CBR doesn't track total bits directly, compute from frame count
359        0
360    }
361}
362
363impl RateController for VbrController {
364    fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput {
365        self.get_rc(frame_type, complexity)
366    }
367
368    fn update_stats(&mut self, stats: &FrameStats) {
369        self.update(stats);
370    }
371
372    fn reset(&mut self) {
373        VbrController::reset(self);
374    }
375
376    fn current_qp(&self) -> f32 {
377        VbrController::current_qp(self)
378    }
379
380    fn frame_count(&self) -> u64 {
381        VbrController::frame_count(self)
382    }
383
384    fn total_bits(&self) -> u64 {
385        0
386    }
387}
388
389impl RateController for CrfController {
390    fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput {
391        self.get_rc(frame_type, complexity)
392    }
393
394    fn update_stats(&mut self, stats: &FrameStats) {
395        self.update(stats);
396    }
397
398    fn reset(&mut self) {
399        CrfController::reset(self);
400    }
401
402    fn current_qp(&self) -> f32 {
403        CrfController::current_qp(self)
404    }
405
406    fn frame_count(&self) -> u64 {
407        CrfController::frame_count(self)
408    }
409
410    fn total_bits(&self) -> u64 {
411        CrfController::total_bits(self)
412    }
413}
414
415#[cfg(test)]
416mod tests {
417    use super::*;
418    use crate::frame::FrameType;
419
420    #[test]
421    fn test_create_controller_cqp() {
422        let config = RcConfig::cqp(28);
423        let mut controller = create_controller(&config);
424
425        let output = controller.get_output(FrameType::Key, 1.0);
426        assert_eq!(output.qp, 28);
427    }
428
429    #[test]
430    fn test_create_controller_cbr() {
431        let config = RcConfig::cbr(5_000_000);
432        let mut controller = create_controller(&config);
433
434        let output = controller.get_output(FrameType::Key, 1.0);
435        assert!(!output.drop_frame);
436        assert!(output.target_bits > 0);
437    }
438
439    #[test]
440    fn test_create_controller_vbr() {
441        let config = RcConfig::vbr(5_000_000, 10_000_000);
442        let mut controller = create_controller(&config);
443
444        let output = controller.get_output(FrameType::Key, 1.0);
445        assert!(output.target_bits > 0);
446    }
447
448    #[test]
449    fn test_create_controller_crf() {
450        let config = RcConfig::crf(23.0);
451        let mut controller = create_controller(&config);
452
453        let output = controller.get_output(FrameType::Key, 1.0);
454        assert!(output.qp > 0);
455    }
456
457    #[test]
458    fn test_controller_trait_update() {
459        let config = RcConfig::cqp(28);
460        let mut controller = create_controller(&config);
461
462        let mut stats = FrameStats::new(0, FrameType::Key);
463        stats.bits = 100_000;
464        stats.qp_f = 28.0;
465
466        controller.update_stats(&stats);
467        assert_eq!(controller.frame_count(), 1);
468    }
469
470    #[test]
471    fn test_controller_trait_reset() {
472        let config = RcConfig::cqp(28);
473        let mut controller = create_controller(&config);
474
475        let mut stats = FrameStats::new(0, FrameType::Key);
476        stats.bits = 100_000;
477        controller.update_stats(&stats);
478
479        controller.reset();
480        assert_eq!(controller.frame_count(), 0);
481    }
482
483    #[test]
484    fn test_all_modes_covered() {
485        for mode in [
486            RateControlMode::Cqp,
487            RateControlMode::Cbr,
488            RateControlMode::Vbr,
489            RateControlMode::Abr,
490            RateControlMode::Crf,
491        ] {
492            let config = RcConfig {
493                mode,
494                target_bitrate: 5_000_000,
495                ..Default::default()
496            };
497
498            let mut controller = create_controller(&config);
499            let output = controller.get_output(FrameType::Inter, 1.0);
500
501            // All controllers should produce valid output
502            assert!(output.qp > 0 || output.drop_frame);
503        }
504    }
505}