Skip to main content

atmos/os_lib/webp/
vp8_arithmetic_decoder.rs

1use crate::os_lib::webp::decoder::DecodingError;
2use alloc::boxed::Box;
3use alloc::vec::Vec;
4
5use super::vp8::TreeNode;
6
7#[must_use]
8#[repr(transparent)]
9pub(crate) struct BitResult<T> {
10    value_if_not_past_eof: T,
11}
12
13#[must_use]
14pub(crate) struct BitResultAccumulator;
15
16impl<T> BitResult<T> {
17    const fn ok(value: T) -> Self {
18        Self {
19            value_if_not_past_eof: value,
20        }
21    }
22
23    /// Instead of checking this result now, accumulate the burden of checking
24    /// into an accumulator. This accumulator must be checked in the end.
25    #[inline(always)]
26    pub(crate) fn or_accumulate(self, acc: &mut BitResultAccumulator) -> T {
27        let _ = acc;
28        self.value_if_not_past_eof
29    }
30}
31
32impl<T: Default> BitResult<T> {
33    fn err() -> Self {
34        Self {
35            value_if_not_past_eof: T::default(),
36        }
37    }
38}
39
40#[cfg_attr(test, derive(Debug))]
41pub(crate) struct ArithmeticDecoder {
42    chunks: Box<[[u8; 4]]>,
43    state: State,
44    final_bytes: [u8; 3],
45    final_bytes_remaining: i8,
46}
47
48#[cfg_attr(test, derive(Debug))]
49#[derive(Clone, Copy)]
50struct State {
51    chunk_index: usize,
52    value: u64,
53    range: u32,
54    bit_count: i32,
55}
56
57#[cfg_attr(test, derive(Debug))]
58struct FastDecoder<'a> {
59    chunks: &'a [[u8; 4]],
60    uncommitted_state: State,
61    save_state: &'a mut State,
62}
63
64impl ArithmeticDecoder {
65    pub(crate) fn new() -> ArithmeticDecoder {
66        let state = State {
67            chunk_index: 0,
68            value: 0,
69            range: 255,
70            bit_count: -8,
71        };
72        ArithmeticDecoder {
73            chunks: Box::new([]),
74            state,
75            final_bytes: [0; 3],
76            final_bytes_remaining: Self::FINAL_BYTES_REMAINING_EOF,
77        }
78    }
79
80    pub(crate) fn init(&mut self, mut buf: Vec<[u8; 4]>, len: usize) -> Result<(), DecodingError> {
81        let mut final_bytes = [0; 3];
82        let final_bytes_remaining = if len == 4 * buf.len() {
83            0
84        } else {
85            // Pop the last chunk (which is partial), then get length.
86            let Some(last_chunk) = buf.pop() else {
87                return Err(DecodingError::NotEnoughInitData);
88            };
89            let len_rounded_down = 4 * buf.len();
90            let num_bytes_popped = len - len_rounded_down;
91            debug_assert!(num_bytes_popped <= 3);
92            final_bytes[..num_bytes_popped].copy_from_slice(&last_chunk[..num_bytes_popped]);
93            for i in num_bytes_popped..4 {
94                debug_assert_eq!(last_chunk[i], 0, "unexpected {last_chunk:?}");
95            }
96            num_bytes_popped as i8
97        };
98
99        let chunks = buf.into_boxed_slice();
100        let state = State {
101            chunk_index: 0,
102            value: 0,
103            range: 255,
104            bit_count: -8,
105        };
106        *self = Self {
107            chunks,
108            state,
109            final_bytes,
110            final_bytes_remaining,
111        };
112        Ok(())
113    }
114
115    /// Start a span of reading operations from the buffer, without stopping
116    /// when the buffer runs out. For all valid webp images, the buffer will not
117    /// run out prematurely. Conversely if the buffer ends early, the webp image
118    /// cannot be correctly decoded and any intermediate results need to be
119    /// discarded anyway.
120    ///
121    /// Each call to `start_accumulated_result` must be followed by a call to
122    /// `check` on the *same* `ArithmeticDecoder`.
123    #[inline(always)]
124    pub(crate) fn start_accumulated_result(&mut self) -> BitResultAccumulator {
125        BitResultAccumulator
126    }
127
128    /// Check that the read operations done so far were all valid.
129    #[inline(always)]
130    pub(crate) fn check<T>(
131        &self,
132        acc: BitResultAccumulator,
133        value_if_not_past_eof: T,
134    ) -> Result<T, DecodingError> {
135        // The accumulator does not store any state because doing so is
136        // too computationally expensive. Passing it around is a bit of
137        // formality (that is optimized out) to ensure we call `check` .
138        // Instead we check whether we have read past the end of the file.
139        let BitResultAccumulator = acc;
140
141        if self.is_past_eof() {
142            Err(DecodingError::BitStreamError)
143        } else {
144            Ok(value_if_not_past_eof)
145        }
146    }
147
148    fn keep_accumulating<T>(
149        &self,
150        acc: BitResultAccumulator,
151        value_if_not_past_eof: T,
152    ) -> BitResult<T> {
153        // The BitResult will be checked later by a different accumulator.
154        // Because it does not carry state, that is fine.
155        let BitResultAccumulator = acc;
156
157        BitResult::ok(value_if_not_past_eof)
158    }
159
160    // Do not inline this because inlining seems to worsen performance.
161    #[inline(never)]
162    pub(crate) fn read_bool(&mut self, probability: u8) -> BitResult<bool> {
163        if let Some(b) = self.fast().read_bool(probability) {
164            return BitResult::ok(b);
165        }
166
167        self.cold_read_bool(probability)
168    }
169
170    // Do not inline this because inlining seems to worsen performance.
171    #[inline(never)]
172    pub(crate) fn read_flag(&mut self) -> BitResult<bool> {
173        if let Some(b) = self.fast().read_flag() {
174            return BitResult::ok(b);
175        }
176
177        self.cold_read_flag()
178    }
179
180    // Do not inline this because inlining seems to worsen performance.
181    #[inline(never)]
182    pub(crate) fn read_literal(&mut self, n: u8) -> BitResult<u8> {
183        if let Some(v) = self.fast().read_literal(n) {
184            return BitResult::ok(v);
185        }
186
187        self.cold_read_literal(n)
188    }
189
190    // Do not inline this because inlining seems to worsen performance.
191    #[inline(never)]
192    pub(crate) fn read_optional_signed_value(&mut self, n: u8) -> BitResult<i32> {
193        if let Some(v) = self.fast().read_optional_signed_value(n) {
194            return BitResult::ok(v);
195        }
196
197        self.cold_read_optional_signed_value(n)
198    }
199
200    // This is generic and inlined just to skip the first bounds check.
201    #[inline]
202    pub(crate) fn read_with_tree<const N: usize>(&mut self, tree: &[TreeNode; N]) -> BitResult<i8> {
203        let first_node = tree[0];
204        self.read_with_tree_with_first_node(tree, first_node)
205    }
206
207    // Do not inline this because inlining significantly worsens performance.
208    #[inline(never)]
209    pub(crate) fn read_with_tree_with_first_node(
210        &mut self,
211        tree: &[TreeNode],
212        first_node: TreeNode,
213    ) -> BitResult<i8> {
214        if let Some(v) = self.fast().read_with_tree(tree, first_node) {
215            return BitResult::ok(v);
216        }
217
218        self.cold_read_with_tree(tree, usize::from(first_node.index))
219    }
220
221    // As a similar (but different) speedup to BitResult, the FastDecoder reads
222    // bits under an assumption and validates it at the end.
223    //
224    // The idea here is that for normal-sized webp images, the vast majority
225    // of bits are somewhere other than in the last four bytes. Therefore we
226    // can pretend the buffer has infinite size. After we are done reading,
227    // we check if we actually read past the end of `self.chunks`.
228    // If so, we backtrack (or rather we discard `uncommitted_state`)
229    // and try again with the slow approach. This might result in doing double
230    // work for those last few bytes -- in fact we even keep retrying the fast
231    // method to save an if-statement --, but more than make up for that by
232    // speeding up reading from the other thousands or millions of bytes.
233    fn fast(&mut self) -> FastDecoder<'_> {
234        FastDecoder {
235            chunks: &self.chunks,
236            uncommitted_state: self.state,
237            save_state: &mut self.state,
238        }
239    }
240
241    const FINAL_BYTES_REMAINING_EOF: i8 = -0xE;
242
243    fn load_from_final_bytes(&mut self) {
244        match self.final_bytes_remaining {
245            1.. => {
246                self.final_bytes_remaining -= 1;
247                let byte = self.final_bytes[0];
248                self.final_bytes.rotate_left(1);
249                self.state.value <<= 8;
250                self.state.value |= u64::from(byte);
251                self.state.bit_count += 8;
252            }
253            0 => {
254                // libwebp seems to (sometimes?) allow bitstreams that read one byte past the end.
255                // This replicates that logic.
256                self.final_bytes_remaining -= 1;
257                self.state.value <<= 8;
258                self.state.bit_count += 8;
259            }
260            _ => {
261                self.final_bytes_remaining = Self::FINAL_BYTES_REMAINING_EOF;
262            }
263        }
264    }
265
266    fn is_past_eof(&self) -> bool {
267        self.final_bytes_remaining == Self::FINAL_BYTES_REMAINING_EOF
268    }
269
270    fn cold_read_bit(&mut self, probability: u8) -> BitResult<bool> {
271        if self.state.bit_count < 0 {
272            if let Some(chunk) = self.chunks.get(self.state.chunk_index).copied() {
273                let v = u32::from_be_bytes(chunk);
274                self.state.chunk_index += 1;
275                self.state.value <<= 32;
276                self.state.value |= u64::from(v);
277                self.state.bit_count += 32;
278            } else {
279                self.load_from_final_bytes();
280                if self.is_past_eof() {
281                    return BitResult::err();
282                }
283            }
284        }
285        debug_assert!(self.state.bit_count >= 0);
286
287        let probability = u32::from(probability);
288        let split = 1 + (((self.state.range - 1) * probability) >> 8);
289        let bigsplit = u64::from(split) << self.state.bit_count;
290
291        let retval = if let Some(new_value) = self.state.value.checked_sub(bigsplit) {
292            self.state.range -= split;
293            self.state.value = new_value;
294            true
295        } else {
296            self.state.range = split;
297            false
298        };
299        debug_assert!(self.state.range > 0);
300
301        // Compute shift required to satisfy `self.state.range >= 128`.
302        // Apply that shift to `self.state.range` and `self.state.bitcount`.
303        //
304        // Subtract 24 because we only care about leading zeros in the
305        // lowest byte of `self.state.range` which is a `u32`.
306        let shift = self.state.range.leading_zeros().saturating_sub(24);
307        self.state.range <<= shift;
308        self.state.bit_count -= shift as i32;
309        debug_assert!(self.state.range >= 128);
310
311        BitResult::ok(retval)
312    }
313
314    #[cold]
315    #[inline(never)]
316    fn cold_read_bool(&mut self, probability: u8) -> BitResult<bool> {
317        self.cold_read_bit(probability)
318    }
319
320    #[cold]
321    #[inline(never)]
322    fn cold_read_flag(&mut self) -> BitResult<bool> {
323        self.cold_read_bit(128)
324    }
325
326    #[cold]
327    #[inline(never)]
328    fn cold_read_literal(&mut self, n: u8) -> BitResult<u8> {
329        let mut v = 0u8;
330        let mut res = self.start_accumulated_result();
331
332        for _ in 0..n {
333            let b = self.cold_read_flag().or_accumulate(&mut res);
334            v = (v << 1) + u8::from(b);
335        }
336
337        self.keep_accumulating(res, v)
338    }
339
340    #[cold]
341    #[inline(never)]
342    fn cold_read_optional_signed_value(&mut self, n: u8) -> BitResult<i32> {
343        let mut res = self.start_accumulated_result();
344        let flag = self.cold_read_flag().or_accumulate(&mut res);
345        if !flag {
346            // We should not read further bits if the flag is not set.
347            return self.keep_accumulating(res, 0);
348        }
349        let magnitude = self.cold_read_literal(n).or_accumulate(&mut res);
350        let sign = self.cold_read_flag().or_accumulate(&mut res);
351
352        let value = if sign {
353            -i32::from(magnitude)
354        } else {
355            i32::from(magnitude)
356        };
357        self.keep_accumulating(res, value)
358    }
359
360    #[cold]
361    #[inline(never)]
362    fn cold_read_with_tree(&mut self, tree: &[TreeNode], start: usize) -> BitResult<i8> {
363        let mut index = start;
364        let mut res = self.start_accumulated_result();
365
366        loop {
367            let node = tree[index];
368            let prob = node.prob;
369            let b = self.cold_read_bit(prob).or_accumulate(&mut res);
370            let t = if b { node.right } else { node.left };
371            let new_index = usize::from(t);
372            if new_index < tree.len() {
373                index = new_index;
374            } else {
375                let value = TreeNode::value_from_branch(t);
376                return self.keep_accumulating(res, value);
377            }
378        }
379    }
380}
381
382impl FastDecoder<'_> {
383    fn commit_if_valid<T>(self, value_if_not_past_eof: T) -> Option<T> {
384        // If `chunk_index > self.chunks.len()`, it means we used zeroes
385        // instead of an actual chunk and `value_if_not_past_eof` is nonsense.
386        if self.uncommitted_state.chunk_index <= self.chunks.len() {
387            *self.save_state = self.uncommitted_state;
388            Some(value_if_not_past_eof)
389        } else {
390            None
391        }
392    }
393
394    fn read_bool(mut self, probability: u8) -> Option<bool> {
395        let bit = self.fast_read_bit(probability);
396        self.commit_if_valid(bit)
397    }
398
399    fn read_flag(mut self) -> Option<bool> {
400        let value = self.fast_read_flag();
401        self.commit_if_valid(value)
402    }
403
404    fn read_literal(mut self, n: u8) -> Option<u8> {
405        let value = self.fast_read_literal(n);
406        self.commit_if_valid(value)
407    }
408
409    fn read_optional_signed_value(mut self, n: u8) -> Option<i32> {
410        let flag = self.fast_read_flag();
411        if !flag {
412            // We should not read further bits if the flag is not set.
413            return self.commit_if_valid(0);
414        }
415        let magnitude = self.fast_read_literal(n);
416        let sign = self.fast_read_flag();
417        let value = if sign {
418            -i32::from(magnitude)
419        } else {
420            i32::from(magnitude)
421        };
422        self.commit_if_valid(value)
423    }
424
425    fn read_with_tree(mut self, tree: &[TreeNode], first_node: TreeNode) -> Option<i8> {
426        let value = self.fast_read_with_tree(tree, first_node);
427        self.commit_if_valid(value)
428    }
429
430    fn fast_read_bit(&mut self, probability: u8) -> bool {
431        let State {
432            mut chunk_index,
433            mut value,
434            mut range,
435            mut bit_count,
436        } = self.uncommitted_state;
437
438        if bit_count < 0 {
439            let chunk = self.chunks.get(chunk_index).copied();
440            // We ignore invalid data inside the `fast_` functions,
441            // but we increase `chunk_index` below, so we can check
442            // whether we read invalid data in `commit_if_valid`.
443            let chunk = chunk.unwrap_or_default();
444
445            let v = u32::from_be_bytes(chunk);
446            chunk_index += 1;
447            value <<= 32;
448            value |= u64::from(v);
449            bit_count += 32;
450        }
451        debug_assert!(bit_count >= 0);
452
453        let probability = u32::from(probability);
454        let split = 1 + (((range - 1) * probability) >> 8);
455        let bigsplit = u64::from(split) << bit_count;
456
457        let retval = if let Some(new_value) = value.checked_sub(bigsplit) {
458            range -= split;
459            value = new_value;
460            true
461        } else {
462            range = split;
463            false
464        };
465        debug_assert!(range > 0);
466
467        // Compute shift required to satisfy `range >= 128`.
468        // Apply that shift to `range` and `self.bitcount`.
469        //
470        // Subtract 24 because we only care about leading zeros in the
471        // lowest byte of `range` which is a `u32`.
472        let shift = range.leading_zeros().saturating_sub(24);
473        range <<= shift;
474        bit_count -= shift as i32;
475        debug_assert!(range >= 128);
476
477        self.uncommitted_state = State {
478            chunk_index,
479            value,
480            range,
481            bit_count,
482        };
483        retval
484    }
485
486    fn fast_read_flag(&mut self) -> bool {
487        let State {
488            mut chunk_index,
489            mut value,
490            mut range,
491            mut bit_count,
492        } = self.uncommitted_state;
493
494        if bit_count < 0 {
495            let chunk = self.chunks.get(chunk_index).copied();
496            // We ignore invalid data inside the `fast_` functions,
497            // but we increase `chunk_index` below, so we can check
498            // whether we read invalid data in `commit_if_valid`.
499            let chunk = chunk.unwrap_or_default();
500
501            let v = u32::from_be_bytes(chunk);
502            chunk_index += 1;
503            value <<= 32;
504            value |= u64::from(v);
505            bit_count += 32;
506        }
507        debug_assert!(bit_count >= 0);
508
509        let half_range = range / 2;
510        let split = range - half_range;
511        let bigsplit = u64::from(split) << bit_count;
512
513        let retval = if let Some(new_value) = value.checked_sub(bigsplit) {
514            range = half_range;
515            value = new_value;
516            true
517        } else {
518            range = split;
519            false
520        };
521        debug_assert!(range > 0);
522
523        // Compute shift required to satisfy `range >= 128`.
524        // Apply that shift to `range` and `self.bitcount`.
525        //
526        // Subtract 24 because we only care about leading zeros in the
527        // lowest byte of `range` which is a `u32`.
528        let shift = range.leading_zeros().saturating_sub(24);
529        range <<= shift;
530        bit_count -= shift as i32;
531        debug_assert!(range >= 128);
532
533        self.uncommitted_state = State {
534            chunk_index,
535            value,
536            range,
537            bit_count,
538        };
539        retval
540    }
541
542    fn fast_read_literal(&mut self, n: u8) -> u8 {
543        let mut v = 0u8;
544        for _ in 0..n {
545            let b = self.fast_read_flag();
546            v = (v << 1) + u8::from(b);
547        }
548        v
549    }
550
551    fn fast_read_with_tree(&mut self, tree: &[TreeNode], mut node: TreeNode) -> i8 {
552        loop {
553            let prob = node.prob;
554            let b = self.fast_read_bit(prob);
555            let i = if b { node.right } else { node.left };
556            let Some(next_node) = tree.get(usize::from(i)) else {
557                return TreeNode::value_from_branch(i);
558            };
559            node = *next_node;
560        }
561    }
562}
563
564