Skip to main content

oximedia_io/bits/
exp_golomb.rs

1//! Exp-Golomb coding implementation.
2//!
3//! Exponential-Golomb (Exp-Golomb) codes are variable-length codes used
4//! in H.264/AVC and other video coding standards for encoding integers.
5//!
6//! # Encoding Format
7//!
8//! An Exp-Golomb code consists of:
9//! 1. A prefix of `M` zero bits
10//! 2. A separator `1` bit
11//! 3. A suffix of `M` information bits
12//!
13//! The value is calculated as: `2^M + suffix - 1`
14//!
15//! # Examples
16//!
17//! | Value | Code     | Binary  |
18//! |-------|----------|---------|
19//! | 0     | 1        | 1       |
20//! | 1     | 010      | 010     |
21//! | 2     | 011      | 011     |
22//! | 3     | 00100    | 00100   |
23//! | 4     | 00101    | 00101   |
24//!
25//! # Signed Values
26//!
27//! Signed Exp-Golomb (se(v)) maps unsigned values to signed:
28//! - 0 -> 0
29//! - 1 -> 1
30//! - 2 -> -1
31//! - 3 -> 2
32//! - 4 -> -2
33
34use super::BitReader;
35use oximedia_core::{OxiError, OxiResult};
36
37impl BitReader<'_> {
38    /// Reads an unsigned Exp-Golomb coded integer (ue(v)).
39    ///
40    /// This is used extensively in H.264 for encoding syntax elements.
41    ///
42    /// # Errors
43    ///
44    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
45    /// Returns [`OxiError::InvalidData`] if the code is malformed or too long.
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// use oximedia_io::bits::BitReader;
51    ///
52    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
53    /// // ue(0) = 1 (single bit)
54    /// let data = [0b10000000];
55    /// let mut reader = BitReader::new(&data);
56    /// assert_eq!(reader.read_exp_golomb()?, 0);
57    ///
58    /// // ue(1) = 010
59    /// let data = [0b01000000];
60    /// let mut reader = BitReader::new(&data);
61    /// assert_eq!(reader.read_exp_golomb()?, 1);
62    ///
63    /// // ue(2) = 011
64    /// let data = [0b01100000];
65    /// let mut reader = BitReader::new(&data);
66    /// assert_eq!(reader.read_exp_golomb()?, 2);
67    /// # Ok(())
68    /// # }
69    /// ```
70    pub fn read_exp_golomb(&mut self) -> OxiResult<u64> {
71        // Count leading zeros
72        let mut leading_zeros: u8 = 0;
73        while self.read_bit()? == 0 {
74            leading_zeros += 1;
75            if leading_zeros > 63 {
76                return Err(OxiError::InvalidData(
77                    "Exp-Golomb code too long (> 63 leading zeros)".to_string(),
78                ));
79            }
80        }
81
82        if leading_zeros == 0 {
83            return Ok(0);
84        }
85
86        // Read the suffix bits
87        let suffix = self.read_bits(leading_zeros)?;
88
89        // Calculate value: 2^M + suffix - 1
90        Ok((1u64 << leading_zeros) - 1 + suffix)
91    }
92
93    /// Reads a signed Exp-Golomb coded integer (se(v)).
94    ///
95    /// Maps unsigned Exp-Golomb values to signed:
96    /// - 0 -> 0
97    /// - 1 -> 1
98    /// - 2 -> -1
99    /// - 3 -> 2
100    /// - 4 -> -2
101    /// - etc.
102    ///
103    /// # Errors
104    ///
105    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
106    /// Returns [`OxiError::InvalidData`] if the code is malformed.
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// use oximedia_io::bits::BitReader;
112    ///
113    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
114    /// // se(0) = 1 -> value 0
115    /// let data = [0b10000000];
116    /// let mut reader = BitReader::new(&data);
117    /// assert_eq!(reader.read_signed_exp_golomb()?, 0);
118    ///
119    /// // se(+1) = 010 -> value 1
120    /// let data = [0b01000000];
121    /// let mut reader = BitReader::new(&data);
122    /// assert_eq!(reader.read_signed_exp_golomb()?, 1);
123    ///
124    /// // se(-1) = 011 -> value 2
125    /// let data = [0b01100000];
126    /// let mut reader = BitReader::new(&data);
127    /// assert_eq!(reader.read_signed_exp_golomb()?, -1);
128    /// # Ok(())
129    /// # }
130    /// ```
131    #[allow(clippy::cast_possible_wrap)]
132    pub fn read_signed_exp_golomb(&mut self) -> OxiResult<i64> {
133        let ue = self.read_exp_golomb()?;
134
135        // Map: ue -> se
136        // 0 -> 0, 1 -> 1, 2 -> -1, 3 -> 2, 4 -> -2, ...
137        // Formula: if odd, positive (ue+1)/2; if even, negative -(ue/2)
138        let abs_value = ue.div_ceil(2) as i64;
139        if ue & 1 == 0 {
140            Ok(-abs_value)
141        } else {
142            Ok(abs_value)
143        }
144    }
145
146    /// Reads an unsigned Exp-Golomb coded integer, alias for `read_exp_golomb`.
147    ///
148    /// This follows H.264 naming convention (ue(v)).
149    ///
150    /// # Errors
151    ///
152    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
153    /// Returns [`OxiError::InvalidData`] if the code is malformed.
154    #[inline]
155    pub fn read_ue(&mut self) -> OxiResult<u64> {
156        self.read_exp_golomb()
157    }
158
159    /// Reads a signed Exp-Golomb coded integer, alias for `read_signed_exp_golomb`.
160    ///
161    /// This follows H.264 naming convention (se(v)).
162    ///
163    /// # Errors
164    ///
165    /// Returns [`OxiError::UnexpectedEof`] if there are not enough bits.
166    /// Returns [`OxiError::InvalidData`] if the code is malformed.
167    #[inline]
168    pub fn read_se(&mut self) -> OxiResult<i64> {
169        self.read_signed_exp_golomb()
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn test_read_exp_golomb_zero() {
179        // ue(0) = 1
180        let data = [0b10000000];
181        let mut reader = BitReader::new(&data);
182        assert_eq!(
183            reader
184                .read_exp_golomb()
185                .expect("read_exp_golomb should succeed"),
186            0
187        );
188        assert_eq!(reader.bits_read(), 1);
189    }
190
191    #[test]
192    fn test_read_exp_golomb_one() {
193        // ue(1) = 010
194        let data = [0b01000000];
195        let mut reader = BitReader::new(&data);
196        assert_eq!(
197            reader
198                .read_exp_golomb()
199                .expect("read_exp_golomb should succeed"),
200            1
201        );
202        assert_eq!(reader.bits_read(), 3);
203    }
204
205    #[test]
206    fn test_read_exp_golomb_two() {
207        // ue(2) = 011
208        let data = [0b01100000];
209        let mut reader = BitReader::new(&data);
210        assert_eq!(
211            reader
212                .read_exp_golomb()
213                .expect("read_exp_golomb should succeed"),
214            2
215        );
216        assert_eq!(reader.bits_read(), 3);
217    }
218
219    #[test]
220    fn test_read_exp_golomb_three() {
221        // ue(3) = 00100
222        let data = [0b00100000];
223        let mut reader = BitReader::new(&data);
224        assert_eq!(
225            reader
226                .read_exp_golomb()
227                .expect("read_exp_golomb should succeed"),
228            3
229        );
230        assert_eq!(reader.bits_read(), 5);
231    }
232
233    #[test]
234    fn test_read_exp_golomb_four() {
235        // ue(4) = 00101
236        let data = [0b00101000];
237        let mut reader = BitReader::new(&data);
238        assert_eq!(
239            reader
240                .read_exp_golomb()
241                .expect("read_exp_golomb should succeed"),
242            4
243        );
244        assert_eq!(reader.bits_read(), 5);
245    }
246
247    #[test]
248    fn test_read_exp_golomb_five() {
249        // ue(5) = 00110
250        let data = [0b00110000];
251        let mut reader = BitReader::new(&data);
252        assert_eq!(
253            reader
254                .read_exp_golomb()
255                .expect("read_exp_golomb should succeed"),
256            5
257        );
258        assert_eq!(reader.bits_read(), 5);
259    }
260
261    #[test]
262    fn test_read_exp_golomb_six() {
263        // ue(6) = 00111
264        let data = [0b00111000];
265        let mut reader = BitReader::new(&data);
266        assert_eq!(
267            reader
268                .read_exp_golomb()
269                .expect("read_exp_golomb should succeed"),
270            6
271        );
272        assert_eq!(reader.bits_read(), 5);
273    }
274
275    #[test]
276    fn test_read_exp_golomb_seven() {
277        // ue(7) = 0001000
278        let data = [0b00010000];
279        let mut reader = BitReader::new(&data);
280        assert_eq!(
281            reader
282                .read_exp_golomb()
283                .expect("read_exp_golomb should succeed"),
284            7
285        );
286        assert_eq!(reader.bits_read(), 7);
287    }
288
289    #[test]
290    fn test_read_exp_golomb_large() {
291        // ue(14) = 0001111
292        let data = [0b00011110];
293        let mut reader = BitReader::new(&data);
294        assert_eq!(
295            reader
296                .read_exp_golomb()
297                .expect("read_exp_golomb should succeed"),
298            14
299        );
300    }
301
302    #[test]
303    fn test_read_signed_exp_golomb_zero() {
304        // se(0) = ue(0) = 1
305        let data = [0b10000000];
306        let mut reader = BitReader::new(&data);
307        assert_eq!(
308            reader
309                .read_signed_exp_golomb()
310                .expect("read_signed_exp_golomb should succeed"),
311            0
312        );
313    }
314
315    #[test]
316    fn test_read_signed_exp_golomb_positive_one() {
317        // se(+1) = ue(1) = 010
318        let data = [0b01000000];
319        let mut reader = BitReader::new(&data);
320        assert_eq!(
321            reader
322                .read_signed_exp_golomb()
323                .expect("read_signed_exp_golomb should succeed"),
324            1
325        );
326    }
327
328    #[test]
329    fn test_read_signed_exp_golomb_negative_one() {
330        // se(-1) = ue(2) = 011
331        let data = [0b01100000];
332        let mut reader = BitReader::new(&data);
333        assert_eq!(
334            reader
335                .read_signed_exp_golomb()
336                .expect("read_signed_exp_golomb should succeed"),
337            -1
338        );
339    }
340
341    #[test]
342    fn test_read_signed_exp_golomb_positive_two() {
343        // se(+2) = ue(3) = 00100
344        let data = [0b00100000];
345        let mut reader = BitReader::new(&data);
346        assert_eq!(
347            reader
348                .read_signed_exp_golomb()
349                .expect("read_signed_exp_golomb should succeed"),
350            2
351        );
352    }
353
354    #[test]
355    fn test_read_signed_exp_golomb_negative_two() {
356        // se(-2) = ue(4) = 00101
357        let data = [0b00101000];
358        let mut reader = BitReader::new(&data);
359        assert_eq!(
360            reader
361                .read_signed_exp_golomb()
362                .expect("read_signed_exp_golomb should succeed"),
363            -2
364        );
365    }
366
367    #[test]
368    fn test_read_signed_exp_golomb_sequence() {
369        // Test the mapping: 0->0, 1->1, 2->-1, 3->2, 4->-2, 5->3, 6->-3
370        let test_cases: [(u64, i64); 7] =
371            [(0, 0), (1, 1), (2, -1), (3, 2), (4, -2), (5, 3), (6, -3)];
372
373        for (ue_val, expected_se) in test_cases {
374            let abs_value = ((ue_val + 1) / 2) as i64;
375            let se_val = if ue_val & 1 == 0 {
376                -abs_value
377            } else {
378                abs_value
379            };
380            assert_eq!(
381                se_val, expected_se,
382                "ue({ue_val}) should map to se({expected_se})"
383            );
384        }
385    }
386
387    #[test]
388    fn test_read_multiple_exp_golomb() {
389        // Two values: ue(0)=1 and ue(1)=010 packed together
390        let data = [0b10100000];
391        let mut reader = BitReader::new(&data);
392        assert_eq!(
393            reader
394                .read_exp_golomb()
395                .expect("read_exp_golomb should succeed"),
396            0
397        );
398        assert_eq!(
399            reader
400                .read_exp_golomb()
401                .expect("read_exp_golomb should succeed"),
402            1
403        );
404    }
405
406    #[test]
407    fn test_read_ue_alias() {
408        let data = [0b01000000];
409        let mut reader = BitReader::new(&data);
410        assert_eq!(reader.read_ue().expect("read_ue should succeed"), 1);
411    }
412
413    #[test]
414    fn test_read_se_alias() {
415        let data = [0b01100000];
416        let mut reader = BitReader::new(&data);
417        assert_eq!(reader.read_se().expect("read_se should succeed"), -1);
418    }
419
420    #[test]
421    fn test_exp_golomb_eof() {
422        // Not enough bits
423        let data = [0b00000000];
424        let mut reader = BitReader::new(&data);
425        let result = reader.read_exp_golomb();
426        assert!(result.is_err());
427    }
428
429    // Additional comprehensive tests
430
431    #[test]
432    fn test_exp_golomb_boundary_values() {
433        // Test values at power-of-2 boundaries
434        // ue(14) = 0001111 (3 leading zeros, suffix=111)
435        let data = [0b00011110];
436        let mut reader = BitReader::new(&data);
437        assert_eq!(
438            reader
439                .read_exp_golomb()
440                .expect("read_exp_golomb should succeed"),
441            14
442        );
443
444        // ue(30) = 00011111 (3 leading zeros, suffix = 111)
445        let data = [0b00011111];
446        let mut reader = BitReader::new(&data);
447        assert_eq!(
448            reader
449                .read_exp_golomb()
450                .expect("read_exp_golomb should succeed"),
451            14
452        );
453    }
454
455    #[test]
456    fn test_exp_golomb_consecutive_zeros() {
457        // Multiple ue(0) values in a row
458        let data = [0b11110000]; // Four ue(0) values
459        let mut reader = BitReader::new(&data);
460        assert_eq!(
461            reader
462                .read_exp_golomb()
463                .expect("read_exp_golomb should succeed"),
464            0
465        );
466        assert_eq!(
467            reader
468                .read_exp_golomb()
469                .expect("read_exp_golomb should succeed"),
470            0
471        );
472        assert_eq!(
473            reader
474                .read_exp_golomb()
475                .expect("read_exp_golomb should succeed"),
476            0
477        );
478        assert_eq!(
479            reader
480                .read_exp_golomb()
481                .expect("read_exp_golomb should succeed"),
482            0
483        );
484    }
485
486    #[test]
487    fn test_signed_exp_golomb_range() {
488        // Test the full mapping for small values
489        let test_cases = [
490            (0b10000000, 0),  // ue(0) -> se(0)
491            (0b01000000, 1),  // ue(1) -> se(1)
492            (0b01100000, -1), // ue(2) -> se(-1)
493            (0b00100000, 2),  // ue(3) -> se(2)
494            (0b00101000, -2), // ue(4) -> se(-2)
495            (0b00110000, 3),  // ue(5) -> se(3)
496            (0b00111000, -3), // ue(6) -> se(-3)
497        ];
498
499        for (data_byte, expected) in test_cases {
500            let data = [data_byte];
501            let mut reader = BitReader::new(&data);
502            assert_eq!(
503                reader
504                    .read_signed_exp_golomb()
505                    .expect("read_signed_exp_golomb should succeed"),
506                expected
507            );
508        }
509    }
510
511    #[test]
512    fn test_signed_exp_golomb_large_values() {
513        // Test larger signed values
514        // se(5) = ue(9) = 0001010 (3 leading zeros, suffix=010)
515        // Binary: 0001010
516        let data = [0b00010100];
517        let mut reader = BitReader::new(&data);
518        assert_eq!(
519            reader
520                .read_signed_exp_golomb()
521                .expect("read_signed_exp_golomb should succeed"),
522            5
523        );
524
525        // se(-5) = ue(10) = 0001011 (3 leading zeros, suffix=011)
526        // Binary: 0001011
527        let data = [0b00010110];
528        let mut reader = BitReader::new(&data);
529        assert_eq!(
530            reader
531                .read_signed_exp_golomb()
532                .expect("read_signed_exp_golomb should succeed"),
533            -5
534        );
535    }
536
537    #[test]
538    fn test_exp_golomb_mixed_with_other_reads() {
539        // Test exp-golomb mixed with regular bit reads
540        let data = [0b11100000]; // flag(1), flag(1), ue(0)=1, ...
541        let mut reader = BitReader::new(&data);
542
543        assert!(reader.read_flag().expect("read_flag should succeed"));
544        assert!(reader.read_flag().expect("read_flag should succeed"));
545        assert_eq!(
546            reader
547                .read_exp_golomb()
548                .expect("read_exp_golomb should succeed"),
549            0
550        );
551    }
552
553    #[test]
554    fn test_exp_golomb_too_many_leading_zeros() {
555        // Test error handling for too many leading zeros (>63)
556        let data = [0x00; 10]; // 80 zero bits
557        let mut reader = BitReader::new(&data);
558        let result = reader.read_exp_golomb();
559        assert!(result.is_err());
560    }
561
562    #[test]
563    fn test_exp_golomb_insufficient_suffix_bits() {
564        // Leading zeros indicate we need more bits than available
565        let data = [0b00000001]; // 7 leading zeros, but only 1 bit left
566        let mut reader = BitReader::new(&data);
567        let result = reader.read_exp_golomb();
568        assert!(result.is_err());
569    }
570
571    #[test]
572    fn test_exp_golomb_arithmetic() {
573        // Verify the calculation: 2^M + suffix - 1
574        // For ue(10): M=3, suffix=3, value = 2^3 + 3 - 1 = 8 + 3 - 1 = 10
575        // Binary: 0001011
576        let data = [0b00010110];
577        let mut reader = BitReader::new(&data);
578        assert_eq!(
579            reader
580                .read_exp_golomb()
581                .expect("read_exp_golomb should succeed"),
582            10
583        );
584    }
585
586    #[test]
587    fn test_signed_zero_mapping() {
588        // Ensure se(0) maps correctly from ue(0)
589        let data = [0b10000000];
590        let mut reader = BitReader::new(&data);
591        let value = reader.read_se().expect("read_se should succeed");
592        assert_eq!(value, 0);
593    }
594
595    #[test]
596    fn test_alternating_signed_pattern() {
597        // Test that signed values alternate positive/negative correctly
598        // Pack: se(1)=ue(1)=010, se(-1)=ue(2)=011, se(2)=ue(3)=00100
599        let data = [
600            0b01001100, // 010 011 00...
601            0b10000000, // ...100
602        ];
603        let mut reader = BitReader::new(&data);
604
605        assert_eq!(reader.read_se().expect("read_se should succeed"), 1);
606        assert_eq!(reader.read_se().expect("read_se should succeed"), -1);
607        assert_eq!(reader.read_se().expect("read_se should succeed"), 2);
608    }
609
610    #[test]
611    fn test_ue_se_alias_consistency() {
612        // Ensure ue/se aliases work identically to full names
613        let data = [0b01000000, 0b01100000];
614        let mut reader = BitReader::new(&data);
615
616        let ue_val = reader.read_ue().expect("read_ue should succeed");
617        let se_val = reader.read_se().expect("read_se should succeed");
618
619        let mut reader2 = BitReader::new(&data);
620        assert_eq!(
621            reader2
622                .read_exp_golomb()
623                .expect("read_exp_golomb should succeed"),
624            ue_val
625        );
626        assert_eq!(
627            reader2
628                .read_signed_exp_golomb()
629                .expect("read_signed_exp_golomb should succeed"),
630            se_val
631        );
632    }
633}