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