]>
Commit | Line | Data |
---|---|---|
3952bfd9 KS |
1 | use super::rdo::*; |
2 | ||
3 | pub struct RateControl { | |
4 | pub lambda: f32, | |
5 | tgt_br: u32, | |
6 | budget: isize, | |
7 | cur_time: u32, | |
8 | ts_num: u32, | |
9 | ts_den: u32, | |
10 | mb_w: usize, | |
11 | mb_h: usize, | |
12 | projected: usize, | |
13 | } | |
14 | ||
15 | // todo intra/inter decision, better allocation for intra frames | |
16 | impl RateControl { | |
17 | pub fn new() -> Self { | |
18 | Self { | |
19 | lambda: 1.0, | |
20 | tgt_br: 0, | |
21 | budget: 0, | |
22 | cur_time: 0, | |
23 | ts_num: 0, | |
24 | ts_den: 0, | |
25 | mb_w: 0, | |
26 | mb_h: 0, | |
27 | projected: 0, | |
28 | } | |
29 | } | |
30 | pub fn init(&mut self, mb_w: usize, mb_h: usize, bitrate: u32, ts_num: u32, ts_den: u32) { | |
31 | self.mb_w = mb_w; | |
32 | self.mb_h = mb_h; | |
33 | self.lambda = 1.0; | |
34 | self.cur_time = 0; | |
35 | if bitrate == 0 || ts_num == 0 || ts_den == 0 { | |
36 | self.tgt_br = 0; | |
37 | self.budget = 0; | |
38 | } else { | |
39 | self.tgt_br = bitrate; | |
40 | self.budget = bitrate as isize; | |
41 | self.ts_num = ts_num; | |
42 | self.ts_den = ts_den; | |
43 | } | |
44 | } | |
45 | pub fn guess_quant(&mut self, intra: bool, huffman: bool) -> usize { | |
46 | let fsize = self.get_target_frame_size(intra); | |
47 | self.projected = fsize; | |
48 | if fsize > 0 { | |
49 | for q in 0..64 { | |
50 | let est_fsize = estimate_frame_size(intra, huffman, q, self.mb_w, self.mb_h); | |
51 | if fsize < est_fsize - est_fsize / 10 { | |
52 | return q.saturating_sub(1); | |
53 | } | |
54 | if fsize < est_fsize + est_fsize / 10 { | |
55 | return q; | |
56 | } | |
57 | } | |
58 | 63 | |
59 | } else { | |
60 | 42 | |
61 | } | |
62 | } | |
63 | pub fn update(&mut self, dsize: usize) { | |
64 | const LAMBDA_STEP: f32 = 1.0 / 32.0; | |
65 | ||
66 | if self.tgt_br == 0 { | |
67 | return; | |
68 | } | |
69 | if (self.projected > dsize + dsize / 10) && self.lambda > LAMBDA_STEP { | |
70 | self.lambda -= LAMBDA_STEP; | |
71 | } else if self.projected < dsize - dsize / 10 { | |
72 | self.lambda += LAMBDA_STEP; | |
73 | } | |
74 | self.budget -= dsize as isize; | |
75 | self.cur_time += self.ts_num; | |
76 | while self.cur_time >= self.ts_den { | |
77 | self.cur_time -= self.ts_den; | |
78 | self.budget += self.tgt_br as isize; | |
79 | } | |
80 | } | |
81 | fn get_target_frame_size(&self, intra: bool) -> usize { | |
82 | if self.tgt_br == 0 { | |
83 | 0 | |
84 | } else { | |
85 | let mut avg_fsize = self.budget / ((self.ts_den - self.cur_time) as isize); | |
86 | if avg_fsize > 0 { | |
87 | // todo better intra/inter selection | |
88 | if intra { | |
89 | avg_fsize *= 3; | |
90 | } | |
91 | avg_fsize as usize | |
92 | } else { | |
93 | (self.tgt_br as usize) * (self.ts_num as usize) / (self.ts_den as usize) / 2 | |
94 | } | |
95 | } | |
96 | } | |
97 | } |