/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zune-jpeg-0.5.5/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 | | // drop bits read |
101 | | ($stream).drop_bits(code_length as u8); |
102 | | }; |
103 | | } |
104 | | |
105 | | /// A `BitStream` struct, a bit by bit reader with super powers |
106 | | /// |
107 | | #[rustfmt::skip] |
108 | | pub(crate) struct BitStream { |
109 | | /// A MSB type buffer that is used for some certain operations |
110 | | pub buffer: u64, |
111 | | /// A TOP aligned MSB type buffer that is used to accelerate some operations like |
112 | | /// peek_bits and get_bits. |
113 | | /// |
114 | | /// By top aligned, I mean the top bit (63) represents the top bit in the buffer. |
115 | | aligned_buffer: u64, |
116 | | /// Tell us the bits left the two buffer |
117 | | pub(crate) bits_left: u8, |
118 | | /// Did we find a marker(RST/EOF) during decoding? |
119 | | pub marker: Option<Marker>, |
120 | | /// An i16 with the bit corresponding to successive_low set to 1, others 0. |
121 | | pub successive_low_mask: i16, |
122 | | spec_start: u8, |
123 | | spec_end: u8, |
124 | | pub eob_run: i32, |
125 | | pub overread_by: usize, |
126 | | /// True if we have seen end of image marker. |
127 | | /// Don't read anything after that. |
128 | | pub seen_eoi: bool, |
129 | | } |
130 | | |
131 | | impl BitStream { |
132 | | /// Create a new BitStream |
133 | | #[rustfmt::skip] |
134 | 1.49k | pub(crate) const fn new() -> BitStream { |
135 | 1.49k | BitStream { |
136 | 1.49k | buffer: 0, |
137 | 1.49k | aligned_buffer: 0, |
138 | 1.49k | bits_left: 0, |
139 | 1.49k | marker: None, |
140 | 1.49k | successive_low_mask: 1, |
141 | 1.49k | spec_start: 0, |
142 | 1.49k | spec_end: 0, |
143 | 1.49k | eob_run: 0, |
144 | 1.49k | overread_by: 0, |
145 | 1.49k | seen_eoi: false, |
146 | 1.49k | } |
147 | 1.49k | } |
148 | | |
149 | | /// Create a new Bitstream for progressive decoding |
150 | | #[allow(clippy::redundant_field_names)] |
151 | | #[rustfmt::skip] |
152 | 3.97k | pub(crate) fn new_progressive(al: u8, spec_start: u8, spec_end: u8) -> BitStream { |
153 | 3.97k | BitStream { |
154 | 3.97k | buffer: 0, |
155 | 3.97k | aligned_buffer: 0, |
156 | 3.97k | bits_left: 0, |
157 | 3.97k | marker: None, |
158 | 3.97k | successive_low_mask: 1i16 << al, |
159 | 3.97k | spec_start: spec_start, |
160 | 3.97k | spec_end: spec_end, |
161 | 3.97k | eob_run: 0, |
162 | 3.97k | overread_by: 0, |
163 | 3.97k | seen_eoi: false, |
164 | 3.97k | } |
165 | 3.97k | } |
166 | | |
167 | | /// Refill the bit buffer by (a maximum of) 32 bits |
168 | | /// |
169 | | /// # Arguments |
170 | | /// - `reader`:`&mut BufReader<R>`: A mutable reference to an underlying |
171 | | /// File/Memory buffer containing a valid JPEG stream |
172 | | /// |
173 | | /// This function will only refill if `self.count` is less than 32 |
174 | | #[inline(always)] // to many call sites? ( perf improvement by 4%) |
175 | 3.60G | pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors> |
176 | 3.60G | where |
177 | 3.60G | T: ZByteReaderTrait |
178 | | { |
179 | | /// Macro version of a single byte refill. |
180 | | /// Arguments |
181 | | /// buffer-> our io buffer, because rust macros cannot get values from |
182 | | /// the surrounding environment bits_left-> number of bits left |
183 | | /// to full refill |
184 | | macro_rules! refill { |
185 | | ($buffer:expr,$byte:expr,$bits_left:expr) => { |
186 | | // read a byte from the stream |
187 | | $byte = u64::from(reader.read_u8()); |
188 | | self.overread_by += usize::from(reader.eof()?); |
189 | | // append to the buffer |
190 | | // JPEG is a MSB type buffer so that means we append this |
191 | | // to the lower end (0..8) of the buffer and push the rest bits above.. |
192 | | $buffer = ($buffer << 8) | $byte; |
193 | | // Increment bits left |
194 | | $bits_left += 8; |
195 | | // Check for special case of OxFF, to see if it's a stream or a marker |
196 | | if $byte == 0xff { |
197 | | // read next byte |
198 | | let mut next_byte = u64::from(reader.read_u8()); |
199 | | // Byte snuffing, if we encounter byte snuff, we skip the byte |
200 | | if next_byte != 0x00 { |
201 | | // skip that byte we read |
202 | | while next_byte == 0xFF { |
203 | | next_byte = u64::from(reader.read_u8()); |
204 | | } |
205 | | |
206 | | if next_byte != 0x00 { |
207 | | // Undo the byte append and return |
208 | | $buffer >>= 8; |
209 | | $bits_left -= 8; |
210 | | |
211 | | if $bits_left != 0 { |
212 | | self.aligned_buffer = $buffer << (64 - $bits_left); |
213 | | } |
214 | | |
215 | | self.marker = Marker::from_u8(next_byte as u8); |
216 | | if next_byte == 0xD9 { |
217 | | // special handling for eoi, fill some bytes,even if its zero, |
218 | | // removes some panics |
219 | | self.buffer <<= 8; |
220 | | self.bits_left += 8; |
221 | | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
222 | | } |
223 | | |
224 | | return Ok(false); |
225 | | } |
226 | | } |
227 | | } |
228 | | }; |
229 | | } |
230 | | |
231 | | // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits) |
232 | 3.60G | if self.bits_left < 32 { |
233 | 458M | if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi{ |
234 | | // found a marker, or we are in EOI |
235 | | // also we are in over-reading mode, where we fill it with zeroes |
236 | | |
237 | | // fill with zeroes |
238 | 439M | self.buffer <<= 32; |
239 | 439M | self.bits_left += 32; |
240 | 439M | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
241 | 439M | return Ok(true); |
242 | 18.4M | } |
243 | | |
244 | | // we optimize for the case where we don't have 255 in the stream and have 4 bytes left |
245 | | // as it is the common case |
246 | | // |
247 | | // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is |
248 | | // guaranteed not to advance in case of failure (is this true), so |
249 | | // we revert the read later on (if we have 255), if this fails, we use the normal |
250 | | // byte at a time read |
251 | | |
252 | 18.4M | if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() { |
253 | | // we have 4 bytes to spare, read the 4 bytes into a temporary buffer |
254 | | // create buffer |
255 | 18.4M | let msb_buf = u32::from_be_bytes(bytes); |
256 | | // check if we have 0xff |
257 | 18.4M | if !has_byte(msb_buf, 255) { |
258 | 16.9M | self.bits_left += 32; |
259 | 16.9M | self.buffer <<= 32; |
260 | 16.9M | self.buffer |= u64::from(msb_buf); |
261 | 16.9M | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
262 | 16.9M | return Ok(true); |
263 | 1.50M | } |
264 | | |
265 | 1.50M | reader.rewind(4)?; |
266 | 1.65k | } |
267 | | // This serves two reasons, |
268 | | // 1: Make clippy shut up |
269 | | // 2: Favour register reuse |
270 | | let mut byte; |
271 | | // 4 refills, if all succeed the stream should contain enough bits to decode a |
272 | | // value |
273 | 1.50M | refill!(self.buffer, byte, self.bits_left); |
274 | 1.46M | refill!(self.buffer, byte, self.bits_left); |
275 | 1.42M | refill!(self.buffer, byte, self.bits_left); |
276 | 1.39M | refill!(self.buffer, byte, self.bits_left); |
277 | | // Construct an MSB buffer whose top bits are the bitstream we are currently holding. |
278 | 1.35M | self.aligned_buffer = self.buffer << (64 - self.bits_left); |
279 | 3.14G | } |
280 | 3.15G | return Ok(true); |
281 | 3.60G | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 175 | 2.86G | pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors> | 176 | 2.86G | where | 177 | 2.86G | T: ZByteReaderTrait | 178 | | { | 179 | | /// Macro version of a single byte refill. | 180 | | /// Arguments | 181 | | /// buffer-> our io buffer, because rust macros cannot get values from | 182 | | /// the surrounding environment bits_left-> number of bits left | 183 | | /// to full refill | 184 | | macro_rules! refill { | 185 | | ($buffer:expr,$byte:expr,$bits_left:expr) => { | 186 | | // read a byte from the stream | 187 | | $byte = u64::from(reader.read_u8()); | 188 | | self.overread_by += usize::from(reader.eof()?); | 189 | | // append to the buffer | 190 | | // JPEG is a MSB type buffer so that means we append this | 191 | | // to the lower end (0..8) of the buffer and push the rest bits above.. | 192 | | $buffer = ($buffer << 8) | $byte; | 193 | | // Increment bits left | 194 | | $bits_left += 8; | 195 | | // Check for special case of OxFF, to see if it's a stream or a marker | 196 | | if $byte == 0xff { | 197 | | // read next byte | 198 | | let mut next_byte = u64::from(reader.read_u8()); | 199 | | // Byte snuffing, if we encounter byte snuff, we skip the byte | 200 | | if next_byte != 0x00 { | 201 | | // skip that byte we read | 202 | | while next_byte == 0xFF { | 203 | | next_byte = u64::from(reader.read_u8()); | 204 | | } | 205 | | | 206 | | if next_byte != 0x00 { | 207 | | // Undo the byte append and return | 208 | | $buffer >>= 8; | 209 | | $bits_left -= 8; | 210 | | | 211 | | if $bits_left != 0 { | 212 | | self.aligned_buffer = $buffer << (64 - $bits_left); | 213 | | } | 214 | | | 215 | | self.marker = Marker::from_u8(next_byte as u8); | 216 | | if next_byte == 0xD9 { | 217 | | // special handling for eoi, fill some bytes,even if its zero, | 218 | | // removes some panics | 219 | | self.buffer <<= 8; | 220 | | self.bits_left += 8; | 221 | | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 222 | | } | 223 | | | 224 | | return Ok(false); | 225 | | } | 226 | | } | 227 | | } | 228 | | }; | 229 | | } | 230 | | | 231 | | // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits) | 232 | 2.86G | if self.bits_left < 32 { | 233 | 334M | if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi{ | 234 | | // found a marker, or we are in EOI | 235 | | // also we are in over-reading mode, where we fill it with zeroes | 236 | | | 237 | | // fill with zeroes | 238 | 317M | self.buffer <<= 32; | 239 | 317M | self.bits_left += 32; | 240 | 317M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 241 | 317M | return Ok(true); | 242 | 16.2M | } | 243 | | | 244 | | // we optimize for the case where we don't have 255 in the stream and have 4 bytes left | 245 | | // as it is the common case | 246 | | // | 247 | | // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is | 248 | | // guaranteed not to advance in case of failure (is this true), so | 249 | | // we revert the read later on (if we have 255), if this fails, we use the normal | 250 | | // byte at a time read | 251 | | | 252 | 16.2M | if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() { | 253 | | // we have 4 bytes to spare, read the 4 bytes into a temporary buffer | 254 | | // create buffer | 255 | 16.2M | let msb_buf = u32::from_be_bytes(bytes); | 256 | | // check if we have 0xff | 257 | 16.2M | if !has_byte(msb_buf, 255) { | 258 | 14.8M | self.bits_left += 32; | 259 | 14.8M | self.buffer <<= 32; | 260 | 14.8M | self.buffer |= u64::from(msb_buf); | 261 | 14.8M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 262 | 14.8M | return Ok(true); | 263 | 1.39M | } | 264 | | | 265 | 1.39M | reader.rewind(4)?; | 266 | 1.18k | } | 267 | | // This serves two reasons, | 268 | | // 1: Make clippy shut up | 269 | | // 2: Favour register reuse | 270 | | let mut byte; | 271 | | // 4 refills, if all succeed the stream should contain enough bits to decode a | 272 | | // value | 273 | 1.39M | refill!(self.buffer, byte, self.bits_left); | 274 | 1.36M | refill!(self.buffer, byte, self.bits_left); | 275 | 1.33M | refill!(self.buffer, byte, self.bits_left); | 276 | 1.30M | refill!(self.buffer, byte, self.bits_left); | 277 | | // Construct an MSB buffer whose top bits are the bitstream we are currently holding. | 278 | 1.27M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 279 | 2.52G | } | 280 | 2.52G | return Ok(true); | 281 | 2.86G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::refill::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 175 | 746M | pub fn refill<T>(&mut self, reader: &mut ZReader<T>) -> Result<bool, DecodeErrors> | 176 | 746M | where | 177 | 746M | T: ZByteReaderTrait | 178 | | { | 179 | | /// Macro version of a single byte refill. | 180 | | /// Arguments | 181 | | /// buffer-> our io buffer, because rust macros cannot get values from | 182 | | /// the surrounding environment bits_left-> number of bits left | 183 | | /// to full refill | 184 | | macro_rules! refill { | 185 | | ($buffer:expr,$byte:expr,$bits_left:expr) => { | 186 | | // read a byte from the stream | 187 | | $byte = u64::from(reader.read_u8()); | 188 | | self.overread_by += usize::from(reader.eof()?); | 189 | | // append to the buffer | 190 | | // JPEG is a MSB type buffer so that means we append this | 191 | | // to the lower end (0..8) of the buffer and push the rest bits above.. | 192 | | $buffer = ($buffer << 8) | $byte; | 193 | | // Increment bits left | 194 | | $bits_left += 8; | 195 | | // Check for special case of OxFF, to see if it's a stream or a marker | 196 | | if $byte == 0xff { | 197 | | // read next byte | 198 | | let mut next_byte = u64::from(reader.read_u8()); | 199 | | // Byte snuffing, if we encounter byte snuff, we skip the byte | 200 | | if next_byte != 0x00 { | 201 | | // skip that byte we read | 202 | | while next_byte == 0xFF { | 203 | | next_byte = u64::from(reader.read_u8()); | 204 | | } | 205 | | | 206 | | if next_byte != 0x00 { | 207 | | // Undo the byte append and return | 208 | | $buffer >>= 8; | 209 | | $bits_left -= 8; | 210 | | | 211 | | if $bits_left != 0 { | 212 | | self.aligned_buffer = $buffer << (64 - $bits_left); | 213 | | } | 214 | | | 215 | | self.marker = Marker::from_u8(next_byte as u8); | 216 | | if next_byte == 0xD9 { | 217 | | // special handling for eoi, fill some bytes,even if its zero, | 218 | | // removes some panics | 219 | | self.buffer <<= 8; | 220 | | self.bits_left += 8; | 221 | | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 222 | | } | 223 | | | 224 | | return Ok(false); | 225 | | } | 226 | | } | 227 | | } | 228 | | }; | 229 | | } | 230 | | | 231 | | // 32 bits is enough for a decode(16 bits) and receive_extend(max 16 bits) | 232 | 746M | if self.bits_left < 32 { | 233 | 124M | if self.marker.is_some() || self.overread_by > 0 || self.seen_eoi{ | 234 | | // found a marker, or we are in EOI | 235 | | // also we are in over-reading mode, where we fill it with zeroes | 236 | | | 237 | | // fill with zeroes | 238 | 121M | self.buffer <<= 32; | 239 | 121M | self.bits_left += 32; | 240 | 121M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 241 | 121M | return Ok(true); | 242 | 2.20M | } | 243 | | | 244 | | // we optimize for the case where we don't have 255 in the stream and have 4 bytes left | 245 | | // as it is the common case | 246 | | // | 247 | | // so we always read 4 bytes, if read_fixed_bytes errors out, the cursor is | 248 | | // guaranteed not to advance in case of failure (is this true), so | 249 | | // we revert the read later on (if we have 255), if this fails, we use the normal | 250 | | // byte at a time read | 251 | | | 252 | 2.20M | if let Ok(bytes) = reader.read_fixed_bytes_or_error::<4>() { | 253 | | // we have 4 bytes to spare, read the 4 bytes into a temporary buffer | 254 | | // create buffer | 255 | 2.20M | let msb_buf = u32::from_be_bytes(bytes); | 256 | | // check if we have 0xff | 257 | 2.20M | if !has_byte(msb_buf, 255) { | 258 | 2.09M | self.bits_left += 32; | 259 | 2.09M | self.buffer <<= 32; | 260 | 2.09M | self.buffer |= u64::from(msb_buf); | 261 | 2.09M | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 262 | 2.09M | return Ok(true); | 263 | 113k | } | 264 | | | 265 | 113k | reader.rewind(4)?; | 266 | 464 | } | 267 | | // This serves two reasons, | 268 | | // 1: Make clippy shut up | 269 | | // 2: Favour register reuse | 270 | | let mut byte; | 271 | | // 4 refills, if all succeed the stream should contain enough bits to decode a | 272 | | // value | 273 | 113k | refill!(self.buffer, byte, self.bits_left); | 274 | 104k | refill!(self.buffer, byte, self.bits_left); | 275 | 94.6k | refill!(self.buffer, byte, self.bits_left); | 276 | 84.2k | refill!(self.buffer, byte, self.bits_left); | 277 | | // Construct an MSB buffer whose top bits are the bitstream we are currently holding. | 278 | 74.8k | self.aligned_buffer = self.buffer << (64 - self.bits_left); | 279 | 622M | } | 280 | 622M | return Ok(true); | 281 | 746M | } |
|
282 | | /// Decode the DC coefficient in a MCU block. |
283 | | /// |
284 | | /// The decoded coefficient is written to `dc_prediction` |
285 | | /// |
286 | | #[allow( |
287 | | clippy::cast_possible_truncation, |
288 | | clippy::cast_sign_loss, |
289 | | clippy::unwrap_used |
290 | | )] |
291 | | #[inline(always)] |
292 | 324M | fn decode_dc<T>( |
293 | 324M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32 |
294 | 324M | ) -> Result<bool, DecodeErrors> |
295 | 324M | where |
296 | 324M | T: ZByteReaderTrait |
297 | | { |
298 | | let (mut symbol, r); |
299 | | |
300 | 324M | if self.bits_left < 32 { |
301 | 24.8M | self.refill(reader)?; |
302 | 299M | }; |
303 | | // look a head HUFF_LOOKAHEAD bits into the bitstream |
304 | 324M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
305 | 324M | symbol = dc_table.lookup[symbol as usize]; |
306 | | |
307 | 324M | decode_huff!(self, symbol, dc_table); |
308 | | |
309 | 324M | if symbol != 0 { |
310 | 25.3M | r = self.get_bits(symbol as u8); |
311 | 25.3M | symbol = huff_extend(r, symbol); |
312 | 299M | } |
313 | | // Update DC prediction |
314 | 324M | *dc_prediction = dc_prediction.wrapping_add(symbol); |
315 | | |
316 | 324M | return Ok(true); |
317 | 324M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 292 | 213M | fn decode_dc<T>( | 293 | 213M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32 | 294 | 213M | ) -> Result<bool, DecodeErrors> | 295 | 213M | where | 296 | 213M | T: ZByteReaderTrait | 297 | | { | 298 | | let (mut symbol, r); | 299 | | | 300 | 213M | if self.bits_left < 32 { | 301 | 14.8M | self.refill(reader)?; | 302 | 198M | }; | 303 | | // look a head HUFF_LOOKAHEAD bits into the bitstream | 304 | 213M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 305 | 213M | symbol = dc_table.lookup[symbol as usize]; | 306 | | | 307 | 213M | decode_huff!(self, symbol, dc_table); | 308 | | | 309 | 213M | if symbol != 0 { | 310 | 12.0M | r = self.get_bits(symbol as u8); | 311 | 12.0M | symbol = huff_extend(r, symbol); | 312 | 201M | } | 313 | | // Update DC prediction | 314 | 213M | *dc_prediction = dc_prediction.wrapping_add(symbol); | 315 | | | 316 | 213M | return Ok(true); | 317 | 213M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_dc::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 292 | 111M | fn decode_dc<T>( | 293 | 111M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, dc_prediction: &mut i32 | 294 | 111M | ) -> Result<bool, DecodeErrors> | 295 | 111M | where | 296 | 111M | T: ZByteReaderTrait | 297 | | { | 298 | | let (mut symbol, r); | 299 | | | 300 | 111M | if self.bits_left < 32 { | 301 | 10.0M | self.refill(reader)?; | 302 | 101M | }; | 303 | | // look a head HUFF_LOOKAHEAD bits into the bitstream | 304 | 111M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 305 | 111M | symbol = dc_table.lookup[symbol as usize]; | 306 | | | 307 | 111M | decode_huff!(self, symbol, dc_table); | 308 | | | 309 | 111M | if symbol != 0 { | 310 | 13.3M | r = self.get_bits(symbol as u8); | 311 | 13.3M | symbol = huff_extend(r, symbol); | 312 | 98.0M | } | 313 | | // Update DC prediction | 314 | 111M | *dc_prediction = dc_prediction.wrapping_add(symbol); | 315 | | | 316 | 111M | return Ok(true); | 317 | 111M | } |
|
318 | | |
319 | | /// Decode a Minimum Code Unit(MCU) as quickly as possible |
320 | | /// |
321 | | /// # Arguments |
322 | | /// - reader: The bitstream from where we read more bits. |
323 | | /// - dc_table: The Huffman table used to decode the DC coefficient |
324 | | /// - ac_table: The Huffman table used to decode AC values |
325 | | /// - block: A memory region where we will write out the decoded values |
326 | | /// - DC prediction: Last DC value for this component |
327 | | /// |
328 | | #[allow( |
329 | | clippy::many_single_char_names, |
330 | | clippy::cast_possible_truncation, |
331 | | clippy::cast_sign_loss |
332 | | )] |
333 | | #[inline(never)] |
334 | 86.3M | pub fn decode_mcu_block<T>( |
335 | 86.3M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable, |
336 | 86.3M | qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32 |
337 | 86.3M | ) -> Result<(), DecodeErrors> |
338 | 86.3M | where |
339 | 86.3M | T: ZByteReaderTrait |
340 | | { |
341 | | // Get fast AC table as a reference before we enter the hot path |
342 | 86.3M | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); |
343 | | |
344 | | let (mut symbol, mut r, mut fast_ac); |
345 | | // Decode AC coefficients |
346 | 86.3M | let mut pos: usize = 1; |
347 | | |
348 | | // decode DC, dc prediction will contain the value |
349 | 86.3M | self.decode_dc(reader, dc_table, dc_prediction)?; |
350 | | |
351 | | // set dc to be the dc prediction. |
352 | 86.3M | block[0] = *dc_prediction * qt_table[0]; |
353 | | |
354 | 2.40G | while pos < 64 { |
355 | 2.36G | self.refill(reader)?; |
356 | 2.36G | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
357 | 2.36G | fast_ac = ac_lookup[symbol as usize]; |
358 | 2.36G | symbol = ac_table.lookup[symbol as usize]; |
359 | | |
360 | 2.36G | if fast_ac != 0 { |
361 | 2.27G | // FAST AC path |
362 | 2.27G | pos += ((fast_ac >> 4) & 15) as usize; // run |
363 | 2.27G | let t_pos = UN_ZIGZAG[min(pos, 63)] & 63; |
364 | 2.27G | |
365 | 2.27G | block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value |
366 | 2.27G | self.drop_bits((fast_ac & 15) as u8); |
367 | 2.27G | pos += 1; |
368 | 2.27G | } else { |
369 | 94.5M | decode_huff!(self, symbol, ac_table); |
370 | | |
371 | 94.5M | r = symbol >> 4; |
372 | 94.5M | symbol &= 15; |
373 | | |
374 | 94.5M | if symbol != 0 { |
375 | 50.8M | pos += r as usize; |
376 | 50.8M | r = self.get_bits(symbol as u8); |
377 | 50.8M | symbol = huff_extend(r, symbol); |
378 | 50.8M | let t_pos = UN_ZIGZAG[pos & 63] & 63; |
379 | 50.8M | |
380 | 50.8M | block[t_pos] = symbol * qt_table[t_pos]; |
381 | 50.8M | |
382 | 50.8M | pos += 1; |
383 | 50.8M | } else if r != 15 { |
384 | 43.6M | return Ok(()); |
385 | 140k | } else { |
386 | 140k | pos += 16; |
387 | 140k | } |
388 | | } |
389 | | } |
390 | 42.7M | return Ok(()); |
391 | 86.3M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 334 | 67.1M | pub fn decode_mcu_block<T>( | 335 | 67.1M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable, | 336 | 67.1M | qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32 | 337 | 67.1M | ) -> Result<(), DecodeErrors> | 338 | 67.1M | where | 339 | 67.1M | T: ZByteReaderTrait | 340 | | { | 341 | | // Get fast AC table as a reference before we enter the hot path | 342 | 67.1M | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); | 343 | | | 344 | | let (mut symbol, mut r, mut fast_ac); | 345 | | // Decode AC coefficients | 346 | 67.1M | let mut pos: usize = 1; | 347 | | | 348 | | // decode DC, dc prediction will contain the value | 349 | 67.1M | self.decode_dc(reader, dc_table, dc_prediction)?; | 350 | | | 351 | | // set dc to be the dc prediction. | 352 | 67.1M | block[0] = *dc_prediction * qt_table[0]; | 353 | | | 354 | 1.95G | while pos < 64 { | 355 | 1.93G | self.refill(reader)?; | 356 | 1.93G | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 357 | 1.93G | fast_ac = ac_lookup[symbol as usize]; | 358 | 1.93G | symbol = ac_table.lookup[symbol as usize]; | 359 | | | 360 | 1.93G | if fast_ac != 0 { | 361 | 1.88G | // FAST AC path | 362 | 1.88G | pos += ((fast_ac >> 4) & 15) as usize; // run | 363 | 1.88G | let t_pos = UN_ZIGZAG[min(pos, 63)] & 63; | 364 | 1.88G | | 365 | 1.88G | block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value | 366 | 1.88G | self.drop_bits((fast_ac & 15) as u8); | 367 | 1.88G | pos += 1; | 368 | 1.88G | } else { | 369 | 43.3M | decode_huff!(self, symbol, ac_table); | 370 | | | 371 | 43.3M | r = symbol >> 4; | 372 | 43.3M | symbol &= 15; | 373 | | | 374 | 43.3M | if symbol != 0 { | 375 | 5.60M | pos += r as usize; | 376 | 5.60M | r = self.get_bits(symbol as u8); | 377 | 5.60M | symbol = huff_extend(r, symbol); | 378 | 5.60M | let t_pos = UN_ZIGZAG[pos & 63] & 63; | 379 | 5.60M | | 380 | 5.60M | block[t_pos] = symbol * qt_table[t_pos]; | 381 | 5.60M | | 382 | 5.60M | pos += 1; | 383 | 37.7M | } else if r != 15 { | 384 | 37.5M | return Ok(()); | 385 | 114k | } else { | 386 | 114k | pos += 16; | 387 | 114k | } | 388 | | } | 389 | | } | 390 | 29.5M | return Ok(()); | 391 | 67.1M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_block::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 334 | 19.2M | pub fn decode_mcu_block<T>( | 335 | 19.2M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, ac_table: &HuffmanTable, | 336 | 19.2M | qt_table: &[i32; DCT_BLOCK], block: &mut [i32; 64], dc_prediction: &mut i32 | 337 | 19.2M | ) -> Result<(), DecodeErrors> | 338 | 19.2M | where | 339 | 19.2M | T: ZByteReaderTrait | 340 | | { | 341 | | // Get fast AC table as a reference before we enter the hot path | 342 | 19.2M | let ac_lookup = ac_table.ac_lookup.as_ref().unwrap(); | 343 | | | 344 | | let (mut symbol, mut r, mut fast_ac); | 345 | | // Decode AC coefficients | 346 | 19.2M | let mut pos: usize = 1; | 347 | | | 348 | | // decode DC, dc prediction will contain the value | 349 | 19.2M | self.decode_dc(reader, dc_table, dc_prediction)?; | 350 | | | 351 | | // set dc to be the dc prediction. | 352 | 19.2M | block[0] = *dc_prediction * qt_table[0]; | 353 | | | 354 | 450M | while pos < 64 { | 355 | 437M | self.refill(reader)?; | 356 | 437M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 357 | 437M | fast_ac = ac_lookup[symbol as usize]; | 358 | 437M | symbol = ac_table.lookup[symbol as usize]; | 359 | | | 360 | 437M | if fast_ac != 0 { | 361 | 385M | // FAST AC path | 362 | 385M | pos += ((fast_ac >> 4) & 15) as usize; // run | 363 | 385M | let t_pos = UN_ZIGZAG[min(pos, 63)] & 63; | 364 | 385M | | 365 | 385M | block[t_pos] = i32::from(fast_ac >> 8) * (qt_table[t_pos]); // Value | 366 | 385M | self.drop_bits((fast_ac & 15) as u8); | 367 | 385M | pos += 1; | 368 | 385M | } else { | 369 | 51.2M | decode_huff!(self, symbol, ac_table); | 370 | | | 371 | 51.2M | r = symbol >> 4; | 372 | 51.2M | symbol &= 15; | 373 | | | 374 | 51.2M | if symbol != 0 { | 375 | 45.2M | pos += r as usize; | 376 | 45.2M | r = self.get_bits(symbol as u8); | 377 | 45.2M | symbol = huff_extend(r, symbol); | 378 | 45.2M | let t_pos = UN_ZIGZAG[pos & 63] & 63; | 379 | 45.2M | | 380 | 45.2M | block[t_pos] = symbol * qt_table[t_pos]; | 381 | 45.2M | | 382 | 45.2M | pos += 1; | 383 | 45.2M | } else if r != 15 { | 384 | 6.02M | return Ok(()); | 385 | 26.5k | } else { | 386 | 26.5k | pos += 16; | 387 | 26.5k | } | 388 | | } | 389 | | } | 390 | 13.2M | return Ok(()); | 391 | 19.2M | } |
|
392 | | |
393 | | /// Peek `look_ahead` bits ahead without discarding them from the buffer |
394 | | #[inline(always)] |
395 | | #[allow(clippy::cast_possible_truncation)] |
396 | 3.87G | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { |
397 | 3.87G | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 |
398 | 3.87G | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Line | Count | Source | 396 | 7.85M | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 397 | 7.85M | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 398 | 7.85M | } |
<zune_jpeg::bitstream::BitStream>::peek_bits::<9> Line | Count | Source | 396 | 3.02G | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 397 | 3.02G | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 398 | 3.02G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::peek_bits::<9> <zune_jpeg::bitstream::BitStream>::peek_bits::<16> Line | Count | Source | 396 | 210k | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 397 | 210k | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 398 | 210k | } |
<zune_jpeg::bitstream::BitStream>::peek_bits::<9> Line | Count | Source | 396 | 839M | const fn peek_bits<const LOOKAHEAD: u8>(&self) -> i32 { | 397 | 839M | (self.aligned_buffer >> (64 - LOOKAHEAD)) as i32 | 398 | 839M | } |
|
399 | | |
400 | | /// Discard the next `N` bits without checking |
401 | | #[inline] |
402 | 6.40G | fn drop_bits(&mut self, n: u8) { |
403 | 6.40G | debug_assert!(self.bits_left >= n); |
404 | | //self.bits_left -= n; |
405 | 6.40G | self.bits_left = self.bits_left.saturating_sub(n); |
406 | 6.40G | self.aligned_buffer <<= n; |
407 | 6.40G | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits <zune_jpeg::bitstream::BitStream>::drop_bits Line | Count | Source | 402 | 2.54G | fn drop_bits(&mut self, n: u8) { | 403 | 2.54G | debug_assert!(self.bits_left >= n); | 404 | | //self.bits_left -= n; | 405 | 2.54G | self.bits_left = self.bits_left.saturating_sub(n); | 406 | 2.54G | self.aligned_buffer <<= n; | 407 | 2.54G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits <zune_jpeg::bitstream::BitStream>::drop_bits Line | Count | Source | 402 | 3.02G | fn drop_bits(&mut self, n: u8) { | 403 | 3.02G | debug_assert!(self.bits_left >= n); | 404 | | //self.bits_left -= n; | 405 | 3.02G | self.bits_left = self.bits_left.saturating_sub(n); | 406 | 3.02G | self.aligned_buffer <<= n; | 407 | 3.02G | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::drop_bits <zune_jpeg::bitstream::BitStream>::drop_bits Line | Count | Source | 402 | 839M | fn drop_bits(&mut self, n: u8) { | 403 | 839M | debug_assert!(self.bits_left >= n); | 404 | | //self.bits_left -= n; | 405 | 839M | self.bits_left = self.bits_left.saturating_sub(n); | 406 | 839M | self.aligned_buffer <<= n; | 407 | 839M | } |
|
408 | | |
409 | | /// Read `n_bits` from the buffer and discard them |
410 | | #[inline(always)] |
411 | | #[allow(clippy::cast_possible_truncation)] |
412 | 185M | fn get_bits(&mut self, n_bits: u8) -> i32 { |
413 | 185M | let mask = (1_u64 << n_bits) - 1; |
414 | | |
415 | 185M | self.aligned_buffer = self.aligned_buffer.rotate_left(u32::from(n_bits)); |
416 | 185M | let bits = (self.aligned_buffer & mask) as i32; |
417 | 185M | self.bits_left = self.bits_left.wrapping_sub(n_bits); |
418 | 185M | bits |
419 | 185M | } |
420 | | |
421 | | /// Decode a DC block |
422 | | #[allow(clippy::cast_possible_truncation)] |
423 | | #[inline] |
424 | 238M | pub(crate) fn decode_prog_dc_first<T>( |
425 | 238M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16, |
426 | 238M | dc_prediction: &mut i32 |
427 | 238M | ) -> Result<(), DecodeErrors> |
428 | 238M | where |
429 | 238M | T: ZByteReaderTrait |
430 | | { |
431 | 238M | self.decode_dc(reader, dc_table, dc_prediction)?; |
432 | 238M | *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask); |
433 | 238M | return Ok(()); |
434 | 238M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 424 | 146M | pub(crate) fn decode_prog_dc_first<T>( | 425 | 146M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16, | 426 | 146M | dc_prediction: &mut i32 | 427 | 146M | ) -> Result<(), DecodeErrors> | 428 | 146M | where | 429 | 146M | T: ZByteReaderTrait | 430 | | { | 431 | 146M | self.decode_dc(reader, dc_table, dc_prediction)?; | 432 | 146M | *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask); | 433 | 146M | return Ok(()); | 434 | 146M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_prog_dc_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 424 | 92.1M | pub(crate) fn decode_prog_dc_first<T>( | 425 | 92.1M | &mut self, reader: &mut ZReader<T>, dc_table: &HuffmanTable, block: &mut i16, | 426 | 92.1M | dc_prediction: &mut i32 | 427 | 92.1M | ) -> Result<(), DecodeErrors> | 428 | 92.1M | where | 429 | 92.1M | T: ZByteReaderTrait | 430 | | { | 431 | 92.1M | self.decode_dc(reader, dc_table, dc_prediction)?; | 432 | 92.1M | *block = (*dc_prediction as i16).wrapping_mul(self.successive_low_mask); | 433 | 92.1M | return Ok(()); | 434 | 92.1M | } |
|
435 | | #[inline] |
436 | 174M | pub(crate) fn decode_prog_dc_refine<T>( |
437 | 174M | &mut self, reader: &mut ZReader<T>, block: &mut i16 |
438 | 174M | ) -> Result<(), DecodeErrors> |
439 | 174M | where |
440 | 174M | T: ZByteReaderTrait |
441 | | { |
442 | | // refinement scan |
443 | 174M | if self.bits_left < 1 { |
444 | 5.44M | self.refill(reader)?; |
445 | | // if we find a marker, it may happens we don't refill. |
446 | | // So let's confirm again that refill worked |
447 | 5.44M | if self.bits_left < 1 { |
448 | 32 | return Err(DecodeErrors::Format( |
449 | 32 | "Marker found where not expected in refine bit".to_string() |
450 | 32 | )); |
451 | 5.44M | } |
452 | 169M | } |
453 | | |
454 | 174M | if self.get_bit() == 1 { |
455 | 4.98M | *block = block.wrapping_add(self.successive_low_mask); |
456 | 169M | } |
457 | | |
458 | 174M | Ok(()) |
459 | 174M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 436 | 148M | pub(crate) fn decode_prog_dc_refine<T>( | 437 | 148M | &mut self, reader: &mut ZReader<T>, block: &mut i16 | 438 | 148M | ) -> Result<(), DecodeErrors> | 439 | 148M | where | 440 | 148M | T: ZByteReaderTrait | 441 | | { | 442 | | // refinement scan | 443 | 148M | if self.bits_left < 1 { | 444 | 4.62M | self.refill(reader)?; | 445 | | // if we find a marker, it may happens we don't refill. | 446 | | // So let's confirm again that refill worked | 447 | 4.62M | if self.bits_left < 1 { | 448 | 29 | return Err(DecodeErrors::Format( | 449 | 29 | "Marker found where not expected in refine bit".to_string() | 450 | 29 | )); | 451 | 4.62M | } | 452 | 143M | } | 453 | | | 454 | 148M | if self.get_bit() == 1 { | 455 | 4.89M | *block = block.wrapping_add(self.successive_low_mask); | 456 | 143M | } | 457 | | | 458 | 148M | Ok(()) | 459 | 148M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_prog_dc_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 436 | 26.3M | pub(crate) fn decode_prog_dc_refine<T>( | 437 | 26.3M | &mut self, reader: &mut ZReader<T>, block: &mut i16 | 438 | 26.3M | ) -> Result<(), DecodeErrors> | 439 | 26.3M | where | 440 | 26.3M | T: ZByteReaderTrait | 441 | | { | 442 | | // refinement scan | 443 | 26.3M | if self.bits_left < 1 { | 444 | 823k | self.refill(reader)?; | 445 | | // if we find a marker, it may happens we don't refill. | 446 | | // So let's confirm again that refill worked | 447 | 823k | if self.bits_left < 1 { | 448 | 3 | return Err(DecodeErrors::Format( | 449 | 3 | "Marker found where not expected in refine bit".to_string() | 450 | 3 | )); | 451 | 823k | } | 452 | 25.5M | } | 453 | | | 454 | 26.3M | if self.get_bit() == 1 { | 455 | 90.0k | *block = block.wrapping_add(self.successive_low_mask); | 456 | 26.2M | } | 457 | | | 458 | 26.3M | Ok(()) | 459 | 26.3M | } |
|
460 | | |
461 | | /// Get a single bit from the bitstream |
462 | 2.54G | fn get_bit(&mut self) -> u8 { |
463 | 2.54G | let k = (self.aligned_buffer >> 63) as u8; |
464 | | // discard a bit |
465 | 2.54G | self.drop_bits(1); |
466 | 2.54G | return k; |
467 | 2.54G | } |
468 | 80.0M | pub(crate) fn decode_mcu_ac_first<T>( |
469 | 80.0M | &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64] |
470 | 80.0M | ) -> Result<bool, DecodeErrors> |
471 | 80.0M | where |
472 | 80.0M | T: ZByteReaderTrait |
473 | | { |
474 | 80.0M | let fast_ac = ac_table.ac_lookup.as_ref().unwrap(); |
475 | 80.0M | let bit = self.successive_low_mask; |
476 | | |
477 | 80.0M | let mut k = self.spec_start as usize; |
478 | | let (mut symbol, mut r, mut fac); |
479 | | |
480 | | // EOB runs are handled in mcu_prog.rs |
481 | | 'block: loop { |
482 | 723M | self.refill(reader)?; |
483 | | |
484 | 723M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
485 | 723M | fac = fast_ac[symbol as usize]; |
486 | 723M | symbol = ac_table.lookup[symbol as usize]; |
487 | | |
488 | 723M | if fac != 0 { |
489 | 630M | // fast ac path |
490 | 630M | k += ((fac >> 4) & 15) as usize; // run |
491 | 630M | block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value |
492 | 630M | self.drop_bits((fac & 15) as u8); |
493 | 630M | k += 1; |
494 | 630M | } else { |
495 | 93.4M | decode_huff!(self, symbol, ac_table); |
496 | | |
497 | 93.4M | r = symbol >> 4; |
498 | 93.4M | symbol &= 15; |
499 | | |
500 | 93.4M | if symbol != 0 { |
501 | 74.0M | k += r as usize; |
502 | 74.0M | r = self.get_bits(symbol as u8); |
503 | 74.0M | symbol = huff_extend(r, symbol); |
504 | 74.0M | block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit); |
505 | 74.0M | k += 1; |
506 | 74.0M | } else { |
507 | 19.3M | if r != 15 { |
508 | 19.3M | self.eob_run = 1 << r; |
509 | 19.3M | self.eob_run += self.get_bits(r as u8); |
510 | 19.3M | self.eob_run -= 1; |
511 | 19.3M | break; |
512 | 49.9k | } |
513 | | |
514 | 49.9k | k += 16; |
515 | | } |
516 | | } |
517 | | |
518 | 704M | if k > self.spec_end as usize { |
519 | 60.7M | break 'block; |
520 | 643M | } |
521 | | } |
522 | 80.0M | return Ok(true); |
523 | 80.0M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 468 | 36.6M | pub(crate) fn decode_mcu_ac_first<T>( | 469 | 36.6M | &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64] | 470 | 36.6M | ) -> Result<bool, DecodeErrors> | 471 | 36.6M | where | 472 | 36.6M | T: ZByteReaderTrait | 473 | | { | 474 | 36.6M | let fast_ac = ac_table.ac_lookup.as_ref().unwrap(); | 475 | 36.6M | let bit = self.successive_low_mask; | 476 | | | 477 | 36.6M | let mut k = self.spec_start as usize; | 478 | | let (mut symbol, mut r, mut fac); | 479 | | | 480 | | // EOB runs are handled in mcu_prog.rs | 481 | | 'block: loop { | 482 | 466M | self.refill(reader)?; | 483 | | | 484 | 466M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 485 | 466M | fac = fast_ac[symbol as usize]; | 486 | 466M | symbol = ac_table.lookup[symbol as usize]; | 487 | | | 488 | 466M | if fac != 0 { | 489 | 438M | // fast ac path | 490 | 438M | k += ((fac >> 4) & 15) as usize; // run | 491 | 438M | block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value | 492 | 438M | self.drop_bits((fac & 15) as u8); | 493 | 438M | k += 1; | 494 | 438M | } else { | 495 | 27.5M | decode_huff!(self, symbol, ac_table); | 496 | | | 497 | 27.5M | r = symbol >> 4; | 498 | 27.5M | symbol &= 15; | 499 | | | 500 | 27.5M | if symbol != 0 { | 501 | 8.42M | k += r as usize; | 502 | 8.42M | r = self.get_bits(symbol as u8); | 503 | 8.42M | symbol = huff_extend(r, symbol); | 504 | 8.42M | block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit); | 505 | 8.42M | k += 1; | 506 | 8.42M | } else { | 507 | 19.1M | if r != 15 { | 508 | 19.1M | self.eob_run = 1 << r; | 509 | 19.1M | self.eob_run += self.get_bits(r as u8); | 510 | 19.1M | self.eob_run -= 1; | 511 | 19.1M | break; | 512 | 10.7k | } | 513 | | | 514 | 10.7k | k += 16; | 515 | | } | 516 | | } | 517 | | | 518 | 447M | if k > self.spec_end as usize { | 519 | 17.4M | break 'block; | 520 | 429M | } | 521 | | } | 522 | 36.6M | return Ok(true); | 523 | 36.6M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_first::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 468 | 43.4M | pub(crate) fn decode_mcu_ac_first<T>( | 469 | 43.4M | &mut self, reader: &mut ZReader<T>, ac_table: &HuffmanTable, block: &mut [i16; 64] | 470 | 43.4M | ) -> Result<bool, DecodeErrors> | 471 | 43.4M | where | 472 | 43.4M | T: ZByteReaderTrait | 473 | | { | 474 | 43.4M | let fast_ac = ac_table.ac_lookup.as_ref().unwrap(); | 475 | 43.4M | let bit = self.successive_low_mask; | 476 | | | 477 | 43.4M | let mut k = self.spec_start as usize; | 478 | | let (mut symbol, mut r, mut fac); | 479 | | | 480 | | // EOB runs are handled in mcu_prog.rs | 481 | | 'block: loop { | 482 | 257M | self.refill(reader)?; | 483 | | | 484 | 257M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 485 | 257M | fac = fast_ac[symbol as usize]; | 486 | 257M | symbol = ac_table.lookup[symbol as usize]; | 487 | | | 488 | 257M | if fac != 0 { | 489 | 191M | // fast ac path | 490 | 191M | k += ((fac >> 4) & 15) as usize; // run | 491 | 191M | block[UN_ZIGZAG[min(k, 63)] & 63] = (fac >> 8).wrapping_mul(bit); // value | 492 | 191M | self.drop_bits((fac & 15) as u8); | 493 | 191M | k += 1; | 494 | 191M | } else { | 495 | 65.8M | decode_huff!(self, symbol, ac_table); | 496 | | | 497 | 65.8M | r = symbol >> 4; | 498 | 65.8M | symbol &= 15; | 499 | | | 500 | 65.8M | if symbol != 0 { | 501 | 65.6M | k += r as usize; | 502 | 65.6M | r = self.get_bits(symbol as u8); | 503 | 65.6M | symbol = huff_extend(r, symbol); | 504 | 65.6M | block[UN_ZIGZAG[k & 63] & 63] = (symbol as i16).wrapping_mul(bit); | 505 | 65.6M | k += 1; | 506 | 65.6M | } else { | 507 | 201k | if r != 15 { | 508 | 162k | self.eob_run = 1 << r; | 509 | 162k | self.eob_run += self.get_bits(r as u8); | 510 | 162k | self.eob_run -= 1; | 511 | 162k | break; | 512 | 39.2k | } | 513 | | | 514 | 39.2k | k += 16; | 515 | | } | 516 | | } | 517 | | | 518 | 257M | if k > self.spec_end as usize { | 519 | 43.2M | break 'block; | 520 | 213M | } | 521 | | } | 522 | 43.4M | return Ok(true); | 523 | 43.4M | } |
|
524 | | #[allow(clippy::too_many_lines, clippy::op_ref)] |
525 | 60.4M | pub(crate) fn decode_mcu_ac_refine<T>( |
526 | 60.4M | &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64] |
527 | 60.4M | ) -> Result<bool, DecodeErrors> |
528 | 60.4M | where |
529 | 60.4M | T: ZByteReaderTrait |
530 | | { |
531 | 60.4M | let bit = self.successive_low_mask; |
532 | | |
533 | 60.4M | let mut k = self.spec_start; |
534 | | let (mut symbol, mut r); |
535 | | |
536 | 60.4M | if self.eob_run == 0 { |
537 | | 'no_eob: loop { |
538 | | // Decode a coefficient from the bit stream |
539 | 446M | self.refill(reader)?; |
540 | | |
541 | 446M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); |
542 | 446M | symbol = table.lookup[symbol as usize]; |
543 | | |
544 | 446M | decode_huff!(self, symbol, table); |
545 | | |
546 | 446M | r = symbol >> 4; |
547 | 446M | symbol &= 15; |
548 | | |
549 | 446M | if symbol == 0 { |
550 | 16.0M | if r != 15 { |
551 | | // EOB run is 2^r + bits |
552 | 15.9M | self.eob_run = 1 << r; |
553 | 15.9M | self.eob_run += self.get_bits(r as u8); |
554 | | // EOB runs are handled by the eob logic |
555 | 15.9M | break 'no_eob; |
556 | 47.3k | } |
557 | | } else { |
558 | 430M | if symbol != 1 { |
559 | 324 | return Err(DecodeErrors::HuffmanDecode( |
560 | 324 | "Bad Huffman code, corrupt JPEG?".to_string() |
561 | 324 | )); |
562 | 430M | } |
563 | | // get sign bit |
564 | | // We assume we have enough bits, which should be correct for sane images |
565 | | // since we refill by 32 above |
566 | 430M | if self.get_bit() == 1 { |
567 | 1.11M | symbol = i32::from(bit); |
568 | 429M | } else { |
569 | 429M | symbol = i32::from(-bit); |
570 | 429M | } |
571 | | } |
572 | | |
573 | | // Advance over already nonzero coefficients appending |
574 | | // correction bits to the non-zeroes. |
575 | | // A correction bit is 1 if the absolute value of the coefficient must be increased |
576 | | |
577 | 430M | if k <= self.spec_end { |
578 | | 'advance_nonzero: loop { |
579 | 2.23G | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; |
580 | | |
581 | 2.23G | if *coefficient != 0 { |
582 | 1.83G | if self.get_bit() == 1 && (*coefficient & bit) == 0 { |
583 | 1.29M | if *coefficient >= 0 { |
584 | 145k | *coefficient += bit; |
585 | 1.15M | } else { |
586 | 1.15M | *coefficient -= bit; |
587 | 1.15M | } |
588 | 1.83G | } |
589 | | |
590 | 1.83G | if self.bits_left < 1 { |
591 | 29.1M | self.refill(reader)?; |
592 | 1.80G | } |
593 | | } else { |
594 | 401M | r -= 1; |
595 | | |
596 | 401M | if r < 0 { |
597 | | // reached target zero coefficient. |
598 | 397M | break 'advance_nonzero; |
599 | 3.25M | } |
600 | | }; |
601 | | |
602 | 1.83G | if k == self.spec_end { |
603 | 31.2M | break 'advance_nonzero; |
604 | 1.80G | } |
605 | | |
606 | 1.80G | k += 1; |
607 | | } |
608 | 1.83M | } |
609 | | |
610 | 430M | if symbol != 0 { |
611 | 430M | let pos = UN_ZIGZAG[k as usize & 63]; |
612 | 430M | // output new non-zero coefficient. |
613 | 430M | block[pos & 63] = symbol as i16; |
614 | 430M | } |
615 | | |
616 | 430M | k += 1; |
617 | | |
618 | 430M | if k > self.spec_end { |
619 | 40.5M | break 'no_eob; |
620 | 390M | } |
621 | | } |
622 | 4.01M | } |
623 | 60.4M | if self.eob_run > 0 { |
624 | | // only run if block does not consists of purely zeroes |
625 | 19.9M | if &block[1..] != &[0; 63] { |
626 | 6.72M | self.refill(reader)?; |
627 | | |
628 | 135M | while k <= self.spec_end { |
629 | 129M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; |
630 | | |
631 | 129M | if *coefficient != 0 && self.get_bit() == 1 { |
632 | | // check if we already modified it, if so do nothing, otherwise |
633 | | // append the correction bit. |
634 | 17.8M | if (*coefficient & bit) == 0 { |
635 | 3.47M | if *coefficient >= 0 { |
636 | 365k | *coefficient = coefficient.wrapping_add(bit); |
637 | 3.11M | } else { |
638 | 3.11M | *coefficient = coefficient.wrapping_sub(bit); |
639 | 3.11M | } |
640 | 14.3M | } |
641 | 111M | } |
642 | 129M | if self.bits_left < 1 { |
643 | | // refill at the last possible moment |
644 | 1.47M | self.refill(reader)?; |
645 | 127M | } |
646 | 129M | k += 1; |
647 | | } |
648 | 13.2M | } |
649 | | // count a block completed in EOB run |
650 | 19.9M | self.eob_run -= 1; |
651 | 40.5M | } |
652 | 60.4M | return Ok(true); |
653 | 60.4M | } Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<_> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 525 | 47.6M | pub(crate) fn decode_mcu_ac_refine<T>( | 526 | 47.6M | &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64] | 527 | 47.6M | ) -> Result<bool, DecodeErrors> | 528 | 47.6M | where | 529 | 47.6M | T: ZByteReaderTrait | 530 | | { | 531 | 47.6M | let bit = self.successive_low_mask; | 532 | | | 533 | 47.6M | let mut k = self.spec_start; | 534 | | let (mut symbol, mut r); | 535 | | | 536 | 47.6M | if self.eob_run == 0 { | 537 | | 'no_eob: loop { | 538 | | // Decode a coefficient from the bit stream | 539 | 413M | self.refill(reader)?; | 540 | | | 541 | 413M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 542 | 413M | symbol = table.lookup[symbol as usize]; | 543 | | | 544 | 413M | decode_huff!(self, symbol, table); | 545 | | | 546 | 413M | r = symbol >> 4; | 547 | 413M | symbol &= 15; | 548 | | | 549 | 413M | if symbol == 0 { | 550 | 6.14M | if r != 15 { | 551 | | // EOB run is 2^r + bits | 552 | 6.14M | self.eob_run = 1 << r; | 553 | 6.14M | self.eob_run += self.get_bits(r as u8); | 554 | | // EOB runs are handled by the eob logic | 555 | 6.14M | break 'no_eob; | 556 | 1.32k | } | 557 | | } else { | 558 | 406M | if symbol != 1 { | 559 | 220 | return Err(DecodeErrors::HuffmanDecode( | 560 | 220 | "Bad Huffman code, corrupt JPEG?".to_string() | 561 | 220 | )); | 562 | 406M | } | 563 | | // get sign bit | 564 | | // We assume we have enough bits, which should be correct for sane images | 565 | | // since we refill by 32 above | 566 | 406M | if self.get_bit() == 1 { | 567 | 1.08M | symbol = i32::from(bit); | 568 | 405M | } else { | 569 | 405M | symbol = i32::from(-bit); | 570 | 405M | } | 571 | | } | 572 | | | 573 | | // Advance over already nonzero coefficients appending | 574 | | // correction bits to the non-zeroes. | 575 | | // A correction bit is 1 if the absolute value of the coefficient must be increased | 576 | | | 577 | 406M | if k <= self.spec_end { | 578 | | 'advance_nonzero: loop { | 579 | 2.09G | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 580 | | | 581 | 2.09G | if *coefficient != 0 { | 582 | 1.71G | if self.get_bit() == 1 && (*coefficient & bit) == 0 { | 583 | 952k | if *coefficient >= 0 { | 584 | 125k | *coefficient += bit; | 585 | 827k | } else { | 586 | 827k | *coefficient -= bit; | 587 | 827k | } | 588 | 1.71G | } | 589 | | | 590 | 1.71G | if self.bits_left < 1 { | 591 | 27.0M | self.refill(reader)?; | 592 | 1.68G | } | 593 | | } else { | 594 | 378M | r -= 1; | 595 | | | 596 | 378M | if r < 0 { | 597 | | // reached target zero coefficient. | 598 | 375M | break 'advance_nonzero; | 599 | 2.91M | } | 600 | | }; | 601 | | | 602 | 1.71G | if k == self.spec_end { | 603 | 29.3M | break 'advance_nonzero; | 604 | 1.68G | } | 605 | | | 606 | 1.68G | k += 1; | 607 | | } | 608 | 1.81M | } | 609 | | | 610 | 406M | if symbol != 0 { | 611 | 406M | let pos = UN_ZIGZAG[k as usize & 63]; | 612 | 406M | // output new non-zero coefficient. | 613 | 406M | block[pos & 63] = symbol as i16; | 614 | 406M | } | 615 | | | 616 | 406M | k += 1; | 617 | | | 618 | 406M | if k > self.spec_end { | 619 | 38.0M | break 'no_eob; | 620 | 368M | } | 621 | | } | 622 | 3.38M | } | 623 | 47.6M | if self.eob_run > 0 { | 624 | | // only run if block does not consists of purely zeroes | 625 | 9.52M | if &block[1..] != &[0; 63] { | 626 | 1.94M | self.refill(reader)?; | 627 | | | 628 | 102M | while k <= self.spec_end { | 629 | 100M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 630 | | | 631 | 100M | if *coefficient != 0 && self.get_bit() == 1 { | 632 | | // check if we already modified it, if so do nothing, otherwise | 633 | | // append the correction bit. | 634 | 16.7M | if (*coefficient & bit) == 0 { | 635 | 3.20M | if *coefficient >= 0 { | 636 | 348k | *coefficient = coefficient.wrapping_add(bit); | 637 | 2.85M | } else { | 638 | 2.85M | *coefficient = coefficient.wrapping_sub(bit); | 639 | 2.85M | } | 640 | 13.5M | } | 641 | 83.6M | } | 642 | 100M | if self.bits_left < 1 { | 643 | | // refill at the last possible moment | 644 | 1.10M | self.refill(reader)?; | 645 | 99.2M | } | 646 | 100M | k += 1; | 647 | | } | 648 | 7.58M | } | 649 | | // count a block completed in EOB run | 650 | 9.52M | self.eob_run -= 1; | 651 | 38.0M | } | 652 | 47.6M | return Ok(true); | 653 | 47.6M | } |
Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Unexecuted instantiation: <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> <zune_jpeg::bitstream::BitStream>::decode_mcu_ac_refine::<zune_core::bytestream::reader::no_std_readers::ZCursor<&[u8]>> Line | Count | Source | 525 | 12.8M | pub(crate) fn decode_mcu_ac_refine<T>( | 526 | 12.8M | &mut self, reader: &mut ZReader<T>, table: &HuffmanTable, block: &mut [i16; 64] | 527 | 12.8M | ) -> Result<bool, DecodeErrors> | 528 | 12.8M | where | 529 | 12.8M | T: ZByteReaderTrait | 530 | | { | 531 | 12.8M | let bit = self.successive_low_mask; | 532 | | | 533 | 12.8M | let mut k = self.spec_start; | 534 | | let (mut symbol, mut r); | 535 | | | 536 | 12.8M | if self.eob_run == 0 { | 537 | | 'no_eob: loop { | 538 | | // Decode a coefficient from the bit stream | 539 | 33.8M | self.refill(reader)?; | 540 | | | 541 | 33.8M | symbol = self.peek_bits::<HUFF_LOOKAHEAD>(); | 542 | 33.8M | symbol = table.lookup[symbol as usize]; | 543 | | | 544 | 33.8M | decode_huff!(self, symbol, table); | 545 | | | 546 | 33.8M | r = symbol >> 4; | 547 | 33.8M | symbol &= 15; | 548 | | | 549 | 33.8M | if symbol == 0 { | 550 | 9.87M | if r != 15 { | 551 | | // EOB run is 2^r + bits | 552 | 9.82M | self.eob_run = 1 << r; | 553 | 9.82M | self.eob_run += self.get_bits(r as u8); | 554 | | // EOB runs are handled by the eob logic | 555 | 9.82M | break 'no_eob; | 556 | 45.9k | } | 557 | | } else { | 558 | 23.9M | if symbol != 1 { | 559 | 104 | return Err(DecodeErrors::HuffmanDecode( | 560 | 104 | "Bad Huffman code, corrupt JPEG?".to_string() | 561 | 104 | )); | 562 | 23.9M | } | 563 | | // get sign bit | 564 | | // We assume we have enough bits, which should be correct for sane images | 565 | | // since we refill by 32 above | 566 | 23.9M | if self.get_bit() == 1 { | 567 | 30.2k | symbol = i32::from(bit); | 568 | 23.9M | } else { | 569 | 23.9M | symbol = i32::from(-bit); | 570 | 23.9M | } | 571 | | } | 572 | | | 573 | | // Advance over already nonzero coefficients appending | 574 | | // correction bits to the non-zeroes. | 575 | | // A correction bit is 1 if the absolute value of the coefficient must be increased | 576 | | | 577 | 24.0M | if k <= self.spec_end { | 578 | | 'advance_nonzero: loop { | 579 | 142M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 580 | | | 581 | 142M | if *coefficient != 0 { | 582 | 119M | if self.get_bit() == 1 && (*coefficient & bit) == 0 { | 583 | 344k | if *coefficient >= 0 { | 584 | 20.0k | *coefficient += bit; | 585 | 324k | } else { | 586 | 324k | *coefficient -= bit; | 587 | 324k | } | 588 | 119M | } | 589 | | | 590 | 119M | if self.bits_left < 1 { | 591 | 2.03M | self.refill(reader)?; | 592 | 117M | } | 593 | | } else { | 594 | 22.3M | r -= 1; | 595 | | | 596 | 22.3M | if r < 0 { | 597 | | // reached target zero coefficient. | 598 | 22.0M | break 'advance_nonzero; | 599 | 339k | } | 600 | | }; | 601 | | | 602 | 120M | if k == self.spec_end { | 603 | 1.96M | break 'advance_nonzero; | 604 | 118M | } | 605 | | | 606 | 118M | k += 1; | 607 | | } | 608 | 17.3k | } | 609 | | | 610 | 24.0M | if symbol != 0 { | 611 | 23.9M | let pos = UN_ZIGZAG[k as usize & 63]; | 612 | 23.9M | // output new non-zero coefficient. | 613 | 23.9M | block[pos & 63] = symbol as i16; | 614 | 23.9M | } | 615 | | | 616 | 24.0M | k += 1; | 617 | | | 618 | 24.0M | if k > self.spec_end { | 619 | 2.42M | break 'no_eob; | 620 | 21.5M | } | 621 | | } | 622 | 634k | } | 623 | 12.8M | if self.eob_run > 0 { | 624 | | // only run if block does not consists of purely zeroes | 625 | 10.4M | if &block[1..] != &[0; 63] { | 626 | 4.78M | self.refill(reader)?; | 627 | | | 628 | 33.4M | while k <= self.spec_end { | 629 | 28.6M | let coefficient = &mut block[UN_ZIGZAG[k as usize & 63] & 63]; | 630 | | | 631 | 28.6M | if *coefficient != 0 && self.get_bit() == 1 { | 632 | | // check if we already modified it, if so do nothing, otherwise | 633 | | // append the correction bit. | 634 | 1.11M | if (*coefficient & bit) == 0 { | 635 | 274k | if *coefficient >= 0 { | 636 | 17.0k | *coefficient = coefficient.wrapping_add(bit); | 637 | 257k | } else { | 638 | 257k | *coefficient = coefficient.wrapping_sub(bit); | 639 | 257k | } | 640 | 844k | } | 641 | 27.5M | } | 642 | 28.6M | if self.bits_left < 1 { | 643 | | // refill at the last possible moment | 644 | 370k | self.refill(reader)?; | 645 | 28.2M | } | 646 | 28.6M | k += 1; | 647 | | } | 648 | 5.67M | } | 649 | | // count a block completed in EOB run | 650 | 10.4M | self.eob_run -= 1; | 651 | 2.42M | } | 652 | 12.8M | return Ok(true); | 653 | 12.8M | } |
|
654 | | |
655 | 24.4k | pub fn update_progressive_params(&mut self, _ah: u8, al: u8, spec_start: u8, spec_end: u8) { |
656 | 24.4k | self.successive_low_mask = 1i16 << al; |
657 | 24.4k | self.spec_start = spec_start; |
658 | 24.4k | self.spec_end = spec_end; |
659 | 24.4k | } |
660 | | |
661 | | /// Reset the stream if we have a restart marker |
662 | | /// |
663 | | /// Restart markers indicate drop those bits in the stream and zero out |
664 | | /// everything |
665 | | #[cold] |
666 | 187k | pub fn reset(&mut self) { |
667 | 187k | self.bits_left = 0; |
668 | 187k | self.marker = None; |
669 | 187k | self.buffer = 0; |
670 | 187k | self.aligned_buffer = 0; |
671 | 187k | self.eob_run = 0; |
672 | 187k | } |
673 | | } |
674 | | |
675 | | /// Do the equivalent of JPEG HUFF_EXTEND |
676 | | #[inline(always)] |
677 | 150M | fn huff_extend(x: i32, s: i32) -> i32 { |
678 | | // if x<s return x else return x+offset[s] where offset[s] = ( (-1<<s)+1) |
679 | 150M | (x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((-1) << (s)) + 1)) |
680 | 150M | } |
681 | | |
682 | 18.4M | const fn has_zero(v: u32) -> bool { |
683 | | // Retrieved from Stanford bithacks |
684 | | // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord |
685 | 18.4M | return !((((v & 0x7F7F_7F7F) + 0x7F7F_7F7F) | v) | 0x7F7F_7F7F) != 0; |
686 | 18.4M | } |
687 | | |
688 | 18.4M | const fn has_byte(b: u32, val: u8) -> bool { |
689 | | // Retrieved from Stanford bithacks |
690 | | // @ https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord |
691 | 18.4M | has_zero(b ^ ((!0_u32 / 255) * (val as u32))) |
692 | 18.4M | } |
693 | | |
694 | | // mod tests { |
695 | | // use zune_core::bytestream::ZCursor; |
696 | | // use zune_core::colorspace::ColorSpace; |
697 | | // use zune_core::options::DecoderOptions; |
698 | | // |
699 | | // use crate::errors::DecodeErrors; |
700 | | // use crate::JpegDecoder; |
701 | | // |
702 | | // #[test] |
703 | | // fn test_image() { |
704 | | // let img = "/Users/etemesi/Downloads/nepo.jpg"; |
705 | | // let data = std::fs::read(img).unwrap(); |
706 | | // let options = DecoderOptions::new_cmd().jpeg_set_out_colorspace(ColorSpace::RGB); |
707 | | // let mut decoder = JpegDecoder::new_with_options(ZCursor::new(&data[..]), options); |
708 | | // |
709 | | // decoder.decode().unwrap(); |
710 | | // println!("{:?}",decoder.options.jpeg_get_out_colorspace()) |
711 | | // |
712 | | // } |
713 | | // } |