1#![allow(clippy::cast_lossless)]
25#![allow(clippy::cast_precision_loss)]
26#![allow(clippy::cast_possible_truncation)]
27#![allow(clippy::cast_sign_loss)]
28#![allow(clippy::cast_possible_wrap)]
29#![allow(clippy::too_many_arguments)]
30#![allow(clippy::struct_excessive_bools)]
31#![forbid(unsafe_code)]
32
33use crate::frame::FrameType;
34
35use super::buffer::BufferModel;
36use super::types::{FrameStats, GopStats, RcConfig, RcOutput};
37
38#[derive(Clone, Debug)]
40pub struct VbrController {
41 target_bitrate: u64,
43 max_bitrate: u64,
45 min_bitrate: u64,
47 current_qp: f32,
49 min_qp: u8,
51 max_qp: u8,
53 i_qp_offset: i8,
55 b_qp_offset: i8,
57 framerate: f64,
59 gop_length: u32,
61 frame_count: u64,
63 total_bits: u64,
65 current_gop: GopStats,
67 gop_history: Vec<GopStats>,
69 max_gop_history: usize,
71 pass: u8,
73 first_pass_data: Option<FirstPassData>,
75 quality_stability: f32,
77 bit_reservoir: i64,
79 max_reservoir: i64,
81 vbv_buffer: Option<BufferModel>,
83 enable_vbv: bool,
85 lookahead_size: usize,
87 lookahead_frames: Vec<LookaheadFrameData>,
89 rate_model: RatePredictionModel,
91 adaptive_gop: bool,
93 scene_change_threshold: f32,
95 enable_aq: bool,
97 #[allow(dead_code)]
99 aq_strength: f32,
100 pid_state: PidControllerState,
102 rdo_params: RdoParameters,
104 frame_type_state: FrameTypeDecisionState,
106}
107
108#[derive(Clone, Debug, Default)]
110pub struct FirstPassData {
111 pub frame_complexity: Vec<f32>,
113 pub spatial_complexity: Vec<f32>,
115 pub temporal_complexity: Vec<f32>,
117 pub gop_complexity: Vec<f32>,
119 pub total_complexity: f32,
121 pub frame_count: u64,
123 pub suggested_bits: Vec<u64>,
125 pub scene_changes: Vec<u64>,
127 pub gop_boundaries: Vec<u64>,
129 pub recommended_qp: Vec<f32>,
131}
132
133impl FirstPassData {
134 pub fn add_frame(&mut self, spatial: f32, temporal: f32, combined: f32) {
136 self.frame_complexity.push(combined);
137 self.spatial_complexity.push(spatial);
138 self.temporal_complexity.push(temporal);
139 self.total_complexity += combined;
140 self.frame_count += 1;
141 }
142
143 pub fn mark_scene_change(&mut self, frame_num: u64) {
145 self.scene_changes.push(frame_num);
146 }
147
148 pub fn add_gop_boundary(&mut self, frame_num: u64) {
150 self.gop_boundaries.push(frame_num);
151 }
152
153 pub fn finalize_gop(&mut self) {
155 let gop_start = self
156 .gop_complexity
157 .last()
158 .map(|_| self.gop_boundaries.last().copied().unwrap_or(0))
159 .unwrap_or(0) as usize;
160
161 let gop_sum: f32 = self
162 .frame_complexity
163 .get(gop_start..)
164 .map(|slice| slice.iter().sum())
165 .unwrap_or(0.0);
166
167 self.gop_complexity.push(gop_sum);
168 }
169
170 pub fn calculate_bit_allocation(&mut self, total_bits: u64) {
172 if self.total_complexity <= 0.0 || self.frame_complexity.is_empty() {
173 return;
174 }
175
176 let bits_per_complexity = total_bits as f64 / self.total_complexity as f64;
177
178 self.suggested_bits = self
179 .frame_complexity
180 .iter()
181 .map(|c| ((*c as f64) * bits_per_complexity) as u64)
182 .collect();
183
184 let avg_complexity = self.total_complexity / self.frame_count as f32;
186
187 for complexity in &self.frame_complexity {
188 let complexity_ratio = complexity / avg_complexity;
189 let qp_adjustment = (complexity_ratio - 1.0) * 4.0;
191 let base_qp = 28.0;
192 let recommended = (base_qp + qp_adjustment).clamp(18.0, 51.0);
193 self.recommended_qp.push(recommended);
194 }
195 }
196
197 #[must_use]
199 pub fn get_suggested_bits(&self, frame_num: u64) -> Option<u64> {
200 self.suggested_bits.get(frame_num as usize).copied()
201 }
202
203 #[must_use]
205 pub fn get_recommended_qp(&self, frame_num: u64) -> Option<f32> {
206 self.recommended_qp.get(frame_num as usize).copied()
207 }
208
209 #[must_use]
211 pub fn is_scene_change(&self, frame_num: u64) -> bool {
212 self.scene_changes.contains(&frame_num)
213 }
214}
215
216#[derive(Clone, Debug, Default)]
218struct LookaheadFrameData {
219 #[allow(dead_code)]
221 frame_index: u64,
222 #[allow(dead_code)]
224 spatial_complexity: f32,
225 #[allow(dead_code)]
227 temporal_complexity: f32,
228 combined_complexity: f32,
230 is_scene_change: bool,
232 #[allow(dead_code)]
234 predicted_type: FrameType,
235 #[allow(dead_code)]
237 predicted_bits: u64,
238}
239
240#[derive(Clone, Debug)]
242struct RatePredictionModel {
243 linear_a: f64,
245 linear_b: f64,
246 quad_a: f64,
248 quad_b: f64,
249 quad_c: f64,
250 power_a: f64,
252 power_b: f64,
253 active_model: u8,
255 history_complexity: Vec<f32>,
257 history_bits: Vec<u64>,
258 max_history: usize,
260 update_count: u32,
262}
263
264impl Default for RatePredictionModel {
265 fn default() -> Self {
266 Self {
267 linear_a: 100_000.0,
268 linear_b: 50_000.0,
269 quad_a: 10_000.0,
270 quad_b: 50_000.0,
271 quad_c: 20_000.0,
272 power_a: 100_000.0,
273 power_b: 1.2,
274 active_model: 0,
275 history_complexity: Vec::new(),
276 history_bits: Vec::new(),
277 max_history: 100,
278 update_count: 0,
279 }
280 }
281}
282
283impl RatePredictionModel {
284 fn predict(&self, complexity: f32) -> u64 {
286 if complexity <= 0.0 {
287 return 50_000;
288 }
289
290 let prediction = match self.active_model {
291 0 => self.predict_linear(complexity),
292 1 => self.predict_quadratic(complexity),
293 2 => self.predict_power(complexity),
294 _ => self.predict_linear(complexity),
295 };
296
297 prediction.max(1000.0) as u64
298 }
299
300 fn predict_linear(&self, complexity: f32) -> f64 {
302 self.linear_a * complexity as f64 + self.linear_b
303 }
304
305 fn predict_quadratic(&self, complexity: f32) -> f64 {
307 let c = complexity as f64;
308 self.quad_a * c * c + self.quad_b * c + self.quad_c
309 }
310
311 fn predict_power(&self, complexity: f32) -> f64 {
313 self.power_a * (complexity as f64).powf(self.power_b)
314 }
315
316 fn update(&mut self, complexity: f32, bits: u64) {
318 self.history_complexity.push(complexity);
319 self.history_bits.push(bits);
320
321 if self.history_complexity.len() > self.max_history {
322 self.history_complexity.remove(0);
323 self.history_bits.remove(0);
324 }
325
326 self.update_count += 1;
328 if self.update_count >= 10 {
329 self.fit_models();
330 self.update_count = 0;
331 }
332 }
333
334 fn fit_models(&mut self) {
336 if self.history_complexity.len() < 5 {
337 return;
338 }
339
340 self.fit_linear_model();
341 self.fit_quadratic_model();
342 self.fit_power_model();
343 self.select_best_model();
344 }
345
346 fn fit_linear_model(&mut self) {
348 let n = self.history_complexity.len();
349 let mut sum_x = 0.0;
350 let mut sum_y = 0.0;
351 let mut sum_xy = 0.0;
352 let mut sum_xx = 0.0;
353
354 for i in 0..n {
355 let x = self.history_complexity[i] as f64;
356 let y = self.history_bits[i] as f64;
357 sum_x += x;
358 sum_y += y;
359 sum_xy += x * y;
360 sum_xx += x * x;
361 }
362
363 let n_f = n as f64;
364 let denominator = n_f * sum_xx - sum_x * sum_x;
365
366 if denominator.abs() > 1e-6 {
367 self.linear_a = (n_f * sum_xy - sum_x * sum_y) / denominator;
368 self.linear_b = (sum_y - self.linear_a * sum_x) / n_f;
369 }
370 }
371
372 fn fit_quadratic_model(&mut self) {
374 let n = self.history_complexity.len();
377 if n < 3 {
378 return;
379 }
380
381 let mut sum_x = 0.0;
382 let mut sum_y = 0.0;
383 let mut sum_x2 = 0.0;
384 let mut sum_xy = 0.0;
385
386 for i in 0..n {
387 let x = self.history_complexity[i] as f64;
388 let y = self.history_bits[i] as f64;
389 sum_x += x;
390 sum_y += y;
391 sum_x2 += x * x;
392 sum_xy += x * y;
393 }
394
395 let n_f = n as f64;
396 let avg_x = sum_x / n_f;
397 let avg_y = sum_y / n_f;
398
399 self.quad_b = self.linear_a;
401 self.quad_a = (sum_xy - n_f * avg_x * avg_y) / (sum_x2 - n_f * avg_x * avg_x) * 0.1;
402 self.quad_c = avg_y - self.quad_b * avg_x - self.quad_a * avg_x * avg_x;
403 }
404
405 fn fit_power_model(&mut self) {
407 let n = self.history_complexity.len();
408 let mut sum_log_x = 0.0;
409 let mut sum_log_y = 0.0;
410 let mut sum_log_xy = 0.0;
411 let mut sum_log_xx = 0.0;
412 let mut count = 0;
413
414 for i in 0..n {
415 let x = self.history_complexity[i] as f64;
416 let y = self.history_bits[i] as f64;
417
418 if x > 0.0 && y > 0.0 {
419 let log_x = x.ln();
420 let log_y = y.ln();
421 sum_log_x += log_x;
422 sum_log_y += log_y;
423 sum_log_xy += log_x * log_y;
424 sum_log_xx += log_x * log_x;
425 count += 1;
426 }
427 }
428
429 if count < 3 {
430 return;
431 }
432
433 let n_f = count as f64;
434 let denominator = n_f * sum_log_xx - sum_log_x * sum_log_x;
435
436 if denominator.abs() > 1e-6 {
437 self.power_b = (n_f * sum_log_xy - sum_log_x * sum_log_y) / denominator;
438 let log_a = (sum_log_y - self.power_b * sum_log_x) / n_f;
439 self.power_a = log_a.exp();
440 }
441 }
442
443 fn select_best_model(&mut self) {
445 if self.history_complexity.len() < 5 {
446 return;
447 }
448
449 let mut error_linear = 0.0;
450 let mut error_quadratic = 0.0;
451 let mut error_power = 0.0;
452
453 for i in 0..self.history_complexity.len() {
454 let complexity = self.history_complexity[i];
455 let actual_bits = self.history_bits[i] as f64;
456
457 let pred_linear = self.predict_linear(complexity);
458 let pred_quadratic = self.predict_quadratic(complexity);
459 let pred_power = self.predict_power(complexity);
460
461 error_linear += (actual_bits - pred_linear).abs();
462 error_quadratic += (actual_bits - pred_quadratic).abs();
463 error_power += (actual_bits - pred_power).abs();
464 }
465
466 if error_linear <= error_quadratic && error_linear <= error_power {
468 self.active_model = 0;
469 } else if error_quadratic <= error_power {
470 self.active_model = 1;
471 } else {
472 self.active_model = 2;
473 }
474 }
475}
476
477#[derive(Clone, Debug, Default)]
479struct PidControllerState {
480 kp: f32,
482 ki: f32,
484 kd: f32,
486 prev_error: f32,
488 integral: f32,
490 max_integral: f32,
492}
493
494impl PidControllerState {
495 fn new() -> Self {
497 Self {
498 kp: 0.5,
499 ki: 0.1,
500 kd: 0.05,
501 prev_error: 0.0,
502 integral: 0.0,
503 max_integral: 10.0,
504 }
505 }
506
507 fn calculate(&mut self, error: f32) -> f32 {
509 let p_term = self.kp * error;
511
512 self.integral += error;
514 self.integral = self.integral.clamp(-self.max_integral, self.max_integral);
515 let i_term = self.ki * self.integral;
516
517 let d_term = self.kd * (error - self.prev_error);
519 self.prev_error = error;
520
521 p_term + i_term + d_term
522 }
523
524 fn reset(&mut self) {
526 self.prev_error = 0.0;
527 self.integral = 0.0;
528 }
529}
530
531#[derive(Clone, Debug)]
533struct RdoParameters {
534 base_lambda: f64,
536 i_lambda_mult: f64,
538 b_lambda_mult: f64,
540 #[allow(dead_code)]
542 psy_rd: bool,
543 #[allow(dead_code)]
545 psy_strength: f64,
546}
547
548impl Default for RdoParameters {
549 fn default() -> Self {
550 Self {
551 base_lambda: 1.0,
552 i_lambda_mult: 0.6,
553 b_lambda_mult: 1.4,
554 psy_rd: true,
555 psy_strength: 1.0,
556 }
557 }
558}
559
560impl RdoParameters {
561 fn calculate_lambda(&self, qp: f32, frame_type: FrameType) -> f64 {
563 let base = 0.85 * 2.0_f64.powf((f64::from(qp) - 12.0) / 3.0);
564
565 let multiplier = match frame_type {
566 FrameType::Key => self.i_lambda_mult,
567 FrameType::BiDir => self.b_lambda_mult,
568 _ => 1.0,
569 };
570
571 base * multiplier * self.base_lambda
572 }
573
574 fn calculate_lambda_me(&self, lambda: f64) -> f64 {
576 lambda.sqrt()
577 }
578}
579
580#[derive(Clone, Debug, Default)]
582struct FrameTypeDecisionState {
583 frames_since_keyframe: u32,
585 consecutive_b_frames: u32,
587 max_b_frames: u32,
589 force_keyframe: bool,
591}
592
593impl FrameTypeDecisionState {
594 fn new(max_b_frames: u32) -> Self {
596 Self {
597 frames_since_keyframe: 0,
598 consecutive_b_frames: 0,
599 max_b_frames,
600 force_keyframe: false,
601 }
602 }
603
604 fn decide_type(
606 &mut self,
607 gop_length: u32,
608 is_scene_change: bool,
609 adaptive_gop: bool,
610 ) -> FrameType {
611 if self.force_keyframe
613 || self.frames_since_keyframe == 0
614 || (!adaptive_gop && self.frames_since_keyframe >= gop_length)
615 || is_scene_change
616 {
617 self.frames_since_keyframe = 1;
618 self.consecutive_b_frames = 0;
619 self.force_keyframe = false;
620 return FrameType::Key;
621 }
622
623 self.frames_since_keyframe += 1;
624
625 if self.max_b_frames > 0 && self.consecutive_b_frames < self.max_b_frames {
627 let mini_gop_pos = self.frames_since_keyframe % (self.max_b_frames + 1);
629 if mini_gop_pos > 0 && mini_gop_pos <= self.max_b_frames {
630 self.consecutive_b_frames += 1;
631 return FrameType::BiDir;
632 }
633 }
634
635 self.consecutive_b_frames = 0;
636 FrameType::Inter
637 }
638
639 fn force_next_keyframe(&mut self) {
641 self.force_keyframe = true;
642 }
643}
644
645impl VbrController {
646 #[must_use]
648 pub fn new(config: &RcConfig) -> Self {
649 let max_bitrate = config.max_bitrate.unwrap_or(config.target_bitrate * 2);
650 let min_bitrate = config.min_bitrate.unwrap_or(config.target_bitrate / 4);
651 let framerate = config.framerate();
652
653 let vbv_buffer = if config.buffer_size > 0 {
654 Some(BufferModel::new(
655 config.buffer_size,
656 config.target_bitrate,
657 framerate,
658 config.initial_buffer_fullness as f64,
659 ))
660 } else {
661 None
662 };
663
664 Self {
665 target_bitrate: config.target_bitrate,
666 max_bitrate,
667 min_bitrate,
668 current_qp: config.initial_qp as f32,
669 min_qp: config.min_qp,
670 max_qp: config.max_qp,
671 i_qp_offset: config.i_qp_offset,
672 b_qp_offset: config.b_qp_offset,
673 framerate,
674 gop_length: config.gop_length,
675 frame_count: 0,
676 total_bits: 0,
677 current_gop: GopStats::new(0, 0),
678 gop_history: Vec::new(),
679 max_gop_history: 10,
680 pass: 0,
681 first_pass_data: None,
682 quality_stability: 0.5,
683 bit_reservoir: 0,
684 max_reservoir: (config.target_bitrate as i64) * 2,
685 vbv_buffer,
686 enable_vbv: config.buffer_size > 0,
687 lookahead_size: config.lookahead_depth.min(250),
688 lookahead_frames: Vec::new(),
689 rate_model: RatePredictionModel::default(),
690 adaptive_gop: true,
691 scene_change_threshold: config.scene_cut_threshold,
692 enable_aq: config.enable_aq,
693 aq_strength: config.aq_strength,
694 pid_state: PidControllerState::new(),
695 rdo_params: RdoParameters::default(),
696 frame_type_state: FrameTypeDecisionState::new(3),
697 }
698 }
699
700 pub fn set_pass(&mut self, pass: u8) {
702 self.pass = pass.min(2);
703 if pass == 1 {
704 self.first_pass_data = Some(FirstPassData::default());
705 }
706 }
707
708 pub fn set_quality_stability(&mut self, stability: f32) {
710 self.quality_stability = stability.clamp(0.0, 1.0);
711 }
712
713 pub fn set_vbv_enabled(&mut self, enabled: bool) {
715 self.enable_vbv = enabled;
716 }
717
718 pub fn set_lookahead_size(&mut self, size: usize) {
720 self.lookahead_size = size.clamp(10, 250);
721 self.lookahead_frames.reserve(self.lookahead_size);
722 }
723
724 pub fn set_adaptive_gop(&mut self, enabled: bool) {
726 self.adaptive_gop = enabled;
727 }
728
729 pub fn set_scene_change_threshold(&mut self, threshold: f32) {
731 self.scene_change_threshold = threshold.clamp(0.0, 1.0);
732 }
733
734 pub fn set_first_pass_data(&mut self, data: FirstPassData) {
736 self.first_pass_data = Some(data);
737 }
738
739 pub fn push_lookahead_frame(
741 &mut self,
742 spatial: f32,
743 temporal: f32,
744 combined: f32,
745 is_scene_change: bool,
746 ) {
747 let frame_data = LookaheadFrameData {
748 frame_index: self.frame_count + self.lookahead_frames.len() as u64,
749 spatial_complexity: spatial,
750 temporal_complexity: temporal,
751 combined_complexity: combined,
752 is_scene_change,
753 predicted_type: FrameType::Inter,
754 predicted_bits: self.rate_model.predict(combined),
755 };
756
757 self.lookahead_frames.push(frame_data);
758
759 if self.lookahead_frames.len() > self.lookahead_size {
761 self.lookahead_frames.remove(0);
762 }
763 }
764
765 #[must_use]
767 pub fn get_rc(&mut self, frame_type: FrameType, complexity: f32) -> RcOutput {
768 let is_scene_change = self.detect_scene_change_from_lookahead();
770 let actual_frame_type =
771 self.frame_type_state
772 .decide_type(self.gop_length, is_scene_change, self.adaptive_gop);
773
774 let final_frame_type = if frame_type == FrameType::Key {
776 FrameType::Key
777 } else {
778 actual_frame_type
779 };
780
781 let target_bits = self.calculate_target_bits(final_frame_type, complexity);
783
784 let qp_adjustment = self.calculate_closed_loop_qp_adjustment();
786 let adjusted_qp = self.current_qp + qp_adjustment;
787
788 let offset = match final_frame_type {
790 FrameType::Key => self.i_qp_offset,
791 FrameType::BiDir => self.b_qp_offset,
792 FrameType::Inter | FrameType::Switch => 0,
793 };
794
795 let complexity_adjustment = self.calculate_complexity_adjustment(complexity);
797
798 let vbv_adjustment = if self.enable_vbv {
800 self.calculate_vbv_qp_adjustment()
801 } else {
802 0.0
803 };
804
805 let final_qp = (adjusted_qp + offset as f32 + complexity_adjustment + vbv_adjustment)
806 .clamp(self.min_qp as f32, self.max_qp as f32);
807 let qp = final_qp.round() as u8;
808
809 let (min_bits, max_bits) = self.calculate_bit_limits(final_frame_type, target_bits);
811
812 let lambda = self.rdo_params.calculate_lambda(final_qp, final_frame_type);
814 let lambda_me = self.rdo_params.calculate_lambda_me(lambda);
815
816 let mut output = RcOutput {
817 qp,
818 qp_f: final_qp,
819 target_bits,
820 min_bits,
821 max_bits,
822 lambda,
823 lambda_me,
824 force_keyframe: final_frame_type == FrameType::Key && is_scene_change,
825 ..Default::default()
826 };
827
828 if self.enable_aq {
830 output.qp_offsets = Some(self.calculate_aq_offsets(final_qp));
831 }
832
833 output
834 }
835
836 fn detect_scene_change_from_lookahead(&self) -> bool {
838 if self.lookahead_frames.is_empty() {
839 return false;
840 }
841
842 self.lookahead_frames
844 .first()
845 .map(|f| f.is_scene_change)
846 .unwrap_or(false)
847 }
848
849 fn calculate_target_bits(&self, frame_type: FrameType, complexity: f32) -> u64 {
851 let base_target = self.bits_per_frame_at_bitrate(self.target_bitrate);
852
853 if self.pass == 2 {
855 if let Some(ref data) = self.first_pass_data {
856 if let Some(suggested) = data.get_suggested_bits(self.frame_count) {
857 return suggested;
858 }
859 }
860 }
861
862 let model_prediction = self.rate_model.predict(complexity);
864
865 let type_multiplier = match frame_type {
867 FrameType::Key => 3.0,
868 FrameType::Inter => 1.0,
869 FrameType::BiDir => 0.5,
870 FrameType::Switch => 1.5,
871 };
872
873 let lookahead_mult = self.calculate_lookahead_multiplier();
875
876 let complexity_multiplier: f64 = if complexity > 0.0 {
878 (f64::from(complexity) / f64::from(self.average_complexity())).clamp(0.5, 2.0)
879 } else {
880 1.0
881 };
882
883 let reservoir_adjustment = self.calculate_reservoir_adjustment();
885
886 let target =
888 (base_target as f64 * type_multiplier * complexity_multiplier * lookahead_mult)
889 .max(model_prediction as f64)
890 + reservoir_adjustment;
891
892 let adjusted_target = target.max(base_target as f64 / 4.0);
893
894 adjusted_target as u64
895 }
896
897 fn calculate_lookahead_multiplier(&self) -> f64 {
899 if self.lookahead_frames.is_empty() {
900 return 1.0;
901 }
902
903 let avg_future_complexity: f32 = self
905 .lookahead_frames
906 .iter()
907 .map(|f| f.combined_complexity)
908 .sum::<f32>()
909 / self.lookahead_frames.len() as f32;
910
911 let current_complexity = self
912 .lookahead_frames
913 .first()
914 .map(|f| f.combined_complexity)
915 .unwrap_or(1.0);
916
917 if avg_future_complexity > current_complexity * 1.3 {
919 0.9
921 } else if avg_future_complexity < current_complexity * 0.7 {
922 1.1
924 } else {
925 1.0
926 }
927 }
928
929 fn calculate_closed_loop_qp_adjustment(&mut self) -> f32 {
931 if self.frame_count == 0 {
932 return 0.0;
933 }
934
935 let elapsed_time = self.frame_count as f64 / self.framerate;
936 if elapsed_time <= 0.0 {
937 return 0.0;
938 }
939
940 let actual_bitrate = self.total_bits as f64 / elapsed_time;
941 let error = (actual_bitrate - self.target_bitrate as f64) / self.target_bitrate as f64;
942
943 let pid_output = self.pid_state.calculate(error as f32);
945
946 pid_output * (1.0 - self.quality_stability)
948 }
949
950 fn calculate_complexity_adjustment(&self, complexity: f32) -> f32 {
952 let avg = self.average_complexity();
953 if avg <= 0.0 {
954 return 0.0;
955 }
956
957 let ratio = complexity / avg;
958
959 let adjustment = (ratio - 1.0) * 2.0 * self.quality_stability;
962 adjustment.clamp(-2.0, 2.0)
963 }
964
965 fn calculate_vbv_qp_adjustment(&self) -> f32 {
967 if let Some(ref buffer) = self.vbv_buffer {
968 let fullness = buffer.fullness();
969
970 let target_fullness = 0.5;
973 let error = fullness - target_fullness;
974
975 if error > 0.3 {
977 (error - 0.3) * 20.0
979 } else if error < -0.3 {
980 (error + 0.3) * 20.0
982 } else {
983 error * 5.0
985 }
986 } else {
987 0.0
988 }
989 }
990
991 fn calculate_bit_limits(&self, frame_type: FrameType, target_bits: u64) -> (u64, u64) {
993 let base_min = self.bits_per_frame_at_bitrate(self.min_bitrate) / 4;
994 let base_max = self.bits_per_frame_at_bitrate(self.max_bitrate) * 4;
995
996 let mut min_bits = base_min;
997 let mut max_bits = base_max;
998
999 if self.enable_vbv {
1001 if let Some(ref buffer) = self.vbv_buffer {
1002 let available = buffer.max_frame_bits();
1003 max_bits = max_bits.min(available);
1004
1005 let min_to_prevent_underflow = target_bits / 2;
1007 min_bits = min_bits.max(min_to_prevent_underflow);
1008 }
1009 }
1010
1011 match frame_type {
1013 FrameType::Key => {
1014 max_bits = max_bits.max(target_bits * 5);
1016 }
1017 FrameType::BiDir => {
1018 max_bits = max_bits.min(target_bits * 2);
1020 }
1021 _ => {}
1022 }
1023
1024 (min_bits, max_bits)
1025 }
1026
1027 fn calculate_aq_offsets(&self, _base_qp: f32) -> Vec<f32> {
1029 Vec::new()
1032 }
1033
1034 fn calculate_reservoir_adjustment(&self) -> f64 {
1036 let target_per_frame = self.bits_per_frame_at_bitrate(self.target_bitrate);
1037
1038 let reservoir_factor = self.bit_reservoir as f64 / self.max_reservoir as f64;
1040 reservoir_factor * (target_per_frame as f64 * 0.1)
1041 }
1042
1043 fn bits_per_frame_at_bitrate(&self, bitrate: u64) -> u64 {
1045 if self.framerate <= 0.0 {
1046 return 0;
1047 }
1048 (bitrate as f64 / self.framerate) as u64
1049 }
1050
1051 fn average_complexity(&self) -> f32 {
1053 if self.gop_history.is_empty() {
1054 return 1.0;
1055 }
1056
1057 let total: f32 = self.gop_history.iter().map(|g| g.average_complexity).sum();
1058 (total / self.gop_history.len() as f32).max(0.01)
1059 }
1060
1061 pub fn update(&mut self, stats: &FrameStats) {
1063 self.frame_count += 1;
1064 self.total_bits += stats.bits;
1065
1066 let target = self.bits_per_frame_at_bitrate(self.target_bitrate);
1068 self.bit_reservoir += target as i64 - stats.bits as i64;
1069 self.bit_reservoir = self
1070 .bit_reservoir
1071 .clamp(-self.max_reservoir, self.max_reservoir);
1072
1073 if self.enable_vbv {
1075 if let Some(ref mut buffer) = self.vbv_buffer {
1076 buffer.fill_for_frame();
1077 buffer.remove_frame_bits(stats.bits);
1078 }
1079 }
1080
1081 self.rate_model.update(stats.complexity, stats.bits);
1083
1084 self.current_gop.add_frame(stats.clone());
1086
1087 if stats.frame_type == FrameType::Key && self.current_gop.frame_count > 1 {
1089 self.finalize_gop();
1090 }
1091
1092 if self.pass == 1 {
1094 if let Some(ref mut data) = self.first_pass_data {
1095 data.add_frame(
1096 stats.spatial_complexity,
1097 stats.temporal_complexity,
1098 stats.complexity,
1099 );
1100
1101 if stats.scene_cut {
1102 data.mark_scene_change(stats.frame_num);
1103 }
1104
1105 if stats.frame_type == FrameType::Key && data.frame_count > 1 {
1106 data.finalize_gop();
1107 data.add_gop_boundary(stats.frame_num);
1108 }
1109 }
1110 }
1111
1112 self.adjust_base_qp(stats);
1114
1115 if !self.lookahead_frames.is_empty() {
1117 self.lookahead_frames.remove(0);
1118 }
1119 }
1120
1121 fn finalize_gop(&mut self) {
1123 self.gop_history.push(self.current_gop.clone());
1124 if self.gop_history.len() > self.max_gop_history {
1125 self.gop_history.remove(0);
1126 }
1127
1128 let next_gop_index = self.current_gop.gop_index + 1;
1129 self.current_gop = GopStats::new(next_gop_index, self.frame_count);
1130 }
1131
1132 fn adjust_base_qp(&mut self, stats: &FrameStats) {
1134 if stats.target_bits == 0 {
1135 return;
1136 }
1137
1138 let accuracy = stats.bits as f32 / stats.target_bits as f32;
1139
1140 let adjustment = if accuracy > 1.3 {
1142 0.15
1143 } else if accuracy > 1.1 {
1144 0.05
1145 } else if accuracy < 0.7 {
1146 -0.15
1147 } else if accuracy < 0.9 {
1148 -0.05
1149 } else {
1150 0.0
1151 };
1152
1153 self.current_qp =
1154 (self.current_qp + adjustment).clamp(self.min_qp as f32, self.max_qp as f32);
1155 }
1156
1157 #[must_use]
1159 pub fn finalize_first_pass(&mut self) -> Option<FirstPassData> {
1160 if self.pass != 1 {
1161 return None;
1162 }
1163
1164 if let Some(ref mut data) = self.first_pass_data {
1165 data.finalize_gop();
1166
1167 let duration = self.frame_count as f64 / self.framerate;
1169 let total_bits = (self.target_bitrate as f64 * duration) as u64;
1170 data.calculate_bit_allocation(total_bits);
1171 }
1172
1173 self.first_pass_data.take()
1174 }
1175
1176 #[must_use]
1178 pub fn target_bitrate(&self) -> u64 {
1179 self.target_bitrate
1180 }
1181
1182 #[must_use]
1184 pub fn max_bitrate(&self) -> u64 {
1185 self.max_bitrate
1186 }
1187
1188 #[must_use]
1190 pub fn min_bitrate(&self) -> u64 {
1191 self.min_bitrate
1192 }
1193
1194 #[must_use]
1196 pub fn current_bitrate(&self) -> f64 {
1197 if self.frame_count == 0 || self.framerate <= 0.0 {
1198 return 0.0;
1199 }
1200 let elapsed = self.frame_count as f64 / self.framerate;
1201 self.total_bits as f64 / elapsed
1202 }
1203
1204 #[must_use]
1206 pub fn current_qp(&self) -> f32 {
1207 self.current_qp
1208 }
1209
1210 #[must_use]
1212 pub fn frame_count(&self) -> u64 {
1213 self.frame_count
1214 }
1215
1216 #[must_use]
1218 pub fn bit_reservoir(&self) -> i64 {
1219 self.bit_reservoir
1220 }
1221
1222 #[must_use]
1224 pub fn vbv_fullness(&self) -> f32 {
1225 self.vbv_buffer
1226 .as_ref()
1227 .map(|b| b.fullness())
1228 .unwrap_or(0.5)
1229 }
1230
1231 pub fn force_keyframe(&mut self) {
1233 self.frame_type_state.force_next_keyframe();
1234 }
1235
1236 pub fn reset(&mut self) {
1238 self.frame_count = 0;
1239 self.total_bits = 0;
1240 self.bit_reservoir = 0;
1241 self.current_gop = GopStats::new(0, 0);
1242 self.gop_history.clear();
1243 self.lookahead_frames.clear();
1244 self.pid_state.reset();
1245 self.frame_type_state = FrameTypeDecisionState::new(self.frame_type_state.max_b_frames);
1246
1247 if let Some(ref mut buffer) = self.vbv_buffer {
1248 buffer.reset();
1249 }
1250 }
1251}
1252
1253impl Default for VbrController {
1254 fn default() -> Self {
1255 Self {
1256 target_bitrate: 5_000_000,
1257 max_bitrate: 10_000_000,
1258 min_bitrate: 1_000_000,
1259 current_qp: 28.0,
1260 min_qp: 1,
1261 max_qp: 63,
1262 i_qp_offset: -2,
1263 b_qp_offset: 2,
1264 framerate: 30.0,
1265 gop_length: 250,
1266 frame_count: 0,
1267 total_bits: 0,
1268 current_gop: GopStats::new(0, 0),
1269 gop_history: Vec::new(),
1270 max_gop_history: 10,
1271 pass: 0,
1272 first_pass_data: None,
1273 quality_stability: 0.5,
1274 bit_reservoir: 0,
1275 max_reservoir: 10_000_000,
1276 vbv_buffer: None,
1277 enable_vbv: false,
1278 lookahead_size: 40,
1279 lookahead_frames: Vec::new(),
1280 rate_model: RatePredictionModel::default(),
1281 adaptive_gop: true,
1282 scene_change_threshold: 0.4,
1283 enable_aq: true,
1284 aq_strength: 1.0,
1285 pid_state: PidControllerState::new(),
1286 rdo_params: RdoParameters::default(),
1287 frame_type_state: FrameTypeDecisionState::new(3),
1288 }
1289 }
1290}
1291
1292#[cfg(test)]
1293mod tests {
1294 use super::*;
1295
1296 fn create_test_controller() -> VbrController {
1297 let config = RcConfig::vbr(5_000_000, 10_000_000);
1298 VbrController::new(&config)
1299 }
1300
1301 #[test]
1302 fn test_vbr_creation() {
1303 let controller = create_test_controller();
1304 assert_eq!(controller.target_bitrate(), 5_000_000);
1305 assert_eq!(controller.max_bitrate(), 10_000_000);
1306 }
1307
1308 #[test]
1309 fn test_get_rc() {
1310 let mut controller = create_test_controller();
1311 let output = controller.get_rc(FrameType::Key, 1.0);
1312
1313 assert!(!output.drop_frame);
1314 assert!(output.target_bits > 0);
1315 assert!(output.qp > 0);
1316 assert!(output.lambda > 0.0);
1317 }
1318
1319 #[test]
1320 fn test_closed_loop_feedback() {
1321 let mut controller = create_test_controller();
1322
1323 for i in 0..30 {
1325 let frame_type = if i % 10 == 0 {
1326 FrameType::Key
1327 } else {
1328 FrameType::Inter
1329 };
1330
1331 let output = controller.get_rc(frame_type, 1.0);
1332
1333 let mut stats = FrameStats::new(i, frame_type);
1334 stats.bits = output.target_bits;
1335 stats.target_bits = output.target_bits;
1336 stats.qp = output.qp;
1337 stats.qp_f = output.qp_f;
1338 stats.complexity = 1.0;
1339
1340 controller.update(&stats);
1341 }
1342
1343 assert_eq!(controller.frame_count(), 30);
1345 assert!(controller.current_bitrate() > 0.0);
1346 }
1347
1348 #[test]
1349 fn test_lookahead_buffer() {
1350 let mut controller = create_test_controller();
1351 controller.set_lookahead_size(20);
1352
1353 for _ in 0..25 {
1355 controller.push_lookahead_frame(1.0, 1.0, 1.0, false);
1356 }
1357
1358 assert!(controller.lookahead_frames.len() <= 20);
1359 }
1360
1361 #[test]
1362 fn test_vbv_compliance() {
1363 let mut config = RcConfig::vbr(5_000_000, 10_000_000);
1364 config.buffer_size = 5_000_000;
1365 let mut controller = VbrController::new(&config);
1366 controller.set_vbv_enabled(true);
1367
1368 let output = controller.get_rc(FrameType::Key, 1.0);
1369 assert!(output.max_bits > 0);
1370
1371 let mut stats = FrameStats::new(0, FrameType::Key);
1372 stats.bits = output.target_bits;
1373 stats.target_bits = output.target_bits;
1374 controller.update(&stats);
1375
1376 let fullness = controller.vbv_fullness();
1377 assert!(fullness >= 0.0 && fullness <= 1.0);
1378 }
1379
1380 #[test]
1381 fn test_rate_prediction_model() {
1382 let mut model = RatePredictionModel::default();
1383
1384 for i in 1..20 {
1386 let complexity = i as f32 * 0.1;
1387 let bits = 50_000 + i * 5_000;
1388 model.update(complexity, bits);
1389 }
1390
1391 let prediction = model.predict(1.5);
1392 assert!(prediction > 0);
1393 }
1394
1395 #[test]
1396 fn test_pid_controller() {
1397 let mut pid = PidControllerState::new();
1398
1399 let mut error = 1.0;
1401 for _ in 0..10 {
1402 let output = pid.calculate(error);
1403 error -= output * 0.1; }
1405
1406 assert!(error.abs() < 1.0);
1408 }
1409
1410 #[test]
1411 fn test_adaptive_gop() {
1412 let mut controller = create_test_controller();
1413 controller.set_adaptive_gop(true);
1414
1415 controller.push_lookahead_frame(1.0, 1.0, 1.0, false);
1417 controller.push_lookahead_frame(5.0, 5.0, 5.0, true); let output = controller.get_rc(FrameType::Inter, 1.0);
1420 assert!(output.qp > 0);
1422 }
1423
1424 #[test]
1425 fn test_two_pass_encoding() {
1426 let mut controller = create_test_controller();
1427 controller.set_pass(1);
1428
1429 for i in 0..30 {
1431 let frame_type = if i % 10 == 0 {
1432 FrameType::Key
1433 } else {
1434 FrameType::Inter
1435 };
1436
1437 let _output = controller.get_rc(frame_type, 1.0 + (i as f32 % 3.0) * 0.2);
1438
1439 let mut stats = FrameStats::new(i, frame_type);
1440 stats.bits = 100_000;
1441 stats.target_bits = 100_000;
1442 stats.spatial_complexity = 1.0;
1443 stats.temporal_complexity = 1.0;
1444 stats.complexity = 1.0;
1445 controller.update(&stats);
1446 }
1447
1448 let first_pass_data = controller.finalize_first_pass().expect("should succeed");
1449 assert_eq!(first_pass_data.frame_count, 30);
1450 assert!(!first_pass_data.suggested_bits.is_empty());
1451
1452 let mut controller2 = create_test_controller();
1454 controller2.set_pass(2);
1455 controller2.set_first_pass_data(first_pass_data);
1456
1457 let output = controller2.get_rc(FrameType::Key, 1.0);
1458 assert!(output.target_bits > 0);
1459 }
1460
1461 #[test]
1462 fn test_frame_type_decision() {
1463 let mut state = FrameTypeDecisionState::new(3);
1464
1465 let ft = state.decide_type(250, false, false);
1467 assert_eq!(ft, FrameType::Key);
1468
1469 for _ in 0..3 {
1471 let ft = state.decide_type(250, false, false);
1472 assert!(matches!(ft, FrameType::BiDir | FrameType::Inter));
1473 }
1474
1475 let ft = state.decide_type(250, true, true);
1477 assert_eq!(ft, FrameType::Key);
1478 }
1479
1480 #[test]
1481 fn test_complexity_adjustment() {
1482 let mut controller = create_test_controller();
1483
1484 let mut gop = GopStats::new(0, 0);
1486 gop.average_complexity = 1.0;
1487 controller.gop_history.push(gop);
1488
1489 let low = controller.calculate_complexity_adjustment(0.5);
1490 let high = controller.calculate_complexity_adjustment(2.0);
1491
1492 assert!(high > low);
1494 }
1495
1496 #[test]
1497 fn test_bit_reservoir() {
1498 let mut controller = create_test_controller();
1499
1500 for i in 0..10 {
1502 let output = controller.get_rc(FrameType::Inter, 1.0);
1503 let mut stats = FrameStats::new(i, FrameType::Inter);
1504 stats.bits = output.target_bits / 2;
1505 stats.target_bits = output.target_bits;
1506 controller.update(&stats);
1507 }
1508
1509 assert!(controller.bit_reservoir() > 0);
1510 }
1511
1512 #[test]
1513 fn test_reset() {
1514 let mut controller = create_test_controller();
1515
1516 for i in 0..10 {
1517 let mut stats = FrameStats::new(i, FrameType::Inter);
1518 stats.bits = 100_000;
1519 controller.update(&stats);
1520 }
1521
1522 controller.reset();
1523 assert_eq!(controller.frame_count(), 0);
1524 assert_eq!(controller.bit_reservoir(), 0);
1525 }
1526}