Skip to main content

zenjxl_decoder/api/inner/
process.rs

1// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6use std::{
7    io::IoSliceMut,
8    ops::{Deref, Range},
9};
10
11use crate::error::Result;
12
13use crate::api::{JxlBitstreamInput, JxlDecoderInner, JxlOutputBuffer, ProcessingResult};
14
15// General implementation strategy:
16// - Anything that is not a section is read into a small buffer.
17// - As soon as we know section sizes, data is read directly into sections.
18// When the start of the populated range in `buf` goes past half of its length,
19// the data in the buffer is moved back to the beginning.
20
21pub(super) struct SmallBuffer {
22    buf: Vec<u8>,
23    range: Range<usize>,
24}
25
26impl SmallBuffer {
27    pub(super) fn refill(
28        &mut self,
29        mut get_input: impl FnMut(&mut [IoSliceMut]) -> Result<usize, std::io::Error>,
30        max: Option<usize>,
31    ) -> Result<usize> {
32        let mut total = 0;
33        loop {
34            if self.range.start >= self.buf.len() / 2 {
35                let start = self.range.start;
36                let len = self.range.len();
37                let (pre, post) = self.buf.split_at_mut(start);
38                pre[0..len].copy_from_slice(&post[0..len]);
39                self.range.start -= start;
40                self.range.end -= start;
41            }
42            if self.range.len() >= self.buf.len() / 2 {
43                break;
44            }
45            let stop = if let Some(max) = max {
46                self.range
47                    .end
48                    .saturating_add(max.saturating_sub(total))
49                    .min(self.buf.len())
50            } else {
51                self.buf.len()
52            };
53            let num = get_input(&mut [IoSliceMut::new(&mut self.buf[self.range.end..stop])])?;
54            total += num;
55            self.range.end += num;
56            if num == 0 {
57                break;
58            }
59        }
60        Ok(total)
61    }
62
63    pub(super) fn take(&mut self, mut buffers: &mut [IoSliceMut]) -> usize {
64        let mut num = 0;
65        while !self.range.is_empty() {
66            let Some((buf, rest)) = buffers.split_first_mut() else {
67                break;
68            };
69            buffers = rest;
70            let len = self.range.len().min(buf.len());
71            // Only copy 'len' bytes, not the entire range, to avoid panic when buf is smaller than range
72            buf[..len].copy_from_slice(&self.buf[self.range.start..self.range.start + len]);
73            self.range.start += len;
74            num += len;
75        }
76        num
77    }
78
79    pub(super) fn consume(&mut self, amount: usize) -> usize {
80        let amount = amount.min(self.range.len());
81        self.range.start += amount;
82        amount
83    }
84
85    pub(super) fn new(initial_size: usize) -> Self {
86        Self {
87            buf: vec![0; initial_size],
88            range: 0..0,
89        }
90    }
91
92    pub(super) fn range(&self) -> Range<usize> {
93        self.range.clone()
94    }
95
96    pub(super) fn enlarge(&mut self) {
97        // Note: we need a *4 here because doubling the buffer size might still not allow refill() to make progress.
98        self.buf.resize(self.buf.len() * 4, 0);
99    }
100
101    pub(super) fn can_read_more(&self) -> bool {
102        self.buf.len() > self.len() * 2 && self.range.end < self.buf.len()
103    }
104}
105
106impl Deref for SmallBuffer {
107    type Target = [u8];
108    fn deref(&self) -> &Self::Target {
109        &self.buf[self.range.clone()]
110    }
111}
112
113impl JxlDecoderInner {
114    /// Process more of the input file.
115    /// This function will return when reaching the next decoding stage (i.e. finished decoding
116    /// file/frame header, or finished decoding a frame).
117    /// If called when decoding a frame with `None` for buffers, the frame will still be read,
118    /// but pixel data will not be produced.
119    #[inline(never)]
120    pub fn process(
121        &mut self,
122        input: &mut dyn JxlBitstreamInput,
123        buffers: Option<&mut [JxlOutputBuffer]>,
124    ) -> Result<ProcessingResult<(), ()>> {
125        ProcessingResult::new(self.codestream_parser.process(
126            &mut self.box_parser,
127            input,
128            &self.options,
129            buffers,
130            false,
131        ))
132    }
133
134    /// Draws all the pixels we have data for.
135    pub fn flush_pixels(&mut self, buffers: &mut [JxlOutputBuffer]) -> Result<()> {
136        let mut input: &[u8] = &[];
137        match self.codestream_parser.process(
138            &mut self.box_parser,
139            &mut input,
140            &self.options,
141            Some(buffers),
142            true,
143        ) {
144            Ok(()) => Ok(()),
145            Err(crate::error::Error::OutOfBounds(_)) => Ok(()),
146            Err(e) => Err(e),
147        }
148    }
149}