• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fmt;
6 use std::io::Write;
7 
8 use crate::bitstream_utils::BitWriter;
9 use crate::bitstream_utils::BitWriterError;
10 
11 #[derive(Debug)]
12 pub enum ObuWriterError {
13     BitWriterError(BitWriterError),
14     UnalignedLeb128,
15 }
16 
17 impl fmt::Display for ObuWriterError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result18     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19         match self {
20             ObuWriterError::BitWriterError(x) => write!(f, "{}", x.to_string()),
21             ObuWriterError::UnalignedLeb128 => {
22                 write!(f, "attempted to write leb128 on unaligned position")
23             }
24         }
25     }
26 }
27 
28 impl From<BitWriterError> for ObuWriterError {
from(err: BitWriterError) -> Self29     fn from(err: BitWriterError) -> Self {
30         ObuWriterError::BitWriterError(err)
31     }
32 }
33 
34 pub type ObuWriterResult<T> = std::result::Result<T, ObuWriterError>;
35 
36 pub struct ObuWriter<W: Write>(BitWriter<W>);
37 
38 impl<W: Write> ObuWriter<W> {
new(writer: W) -> Self39     pub fn new(writer: W) -> Self {
40         Self(BitWriter::new(writer))
41     }
42 
43     /// Writes fixed bit size integer. Corresponds to `f(n)` in AV1 spec defined in 4.10.2.
write_f<T: Into<u32>>(&mut self, bits: usize, value: T) -> ObuWriterResult<usize>44     pub fn write_f<T: Into<u32>>(&mut self, bits: usize, value: T) -> ObuWriterResult<usize> {
45         self.0.write_f(bits, value).map_err(ObuWriterError::BitWriterError)
46     }
47 
48     /// Writes variable length unsigned n-bit number. Corresponds to `uvlc()` in AV1 spec
49     /// defined in 4.10.3.
write_uvlc<T: Into<u32>>(&mut self, value: T) -> ObuWriterResult<usize>50     pub fn write_uvlc<T: Into<u32>>(&mut self, value: T) -> ObuWriterResult<usize> {
51         let value: u32 = value.into();
52         if value == u32::MAX {
53             return self.write_f(32, 0u32);
54         }
55 
56         let value = value + 1;
57         let leading_zeros = (32 - value.leading_zeros()) as usize;
58 
59         Ok(self.write_f(leading_zeros - 1, 0u32)? + self.write_f(leading_zeros, value)?)
60     }
61 
62     /// Writes unsigned little-endian n-byte integer. Corresponds to `le(n)` in AV1 spec
63     /// defined in 4.10.4.
write_le<T: Into<u32>>(&mut self, n: usize, value: T) -> ObuWriterResult<usize>64     pub fn write_le<T: Into<u32>>(&mut self, n: usize, value: T) -> ObuWriterResult<usize> {
65         let value: u32 = value.into();
66         let mut value = value.to_le();
67 
68         for _ in 0..n {
69             self.write_f(4, value & 0xff)?;
70             value >>= 8;
71         }
72 
73         Ok(n)
74     }
75 
76     /// Writes unsigned integer represented by a variable number of little-endian bytes.
77     /// Corresponds to `leb128()` in AV1 spec defined in 4.10.4.
78     ///
79     /// Note: Despite the name, the AV1 4.10.4 limits the value to [`u32::MAX`] = (1 << 32) - 1.
write_leb128<T: Into<u32>>( &mut self, value: T, min_bytes: usize, ) -> ObuWriterResult<usize>80     pub fn write_leb128<T: Into<u32>>(
81         &mut self,
82         value: T,
83         min_bytes: usize,
84     ) -> ObuWriterResult<usize> {
85         if !self.aligned() {
86             return Err(ObuWriterError::UnalignedLeb128);
87         }
88 
89         let value: u32 = value.into();
90         let mut value: u32 = value.to_le();
91         let mut bytes = 0;
92 
93         for _ in 0..8 {
94             bytes += 1;
95 
96             if value >= 0x7f || bytes < min_bytes {
97                 self.write_f(8, 0x80 | (value & 0x7f))?;
98                 value >>= 7;
99             } else {
100                 self.write_f(8, value & 0x7f)?;
101                 break;
102             }
103         }
104 
105         assert!(value < 0x7f);
106 
107         Ok(bytes)
108     }
109 
write_su<T: Into<i32>>(&mut self, bits: usize, value: T) -> ObuWriterResult<usize>110     pub fn write_su<T: Into<i32>>(&mut self, bits: usize, value: T) -> ObuWriterResult<usize> {
111         let mut value: i32 = value.into();
112         if value < 0 {
113             value += 1 << bits;
114         }
115 
116         assert!(value >= 0);
117         self.write_f(bits, value.unsigned_abs())
118     }
119 
aligned(&self) -> bool120     pub fn aligned(&self) -> bool {
121         !self.0.has_data_pending()
122     }
123 }
124 
125 #[cfg(test)]
126 mod tests {
127     use super::*;
128     use crate::codec::av1::reader::Reader;
129 
130     const TEST_VECTOR: &[u32] = &[
131         // some random test values
132         u32::MAX,
133         1,
134         2,
135         3,
136         4,
137         10,
138         20,
139         7312,
140         8832,
141         10123,
142         47457,
143         21390213,
144         u32::MIN,
145         u32::MAX - 1,
146     ];
147 
148     #[test]
test_uvlc()149     fn test_uvlc() {
150         for &value in TEST_VECTOR {
151             let mut buf = Vec::<u8>::new();
152 
153             ObuWriter::new(&mut buf).write_uvlc(value).unwrap();
154 
155             if value == u32::MAX {
156                 // force stop uvlc
157                 buf.push(0x80);
158             }
159 
160             let read = Reader::new(&buf).read_uvlc().unwrap();
161 
162             assert_eq!(read, value, "failed testing {}", value);
163         }
164     }
165 
166     #[test]
test_leb128()167     fn test_leb128() {
168         for &value in TEST_VECTOR {
169             let mut buf = Vec::<u8>::new();
170 
171             ObuWriter::new(&mut buf).write_leb128(value, 0).unwrap();
172             let read = Reader::new(&buf).read_leb128().unwrap();
173 
174             assert_eq!(read, value, "failed testing {}", value);
175         }
176     }
177 
178     #[test]
test_su()179     fn test_su() {
180         let vector =
181             TEST_VECTOR.iter().map(|e| *e as i32).chain(TEST_VECTOR.iter().map(|e| -(*e as i32)));
182 
183         for value in vector {
184             let bits = 32 - value.abs().leading_zeros() as usize + 1; // For sign
185             if bits >= 32 {
186                 // Skip too big nubmers
187                 continue;
188             }
189 
190             let mut buf = Vec::<u8>::new();
191 
192             ObuWriter::new(&mut buf).write_su(bits, value).unwrap();
193 
194             let read = Reader::new(&buf).read_su(bits as usize).unwrap();
195 
196             assert_eq!(read, value, "failed testing {}", value);
197         }
198     }
199 }
200