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}