| // Copyright 2023 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| pri func decoder.decode_mcu!() base.u32 { |
| var ret : base.u32 |
| |
| var bits : base.u64 |
| var n_bits : base.u32 |
| var csel : base.u8[..= 3] |
| |
| var r : base.io_reader |
| var pos : base.u32 |
| |
| // etc_bl and etc_blm1 are the Huffman code's "bit length" and "bit length |
| // minus 1" for the DC (first) and AC (later) components. |
| |
| var dc_h : base.u8[..= 7] |
| var dc_symbol : base.u32[..= 0x0F] |
| var dc_ht_fast : base.u32 |
| var dc_bl : base.u32 |
| var dc_code : base.u32 |
| var dc_blm1 : base.u32[..= 15] |
| var dc_ht_slow : base.u32 |
| var dc_value : base.u32 |
| |
| var ac_h : base.u8[..= 7] |
| var ac_symbol : base.u32[..= 0xFF] |
| var ac_ht_fast : base.u32 |
| var ac_bl : base.u32 |
| var ac_code : base.u32 |
| var ac_blm1 : base.u32[..= 15] |
| var ac_ht_slow : base.u32 |
| var ac_value : base.u32 |
| |
| var ac_rrrr : base.u32[..= 15] |
| var ac_ssss : base.u32[..= 15] |
| var z : base.u32[..= 78] // 78 = 63 + 15. |
| |
| bits = this.bitstream_bits |
| n_bits = this.bitstream_n_bits |
| |
| if this.bitstream_ri > this.bitstream_wi { |
| return 2 // Internal error. |
| } |
| io_bind (io: r, data: this.bitstream_buffer[this.bitstream_ri .. this.bitstream_wi], history_position: this.bitstream_ri as base.u64) { |
| while.goto_done true {{ |
| |
| while.block this.mcu_current_block < this.mcu_num_blocks { |
| assert this.mcu_current_block < 10 via "a < b: a < c; c <= b"(c: this.mcu_num_blocks) |
| while.dc_component this.mcu_zig_index <= 0, |
| inv this.mcu_current_block < 10, |
| { |
| // Load at least 31 bits, by keeping 56 .. 64 loaded. |
| if r.length() < 8 { |
| ret = 1 // Request another fill_bitstream call. |
| break.goto_done |
| } |
| bits |= r.peek_u64be() >> (n_bits & 63) |
| r.skip_u32_fast!(actual: (63 - (n_bits & 63)) >> 3, worst_case: 8) |
| n_bits |= 56 |
| |
| // Read the Huffman-encoded dc_symbol, up to 16 bits long. |
| dc_h = 0 | this.scan_comps_td[this.mcu_blocks_sselector[this.mcu_current_block]] |
| dc_ht_fast = this.huff_tables_fast[dc_h][bits >> 56] as base.u32 |
| dc_bl = dc_ht_fast >> 8 |
| if n_bits >= dc_bl { |
| dc_symbol = 0x0F & dc_ht_fast |
| bits ~mod<<= (dc_bl & 63) |
| n_bits -= dc_bl |
| } else { |
| dc_code = (bits >> 55) as base.u32 |
| dc_blm1 = 8 |
| bits ~mod<<= 9 |
| n_bits ~mod-= 9 |
| while true, |
| inv this.mcu_current_block < 10, |
| { |
| dc_ht_slow = this.huff_tables_slow[dc_h][dc_blm1] |
| if dc_code < (dc_ht_slow >> 8) { |
| dc_symbol = 0x0F & (this.huff_tables_symbols[dc_h][0xFF & (dc_code ~mod+ dc_ht_slow)] as base.u32) |
| break |
| } |
| dc_code = (dc_code ~mod<< 1) | ((bits >> 63) as base.u32) |
| bits ~mod<<= 1 |
| n_bits ~mod-= 1 |
| dc_blm1 = (dc_blm1 + 1) & 15 |
| if dc_blm1 == 0 { |
| dc_symbol = 0 |
| break |
| } |
| } endwhile |
| } |
| |
| // Process the dc_value in the next dc_symbol (up to 15) bits. |
| // |
| // The dc_value is shifted by (64 - dc_symbol) in two steps, |
| // because we want to shift by 64 (not 0) when dc_symbol is 0. |
| dc_value = (((bits >> 32) >> (32 - dc_symbol)) & 0xFFFF_FFFF) as base.u32 |
| if (bits >> 63) == 0 { // EXTEND per section F.2.2.1. |
| dc_value ~mod+= 1 ~mod+ ((0xFFFF_FFFF as base.u32) ~mod<< dc_symbol) |
| } |
| bits ~mod<<= dc_symbol |
| n_bits ~mod-= dc_symbol |
| csel = this.scan_comps_cselector[this.mcu_blocks_sselector[this.mcu_current_block]] |
| this.mcu_previous_dc_values[csel] ~mod+= (dc_value & 0xFFFF) as base.u16 |
| this.mcu_blocks[this.mcu_current_block][0] = this.mcu_previous_dc_values[csel] |
| |
| this.mcu_zig_index = 1 |
| break.dc_component |
| } endwhile.dc_component |
| |
| while.ac_components true, |
| inv this.mcu_current_block < 10, |
| { |
| // Load at least 31 bits, by keeping 56 .. 64 loaded. |
| if r.length() < 8 { |
| ret = 1 // Request another fill_bitstream call. |
| break.goto_done |
| } |
| bits |= r.peek_u64be() >> (n_bits & 63) |
| r.skip_u32_fast!(actual: (63 - (n_bits & 63)) >> 3, worst_case: 8) |
| n_bits |= 56 |
| |
| // Read the Huffman-encoded ac_symbol, up to 16 bits long. |
| ac_h = 4 | this.scan_comps_ta[this.mcu_blocks_sselector[this.mcu_current_block]] |
| ac_ht_fast = this.huff_tables_fast[ac_h][bits >> 56] as base.u32 |
| ac_bl = ac_ht_fast >> 8 |
| if n_bits >= ac_bl { |
| ac_symbol = 0xFF & ac_ht_fast |
| bits ~mod<<= (ac_bl & 63) |
| n_bits -= ac_bl |
| } else { |
| ac_code = (bits >> 55) as base.u32 |
| ac_blm1 = 8 |
| bits ~mod<<= 9 |
| n_bits ~mod-= 9 |
| while true, |
| inv this.mcu_current_block < 10, |
| { |
| ac_ht_slow = this.huff_tables_slow[ac_h][ac_blm1] |
| if ac_code < (ac_ht_slow >> 8) { |
| ac_symbol = this.huff_tables_symbols[ac_h][0xFF & (ac_code ~mod+ ac_ht_slow)] as base.u32 |
| break |
| } |
| ac_code = (ac_code ~mod<< 1) | ((bits >> 63) as base.u32) |
| bits ~mod<<= 1 |
| n_bits ~mod-= 1 |
| ac_blm1 = (ac_blm1 + 1) & 15 |
| if ac_blm1 == 0 { |
| ac_symbol = 0 |
| break |
| } |
| } endwhile |
| } |
| |
| // Split the 8-bit ac_symbol into two 4-bit halves, per section |
| // F.2.2.2 "Decoding procedure for AC coefficients". |
| ac_rrrr = ac_symbol >> 4 |
| ac_ssss = ac_symbol & 15 |
| |
| // Process the ac_value in the next ac_ssss (up to 15) bits. |
| if ac_ssss > 0 { |
| ac_value = ((bits >> (64 - ac_ssss)) & 0xFFFF_FFFF) as base.u32 |
| if (bits >> 63) == 0 { // EXTEND per section F.2.2.1. |
| ac_value ~mod+= 1 ~mod+ ((0xFFFF_FFFF as base.u32) ~mod<< ac_ssss) |
| } |
| bits ~mod<<= ac_ssss |
| n_bits ~mod-= ac_ssss |
| z = this.mcu_zig_index + ac_rrrr |
| this.mcu_blocks[this.mcu_current_block][UNZIG[z]] = (ac_value & 0xFFFF) as base.u16 |
| if (z + 1) > 63 { |
| break.ac_components |
| } |
| this.mcu_zig_index = z + 1 |
| } else if (ac_rrrr < 15) or ((this.mcu_zig_index + 16) > 63) { |
| break.ac_components |
| } else { |
| this.mcu_zig_index = this.mcu_zig_index + 16 |
| } |
| } endwhile.ac_components |
| |
| this.mcu_zig_index = 0 |
| assert this.mcu_current_block < 10 |
| this.mcu_current_block += 1 |
| } endwhile.block |
| this.mcu_current_block = 0 |
| |
| break.goto_done |
| }} endwhile.goto_done |
| |
| pos = (r.position() & 0xFFFF_FFFF) as base.u32 |
| if pos > this.bitstream_wi { |
| ret = 2 // Internal error. |
| } else { |
| assert pos <= 0x800 via "a <= b: a <= c; c <= b"(c: this.bitstream_wi) |
| this.bitstream_ri = pos |
| } |
| } |
| |
| this.bitstream_bits = bits |
| this.bitstream_n_bits = n_bits |
| return ret |
| } |