oximedia_codec/flac/
rice.rs1#![forbid(unsafe_code)]
9#![allow(clippy::cast_possible_truncation)]
10#![allow(clippy::cast_sign_loss)]
11#![allow(clippy::cast_possible_wrap)]
12
13pub const MAX_RICE_PARAM: u8 = 14;
15
16#[inline]
20pub fn zigzag_encode(v: i32) -> u32 {
21 if v >= 0 {
22 (v as u32) << 1
23 } else {
24 ((-v - 1) as u32) << 1 | 1
25 }
26}
27
28#[inline]
30pub fn zigzag_decode(u: u32) -> i32 {
31 if u & 1 == 0 {
32 (u >> 1) as i32
33 } else {
34 -((u >> 1) as i32) - 1
35 }
36}
37
38#[must_use]
42pub fn rice_bit_cost(residuals: &[i32], k: u8) -> u64 {
43 residuals
44 .iter()
45 .map(|&r| {
46 let u = zigzag_encode(r);
47 let quotient = u >> k;
48 1u64 + u64::from(k) + u64::from(quotient)
49 })
50 .sum()
51}
52
53#[must_use]
57pub fn optimal_rice_param(residuals: &[i32]) -> u8 {
58 if residuals.is_empty() {
59 return 0;
60 }
61 let mut best_k = 0u8;
62 let mut best_cost = u64::MAX;
63 for k in 0..=MAX_RICE_PARAM {
64 let cost = rice_bit_cost(residuals, k);
65 if cost < best_cost {
66 best_cost = cost;
67 best_k = k;
68 }
69 }
70 best_k
71}
72
73#[must_use]
77pub fn rice_encode(residuals: &[i32], k: u8) -> Vec<u8> {
78 let mut bits: Vec<bool> = Vec::new();
79
80 for &r in residuals {
81 let u = zigzag_encode(r);
82 let quotient = u >> k;
83 let remainder = u & ((1u32 << k) - 1);
84
85 for _ in 0..quotient {
87 bits.push(true);
88 }
89 bits.push(false);
90
91 for bit_idx in (0..k).rev() {
93 bits.push((remainder >> bit_idx) & 1 != 0);
94 }
95 }
96
97 let mut out = Vec::with_capacity((bits.len() + 7) / 8);
99 let mut byte = 0u8;
100 let mut fill = 0u8;
101 for bit in bits {
102 byte = (byte << 1) | u8::from(bit);
103 fill += 1;
104 if fill == 8 {
105 out.push(byte);
106 byte = 0;
107 fill = 0;
108 }
109 }
110 if fill > 0 {
111 out.push(byte << (8 - fill));
112 }
113 out
114}
115
116pub struct RiceDecoder<'a> {
118 data: &'a [u8],
119 byte_pos: usize,
120 bit_pos: u8,
121}
122
123impl<'a> RiceDecoder<'a> {
124 #[must_use]
126 pub fn new(data: &'a [u8]) -> Self {
127 Self {
128 data,
129 byte_pos: 0,
130 bit_pos: 0,
131 }
132 }
133
134 fn read_bit(&mut self) -> Option<bool> {
135 if self.byte_pos >= self.data.len() {
136 return None;
137 }
138 let bit = (self.data[self.byte_pos] >> (7 - self.bit_pos)) & 1 != 0;
139 self.bit_pos += 1;
140 if self.bit_pos == 8 {
141 self.byte_pos += 1;
142 self.bit_pos = 0;
143 }
144 Some(bit)
145 }
146
147 pub fn decode_one(&mut self, k: u8) -> Option<i32> {
149 let mut quotient = 0u32;
151 loop {
152 let bit = self.read_bit()?;
153 if !bit {
154 break;
155 }
156 quotient += 1;
157 if quotient > 1024 * 1024 {
158 return None; }
160 }
161
162 let mut remainder = 0u32;
164 for _ in 0..k {
165 let bit = self.read_bit()?;
166 remainder = (remainder << 1) | u32::from(bit);
167 }
168
169 let u = (quotient << k) | remainder;
170 Some(zigzag_decode(u))
171 }
172
173 pub fn decode_n(&mut self, count: usize, k: u8) -> Vec<i32> {
175 (0..count).map_while(|_| self.decode_one(k)).collect()
176 }
177}
178
179#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn test_zigzag_encode_decode_identity() {
189 for v in [-100i32, -1, 0, 1, 100, i16::MAX as i32] {
190 let u = zigzag_encode(v);
191 let back = zigzag_decode(u);
192 assert_eq!(back, v, "zigzag roundtrip failed for {v}");
193 }
194 }
195
196 #[test]
197 fn test_zigzag_non_negative_output() {
198 for v in [-200i32, -100, -1, 0, 1, 100, 200] {
200 let _u = zigzag_encode(v);
201 }
202 }
203
204 #[test]
205 fn test_rice_bit_cost_zero_residuals() {
206 let res = vec![0i32; 16];
207 let cost = rice_bit_cost(&res, 0);
208 assert_eq!(cost, 16);
210 }
211
212 #[test]
213 fn test_rice_encode_decode_roundtrip() {
214 let residuals = vec![0i32, 1, -1, 2, -2, 5, -5, 10, -10];
215 let k = optimal_rice_param(&residuals);
216 let encoded = rice_encode(&residuals, k);
217 let mut dec = RiceDecoder::new(&encoded);
218 let decoded = dec.decode_n(residuals.len(), k);
219 assert_eq!(decoded, residuals, "Rice roundtrip must be lossless");
220 }
221
222 #[test]
223 fn test_rice_encode_empty() {
224 let encoded = rice_encode(&[], 4);
225 assert!(encoded.is_empty());
226 }
227
228 #[test]
229 fn test_optimal_rice_param_small_residuals() {
230 let residuals = vec![0i32; 32];
232 let k = optimal_rice_param(&residuals);
233 assert_eq!(k, 0, "All-zero residuals → k=0 is optimal");
234 }
235
236 #[test]
237 fn test_optimal_rice_param_large_residuals() {
238 let residuals: Vec<i32> = (0..32).map(|i| i * 1000).collect();
240 let k_large = optimal_rice_param(&residuals);
241 let k_small = optimal_rice_param(&vec![0i32; 32]);
242 assert!(k_large >= k_small, "Large residuals should use larger k");
243 }
244
245 #[test]
246 fn test_rice_decode_n_partial() {
247 let residuals = vec![1i32, 2, 3];
249 let k = 1;
250 let encoded = rice_encode(&residuals, k);
251 let mut dec = RiceDecoder::new(&encoded);
253 let decoded = dec.decode_n(100, k);
254 assert!(decoded.len() >= residuals.len());
255 assert_eq!(&decoded[..residuals.len()], &residuals[..]);
256 }
257}