Bink Video encoder (only 'b' version for now)
[nihav.git] / nihav-rad / src / codecs / binkvidenc / rc.rs
CommitLineData
217de10b
KS
1use super::BlockMode;
2
3#[derive(Default)]
4pub struct RateControl {
5 bitrate: u32,
6 bitpool: u32,
7 tb_num: u32,
8 tb_den: u32,
9 fpos: u32,
10 quality: u8,
11 lambda: f32,
12 first: bool,
13}
14
15impl RateControl {
16 pub fn new() -> Self {
17 Self {
18 lambda: 1.0,
19 ..Default::default()
20 }
21 }
22 pub fn init(&mut self, tb_num: u32, tb_den: u32, bitrate: u32, quality: u8) {
23 self.tb_num = tb_num;
24 self.tb_den = tb_den;
25 self.bitrate = bitrate;
26 self.quality = quality;
27
28 self.bitpool = self.bitrate;
29 self.fpos = 0;
30 self.first = true;
31 }
32 pub fn metric(&self, diff: u32, bits: usize) -> u32 {
33 diff.saturating_add((self.get_weight() * (bits as f32)) as u32)
34 }
35 fn get_weight(&self) -> f32 {
36 if (0..=100).contains(&self.quality) {
37 self.lambda * ((100 - self.quality) as f32)
38 } else {
39 self.lambda
40 }
41 }
42 pub fn expected_size(&self) -> u32 {
43 if self.bitrate != 0 {
44 (if !self.first {
45 let ticks = self.tb_den - self.fpos;
46 u64::from(self.bitpool) * u64::from(self.tb_num) / u64::from(ticks)
47 } else {
48 u64::from(self.bitrate) * 4 * u64::from(self.tb_num) / u64::from(self.tb_den)
49 }) as u32
50 } else {
51 0
52 }
53 }
54 pub fn update_size(&mut self, real_size: usize) {
55 if self.bitrate != 0 {
56 let bits = (real_size * 8) as u32;
57 let tgt_size = self.expected_size();
58
59 self.fpos += self.tb_num;
60 while self.fpos >= self.tb_den {
61 self.fpos -= self.tb_den;
62 self.bitpool += self.bitrate;
63 }
64 self.bitpool = self.bitpool.saturating_sub(bits);
65
66 if bits > tgt_size + tgt_size / 8 {
67 self.lambda += 0.1;
68 }
69 if bits < tgt_size - tgt_size / 8 {
70 self.lambda -= 0.1;
71 if self.lambda < 0.0 {
72 self.lambda = 0.0;
73 }
74 }
75 self.first = false;
76 }
77 }
78 pub fn pattern_run_threshold(&self) -> u8 {
79 match self.quality {
80 1..=39 => 4,
81 40..=59 => 3,
82 60..=79 => 2,
83 80..=89 => 1,
84 _ => 0,
85 }
86 }
87 pub fn get_quant_ranges(&self) -> [u8; 4] {
88 match self.quality {
89 98..=100 => [ 0, 0, 0, 2 ],
90 92..=97 => [ 2, 16, 4, 16 ],
91 85..=91 => [ 5, 16, 7, 16 ],
92 75..=84 => [ 8, 16, 10, 16 ],
93 55..=74 => [ 11, 16, 12, 16 ],
94 1..=54 => [ 12, 16, 13, 16 ],
95 _ => [ 0, 16, 0, 16 ],
96 }
97 }
98 pub fn modify_forbidden_btypes(&self, forbidden: &mut [bool; 12]) {
99 if self.quality > 98 {
100 forbidden[usize::from(BlockMode::Intra)] = true;
101 }
102 if self.quality > 0 {
103 if self.quality < 80 {
104 forbidden[usize::from(BlockMode::Run)] = true;
105 forbidden[usize::from(BlockMode::Residue)] = true;
106 }
107 if self.quality < 90 {
108 forbidden[usize::from(BlockMode::Raw)] = true;
109 }
110 }
111 }
112}