std/vp8: parse the residuals This commit, part of a series, is inspired by pull request PR #168 by Damian Kaczmarek (with AI assistance), with some modifications. Updates PR #168
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c index 6930981..36822c2 100644 --- a/release/c/wuffs-unsupported-snapshot.c +++ b/release/c/wuffs-unsupported-snapshot.c
@@ -15529,10 +15529,9 @@ uint32_t f_quant_y2ac_delta; uint32_t f_quant_uvdc_delta; uint32_t f_quant_uvac_delta; + uint16_t f_dequants[4][3][2]; uint32_t f_prob_skip; uint8_t f_mb_subblock_modes[16]; - uint8_t f_mb_left_modes[4]; - uint8_t f_mb_top_modes[1024][4]; uint32_t f_dst_x; uint32_t f_dst_y; wuffs_base__pixel_swizzler f_swizzler; @@ -15548,6 +15547,9 @@ struct { uint8_t f_coeff_probs[1056]; + uint16_t f_mb_coeffs[25][16]; + uint32_t f_mb_states_left; + uint32_t f_mb_states_top[1024]; struct { uint64_t v_i; @@ -80968,6 +80970,12 @@ }; static const uint8_t +WUFFS_VP8__CLIP_9[16] WUFFS_BASE__POTENTIALLY_UNUSED = { + 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, + 8u, 9u, 9u, 9u, 9u, 9u, 9u, 9u, +}; + +static const uint8_t WUFFS_VP8__SUBBLOCK_MODE_PROBS[10][10][9] WUFFS_BASE__POTENTIALLY_UNUSED = { { { @@ -81304,6 +81312,30 @@ }; static const uint8_t +WUFFS_VP8__CATEGORY_PROBS[4][16] WUFFS_BASE__POTENTIALLY_UNUSED = { + { + 173u, 148u, 140u, 0u, 0u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, + }, { + 176u, 155u, 140u, 135u, 0u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, + }, { + 180u, 157u, 141u, 134u, 130u, 0u, 0u, 0u, + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, + }, { + 254u, 254u, 243u, 230u, 196u, 177u, 153u, 140u, + 133u, 130u, 129u, 0u, 0u, 0u, 0u, 0u, + }, +}; + +static const uint32_t +WUFFS_VP8__COEFF_BANDS_33[17] WUFFS_BASE__POTENTIALLY_UNUSED = { + 0u, 33u, 66u, 99u, 198u, 132u, 165u, 198u, + 198u, 198u, 198u, 198u, 198u, 198u, 198u, 231u, + 0u, +}; + +static const uint8_t WUFFS_VP8__COEFF_UPDATE_PROBS[1056] WUFFS_BASE__POTENTIALLY_UNUSED = { 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, @@ -81575,6 +81607,51 @@ 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u, }; +static const uint16_t +WUFFS_VP8__DEQUANTS[2][128] WUFFS_BASE__POTENTIALLY_UNUSED = { + { + 4u, 5u, 6u, 7u, 8u, 9u, 10u, 10u, + 11u, 12u, 13u, 14u, 15u, 16u, 17u, 17u, + 18u, 19u, 20u, 20u, 21u, 21u, 22u, 22u, + 23u, 23u, 24u, 25u, 25u, 26u, 27u, 28u, + 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, + 37u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, + 44u, 45u, 46u, 46u, 47u, 48u, 49u, 50u, + 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, + 59u, 60u, 61u, 62u, 63u, 64u, 65u, 66u, + 67u, 68u, 69u, 70u, 71u, 72u, 73u, 74u, + 75u, 76u, 76u, 77u, 78u, 79u, 80u, 81u, + 82u, 83u, 84u, 85u, 86u, 87u, 88u, 89u, + 91u, 93u, 95u, 96u, 98u, 100u, 101u, 102u, + 104u, 106u, 108u, 110u, 112u, 114u, 116u, 118u, + 122u, 124u, 126u, 128u, 130u, 132u, 134u, 136u, + 138u, 140u, 143u, 145u, 148u, 151u, 154u, 157u, + }, { + 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, + 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, + 20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, + 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, + 36u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, + 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 60u, + 62u, 64u, 66u, 68u, 70u, 72u, 74u, 76u, + 78u, 80u, 82u, 84u, 86u, 88u, 90u, 92u, + 94u, 96u, 98u, 100u, 102u, 104u, 106u, 108u, + 110u, 112u, 114u, 116u, 119u, 122u, 125u, 128u, + 131u, 134u, 137u, 140u, 143u, 146u, 149u, 152u, + 155u, 158u, 161u, 164u, 167u, 170u, 173u, 177u, + 181u, 185u, 189u, 193u, 197u, 201u, 205u, 209u, + 213u, 217u, 221u, 225u, 229u, 234u, 239u, 245u, + 249u, 254u, 259u, 264u, 269u, 274u, 279u, 284u, + }, +}; + +static const uint8_t +WUFFS_VP8__ZIGZAG[16] WUFFS_BASE__POTENTIALLY_UNUSED = { + 0u, 1u, 4u, 8u, 5u, 2u, 3u, 6u, + 9u, 12u, 13u, 10u, 7u, 11u, 14u, 15u, +}; + // ---------------- Private Initializer Prototypes // ---------------- Private Function Prototypes @@ -81635,6 +81712,17 @@ wuffs_base__slice_u8 a_workbuf); WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__calculate_dequants( + wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__clip_127( + const wuffs_vp8__decoder* self, + uint32_t a_a); + +WUFFS_BASE__GENERATED_C_CODE static wuffs_base__status wuffs_vp8__decoder__decode_other_partition_lengths( wuffs_vp8__decoder* self, @@ -81683,6 +81771,41 @@ uint8_t a_left_mode); WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__decode_residuals( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_mbx, + uint32_t a_mby, + uint32_t a_seg, + uint32_t a_luma_mode, + uint32_t a_chroma_mode); + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__initialize_mb_coeffs( + wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__decode_block_coefficients( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_mby, + uint32_t a_seg, + uint32_t a_b, + uint32_t a_plane, + uint32_t a_context); + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__decode_large_value( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_part, + uint32_t a_prob_base); + +WUFFS_BASE__GENERATED_C_CODE static wuffs_base__status wuffs_vp8__decoder__do_decode_image_config( wuffs_vp8__decoder* self, @@ -82010,6 +82133,7 @@ self->private_impl.f_quant_y2ac_delta = wuffs_vp8__decoder__read_signed(self, a_workbuf, 0u, 4u); self->private_impl.f_quant_uvdc_delta = wuffs_vp8__decoder__read_signed(self, a_workbuf, 0u, 4u); self->private_impl.f_quant_uvac_delta = wuffs_vp8__decoder__read_signed(self, a_workbuf, 0u, 4u); + wuffs_vp8__decoder__calculate_dequants(self); if ( ! self->private_impl.f_is_key_frame) { return wuffs_base__make_status(wuffs_vp8__error__unsupported_vp8_file); } @@ -82139,6 +82263,56 @@ return wuffs_base__make_empty_struct(); } +// -------- func vp8.decoder.calculate_dequants + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__calculate_dequants( + wuffs_vp8__decoder* self) { + uint32_t v_seg = 0; + uint32_t v_q = 0; + + v_seg = 0u; + while (v_seg < 4u) { + v_q = self->private_impl.f_quant_yac_qi; + if ( ! self->private_impl.f_seg_enabled) { + } else if (self->private_impl.f_seg_absolute) { + v_q = wuffs_base__utility__sign_extend_convert_u8_u32(self->private_impl.f_seg_quants[v_seg]); + } else { + v_q += wuffs_base__utility__sign_extend_convert_u8_u32(self->private_impl.f_seg_quants[v_seg]); + } + self->private_impl.f_dequants[v_seg][0u][0u] = WUFFS_VP8__DEQUANTS[0u][wuffs_vp8__decoder__clip_127(self, ((uint32_t)(v_q + self->private_impl.f_quant_ydc_delta)))]; + self->private_impl.f_dequants[v_seg][0u][1u] = WUFFS_VP8__DEQUANTS[1u][wuffs_vp8__decoder__clip_127(self, v_q)]; + self->private_impl.f_dequants[v_seg][1u][0u] = ((uint16_t)(WUFFS_VP8__DEQUANTS[0u][wuffs_vp8__decoder__clip_127(self, ((uint32_t)(v_q + self->private_impl.f_quant_y2dc_delta)))] * 2u)); + self->private_impl.f_dequants[v_seg][1u][1u] = ((uint16_t)(((uint16_t)(WUFFS_VP8__DEQUANTS[1u][wuffs_vp8__decoder__clip_127(self, ((uint32_t)(v_q + self->private_impl.f_quant_y2ac_delta)))] * 155u)) / 100u)); + if (self->private_impl.f_dequants[v_seg][1u][1u] < 8u) { + self->private_impl.f_dequants[v_seg][1u][1u] = 8u; + } + self->private_impl.f_dequants[v_seg][2u][0u] = WUFFS_VP8__DEQUANTS[0u][wuffs_vp8__decoder__clip_127(self, ((uint32_t)(v_q + self->private_impl.f_quant_uvdc_delta)))]; + if (self->private_impl.f_dequants[v_seg][2u][0u] > 132u) { + self->private_impl.f_dequants[v_seg][2u][0u] = 132u; + } + self->private_impl.f_dequants[v_seg][2u][1u] = WUFFS_VP8__DEQUANTS[1u][wuffs_vp8__decoder__clip_127(self, ((uint32_t)(v_q + self->private_impl.f_quant_uvac_delta)))]; + v_seg += 1u; + } + return wuffs_base__make_empty_struct(); +} + +// -------- func vp8.decoder.clip_127 + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__clip_127( + const wuffs_vp8__decoder* self, + uint32_t a_a) { + if (a_a >= 2147483648u) { + return 0u; + } else if (a_a >= 127u) { + return 127u; + } + return a_a; +} + // -------- func vp8.decoder.decode_other_partition_lengths WUFFS_BASE__GENERATED_C_CODE @@ -82207,18 +82381,12 @@ v_mbx = 0u; while (v_mbx < self->private_impl.f_mbw) { - self->private_impl.f_mb_top_modes[v_mbx][0u] = 0u; - self->private_impl.f_mb_top_modes[v_mbx][1u] = 0u; - self->private_impl.f_mb_top_modes[v_mbx][2u] = 0u; - self->private_impl.f_mb_top_modes[v_mbx][3u] = 0u; + self->private_data.f_mb_states_top[v_mbx] = 0u; v_mbx += 1u; } v_mby = 0u; while (v_mby < self->private_impl.f_mbh) { - self->private_impl.f_mb_left_modes[0u] = 0u; - self->private_impl.f_mb_left_modes[1u] = 0u; - self->private_impl.f_mb_left_modes[2u] = 0u; - self->private_impl.f_mb_left_modes[3u] = 0u; + self->private_data.f_mb_states_left = 0u; v_mbx = 0u; while (v_mbx < self->private_impl.f_mbw) { wuffs_vp8__decoder__decode_one_macroblock(self, a_workbuf, v_mbx, v_mby); @@ -82264,6 +82432,16 @@ wuffs_vp8__decoder__decode_subblock_modes(self, a_workbuf, a_mbx, v_luma_mode); v_chroma_mode = wuffs_vp8__decoder__decode_chroma_mode(self, a_workbuf); if (v_skip) { + self->private_data.f_mb_states_left &= 65535u; + self->private_data.f_mb_states_top[a_mbx] &= 65535u; + } else { + wuffs_vp8__decoder__decode_residuals(self, + a_workbuf, + a_mbx, + a_mby, + v_seg, + v_luma_mode, + v_chroma_mode); } return wuffs_base__make_empty_struct(); } @@ -82326,25 +82504,19 @@ uint8_t v_mode = 0; if (a_luma_mode < 4u) { - self->private_impl.f_mb_top_modes[a_mbx][0u] = v_mode; - self->private_impl.f_mb_top_modes[a_mbx][1u] = v_mode; - self->private_impl.f_mb_top_modes[a_mbx][2u] = v_mode; - self->private_impl.f_mb_top_modes[a_mbx][3u] = v_mode; - self->private_impl.f_mb_left_modes[0u] = v_mode; - self->private_impl.f_mb_left_modes[1u] = v_mode; - self->private_impl.f_mb_left_modes[2u] = v_mode; - self->private_impl.f_mb_left_modes[3u] = v_mode; + self->private_data.f_mb_states_top[a_mbx] = (((uint32_t)(v_mode)) * 4369u); + self->private_data.f_mb_states_left = (((uint32_t)(v_mode)) * 4369u); return wuffs_base__make_empty_struct(); } v_i = 0u; while (v_i < 16u) { if (v_i < 4u) { - v_top_mode = self->private_impl.f_mb_top_modes[a_mbx][v_i]; + v_top_mode = WUFFS_VP8__CLIP_9[(15u & (self->private_data.f_mb_states_top[a_mbx] >> (v_i * 4u)))]; } else { v_top_mode = self->private_impl.f_mb_subblock_modes[(v_i - 4u)]; } if ((v_i & 3u) == 0u) { - v_left_mode = self->private_impl.f_mb_left_modes[(v_i >> 2u)]; + v_left_mode = WUFFS_VP8__CLIP_9[(15u & (self->private_data.f_mb_states_left >> (v_i & 12u)))]; } else { v_left_mode = self->private_impl.f_mb_subblock_modes[(((uint32_t)(v_i + 15u)) & 15u)]; } @@ -82352,14 +82524,16 @@ self->private_impl.f_mb_subblock_modes[v_i] = v_mode; v_i += 1u; } - self->private_impl.f_mb_top_modes[a_mbx][0u] = self->private_impl.f_mb_subblock_modes[12u]; - self->private_impl.f_mb_top_modes[a_mbx][1u] = self->private_impl.f_mb_subblock_modes[13u]; - self->private_impl.f_mb_top_modes[a_mbx][2u] = self->private_impl.f_mb_subblock_modes[14u]; - self->private_impl.f_mb_top_modes[a_mbx][3u] = self->private_impl.f_mb_subblock_modes[15u]; - self->private_impl.f_mb_left_modes[0u] = self->private_impl.f_mb_subblock_modes[3u]; - self->private_impl.f_mb_left_modes[1u] = self->private_impl.f_mb_subblock_modes[7u]; - self->private_impl.f_mb_left_modes[2u] = self->private_impl.f_mb_subblock_modes[11u]; - self->private_impl.f_mb_left_modes[3u] = self->private_impl.f_mb_subblock_modes[15u]; + self->private_data.f_mb_states_top[a_mbx] = ((self->private_data.f_mb_states_top[a_mbx] & 4294901760u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[12u])) << 0u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[13u])) << 4u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[14u])) << 8u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[15u])) << 12u)); + self->private_data.f_mb_states_left = ((self->private_data.f_mb_states_left & 4294901760u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[3u])) << 0u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[7u])) << 4u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[11u])) << 8u) | + (((uint32_t)(self->private_impl.f_mb_subblock_modes[15u])) << 12u)); return wuffs_base__make_empty_struct(); } @@ -82417,6 +82591,245 @@ return 9u; } +// -------- func vp8.decoder.decode_residuals + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__decode_residuals( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_mbx, + uint32_t a_mby, + uint32_t a_seg, + uint32_t a_luma_mode, + uint32_t a_chroma_mode) { + uint32_t v_bc = 0; + uint32_t v_by = 0; + uint32_t v_bx = 0; + uint32_t v_plane = 0; + uint32_t v_lnz = 0; + uint32_t v_tnz = 0; + + wuffs_vp8__decoder__initialize_mb_coeffs(self); + v_plane = 3u; + if (a_luma_mode < 4u) { + v_lnz = (1u & (self->private_data.f_mb_states_left >> 23u)); + self->private_data.f_mb_states_left &= 4286578687u; + v_tnz = (1u & (self->private_data.f_mb_states_top[a_mbx] >> 23u)); + self->private_data.f_mb_states_top[a_mbx] &= 4286578687u; + v_lnz = wuffs_vp8__decoder__decode_block_coefficients(self, + a_workbuf, + a_mby, + a_seg, + 24u, + 1u, + (v_lnz + v_tnz)); + self->private_data.f_mb_states_top[a_mbx] |= (v_lnz << 23u); + self->private_data.f_mb_states_left |= (v_lnz << 23u); + v_plane = 0u; + } + v_by = 0u; + while (v_by < 4u) { + v_lnz = (1u & (self->private_data.f_mb_states_left >> (24u + v_by))); + self->private_data.f_mb_states_left &= (4294967295u ^ (((uint32_t)(1u)) << (24u + v_by))); + v_bx = 0u; + while (v_bx < 4u) { + v_tnz = (1u & (self->private_data.f_mb_states_top[a_mbx] >> (24u + v_bx))); + self->private_data.f_mb_states_top[a_mbx] &= (4294967295u ^ (((uint32_t)(1u)) << (24u + v_bx))); + v_lnz = wuffs_vp8__decoder__decode_block_coefficients(self, + a_workbuf, + a_mby, + a_seg, + ((4u * v_by) + v_bx), + v_plane, + (v_lnz + v_tnz)); + self->private_data.f_mb_states_top[a_mbx] |= (v_lnz << (24u + v_bx)); + v_bx += 1u; + } + self->private_data.f_mb_states_left |= (v_lnz << (24u + v_by)); + v_by += 1u; + } + v_bc = 0u; + while (v_bc <= 2u) { + v_by = 0u; + while (v_by < 2u) { + v_lnz = (1u & (self->private_data.f_mb_states_left >> (28u + v_bc + v_by))); + self->private_data.f_mb_states_left &= (4294967295u ^ (((uint32_t)(1u)) << (28u + v_bc + v_by))); + v_bx = 0u; + while (v_bx < 2u) { + v_tnz = (1u & (self->private_data.f_mb_states_top[a_mbx] >> (28u + v_bc + v_bx))); + self->private_data.f_mb_states_top[a_mbx] &= (4294967295u ^ (((uint32_t)(1u)) << (28u + v_bc + v_bx))); + v_lnz = wuffs_vp8__decoder__decode_block_coefficients(self, + a_workbuf, + a_mby, + a_seg, + ((2u * v_bc) + + (2u * v_by) + + v_bx + + 16u), + 2u, + (v_lnz + v_tnz)); + self->private_data.f_mb_states_top[a_mbx] |= (v_lnz << (28u + v_bc + v_bx)); + v_bx += 1u; + } + self->private_data.f_mb_states_left |= (v_lnz << (28u + v_bc + v_by)); + v_by += 1u; + } + v_bc += 2u; + } + return wuffs_base__make_empty_struct(); +} + +// -------- func vp8.decoder.initialize_mb_coeffs + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__empty_struct +wuffs_vp8__decoder__initialize_mb_coeffs( + wuffs_vp8__decoder* self) { + uint32_t v_i = 0; + uint32_t v_j = 0; + + v_i = 0u; + while (v_i < 25u) { + v_j = 0u; + while (v_j < 16u) { + self->private_data.f_mb_coeffs[v_i][v_j] = 0u; + v_j += 1u; + } + v_i += 1u; + } + return wuffs_base__make_empty_struct(); +} + +// -------- func vp8.decoder.decode_block_coefficients + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__decode_block_coefficients( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_mby, + uint32_t a_seg, + uint32_t a_b, + uint32_t a_plane, + uint32_t a_context) { + uint32_t v_q1 = 0; + uint32_t v_q2 = 0; + uint32_t v_quant = 0; + uint32_t v_i = 0; + uint32_t v_part = 0; + uint32_t v_prob_base = 0; + uint32_t v_v1 = 0; + uint32_t v_value = 0; + + v_q1 = 0u; + if (a_b == 24u) { + v_q1 = 1u; + } else if (a_b >= 16u) { + v_q1 = 2u; + } + v_i = 0u; + if (a_plane == 0u) { + v_i = 1u; + } + v_part = (1u + (a_mby & self->private_impl.f_num_other_partitions_m1)); + v_prob_base = ((a_plane * 264u) + WUFFS_VP8__COEFF_BANDS_33[v_i] + (a_context * 11u)); + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, v_part, ((uint32_t)(self->private_data.f_coeff_probs[(v_prob_base + 0u)]))); + if (v_v1 == 0u) { + return 0u; + } + while (true) { + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, v_part, ((uint32_t)(self->private_data.f_coeff_probs[(v_prob_base + 1u)]))); + if (v_v1 == 0u) { + v_i += 1u; + if (v_i >= 16u) { + break; + } + v_prob_base = ((a_plane * 264u) + WUFFS_VP8__COEFF_BANDS_33[(v_i + 0u)] + 0u); + continue; + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, v_part, ((uint32_t)(self->private_data.f_coeff_probs[(v_prob_base + 2u)]))); + if (v_v1 == 0u) { + v_value = 1u; + v_prob_base = ((a_plane * 264u) + WUFFS_VP8__COEFF_BANDS_33[(v_i + 1u)] + 11u); + } else { + v_value = wuffs_vp8__decoder__decode_large_value(self, a_workbuf, v_part, v_prob_base); + v_prob_base = ((a_plane * 264u) + WUFFS_VP8__COEFF_BANDS_33[(v_i + 1u)] + 22u); + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, v_part, 128u); + if (v_v1 != 0u) { + v_value = ((uint32_t)(0u - v_value)); + } + v_q2 = 0u; + if (v_i != 0u) { + v_q2 = 1u; + } + v_quant = ((uint32_t)(self->private_impl.f_dequants[a_seg][v_q1][v_q2])); + self->private_data.f_mb_coeffs[a_b][WUFFS_VP8__ZIGZAG[v_i]] = ((uint16_t)(((uint32_t)(v_value * v_quant)))); + if (v_i >= 15u) { + break; + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, v_part, ((uint32_t)(self->private_data.f_coeff_probs[(v_prob_base + 0u)]))); + if (v_v1 == 0u) { + break; + } + v_i += 1u; + } + return 1u; +} + +// -------- func vp8.decoder.decode_large_value + +WUFFS_BASE__GENERATED_C_CODE +static uint32_t +wuffs_vp8__decoder__decode_large_value( + wuffs_vp8__decoder* self, + wuffs_base__slice_u8 a_workbuf, + uint32_t a_part, + uint32_t a_prob_base) { + uint32_t v_v1 = 0; + uint32_t v_w1 = 0; + uint32_t v_category = 0; + uint32_t v_value = 0; + uint32_t v_i = 0; + + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 3u)]))); + if (v_v1 == 0u) { + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 4u)]))); + if (v_v1 == 0u) { + return 2u; + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 5u)]))); + return (3u + v_v1); + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 6u)]))); + if (v_v1 == 0u) { + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 7u)]))); + if (v_v1 == 0u) { + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, 159u); + return (5u + v_v1); + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, 165u); + v_w1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, 145u); + return (7u + (2u * v_v1) + v_w1); + } + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 8u)]))); + v_w1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(self->private_data.f_coeff_probs[(a_prob_base + 9u + v_v1)]))); + v_category = ((2u * v_v1) + v_w1); + v_value = 0u; + v_i = 0u; + while (true) { + v_v1 = wuffs_vp8__decoder__read_bit(self, a_workbuf, a_part, ((uint32_t)(WUFFS_VP8__CATEGORY_PROBS[v_category][v_i]))); + v_value <<= 1u; + v_value += v_v1; + v_i = ((v_i + 1u) & 15u); + if (WUFFS_VP8__CATEGORY_PROBS[v_category][v_i] == 0u) { + break; + } + } + return ((v_value & 2047u) + (((uint32_t)(8u)) << v_category) + 3u); +} + // -------- func vp8.decoder.get_quirk WUFFS_BASE__GENERATED_C_CODE
diff --git a/std/vp8/common_consts.wuffs b/std/vp8/common_consts.wuffs index 648ec50..8787329 100644 --- a/std/vp8/common_consts.wuffs +++ b/std/vp8/common_consts.wuffs
@@ -107,6 +107,10 @@ 254, ] +pri const CLIP_9 : roarray[16] base.u8[..= 9] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, +] + // RFC 6386 Section 11.5. Subblock Mode Probability Table. // // Note that the specification (the RFC) differs from the implementation @@ -243,6 +247,31 @@ [112, 19, 12, 61, 195, 128, 48, 4, 24], ]] +// RFC 6386 Section 13.2. Coding of Individual Coefficient Values. +// +// Categories 1 and 2 are inlined. +pri const CATEGORY_PROBS : roarray[4] roarray[16] base.u8 = [[ + // Category 3. + 173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +],[ + // Category 4. + 176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +],[ + // Category 5. + 180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +],[ + // Category 6. + 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0, 0, 0, 0, 0, +]] + +// RFC 6386 Section 13.3. Token Probabilities. +// +// These are the RFC's coeff_bands array values multplied by 33, with an extra +// element at the end so we can index by (i+1). +pri const COEFF_BANDS_33 : roarray[17] base.u32[..= 231] = [ + 0, 33, 66, 99, 198, 132, 165, 198, 198, 198, 198, 198, 198, 198, 198, 231, 0, +] + // RFC 6386 Section 13.4. Token Probability Updates. // // 1056 is (4 planes, 8 bands, 3 contexts, 11 tokens) flattened. @@ -532,3 +561,29 @@ 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128, 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128, ] + +// RFC 6386 Section 14.1. Dequantization. +pri const DEQUANTS : roarray[2] roarray[128] base.u16[..= 284] = [[ + 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, + 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 91, 93, 95, 96, 98, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, + 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 143, 145, 148, 151, 154, 157, +],[ + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, + 110, 112, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, + 155, 158, 161, 164, 167, 170, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, + 213, 217, 221, 225, 229, 234, 239, 245, 249, 254, 259, 264, 269, 274, 279, 284, +]] + +// RFC 6386 Section 20.16. tokens.c. +pri const ZIGZAG : roarray[16] base.u8[..= 15] = [ + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15, +]
diff --git a/std/vp8/decode_first_partition.wuffs b/std/vp8/decode_first_partition.wuffs index ac6e0e6..2941788 100644 --- a/std/vp8/decode_first_partition.wuffs +++ b/std/vp8/decode_first_partition.wuffs
@@ -74,6 +74,7 @@ this.quant_y2ac_delta = this.read_signed!(workbuf: args.workbuf, part: 0, n: 4) this.quant_uvdc_delta = this.read_signed!(workbuf: args.workbuf, part: 0, n: 4) this.quant_uvac_delta = this.read_signed!(workbuf: args.workbuf, part: 0, n: 4) + this.calculate_dequants!() // RFC 6386 Section 9.7. Refresh Golden Frame and Altref Frame. if not this.is_key_frame { @@ -203,6 +204,47 @@ } } +pri func decoder.calculate_dequants!() { + var seg : base.u32 + var q : base.u32 + + seg = 0 + while seg < 4 { + q = this.quant_yac_qi + if not this.seg_enabled { + // No-op. + } else if this.seg_absolute { + q = this.util.sign_extend_convert_u8_u32(a: this.seg_quants[seg]) + } else { + q ~mod+= this.util.sign_extend_convert_u8_u32(a: this.seg_quants[seg]) + } + + this.dequants[seg][0][0] = DEQUANTS[0][this.clip_127(a: q ~mod+ this.quant_ydc_delta)] + this.dequants[seg][0][1] = DEQUANTS[1][this.clip_127(a: q)] + this.dequants[seg][1][0] = DEQUANTS[0][this.clip_127(a: q ~mod+ this.quant_y2dc_delta)] * 2 + this.dequants[seg][1][1] = (DEQUANTS[1][this.clip_127(a: q ~mod+ this.quant_y2ac_delta)] * 155) / 100 + if this.dequants[seg][1][1] < 8 { + this.dequants[seg][1][1] = 8 + } + this.dequants[seg][2][0] = DEQUANTS[0][this.clip_127(a: q ~mod+ this.quant_uvdc_delta)] + if this.dequants[seg][2][0] > 132 { + this.dequants[seg][2][0] = 132 + } + this.dequants[seg][2][1] = DEQUANTS[1][this.clip_127(a: q ~mod+ this.quant_uvac_delta)] + + seg += 1 + } +} + +pri func decoder.clip_127(a: base.u32) base.u32[..= 127] { + if args.a >= 0x8000_0000 { + return 0 + } else if args.a >= 127 { + return 127 + } + return args.a +} + pri func decoder.decode_other_partition_lengths!(workbuf: roslice base.u8) base.status { var v32 : base.u32 var remainder : base.u32
diff --git a/std/vp8/decode_macroblocks.wuffs b/std/vp8/decode_macroblocks.wuffs index 0fb2149..f56f454 100644 --- a/std/vp8/decode_macroblocks.wuffs +++ b/std/vp8/decode_macroblocks.wuffs
@@ -16,10 +16,7 @@ while mbx < this.mbw { assert mbx < 0x400 via "a < b: a < c; c <= b"(c: this.mbw) - this.mb_top_modes[mbx][0] = 0 - this.mb_top_modes[mbx][1] = 0 - this.mb_top_modes[mbx][2] = 0 - this.mb_top_modes[mbx][3] = 0 + this.mb_states_top[mbx] = 0 mbx += 1 } @@ -28,10 +25,7 @@ while mby < this.mbh { assert mby < 0x400 via "a < b: a < c; c <= b"(c: this.mbh) - this.mb_left_modes[0] = 0 - this.mb_left_modes[1] = 0 - this.mb_left_modes[2] = 0 - this.mb_left_modes[3] = 0 + this.mb_states_left = 0 mbx = 0 while mbx < this.mbw, @@ -81,8 +75,14 @@ chroma_mode = this.decode_chroma_mode!(workbuf: args.workbuf) if skip { - // TODO. + // Clear the HNZC bits. + this.mb_states_left &= 0x0000_FFFF + this.mb_states_top[args.mbx] &= 0x0000_FFFF + } else { + this.decode_residuals!( + workbuf: args.workbuf, mbx: args.mbx, mby: args.mby, + seg: seg, luma_mode: luma_mode, chroma_mode: chroma_mode) } } @@ -94,6 +94,11 @@ // 3 = B_HE_PRED = predict columns using column to the left. // 4 = B_PRED = each Y subblock is independently predicted. // +// Returning (as luma_mode) at least 4 (equivalently, returning B_PRED) means +// that we use "intra4x4 prediction" (as opposed to "intra16x16 prediction"). +// (luma_mode >= 4) here is equivalent to libwebp's "is_i4x4 == true" and +// golang.org/x/image/vp8's "usePredY16 == false". +// // The RFC gives an enum in (DC_PRED, V_PRED, H_PRED, TM_PRED, B_PRED) order // but the libwebp implementation uses a different one, (B_DC_PRED, B_TM_PRED, // B_VE_PRED, B_HE_PRED, B_PRED). Modulo the B_ prefixes, it's DC,V,H,TM versus @@ -106,9 +111,11 @@ v1 = this.read_bit!(workbuf: args.workbuf, part: 0, prob: 145) if v1 == 0 { - return 4 // 4=B_PRED. + return 4 // 4=B_PRED. is_i4x4 == true. usePredY16 == false. } + // Otherwise, is_i4x4 == false. usePredY16 == true. + v1 = this.read_bit!(workbuf: args.workbuf, part: 0, prob: 156) if v1 == 0 { v1 = this.read_bit!(workbuf: args.workbuf, part: 0, prob: 163) @@ -144,33 +151,27 @@ workbuf: slice base.u8, mbx: base.u32[..= 0x3FF], luma_mode: base.u32[..= 4]) { - var i : base.u32 - var top_mode : base.u8[..= 9] - var left_mode : base.u8[..= 9] - var mode : base.u8[..= 9] + var i : base.u32 + var top_mode : base.u8[..= 9] + var left_mode : base.u8[..= 9] + var mode : base.u8[..= 9] if args.luma_mode < 4 { - this.mb_top_modes[args.mbx][0] = mode - this.mb_top_modes[args.mbx][1] = mode - this.mb_top_modes[args.mbx][2] = mode - this.mb_top_modes[args.mbx][3] = mode - this.mb_left_modes[0] = mode - this.mb_left_modes[1] = mode - this.mb_left_modes[2] = mode - this.mb_left_modes[3] = mode + this.mb_states_top[args.mbx] = (mode as base.u32) * 0x1111 + this.mb_states_left = (mode as base.u32) * 0x1111 return nothing } i = 0 while i < 16 { if i < 4 { - top_mode = this.mb_top_modes[args.mbx][i] + top_mode = CLIP_9[15 & (this.mb_states_top[args.mbx] >> (i * 4))] } else { top_mode = this.mb_subblock_modes[i - 4] } if (i & 3) == 0 { - left_mode = this.mb_left_modes[i >> 2] + left_mode = CLIP_9[15 & (this.mb_states_left >> (i & 12))] } else { left_mode = this.mb_subblock_modes[(i ~mod+ 15) & 15] } @@ -181,14 +182,16 @@ i += 1 } - this.mb_top_modes[args.mbx][0] = this.mb_subblock_modes[0xC] - this.mb_top_modes[args.mbx][1] = this.mb_subblock_modes[0xD] - this.mb_top_modes[args.mbx][2] = this.mb_subblock_modes[0xE] - this.mb_top_modes[args.mbx][3] = this.mb_subblock_modes[0xF] - this.mb_left_modes[0] = this.mb_subblock_modes[0x3] - this.mb_left_modes[1] = this.mb_subblock_modes[0x7] - this.mb_left_modes[2] = this.mb_subblock_modes[0xB] - this.mb_left_modes[3] = this.mb_subblock_modes[0xF] + this.mb_states_top[args.mbx] = (this.mb_states_top[args.mbx] & 0xFFFF_0000) | + ((this.mb_subblock_modes[0xC] as base.u32) << 0x0) | + ((this.mb_subblock_modes[0xD] as base.u32) << 0x4) | + ((this.mb_subblock_modes[0xE] as base.u32) << 0x8) | + ((this.mb_subblock_modes[0xF] as base.u32) << 0xC) + this.mb_states_left = (this.mb_states_left & 0xFFFF_0000) | + ((this.mb_subblock_modes[0x3] as base.u32) << 0x0) | + ((this.mb_subblock_modes[0x7] as base.u32) << 0x4) | + ((this.mb_subblock_modes[0xB] as base.u32) << 0x8) | + ((this.mb_subblock_modes[0xF] as base.u32) << 0xC) } // RFC 6386 Section 11.3. Subblock Mode Contexts.
diff --git a/std/vp8/decode_residuals.wuffs b/std/vp8/decode_residuals.wuffs new file mode 100644 index 0000000..6060b5a --- /dev/null +++ b/std/vp8/decode_residuals.wuffs
@@ -0,0 +1,292 @@ +// Copyright 2026 The Wuffs Authors. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +pri func decoder.decode_residuals!( + workbuf: slice base.u8, + mbx: base.u32[..= 0x3FF], + mby: base.u32[..= 0x3FF], + seg: base.u32[..= 3], + luma_mode: base.u32[..= 4], + chroma_mode: base.u32[..= 3]) { + var bc : base.u32 + var by : base.u32 + var bx : base.u32 + var plane : base.u32[..= 3] + var lnz : base.u32[..= 1] + var tnz : base.u32[..= 1] + + this.initialize_mb_coeffs!() + + // Handle "intra16x16 prediction". + plane = 3 // Plane 3: Y beginning at coefficient 0. + if args.luma_mode < 4 { + lnz = 1 & (this.mb_states_left >> 23) + this.mb_states_left &= 0xFF7F_FFFF + + tnz = 1 & (this.mb_states_top[args.mbx] >> 23) + this.mb_states_top[args.mbx] &= 0xFF7F_FFFF + + lnz = this.decode_block_coefficients!( + workbuf: args.workbuf, + mby: args.mby, + seg: args.seg, + b: 24, + plane: 1, // Plane 1: Y2. + context: lnz + tnz) + + this.mb_states_top[args.mbx] |= lnz << 23 + this.mb_states_left |= lnz << 23 + plane = 0 // Plane 0: Y beginning at coefficient 1. + } + + // Parse Luma coefficients. + + by = 0 + while by < 4 { + lnz = 1 & (this.mb_states_left >> (24 + by)) + this.mb_states_left &= 0xFFFF_FFFF ^ ((1 as base.u32) << (24 + by)) + + bx = 0 + while bx < 4, + inv by < 4, + { + tnz = 1 & (this.mb_states_top[args.mbx] >> (24 + bx)) + this.mb_states_top[args.mbx] &= 0xFFFF_FFFF ^ ((1 as base.u32) << (24 + bx)) + + lnz = this.decode_block_coefficients!( + workbuf: args.workbuf, + mby: args.mby, + seg: args.seg, + b: (4 * by) + bx, + plane: plane, + context: lnz + tnz) + + this.mb_states_top[args.mbx] |= lnz << (24 + bx) + bx += 1 + } + this.mb_states_left |= lnz << (24 + by) + by += 1 + } + + // Parse Chroma coefficients. + + bc = 0 + while bc <= 2 { + by = 0 + while by < 2, + inv bc <= 2, + { + lnz = 1 & (this.mb_states_left >> (28 + bc + by)) + this.mb_states_left &= 0xFFFF_FFFF ^ ((1 as base.u32) << (28 + bc + by)) + + bx = 0 + while bx < 2, + inv bc <= 2, + inv by < 2, + { + tnz = 1 & (this.mb_states_top[args.mbx] >> (28 + bc + bx)) + this.mb_states_top[args.mbx] &= 0xFFFF_FFFF ^ ((1 as base.u32) << (28 + bc + bx)) + + lnz = this.decode_block_coefficients!( + workbuf: args.workbuf, + mby: args.mby, + seg: args.seg, + b: (2 * bc) + (2 * by) + bx + 16, + plane: 2, // Plane 2: U or V. + context: lnz + tnz) + + this.mb_states_top[args.mbx] |= lnz << (28 + bc + bx) + bx += 1 + } + this.mb_states_left |= lnz << (28 + bc + by) + by += 1 + } + bc += 2 + } +} + +pri func decoder.initialize_mb_coeffs!() { + var i : base.u32 + var j : base.u32 + + i = 0 + while i < 25 { + j = 0 + while j < 16, + inv i < 25, + { + this.mb_coeffs[i][j] = 0 + j += 1 + } + i += 1 + } +} + +pri func decoder.decode_block_coefficients!( + workbuf: slice base.u8, + mby: base.u32[..= 0x3FF], + seg: base.u32[..= 3], + b: base.u32[..= 24], + plane: base.u32[..= 3], + context: base.u32[..= 2]) base.u32[..= 1] { + var q1 : base.u32[..= 2] + var q2 : base.u32[..= 1] + var quant : base.u32 + var i : base.u32 + var part : base.u32[..= 8] + var prob_base : base.u32[..= 1045] + var v1 : base.u32[..= 1] + var value : base.u32 + + q1 = 0 + if args.b == 24 { + q1 = 1 + } else if args.b >= 16 { + q1 = 2 + } + + i = 0 + assert i <= 1 + if args.plane == 0 { + i = 1 + assert i <= 1 + } + + part = 1 + (args.mby & this.num_other_partitions_m1) + prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i] + (args.context * 11) + + v1 = this.read_bit!(workbuf: args.workbuf, part: part, + prob: this.coeff_probs[prob_base + 0] as base.u32) + if v1 == 0 { + return 0 + } + + while true, + pre i < 16, + { + v1 = this.read_bit!(workbuf: args.workbuf, part: part, + prob: this.coeff_probs[prob_base + 1] as base.u32) + if v1 == 0 { + i += 1 + if i >= 16 { + break + } + prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 0] + (0 * 11) + continue + } + + v1 = this.read_bit!(workbuf: args.workbuf, part: part, + prob: this.coeff_probs[prob_base + 2] as base.u32) + if v1 == 0 { + value = 1 + prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 1] + (1 * 11) + } else { + value = this.decode_large_value!( + workbuf: args.workbuf, + part: part, + prob_base: prob_base) + prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 1] + (2 * 11) + } + + v1 = this.read_bit!(workbuf: args.workbuf, part: part, prob: 128) + if v1 <> 0 { + value = 0 ~mod- value + } + + q2 = 0 + if i <> 0 { + q2 = 1 + } + quant = this.dequants[args.seg][q1][q2] as base.u32 + this.mb_coeffs[args.b][ZIGZAG[i]] = ((value ~mod* quant) & 0xFFFF) as base.u16 + + if i >= 15 { + break + } + + v1 = this.read_bit!(workbuf: args.workbuf, part: part, + prob: this.coeff_probs[prob_base + 0] as base.u32) + if v1 == 0 { + break + } + + i += 1 + } + + return 1 +} + +pri func decoder.decode_large_value!( + workbuf: slice base.u8, + part: base.u32[..= 8], + prob_base: base.u32[..= 1045]) base.u32[2 ..= 2114] { + var v1 : base.u32[..= 1] + var w1 : base.u32[..= 1] + var category : base.u32[..= 3] + var value : base.u32 + var i : base.u32[..= 15] + + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 3] as base.u32) + if v1 == 0 { + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 4] as base.u32) + if v1 == 0 { + return 2 + } + + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 5] as base.u32) + return 3 + v1 + } + + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 6] as base.u32) + if v1 == 0 { + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 7] as base.u32) + if v1 == 0 { + // Category 1. + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: 159) + return 5 + v1 + } + + // Category 2. + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: 165) + w1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: 145) + return 7 + (2 * v1) + w1 + } + + // Categories 3, 4, 5, 6. + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 8] as base.u32) + w1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: this.coeff_probs[args.prob_base + 9 + v1] as base.u32) + category = (2 * v1) + w1 + + // Read 3, 4, 5 or 11 extra bits, depending on the category. + value = 0 + i = 0 + while true { + v1 = this.read_bit!(workbuf: args.workbuf, part: args.part, + prob: CATEGORY_PROBS[category][i] as base.u32) + value ~mod<<= 1 + value ~mod+= v1 + + i = (i + 1) & 15 + if CATEGORY_PROBS[category][i] == 0 { + break + } + } + return (value & 0x7FF) + ((8 as base.u32) << category) + 3 +}
diff --git a/std/vp8/decode_vp8.wuffs b/std/vp8/decode_vp8.wuffs index fafc64f..67a247e 100644 --- a/std/vp8/decode_vp8.wuffs +++ b/std/vp8/decode_vp8.wuffs
@@ -88,13 +88,17 @@ quant_uvdc_delta : base.u32, quant_uvac_delta : base.u32, + // Look-up tables derived from the dequantization parameters. + // + // The first index is the segment. The second index is Y/Y2/UV. The + // third index is DC/AC. + dequants : array[4] array[3] array[2] base.u16, + // These 9 bits combine what RFC 6386 calls mb_no_skip_coeff (which we // hold in the 0x100 bit) and prob_skip_false (in the low 8 bits). prob_skip : base.u32[..= 0x1FF], mb_subblock_modes : array[16] base.u8[..= 9], - mb_left_modes : array[4] base.u8[..= 9], - mb_top_modes : array[0x400] array[4] base.u8[..= 9], dst_x : base.u32, dst_y : base.u32, @@ -104,6 +108,25 @@ ) + ( // 1056 is (4 planes, 8 bands, 3 contexts, 11 tokens) flattened. coeff_probs : array[1056] base.u8, + + mb_coeffs : array[25] array[16] base.u16, + + // Macroblock states are a u32 whose bits are packed like this: + // + // - 28 ..= 31 are Chroma (UV) HNZC bits. + // - 24 ..= 27 are Luma4 (Y4) HNZC bits. + // - 23 is Luma16 (Y16) HNZC bit. + // - 16 ..= 22 are unused. + // - 12 ..= 15 are the 3rd predictor mode. + // - 8 ..= 12 are the 2nd predictor mode. + // - 4 ..= 7 are the 1st predictor mode. + // - 0 ..= 3 are the 0th predictor mode. + // + // HNZC stands for has-non-zero-coefficients. + // + // The mb_states_top array is indexed by mbx. + mb_states_left : base.u32, + mb_states_top : array[0x400] base.u32, ) pub func decoder.get_quirk(key: base.u32) base.u64 {