#![allow(clippy::cast_lossless)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::similar_names)]
#![allow(clippy::unused_self)]
#![forbid(unsafe_code)]
pub mod abr;
pub mod allocation;
pub mod analysis;
pub mod aq;
pub mod buffer;
pub mod cbr;
pub mod complexity;
pub mod cqp;
pub mod crf;
pub mod lookahead;
pub mod quantizer;
pub mod scene_adaptive;
pub mod simple_rc;
pub mod types;
pub mod vbr;
pub use abr::{
AbrController, FirstPassStats as AbrFirstPassStats, FramePassStats as AbrFramePassStats,
};
pub use allocation::{AllocationResult, AllocationStrategy, BitrateAllocator, GopAllocationStatus};
pub use analysis::{
AnalysisResult, ContentAnalyzer, ContentType, SceneChangeThreshold, TextureMetrics,
};
pub use aq::{AdaptiveQuantization, AqMode, AqResult, AqStrength};
pub use buffer::{BufferModel, RateBuffer, VbvParams};
pub use cbr::CbrController;
pub use complexity::{ComplexityEstimator, ComplexityResult, MotionAnalyzer, MotionResult};
pub use cqp::CqpController;
pub use crf::{CrfController, QualityPreset};
pub use lookahead::{
AdaptiveAllocation, ContentAdaptiveAllocator, ContentMetrics, Lookahead, LookaheadFrame,
MiniGopInfo, SceneChangeDetector, SceneContentType,
};
pub use quantizer::{BlockQpMap, QpResult, QpSelector, QpStrategy};
pub use scene_adaptive::{
FrameBitTarget, FrameContentMetrics, Scene as AdaptiveScene, SceneAdaptiveAllocator,
SceneAdaptiveConfig, SceneContentType as SceneAdaptiveContentType,
};
pub use simple_rc::{
SimpleRateControlConfig, SimpleRateControlMode, SimpleRateControlStats, SimpleRateController,
};
pub use types::{
FrameStats, GopStats, RateControlMode, RcConfig, RcConfigError, RcOutput, RcState,
};
pub use vbr::{FirstPassData, VbrController};
#[must_use]
pub fn create_controller(config: &RcConfig) -> Box<dyn RateController> {
match config.mode {
RateControlMode::Cqp => Box::new(CqpController::new(config)),
RateControlMode::Cbr => Box::new(CbrController::new(config)),
RateControlMode::Vbr | RateControlMode::Abr => Box::new(VbrController::new(config)),
RateControlMode::Crf => Box::new(CrfController::new(config)),
}
}
pub trait RateController: Send {
fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput;
fn update_stats(&mut self, stats: &FrameStats);
fn reset(&mut self);
fn current_qp(&self) -> f32;
fn frame_count(&self) -> u64;
fn total_bits(&self) -> u64;
}
impl RateController for CqpController {
fn get_output(&mut self, frame_type: crate::frame::FrameType, _complexity: f32) -> RcOutput {
self.get_qp(frame_type)
}
fn update_stats(&mut self, stats: &FrameStats) {
self.update(stats);
}
fn reset(&mut self) {
CqpController::reset(self);
}
fn current_qp(&self) -> f32 {
self.base_qp() as f32
}
fn frame_count(&self) -> u64 {
CqpController::frame_count(self)
}
fn total_bits(&self) -> u64 {
CqpController::total_bits(self)
}
}
impl RateController for CbrController {
fn get_output(&mut self, frame_type: crate::frame::FrameType, _complexity: f32) -> RcOutput {
self.get_rc(frame_type)
}
fn update_stats(&mut self, stats: &FrameStats) {
self.update(stats);
}
fn reset(&mut self) {
CbrController::reset(self);
}
fn current_qp(&self) -> f32 {
CbrController::current_qp(self)
}
fn frame_count(&self) -> u64 {
CbrController::frame_count(self)
}
fn total_bits(&self) -> u64 {
0
}
}
impl RateController for VbrController {
fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput {
self.get_rc(frame_type, complexity)
}
fn update_stats(&mut self, stats: &FrameStats) {
self.update(stats);
}
fn reset(&mut self) {
VbrController::reset(self);
}
fn current_qp(&self) -> f32 {
VbrController::current_qp(self)
}
fn frame_count(&self) -> u64 {
VbrController::frame_count(self)
}
fn total_bits(&self) -> u64 {
0
}
}
impl RateController for CrfController {
fn get_output(&mut self, frame_type: crate::frame::FrameType, complexity: f32) -> RcOutput {
self.get_rc(frame_type, complexity)
}
fn update_stats(&mut self, stats: &FrameStats) {
self.update(stats);
}
fn reset(&mut self) {
CrfController::reset(self);
}
fn current_qp(&self) -> f32 {
CrfController::current_qp(self)
}
fn frame_count(&self) -> u64 {
CrfController::frame_count(self)
}
fn total_bits(&self) -> u64 {
CrfController::total_bits(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::FrameType;
#[test]
fn test_create_controller_cqp() {
let config = RcConfig::cqp(28);
let mut controller = create_controller(&config);
let output = controller.get_output(FrameType::Key, 1.0);
assert_eq!(output.qp, 28);
}
#[test]
fn test_create_controller_cbr() {
let config = RcConfig::cbr(5_000_000);
let mut controller = create_controller(&config);
let output = controller.get_output(FrameType::Key, 1.0);
assert!(!output.drop_frame);
assert!(output.target_bits > 0);
}
#[test]
fn test_create_controller_vbr() {
let config = RcConfig::vbr(5_000_000, 10_000_000);
let mut controller = create_controller(&config);
let output = controller.get_output(FrameType::Key, 1.0);
assert!(output.target_bits > 0);
}
#[test]
fn test_create_controller_crf() {
let config = RcConfig::crf(23.0);
let mut controller = create_controller(&config);
let output = controller.get_output(FrameType::Key, 1.0);
assert!(output.qp > 0);
}
#[test]
fn test_controller_trait_update() {
let config = RcConfig::cqp(28);
let mut controller = create_controller(&config);
let mut stats = FrameStats::new(0, FrameType::Key);
stats.bits = 100_000;
stats.qp_f = 28.0;
controller.update_stats(&stats);
assert_eq!(controller.frame_count(), 1);
}
#[test]
fn test_controller_trait_reset() {
let config = RcConfig::cqp(28);
let mut controller = create_controller(&config);
let mut stats = FrameStats::new(0, FrameType::Key);
stats.bits = 100_000;
controller.update_stats(&stats);
controller.reset();
assert_eq!(controller.frame_count(), 0);
}
#[test]
fn test_all_modes_covered() {
for mode in [
RateControlMode::Cqp,
RateControlMode::Cbr,
RateControlMode::Vbr,
RateControlMode::Abr,
RateControlMode::Crf,
] {
let config = RcConfig {
mode,
target_bitrate: 5_000_000,
..Default::default()
};
let mut controller = create_controller(&config);
let output = controller.get_output(FrameType::Inter, 1.0);
assert!(output.qp > 0 || output.drop_frame);
}
}
}