/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.5.9/src/bitstream.rs
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023. |
3 | | * |
4 | | * This software is free software; |
5 | | * |
6 | | * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license |
7 | | */ |
8 | | |
9 | | #![allow( |
10 | | clippy::if_not_else, |
11 | | clippy::similar_names, |
12 | | clippy::inline_always, |
13 | | clippy::doc_markdown, |
14 | | clippy::cast_sign_loss, |
15 | | clippy::cast_possible_truncation |
16 | | )] |
17 | | |
18 | | //! This file exposes a single struct that can decode a huffman encoded |
19 | | //! Bitstream in a JPEG file |
20 | | //! |
21 | | //! This code is optimized for speed. |
22 | | //! It's meant to be super duper super fast, because everyone else depends on this being fast. |
23 | | //! It's (annoyingly) serial hence we cant use parallel bitstreams(it's variable length coding.) |
24 | | //! |
25 | | //! Furthermore, on the case of refills, we have to do bytewise processing because the standard decided |
26 | | //! that we want to support markers in the middle of streams(seriously few people use RST markers). |
27 | | //! |
28 | | //! So we pull in all optimization steps: |
29 | | //! - use `inline[always]`? ✅ , |
30 | | //! - pre-execute most common cases ✅, |
31 | | //! - add random comments ✅ |
32 | | //! - fast paths ✅. |
33 | | //! |
34 | | //! Speed-wise: It is probably the fastest JPEG BitStream decoder to ever sail the seven seas because of |
35 | | //! a couple of optimization tricks. |
36 | | //! 1. Fast refills from libjpeg-turbo |
37 | | //! 2. As few as possible branches in decoder fast paths. |
38 | | //! 3. Accelerated AC table decoding borrowed from stb_image.h written by Fabian Gissen (@ rygorous), |
39 | | //! improved by me to handle more cases. |
40 | | //! 4. Safe and extensible routines(e.g. cool ways to eliminate bounds check) |
41 | | //! 5. No unsafe here |
42 | | //! |
43 | | //! Readability comes as a second priority(I tried with variable names this time, and we are wayy better than libjpeg). |
44 | | //! |
45 | | //! Anyway if you are reading this it means your cool and I hope you get whatever part of the code you are looking for |
46 | | //! (or learn something cool) |
47 | | //! |
48 | | //! Knock yourself out. |
49 | | use alloc::format; |
50 | | use alloc::string::ToString; |
51 | | use core::cmp::min; |
52 | | |
53 | | use zune_core::bytestream::{ZByteReaderTrait, ZReader}; |
54 | | |
55 | | use crate::errors::DecodeErrors; |
56 | | use crate::huffman::{HuffmanTable, HUFF_LOOKAHEAD}; |
57 | | use crate::marker::Marker; |
58 | | use crate::mcu::DCT_BLOCK; |
59 | | use crate::misc::UN_ZIGZAG; |
60 | | |
61 | | macro_rules! decode_huff { |
62 | | ($stream:tt,$symbol:tt,$table:tt) => { |
63 | | let mut code_length = $symbol >> HUFF_LOOKAHEAD; |
64 | | |
65 | | ($symbol) &= (1 << HUFF_LOOKAHEAD) - 1; |
66 | | |
67 | | if code_length > i32::from(HUFF_LOOKAHEAD) |
68 | | { |
69 | | // if the symbol cannot be resolved in the first HUFF_LOOKAHEAD bits, |
70 | | // we know it lies somewhere between HUFF_LOOKAHEAD and 16 bits since jpeg imposes 16 bit |
71 | | // limit, we can therefore look 16 bits ahead and try to resolve the symbol |
72 | | // starting from 1+HUFF_LOOKAHEAD bits. |
73 | | $symbol = ($stream).peek_bits::<16>() as i32; |
74 | | // (Credits to Sean T. Barrett stb library for this optimization) |
75 | | // maxcode is pre-shifted 16 bytes long so that it has (16-code_length) |
76 | | // zeroes at the end hence we do not need to shift in the inner loop. |
77 | | while code_length < 17{ |
78 | | if $symbol < $table.maxcode[code_length as usize] { |
79 | | break; |
80 | | } |
81 | | code_length += 1; |
82 | | } |
83 | | |
84 | | if code_length == 17{ |
85 | | // symbol could not be decoded. |
86 | | // |
87 | | // We may think, lets fake zeroes, noo |
88 | | // panic, because Huffman codes are sensitive, probably everything |
89 | | // after this will be corrupt, so no need to continue. |
90 | | // panic!("Bad Huffman code length"); |
91 | | return Err(DecodeErrors::Format(format!("Bad Huffman Code 0x{:X}, corrupt JPEG",$symbol))) |
92 | | } |
93 | | |
94 | | $symbol >>= (16-code_length); |
95 | | ($symbol) = i32::from( |
96 | | ($table).values |
97 | | [(($symbol + ($table).offset[code_length as usize]) & 0xFF) as usize], |
98 | | ); |
99 | | } |
100 | | if code_length> i32::from(($stream).bits_left){ |
101 | | return Err(DecodeErrors::Format(format!("Code length {code_length} more than bits left {}",($stream).bits_left))) |
102 | | } |
103 | | // drop bits read |
104 | | ($stream).drop_bits(code_length as u8); |
105 | | }; |
106 | | } |
107 | | |
108 | | /// A `BitStream` struct, a bit by bit reader with super powers |
109 | | /// |
110 | | #[rustfmt::skip] |
111 | | pub(crate) struct BitStream { |
112 | | /// A MSB type buffer that is used for some certain operations |
113 | | pub buffer: u64, |
114 | | /// A TOP aligned MSB type buffer that is used to accelerate some operations like |
115 | | /// peek_bits and get_bits. |
116 | | /// |
117 | | /// By top aligned, I mean the top bit (63) represents the top bit in the buffer. |
118 | | aligned_buffer: u64, |
119 | | /// Tell us the bits left the two buffer |
120 | | pub(crate) bits_left: u8, |
121 | | /// Did we find a marker(RST/EOF) during decoding? |
122 | | pub marker: Option<Marker>, |
123 | | /// An i16 with the bit corresponding to successive_low set to 1, others 0. |
124 | | pub successive_low_mask: i16, |
125 | | spec_start: u8, |
126 | | spec_end: u8, |
127 | | pub eob_run: i32, |
128 | | pub overread_by: usize, |
129 | | /// True if we have seen end of image marker. |
130 | | /// Don't read anything after that. |
131 | | pub seen_eoi: bool, |
132 | | } |
133 | | |
134 | | impl BitStream { |
135 | | /// Create a new BitStream |
136 | | #[rustfmt::skip] |
137 | 1.73k | pub(crate) const fn new() -> BitStream { |
138 | 1.73k | BitStream { |
139 | 1.73k | buffer: 0, |
140 | 1.73k | aligned_buffer: 0, |
141 | 1.73k | bits_left: 0, |
142 | 1.73k | marker: None, |
143 | 1.73k | successive_low_mask: 1, |
144 | 1.73k | spec_start: 0, |
145 | 1.73k | spec_end: 0, |
146 | 1.73k | eob_run: 0, |
147 | 1.73k | overread_by: 0, |
148 | 1.73k | seen_eoi: false, |
149 | 1.73k | } |
150 | 1.73k | } |
151 | | |
152 | | /// Create a new Bitstream for progressive decoding |
153 | | #[allow(clippy::redundant_field_names)] |
154 | | #[rustfmt::skip] |
155 | 4.51k | pub(crate) fn new_progressive(al: u8, spec_start: u8, spec_end: u8) -> BitStream { |
156 | 4.51k | BitStream { |
157 | 4.51k | buffer: 0, |
158 | 4.51k | aligned_buffer: 0, |
159 | 4.51k | bits_left: 0, |
160 | 4.51k | marker: None, |
161 | 4.51k | successive_low_mask: 1i16 << al, |
162 | 4.51k | spec_start: spec_start, |
163 | 4.51k | spec_end: spec_end, |
164 | 4.51k | eob_run: 0, |
165 | 4.51k | overread_by: 0, |
166 | 4.51k | seen_eoi: false, |
167 | 4.51k | } |
168 | 4.51k | } |
169 | | |
170 | | /// Refill the bit buffer by (a maximum of) 32 bits |
171 | | /// |
172 | | /// # Arguments |
173 | | /// - `reader`:`&mut BufReader<R>`: A mutable reference to an underlying |
174 | | /// File/Memory buffer containing a valid JPEG stream |
175 | | /// |
176 | | /// This function will only refill if `self.count` is less than 32 |
177 | | #[inline(always)] // to many call sites? ( perf improvement by 4%) |
178 | 2.12G | pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors> |
179 | 2.12G | where |
180 | 2.12G | T: ZByteReaderTrait |
181 | | { |
182 | | /// Macro version of a single byte refill. |
183 | | /// Arguments |
184 | | /// buffer-> our io buffer, because rust macros cannot get values from |
185 | | /// the surrounding environment bits_left-> number of bits left |
186 | | /// to full refill |
187 | | macro_rules! refill { |
188 | | ($buffer:expr,$byte:expr,$bits_left:expr) => { |
189 | | // read a byte from the stream |
190 | | $byte = u64::from(reader.read_u8()); |
191 | | self.overread_by += usize::from(reader.eof()?); |
192 | | // append to the buffer |
193 | | // JPEG is a MSB type buffer so that means we append this |
194 | | // to the lower end (0..8) of the buffer and push the rest bits above.. |
195 | | $buffer = ($buffer << 8) | $byte; |
196 | | // Increment bits left |
197 | | $bits_left += 8; |
198 | | // Check for special case of OxFF, to see if it's a stream or a marker |
199 | | if $byte == 0xff { |
200 | | // read next byte |
201 | | let mut next_byte = u64::from(reader.read_u8()); |
202 | | // Byte snuffing, if we encounter byte snuff, we skip the byte |
203 | | if next_byte != 0x00 { |
204 | | // skip that byte we read |
205 | | while next_byte == 0xFF { |
206 | | next_byte = u64::from(reader.read_u8()); |
207 | | } |
208 | | |
209 | | if next_byte != 0x00 { |
210 | | // Undo the byte append and return |
211 | | $buffer >>= 8; |
212 | | $bits_left -= 8; |
213 | | |
214 | | if $bits_left != 0 { |
215 | | self.aligned_buffer = $buffer << (64 - $bits_left); |
216 | | } |
217 | | |
218 | | let marker = Marker::from_u8(next_byte as u8); |
219 | | self.marker = marker; |
220 | | |
221 | | if let Some(Marker::UNKNOWN(_)) = marker{ |
222 | | return Err(DecodeErrors::Format("Unknown marker in bit stream".to_string())); |
223 | | } |
224 | | if next_byte == 0xD9 { |
225 | | // special handling for eoi, fill some bytes,even if its zero, |
226 | | // removes some panics |
227 | | self.buffer <<= 8; |
228 | | self.bits_left += 8; |
229 | | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
230 | | } |
231 | | |
232 | | return Ok(false); |
233 | | } |
234 | | } |
235 | | } |
236 | | }; |
237 | | } |
238 | | |
239 | | // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits) |
240 | 2.12G | if self.bits_left < 32 { |
241 | 287M | if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi { |
242 | | // found a marker, or we are in EOI |
243 | | // also we are in over-reading mode, where we fill it with zeroes |
244 | | |
245 | | // fill with zeroes |
246 | 276M | self.buffer <<= 32; |
247 | 276M | self.bits_left += 32; |
248 | 276M | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
249 | 276M | return Ok(true); |
250 | 11.1M | } |
251 | | |
252 | | // we optimize for the case where we don't have 255 in the stream and have 4 bytes left |
253 | | // as it is the common case |
254 | | // |
255 | | // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is |
256 | | // guaranteed not to advance in case of failure (is this true), so |
257 | | // we revert the read later on (if we have 255), if this fails, we use the normal |
258 | | // byte at a time read |
259 | | |
260 | 11.1M | if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() { |
261 | | // we have 4 bytes to spare, read the 4 bytes into a temporary buffer |
262 | | // create buffer |
263 | 11.1M | let msb_buf = u32::from_be_bytes(bytes); |
264 | | // check if we have 0xff |
265 | 11.1M | if !has_byte(msb_buf, 255) { |
266 | 10.2M | self.bits_left += 32; |
267 | 10.2M | self.buffer <<= 32; |
268 | 10.2M | self.buffer |= u64::from(msb_buf); |
269 | 10.2M | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
270 | 10.2M | return Ok(true); |
271 | 962k | } |
272 | | |
273 | 962k | reader.rewind(4)?; |
274 | 1.73k | } |
275 | | // This serves two reasons, |
276 | | // 1: Make clippy shut up |
277 | | // 2: Favour register reuse |
278 | | let mut byte; |
279 | | // 4 refills, if all succeed the stream should contain enough bits to decode a |
280 | | // value |
281 | 963k | refill!(self.buffer, byte, self.bits_left); |
282 | 936k | refill!(self.buffer, byte, self.bits_left); |
283 | 890k | refill!(self.buffer, byte, self.bits_left); |
284 | 859k | refill!(self.buffer, byte, self.bits_left); |
285 | | // Construct an MSB buffer whose top bits are the bitstream we are currently holding. |
286 | 826k | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
287 | 1.83G | } |
288 | 1.83G | return Ok(true); |
289 | 2.12G | } <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 178 | 2.12G | pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors> | 179 | 2.12G | where | 180 | 2.12G | T: ZByteReaderTrait | 181 | | { | 182 | | /// Macro version of a single byte refill. | 183 | | /// Arguments | 184 | | /// buffer-> our io buffer, because rust macros cannot get values from | 185 | | /// the surrounding environment bits_left-> number of bits left | 186 | | /// to full refill | 187 | | macro_rules! refill { | 188 | | ($buffer:expr,$byte:expr,$bits_left:expr) => { | 189 | | // read a byte from the stream | 190 | | $byte = u64::from(reader.read_u8()); | 191 | | self.overread_by += usize::from(reader.eof()?); | 192 | | // append to the buffer | 193 | | // JPEG is a MSB type buffer so that means we append this | 194 | | // to the lower end (0..8) of the buffer and push the rest bits above.. | 195 | | $buffer = ($buffer << 8) | $byte; | 196 | | // Increment bits left | 197 | | $bits_left += 8; | 198 | | // Check for special case of OxFF, to see if it's a stream or a marker | 199 | | if $byte == 0xff { | 200 | | // read next byte | 201 | | let mut next_byte = u64::from(reader.read_u8()); | 202 | | // Byte snuffing, if we encounter byte snuff, we skip the byte | 203 | | if next_byte != 0x00 { | 204 | | // skip that byte we read | 205 | | while next_byte == 0xFF { | 206 | | next_byte = u64::from(reader.read_u8()); | 207 | | } | 208 | | | 209 | | if next_byte != 0x00 { | 210 | | // Undo the byte append and return | 211 | | $buffer >>= 8; | 212 | | $bits_left -= 8; | 213 | | | 214 | | if $bits_left != 0 { | 215 | | self.aligned_buffer = $buffer << (64 - $bits_left); | 216 | | } | 217 | | | 218 | | let marker = Marker::from_u8(next_byte as u8); | 219 | | self.marker = marker; | 220 | | | 221 | | if let Some(Marker::UNKNOWN(_)) = marker{ | 222 | | return Err(DecodeErrors::Format("Unknown marker in bit stream".to_string())); | 223 | | } | 224 | | if next_byte == 0xD9 { | 225 | | // special handling for eoi, fill some bytes,even if its zero, | 226 | | // removes some panics | 227 | | self.buffer <<= 8; | 228 | | self.bits_left += 8; | 229 | | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 230 | | } | 231 | | | 232 | | return Ok(false); | 233 | | } | 234 | | } | 235 | | } | 236 | | }; | 237 | | } | 238 | | | 239 | | // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits) | 240 | 2.12G | if self.bits_left < 32 { | 241 | 287M | if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi { | 242 | | // found a marker, or we are in EOI | 243 | | // also we are in over-reading mode, where we fill it with zeroes | 244 | | | 245 | | // fill with zeroes | 246 | 276M | self.buffer <<= 32; | 247 | 276M | self.bits_left += 32; | 248 | 276M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 249 | 276M | return Ok(true); | 250 | 11.1M | } | 251 | | | 252 | | // we optimize for the case where we don't have 255 in the stream and have 4 bytes left | 253 | | // as it is the common case | 254 | | // | 255 | | // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is | 256 | | // guaranteed not to advance in case of failure (is this true), so | 257 | | // we revert the read later on (if we have 255), if this fails, we use the normal | 258 | | // byte at a time read | 259 | | | 260 | 11.1M | if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() { | 261 | | // we have 4 bytes to spare, read the 4 bytes into a temporary buffer | 262 | | // create buffer | 263 | 11.1M | let msb_buf = u32::from_be_bytes(bytes); | 264 | | // check if we have 0xff | 265 | 11.1M | if !has_byte(msb_buf, 255) { | 266 | 10.2M | self.bits_left += 32; | 267 | 10.2M | self.buffer <<= 32; | 268 | 10.2M | self.buffer |= u64::from(msb_buf); | 269 | 10.2M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 270 | 10.2M | return Ok(true); | 271 | 962k | } | 272 | | | 273 | 962k | reader.rewind(4)?; | 274 | 1.73k | } | 275 | | // This serves two reasons, | 276 | | // 1: Make clippy shut up | 277 | | // 2: Favour register reuse | 278 | | let mut byte; | 279 | | // 4 refills, if all succeed the stream should contain enough bits to decode a | 280 | | // value | 281 | 963k | refill!(self.buffer, byte, self.bits_left); | 282 | 936k | refill!(self.buffer, byte, self.bits_left); | 283 | 890k | refill!(self.buffer, byte, self.bits_left); | 284 | 859k | refill!(self.buffer, byte, self.bits_left); | 285 | | // Construct an MSB buffer whose top bits are the bitstream we are currently holding. | 286 | 826k | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 287 | 1.83G | } | 288 | 1.83G | return Ok(true); | 289 | 2.12G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<_> |
290 | | /// Decode the DC coefficient in a MCU block. |
291 | | /// |
292 | | /// The decoded coefficient is written to `dc_prediction` |
293 | | /// |
294 | | #[allow( |
295 | | clippy::cast_possible_truncation, |
296 | | clippy::cast_sign_loss, |
297 | | clippy::unwrap_used |
298 | | )] |
299 | | #[inline(always)] |
300 | 215M | fn decode_dc<T>( |
301 | 215M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32 |
302 | 215M | ) -> Result<bool, DecodeErrors> |
303 | 215M | where |
304 | 215M | T: ZByteReaderTrait |
305 | | { |
306 | | let (mut symbol, r); |
307 | | |
308 | 215M | if self.bits_left < 32 { |
309 | 17.9M | self.refill(reader)?; |
310 | 197M | }; |
311 | | // look a head HUFF_LOOKAHEAD bits into the bitstream |
312 | 215M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
313 | 215M | symbol = dc_table.lookup[symbol as usize]; |
314 | | |
315 | 215M | decode_huff!(self, symbol, dc_table); |
316 | | |
317 | 215M | if symbol != 0 { |
318 | 13.6M | r = self.get_bits(symbol as u8); |
319 | 13.6M | symbol = huff_extend(r, symbol); |
320 | 201M | } |
321 | | // Update DC prediction |
322 | 215M | *dc_prediction = dc_prediction.wrapping_add(symbol); |
323 | | |
324 | 215M | return Ok(true); |
325 | 215M | } <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 300 | 215M | fn decode_dc<T>( | 301 | 215M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32 | 302 | 215M | ) -> Result<bool, DecodeErrors> | 303 | 215M | where | 304 | 215M | T: ZByteReaderTrait | 305 | | { | 306 | | let (mut symbol, r); | 307 | | | 308 | 215M | if self.bits_left < 32 { | 309 | 17.9M | self.refill(reader)?; | 310 | 197M | }; | 311 | | // look a head HUFF_LOOKAHEAD bits into the bitstream | 312 | 215M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 313 | 215M | symbol = dc_table.lookup[symbol as usize]; | 314 | | | 315 | 215M | decode_huff!(self, symbol, dc_table); | 316 | | | 317 | 215M | if symbol != 0 { | 318 | 13.6M | r = self.get_bits(symbol as u8); | 319 | 13.6M | symbol = huff_extend(r, symbol); | 320 | 201M | } | 321 | | // Update DC prediction | 322 | 215M | *dc_prediction = dc_prediction.wrapping_add(symbol); | 323 | | | 324 | 215M | return Ok(true); | 325 | 215M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<_> |
326 | | |
327 | | /// Like `decode_dc` but we do not need the result of the component, we only want to remove it |
328 | | /// from the bitstream of the MCU. |
329 | 0 | fn discard_dc<T>( |
330 | 0 | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable |
331 | 0 | ) -> Result<bool, DecodeErrors> |
332 | 0 | where |
333 | 0 | T: ZByteReaderTrait |
334 | | { |
335 | | let mut symbol; |
336 | | |
337 | 0 | if self.bits_left < 32 { |
338 | 0 | self.refill(reader)?; |
339 | 0 | }; |
340 | | // look a head HUFF_LOOKAHEAD bits into the bitstream |
341 | 0 | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
342 | 0 | symbol = dc_table.lookup[symbol as usize]; |
343 | | |
344 | 0 | decode_huff!(self, symbol, dc_table); |
345 | | |
346 | 0 | if symbol != 0 { |
347 | 0 | let _ = self.get_bits(symbol as u8); |
348 | 0 | } |
349 | | |
350 | 0 | return Ok(true); |
351 | 0 | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_dc::<_> |
352 | | |
353 | | /// Decode a Minimum Code Unit(MCU) as quickly as possible |
354 | | /// |
355 | | /// # Arguments |
356 | | /// - reader: The bitstream from where we read more bits. |
357 | | /// - dc_table: The Huffman table used to decode the DC coefficient |
358 | | /// - ac_table: The Huffman table used to decode AC values |
359 | | /// - block: A memory region where we will write out the decoded values |
360 | | /// - DC prediction: Last DC value for this component |
361 | | /// |
362 | | #[allow( |
363 | | clippy::many_single_char_names, |
364 | | clippy::cast_possible_truncation, |
365 | | clippy::cast_sign_loss |
366 | | )] |
367 | | #[inline(never)] |
368 | 29.9M | pub fn decode_mcu_block<T>( |
369 | 29.9M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable, |
370 | 29.9M | qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32 |
371 | 29.9M | ) -> Result<u16, DecodeErrors> |
372 | 29.9M | where |
373 | 29.9M | T: ZByteReaderTrait |
374 | | { |
375 | | // Get fast AC table as a reference before we enter the hot path |
376 | 29.9M | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); |
377 | | |
378 | | let (mut symbol, mut r, mut fast_ac); |
379 | | // Decode AC coefficients |
380 | 29.9M | let mut pos: usize = 1; |
381 | 29.9M | if self.bits_left < 1 && self.marker.is_some() { |
382 | 1 | return Err(DecodeErrors::Format( |
383 | 1 | "No more bytes left in stream before marker".to_string() |
384 | 1 | )); |
385 | 29.9M | } |
386 | | // decode DC, dc prediction will contain the value |
387 | 29.9M | self.decode_dc(reader, dc_table, dc_prediction)?; |
388 | | |
389 | | // set dc to be the dc prediction. |
390 | 29.9M | block[0] = *dc_prediction * qt_table[0]; |
391 | | |
392 | 778M | while pos < 64 { |
393 | 760M | self.refill(reader)?; |
394 | 760M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
395 | 760M | fast_ac = ac_lookup[symbol as usize]; |
396 | 760M | symbol = ac_table.lookup[symbol as usize]; |
397 | | |
398 | 760M | if fast_ac != 0 { |
399 | 700M | // FAST AC path |
400 | 700M | pos += ((fast_ac >> 4) & 15) as usize; // run |
401 | 700M | let t_pos = UN_ZIGZAG[min(pos, 63)] & 63; |
402 | 700M | |
403 | 700M | block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value |
404 | 700M | self.drop_bits((fast_ac & 15) as u8); |
405 | 700M | pos += 1; |
406 | 700M | } else { |
407 | 59.7M | decode_huff!(self, symbol, ac_table); |
408 | | |
409 | 59.7M | r = symbol >> 4; |
410 | 59.7M | symbol &= 15; |
411 | | |
412 | 59.7M | if symbol != 0 { |
413 | 47.7M | pos += r as usize; |
414 | 47.7M | r = self.get_bits(symbol as u8); |
415 | 47.7M | symbol = huff_extend(r, symbol); |
416 | 47.7M | let t_pos = UN_ZIGZAG[pos & 63] & 63; |
417 | 47.7M | |
418 | 47.7M | block[t_pos] = symbol * qt_table[t_pos]; |
419 | 47.7M | |
420 | 47.7M | pos += 1; |
421 | 47.7M | } else if r != 15 { |
422 | 11.9M | return Ok(pos as u16); |
423 | 73.0k | } else { |
424 | 73.0k | pos += 16; |
425 | 73.0k | } |
426 | | } |
427 | | } |
428 | | |
429 | 18.0M | return Ok(64); |
430 | 29.9M | } <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 368 | 29.9M | pub fn decode_mcu_block<T>( | 369 | 29.9M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable, | 370 | 29.9M | qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32 | 371 | 29.9M | ) -> Result<u16, DecodeErrors> | 372 | 29.9M | where | 373 | 29.9M | T: ZByteReaderTrait | 374 | | { | 375 | | // Get fast AC table as a reference before we enter the hot path | 376 | 29.9M | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); | 377 | | | 378 | | let (mut symbol, mut r, mut fast_ac); | 379 | | // Decode AC coefficients | 380 | 29.9M | let mut pos: usize = 1; | 381 | 29.9M | if self.bits_left < 1 && self.marker.is_some() { | 382 | 1 | return Err(DecodeErrors::Format( | 383 | 1 | "No more bytes left in stream before marker".to_string() | 384 | 1 | )); | 385 | 29.9M | } | 386 | | // decode DC, dc prediction will contain the value | 387 | 29.9M | self.decode_dc(reader, dc_table, dc_prediction)?; | 388 | | | 389 | | // set dc to be the dc prediction. | 390 | 29.9M | block[0] = *dc_prediction * qt_table[0]; | 391 | | | 392 | 778M | while pos < 64 { | 393 | 760M | self.refill(reader)?; | 394 | 760M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 395 | 760M | fast_ac = ac_lookup[symbol as usize]; | 396 | 760M | symbol = ac_table.lookup[symbol as usize]; | 397 | | | 398 | 760M | if fast_ac != 0 { | 399 | 700M | // FAST AC path | 400 | 700M | pos += ((fast_ac >> 4) & 15) as usize; // run | 401 | 700M | let t_pos = UN_ZIGZAG[min(pos, 63)] & 63; | 402 | 700M | | 403 | 700M | block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value | 404 | 700M | self.drop_bits((fast_ac & 15) as u8); | 405 | 700M | pos += 1; | 406 | 700M | } else { | 407 | 59.7M | decode_huff!(self, symbol, ac_table); | 408 | | | 409 | 59.7M | r = symbol >> 4; | 410 | 59.7M | symbol &= 15; | 411 | | | 412 | 59.7M | if symbol != 0 { | 413 | 47.7M | pos += r as usize; | 414 | 47.7M | r = self.get_bits(symbol as u8); | 415 | 47.7M | symbol = huff_extend(r, symbol); | 416 | 47.7M | let t_pos = UN_ZIGZAG[pos & 63] & 63; | 417 | 47.7M | | 418 | 47.7M | block[t_pos] = symbol * qt_table[t_pos]; | 419 | 47.7M | | 420 | 47.7M | pos += 1; | 421 | 47.7M | } else if r != 15 { | 422 | 11.9M | return Ok(pos as u16); | 423 | 73.0k | } else { | 424 | 73.0k | pos += 16; | 425 | 73.0k | } | 426 | | } | 427 | | } | 428 | | | 429 | 18.0M | return Ok(64); | 430 | 29.9M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<_> |
431 | | |
432 | | /// Advance the bitstream over a block but ignore the data contained. |
433 | | /// |
434 | | /// This updates DC prediction but we never dequantize and we never do any Zig-Zag translation |
435 | | /// either. Still returns the index of the last component read. |
436 | 0 | pub fn discard_mcu_block<T>( |
437 | 0 | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable |
438 | 0 | ) -> Result<u16, DecodeErrors> |
439 | 0 | where |
440 | 0 | T: ZByteReaderTrait |
441 | | { |
442 | | // Get fast AC table as a reference before we enter the hot path |
443 | 0 | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); |
444 | | |
445 | | let (mut symbol, mut r, mut fast_ac); |
446 | | // Decode AC coefficients |
447 | 0 | let mut pos: usize = 1; |
448 | | |
449 | | // decode DC, dc prediction will contain the value |
450 | 0 | self.discard_dc(reader, dc_table)?; |
451 | | |
452 | 0 | while pos < 64 { |
453 | 0 | self.refill(reader)?; |
454 | 0 | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
455 | 0 | fast_ac = ac_lookup[symbol as usize]; |
456 | 0 | symbol = ac_table.lookup[symbol as usize]; |
457 | | |
458 | 0 | if fast_ac != 0 { |
459 | 0 | // FAST AC path |
460 | 0 | pos += ((fast_ac >> 4) & 15) as usize; // run |
461 | 0 |
|
462 | 0 | self.drop_bits((fast_ac & 15) as u8); |
463 | 0 | pos += 1; |
464 | 0 | } else { |
465 | 0 | decode_huff!(self, symbol, ac_table); |
466 | | |
467 | 0 | r = symbol >> 4; |
468 | 0 | symbol &= 15; |
469 | | |
470 | 0 | if symbol != 0 { |
471 | 0 | pos += r as usize; |
472 | 0 | // Advance over bits but ignore. |
473 | 0 | let _ = self.get_bits(symbol as u8); |
474 | 0 |
|
475 | 0 | pos += 1; |
476 | 0 | } else if r != 15 { |
477 | 0 | return Ok(pos as u16); |
478 | 0 | } else { |
479 | 0 | pos += 16; |
480 | 0 | } |
481 | | } |
482 | | } |
483 | | |
484 | 0 | return Ok(64); |
485 | 0 | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::discard_mcu_block::<_> |
486 | | |
487 | | /// Peek `look_ahead` bits ahead without discarding them from the buffer |
488 | | #[inline(always)] |
489 | | #[allow(clippy::cast_possible_truncation)] |
490 | 2.29G | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { |
491 | 2.29G | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 |
492 | 2.29G | } <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Line | Count | Source | 490 | 803k | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 491 | 803k | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 492 | 803k | } |
<zune_jpeg::bitstream::BitStream>::peek_bits::<9> Line | Count | Source | 490 | 2.29G | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 491 | 2.29G | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 492 | 2.29G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<_> |
493 | | |
494 | | /// Discard the next `N` bits without checking |
495 | | #[inline] |
496 | 4.02G | fn drop_bits(&mut self, n: u8) { |
497 | | // PS: Its a good check, but triggers fuzzer and a lot of false positives |
498 | | //debug_assert!(self.bits_left >= n); |
499 | | //self.bits_left -= n; |
500 | 4.02G | self.bits_left = self.bits_left.saturating_sub(n); |
501 | 4.02G | self.aligned_buffer <<= n; |
502 | 4.02G | } <zune_jpeg::bitstream::BitStream>::drop_bits Line | Count | Source | 496 | 2.29G | fn drop_bits(&mut self, n: u8) { | 497 | | // PS: Its a good check, but triggers fuzzer and a lot of false positives | 498 | | //debug_assert!(self.bits_left >= n); | 499 | | //self.bits_left -= n; | 500 | 2.29G | self.bits_left = self.bits_left.saturating_sub(n); | 501 | 2.29G | self.aligned_buffer <<= n; | 502 | 2.29G | } |
<zune_jpeg::bitstream::BitStream>::drop_bits Line | Count | Source | 496 | 1.73G | fn drop_bits(&mut self, n: u8) { | 497 | | // PS: Its a good check, but triggers fuzzer and a lot of false positives | 498 | | //debug_assert!(self.bits_left >= n); | 499 | | //self.bits_left -= n; | 500 | 1.73G | self.bits_left = self.bits_left.saturating_sub(n); | 501 | 1.73G | self.aligned_buffer <<= n; | 502 | 1.73G | } |
|
503 | | |
504 | | /// Read `n_bits` from the buffer and discard them |
505 | | #[inline(always)] |
506 | | #[allow(clippy::cast_possible_truncation)] |
507 | 170M | fn get_bits(&mut self, n_bits: u8) -> i32 { |
508 | 170M | let mask = (1_u64 << n_bits) - 1; |
509 | | |
510 | 170M | self.aligned_buffer = self.aligned_buffer.rotate_left(u32::from(n_bits)); |
511 | 170M | let bits = (self.aligned_buffer & mask) as i32; |
512 | 170M | self.bits_left = self.bits_left.wrapping_sub(n_bits); |
513 | 170M | bits |
514 | 170M | } |
515 | | |
516 | | /// Decode a DC block |
517 | | #[allow(clippy::cast_possible_truncation)] |
518 | | #[inline] |
519 | 185M | pub(crate) fn decode_prog_dc_first<T>( |
520 | 185M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16, |
521 | 185M | dc_prediction: &mut i32 |
522 | 185M | ) -> Result<(), DecodeErrors> |
523 | 185M | where |
524 | 185M | T: ZByteReaderTrait |
525 | | { |
526 | 185M | self.decode_dc(reader, dc_table, dc_prediction)?; |
527 | 185M | *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask); |
528 | 185M | return Ok(()); |
529 | 185M | } <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 519 | 185M | pub(crate) fn decode_prog_dc_first<T>( | 520 | 185M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16, | 521 | 185M | dc_prediction: &mut i32 | 522 | 185M | ) -> Result<(), DecodeErrors> | 523 | 185M | where | 524 | 185M | T: ZByteReaderTrait | 525 | | { | 526 | 185M | self.decode_dc(reader, dc_table, dc_prediction)?; | 527 | 185M | *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask); | 528 | 185M | return Ok(()); | 529 | 185M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<_> |
530 | | #[inline] |
531 | 205M | pub(crate) fn decode_prog_dc_refine<T>( |
532 | 205M | &mut self, reader: &mut ZReader<T>, block: &mut i16 |
533 | 205M | ) -> Result<(), DecodeErrors> |
534 | 205M | where |
535 | 205M | T: ZByteReaderTrait |
536 | | { |
537 | | // refinement scan |
538 | 205M | if self.bits_left < 1 { |
539 | 6.38M | self.refill(reader)?; |
540 | | // if we find a marker, it may happens we don't refill. |
541 | | // So let's confirm again that refill worked |
542 | 6.38M | if self.bits_left < 1 { |
543 | 14 | return Err(DecodeErrors::Format( |
544 | 14 | "Marker found where not expected in refine bit".to_string() |
545 | 14 | )); |
546 | 6.38M | } |
547 | 199M | } |
548 | | |
549 | 205M | if self.get_bit() == 1 { |
550 | 2.41M | *block = block.wrapping_add(self.successive_low_mask); |
551 | 203M | } |
552 | | |
553 | 205M | Ok(()) |
554 | 205M | } <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 531 | 205M | pub(crate) fn decode_prog_dc_refine<T>( | 532 | 205M | &mut self, reader: &mut ZReader<T>, block: &mut i16 | 533 | 205M | ) -> Result<(), DecodeErrors> | 534 | 205M | where | 535 | 205M | T: ZByteReaderTrait | 536 | | { | 537 | | // refinement scan | 538 | 205M | if self.bits_left < 1 { | 539 | 6.38M | self.refill(reader)?; | 540 | | // if we find a marker, it may happens we don't refill. | 541 | | // So let's confirm again that refill worked | 542 | 6.38M | if self.bits_left < 1 { | 543 | 14 | return Err(DecodeErrors::Format( | 544 | 14 | "Marker found where not expected in refine bit".to_string() | 545 | 14 | )); | 546 | 6.38M | } | 547 | 199M | } | 548 | | | 549 | 205M | if self.get_bit() == 1 { | 550 | 2.41M | *block = block.wrapping_add(self.successive_low_mask); | 551 | 203M | } | 552 | | | 553 | 205M | Ok(()) | 554 | 205M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<_> |
555 | | |
556 | | /// Get a single bit from the bitstream |
557 | 1.73G | fn get_bit(&mut self) -> u8 { |
558 | 1.73G | let k = (self.aligned_buffer >> 63) as u8; |
559 | | // discard a bit |
560 | 1.73G | self.drop_bits(1); |
561 | 1.73G | return k; |
562 | 1.73G | } |
563 | 128M | pub(crate) fn decode_mcu_ac_first<T>( |
564 | 128M | &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64] |
565 | 128M | ) -> Result<bool, DecodeErrors> |
566 | 128M | where |
567 | 128M | T: ZByteReaderTrait |
568 | | { |
569 | 128M | let fast_ac = ac_table.ac_lookup.as_ref().unwrap(); |
570 | 128M | let bit = self.successive_low_mask; |
571 | | |
572 | 128M | let mut k = self.spec_start as usize; |
573 | | let (mut symbol, mut r, mut fac); |
574 | | |
575 | | // EOB runs are handled in mcu_prog.rs |
576 | | 'block: loop { |
577 | 1.00G | self.refill(reader)?; |
578 | | // Check for marker in the stream |
579 | | |
580 | 1.00G | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
581 | 1.00G | fac = fast_ac[symbol as usize]; |
582 | 1.00G | symbol = ac_table.lookup[symbol as usize]; |
583 | | |
584 | 1.00G | if fac != 0 { |
585 | 910M | // fast ac path |
586 | 910M | k += ((fac >> 4) & 15) as usize; // run |
587 | 910M | block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value |
588 | 910M | self.drop_bits((fac & 15) as u8); |
589 | 910M | k += 1; |
590 | 910M | } else { |
591 | 91.3M | decode_huff!(self, symbol, ac_table); |
592 | | |
593 | 91.3M | r = symbol >> 4; |
594 | 91.3M | symbol &= 15; |
595 | | |
596 | 91.3M | if symbol != 0 { |
597 | 49.0M | k += r as usize; |
598 | 49.0M | r = self.get_bits(symbol as u8); |
599 | 49.0M | symbol = huff_extend(r, symbol); |
600 | 49.0M | block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit); |
601 | 49.0M | k += 1; |
602 | 49.0M | } else { |
603 | 42.2M | if r != 15 { |
604 | 42.2M | self.eob_run = 1 << r; |
605 | 42.2M | self.eob_run += self.get_bits(r as u8); |
606 | 42.2M | self.eob_run -= 1; |
607 | 42.2M | break; |
608 | 86.8k | } |
609 | | |
610 | 86.8k | k += 16; |
611 | | } |
612 | | } |
613 | | |
614 | 959M | if k > self.spec_end as usize { |
615 | 86.7M | break 'block; |
616 | 872M | } |
617 | | } |
618 | 128M | return Ok(true); |
619 | 128M | } <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 563 | 128M | pub(crate) fn decode_mcu_ac_first<T>( | 564 | 128M | &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64] | 565 | 128M | ) -> Result<bool, DecodeErrors> | 566 | 128M | where | 567 | 128M | T: ZByteReaderTrait | 568 | | { | 569 | 128M | let fast_ac = ac_table.ac_lookup.as_ref().unwrap(); | 570 | 128M | let bit = self.successive_low_mask; | 571 | | | 572 | 128M | let mut k = self.spec_start as usize; | 573 | | let (mut symbol, mut r, mut fac); | 574 | | | 575 | | // EOB runs are handled in mcu_prog.rs | 576 | | 'block: loop { | 577 | 1.00G | self.refill(reader)?; | 578 | | // Check for marker in the stream | 579 | | | 580 | 1.00G | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 581 | 1.00G | fac = fast_ac[symbol as usize]; | 582 | 1.00G | symbol = ac_table.lookup[symbol as usize]; | 583 | | | 584 | 1.00G | if fac != 0 { | 585 | 910M | // fast ac path | 586 | 910M | k += ((fac >> 4) & 15) as usize; // run | 587 | 910M | block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value | 588 | 910M | self.drop_bits((fac & 15) as u8); | 589 | 910M | k += 1; | 590 | 910M | } else { | 591 | 91.3M | decode_huff!(self, symbol, ac_table); | 592 | | | 593 | 91.3M | r = symbol >> 4; | 594 | 91.3M | symbol &= 15; | 595 | | | 596 | 91.3M | if symbol != 0 { | 597 | 49.0M | k += r as usize; | 598 | 49.0M | r = self.get_bits(symbol as u8); | 599 | 49.0M | symbol = huff_extend(r, symbol); | 600 | 49.0M | block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit); | 601 | 49.0M | k += 1; | 602 | 49.0M | } else { | 603 | 42.2M | if r != 15 { | 604 | 42.2M | self.eob_run = 1 << r; | 605 | 42.2M | self.eob_run += self.get_bits(r as u8); | 606 | 42.2M | self.eob_run -= 1; | 607 | 42.2M | break; | 608 | 86.8k | } | 609 | | | 610 | 86.8k | k += 16; | 611 | | } | 612 | | } | 613 | | | 614 | 959M | if k > self.spec_end as usize { | 615 | 86.7M | break 'block; | 616 | 872M | } | 617 | | } | 618 | 128M | return Ok(true); | 619 | 128M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<_> |
620 | | #[allow(clippy::too_many_lines, clippy::op_ref)] |
621 | 52.4M | pub(crate) fn decode_mcu_ac_refine<T>( |
622 | 52.4M | &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64] |
623 | 52.4M | ) -> Result<bool, DecodeErrors> |
624 | 52.4M | where |
625 | 52.4M | T: ZByteReaderTrait |
626 | | { |
627 | 52.4M | let bit = self.successive_low_mask; |
628 | | |
629 | 52.4M | let mut k = self.spec_start; |
630 | | let (mut symbol, mut r); |
631 | | |
632 | 52.4M | if self.eob_run == 0 { |
633 | | 'no_eob: loop { |
634 | | // Decode a coefficient from the bit stream |
635 | 319M | self.refill(reader)?; |
636 | | |
637 | 319M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
638 | 319M | symbol = table.lookup[symbol as usize]; |
639 | | |
640 | 319M | decode_huff!(self, symbol, table); |
641 | | |
642 | 319M | r = symbol >> 4; |
643 | 319M | symbol &= 15; |
644 | | |
645 | 319M | if symbol == 0 { |
646 | 17.5M | if r != 15 { |
647 | | // EOB run is 2^r + bits |
648 | 17.5M | self.eob_run = 1 << r; |
649 | 17.5M | self.eob_run += self.get_bits(r as u8); |
650 | | // EOB runs are handled by the eob logic |
651 | 17.5M | break 'no_eob; |
652 | 9.18k | } |
653 | | } else { |
654 | 301M | if symbol != 1 { |
655 | 265 | return Err(DecodeErrors::HuffmanDecode( |
656 | 265 | "Bad Huffman code, corrupt JPEG?".to_string() |
657 | 265 | )); |
658 | 301M | } |
659 | | // get sign bit |
660 | | // We assume we have enough bits, which should be correct for sane images |
661 | | // since we refill by 32 above |
662 | 301M | if self.get_bit() == 1 { |
663 | 497k | symbol = i32::from(bit); |
664 | 301M | } else { |
665 | 301M | symbol = i32::from(-bit); |
666 | 301M | } |
667 | | } |
668 | | |
669 | | // Advance over already nonzero coefficients appending |
670 | | // correction bits to the non-zeroes. |
671 | | // A correction bit is 1 if the absolute value of the coefficient must be increased |
672 | | |
673 | 302M | if k <= self.spec_end { |
674 | | 'advance_nonzero: loop { |
675 | 1.37G | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; |
676 | | |
677 | 1.37G | if *coefficient != 0 { |
678 | 1.09G | if self.bits_left < 1 { |
679 | 15.5M | self.refill(reader)?; |
680 | 15.5M | if self.bits_left < 1 && self.marker.is_some() { |
681 | 16 | return Err(DecodeErrors::Format( |
682 | 16 | "Marker found where not expected in refine bit".to_string() |
683 | 16 | )); |
684 | 15.5M | } |
685 | 1.08G | } |
686 | 1.09G | if self.get_bit() == 1 && (*coefficient & bit) == 0 { |
687 | 915k | if *coefficient >= 0 { |
688 | 77.3k | *coefficient += bit; |
689 | 838k | } else { |
690 | 838k | *coefficient -= bit; |
691 | 838k | } |
692 | 1.09G | } |
693 | | } else { |
694 | 282M | r -= 1; |
695 | | |
696 | 282M | if r < 0 { |
697 | | // reached target zero coefficient. |
698 | 280M | break 'advance_nonzero; |
699 | 1.73M | } |
700 | | }; |
701 | | |
702 | 1.09G | if k == self.spec_end { |
703 | 20.2M | break 'advance_nonzero; |
704 | 1.07G | } |
705 | | |
706 | 1.07G | k += 1; |
707 | | } |
708 | 1.48M | } |
709 | | |
710 | 302M | if symbol != 0 { |
711 | 301M | let pos = UN_ZIGZAG[k as usize & 63]; |
712 | 301M | // output new non-zero coefficient. |
713 | 301M | block[pos & 63] = symbol as i16; |
714 | 301M | } |
715 | | |
716 | 302M | k += 1; |
717 | | |
718 | 302M | if k > self.spec_end { |
719 | 27.5M | break 'no_eob; |
720 | 274M | } |
721 | | } |
722 | 7.40M | } |
723 | 52.4M | if self.eob_run > 0 { |
724 | | // only run if block does not consists of purely zeroes |
725 | 24.9M | if &block[1..] != &[0; 63] { |
726 | 3.10M | self.refill(reader)?; |
727 | | |
728 | 135M | while k <= self.spec_end { |
729 | 132M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; |
730 | | |
731 | 132M | if *coefficient != 0 && self.get_bit() == 1 { |
732 | | // check if we already modified it, if so do nothing, otherwise |
733 | | // append the correction bit. |
734 | 8.14M | if (*coefficient & bit) == 0 { |
735 | 2.37M | if *coefficient >= 0 { |
736 | 253k | *coefficient = coefficient.wrapping_add(bit); |
737 | 2.12M | } else { |
738 | 2.12M | *coefficient = coefficient.wrapping_sub(bit); |
739 | 2.12M | } |
740 | 5.76M | } |
741 | 124M | } |
742 | 132M | if self.bits_left < 1 { |
743 | | // refill at the last possible moment |
744 | 1.29M | self.refill(reader)?; |
745 | 131M | } |
746 | 132M | k += 1; |
747 | | } |
748 | 21.8M | } |
749 | | // count a block completed in EOB run |
750 | 24.9M | self.eob_run -= 1; |
751 | 27.5M | } |
752 | 52.4M | return Ok(true); |
753 | 52.4M | } <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 621 | 52.4M | pub(crate) fn decode_mcu_ac_refine<T>( | 622 | 52.4M | &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64] | 623 | 52.4M | ) -> Result<bool, DecodeErrors> | 624 | 52.4M | where | 625 | 52.4M | T: ZByteReaderTrait | 626 | | { | 627 | 52.4M | let bit = self.successive_low_mask; | 628 | | | 629 | 52.4M | let mut k = self.spec_start; | 630 | | let (mut symbol, mut r); | 631 | | | 632 | 52.4M | if self.eob_run == 0 { | 633 | | 'no_eob: loop { | 634 | | // Decode a coefficient from the bit stream | 635 | 319M | self.refill(reader)?; | 636 | | | 637 | 319M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 638 | 319M | symbol = table.lookup[symbol as usize]; | 639 | | | 640 | 319M | decode_huff!(self, symbol, table); | 641 | | | 642 | 319M | r = symbol >> 4; | 643 | 319M | symbol &= 15; | 644 | | | 645 | 319M | if symbol == 0 { | 646 | 17.5M | if r != 15 { | 647 | | // EOB run is 2^r + bits | 648 | 17.5M | self.eob_run = 1 << r; | 649 | 17.5M | self.eob_run += self.get_bits(r as u8); | 650 | | // EOB runs are handled by the eob logic | 651 | 17.5M | break 'no_eob; | 652 | 9.18k | } | 653 | | } else { | 654 | 301M | if symbol != 1 { | 655 | 265 | return Err(DecodeErrors::HuffmanDecode( | 656 | 265 | "Bad Huffman code, corrupt JPEG?".to_string() | 657 | 265 | )); | 658 | 301M | } | 659 | | // get sign bit | 660 | | // We assume we have enough bits, which should be correct for sane images | 661 | | // since we refill by 32 above | 662 | 301M | if self.get_bit() == 1 { | 663 | 497k | symbol = i32::from(bit); | 664 | 301M | } else { | 665 | 301M | symbol = i32::from(-bit); | 666 | 301M | } | 667 | | } | 668 | | | 669 | | // Advance over already nonzero coefficients appending | 670 | | // correction bits to the non-zeroes. | 671 | | // A correction bit is 1 if the absolute value of the coefficient must be increased | 672 | | | 673 | 302M | if k <= self.spec_end { | 674 | | 'advance_nonzero: loop { | 675 | 1.37G | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 676 | | | 677 | 1.37G | if *coefficient != 0 { | 678 | 1.09G | if self.bits_left < 1 { | 679 | 15.5M | self.refill(reader)?; | 680 | 15.5M | if self.bits_left < 1 && self.marker.is_some() { | 681 | 16 | return Err(DecodeErrors::Format( | 682 | 16 | "Marker found where not expected in refine bit".to_string() | 683 | 16 | )); | 684 | 15.5M | } | 685 | 1.08G | } | 686 | 1.09G | if self.get_bit() == 1 && (*coefficient & bit) == 0 { | 687 | 915k | if *coefficient >= 0 { | 688 | 77.3k | *coefficient += bit; | 689 | 838k | } else { | 690 | 838k | *coefficient -= bit; | 691 | 838k | } | 692 | 1.09G | } | 693 | | } else { | 694 | 282M | r -= 1; | 695 | | | 696 | 282M | if r < 0 { | 697 | | // reached target zero coefficient. | 698 | 280M | break 'advance_nonzero; | 699 | 1.73M | } | 700 | | }; | 701 | | | 702 | 1.09G | if k == self.spec_end { | 703 | 20.2M | break 'advance_nonzero; | 704 | 1.07G | } | 705 | | | 706 | 1.07G | k += 1; | 707 | | } | 708 | 1.48M | } | 709 | | | 710 | 302M | if symbol != 0 { | 711 | 301M | let pos = UN_ZIGZAG[k as usize & 63]; | 712 | 301M | // output new non-zero coefficient. | 713 | 301M | block[pos & 63] = symbol as i16; | 714 | 301M | } | 715 | | | 716 | 302M | k += 1; | 717 | | | 718 | 302M | if k > self.spec_end { | 719 | 27.5M | break 'no_eob; | 720 | 274M | } | 721 | | } | 722 | 7.40M | } | 723 | 52.4M | if self.eob_run > 0 { | 724 | | // only run if block does not consists of purely zeroes | 725 | 24.9M | if &block[1..] != &[0; 63] { | 726 | 3.10M | self.refill(reader)?; | 727 | | | 728 | 135M | while k <= self.spec_end { | 729 | 132M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 730 | | | 731 | 132M | if *coefficient != 0 && self.get_bit() == 1 { | 732 | | // check if we already modified it, if so do nothing, otherwise | 733 | | // append the correction bit. | 734 | 8.14M | if (*coefficient & bit) == 0 { | 735 | 2.37M | if *coefficient >= 0 { | 736 | 253k | *coefficient = coefficient.wrapping_add(bit); | 737 | 2.12M | } else { | 738 | 2.12M | *coefficient = coefficient.wrapping_sub(bit); | 739 | 2.12M | } | 740 | 5.76M | } | 741 | 124M | } | 742 | 132M | if self.bits_left < 1 { | 743 | | // refill at the last possible moment | 744 | 1.29M | self.refill(reader)?; | 745 | 131M | } | 746 | 132M | k += 1; | 747 | | } | 748 | 21.8M | } | 749 | | // count a block completed in EOB run | 750 | 24.9M | self.eob_run -= 1; | 751 | 27.5M | } | 752 | 52.4M | return Ok(true); | 753 | 52.4M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<_> |
754 | | |
755 | 21.2k | pub fn update_progressive_params(&mut self, _ah: u8, al: u8, spec_start: u8, spec_end: u8) { |
756 | 21.2k | self.successive_low_mask = 1i16 << al; |
757 | 21.2k | self.spec_start = spec_start; |
758 | 21.2k | self.spec_end = spec_end; |
759 | 21.2k | } |
760 | | |
761 | | /// Reset the stream if we have a restart marker |
762 | | /// |
763 | | /// Restart markers indicate drop those bits in the stream and zero out |
764 | | /// everything |
765 | | #[cold] |
766 | 189k | pub fn reset(&mut self) { |
767 | 189k | self.bits_left = 0; |
768 | 189k | self.marker = None; |
769 | 189k | self.buffer = 0; |
770 | 189k | self.aligned_buffer = 0; |
771 | 189k | self.eob_run = 0; |
772 | 189k | } |
773 | | } |
774 | | |
775 | | /// Do the equivalent of JPEG HUFF_EXTEND |
776 | | #[inline(always)] |
777 | 110M | fn huff_extend(x: i32, s: i32) -> i32 { |
778 | | // if x<s return x else return x+offset[s] where offset[s] = ( (-1<<s)+1) |
779 | 110M | (x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((-1) << (s)) + 1)) |
780 | 110M | } |
781 | | |
782 | 11.1M | const fn has_zero(v: u32) -> bool { |
783 | | // Retrieved from Stanford bithacks |
784 | | // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord |
785 | 11.1M | return !((((v & 0x7F7F_7F7F) + 0x7F7F_7F7F) | v) | 0x7F7F_7F7F) != 0; |
786 | 11.1M | } |
787 | | |
788 | 11.1M | const fn has_byte(b: u32, val: u8) -> bool { |
789 | | // Retrieved from Stanford bithacks |
790 | | // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord |
791 | 11.1M | has_zero(b ^ ((!0_u32 / 255) * (val as u32))) |
792 | 11.1M | } |
793 | | |
794 | | // mod tests { |
795 | | // use zune_core::bytestream::ZCursor; |
796 | | // use zune_core::colorspace::ColorSpace; |
797 | | // use zune_core::options::DecoderOptions; |
798 | | // |
799 | | // use crate::JpegDecoder; |
800 | | // |
801 | | // #[test] |
802 | | // fn test_image() { |
803 | | // let img = "/Users/etemesi/Downloads/test_IDX_45_RAND_168601280367171438891916_minimized_837.jpg"; |
804 | | // let data = std::fs::read(img).unwrap(); |
805 | | // let options = DecoderOptions::new_cmd().jpeg_set_out_colorspace(ColorSpace::RGB); |
806 | | // let mut decoder = JpegDecoder::new_with_options(ZCursor::new(&data[..]), options); |
807 | | // |
808 | | // decoder.decode().unwrap(); |
809 | | // println!("{:?}", decoder.options.jpeg_get_out_colorspace()) |
810 | | // } |
811 | | // } |