LibVideo/VP9: Drop the decoder intermediate bounds checks

Checking the bounds of the intermediate values was only implemented to
help debug the decoder. However, it is non-fatal to have the values
exceed the spec-defined bounds, and causes a measurable performance
reduction.

Additionally, the checks were implemented as an assertion, which is
easily broken by bad input files.

I see about a 4-5% decrease in decoding times in the `webm_in_vp9` test
in TestVP9Decode.
This commit is contained in:
Zaggy1024 2023-02-10 11:44:30 -06:00 committed by Andreas Kling
parent 7c607462a4
commit 33ff3427eb
2 changed files with 50 additions and 82 deletions

View file

@ -1099,8 +1099,8 @@ DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_co
// It is a requirement of bitstream conformance that the values written into the Dequant array in steps 1 and 2
// are representable by a signed integer with 8 + BitDepth bits.
for (auto i = 0u; i < block_size * block_size; i++)
VERIFY(check_intermediate_bounds(block_context.frame_context.color_config.bit_depth, dequantized[i]));
// Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal
// to allow these bounds to be violated. Therefore, we can avoid the performance cost here.
// 3. Invoke the 2D inverse transform block process defined in section 8.7.2 with the variable n as input.
// The inverse transform outputs are stored back to the Dequant buffer.
@ -1172,20 +1172,8 @@ inline i32 Decoder::round_2(T value, u8 bits)
return static_cast<i32>(value);
}
inline bool check_bounds(i64 value, u8 bits)
{
i64 const maximum = (1ll << (bits - 1ll)) - 1ll;
return value >= ~maximum && value <= maximum;
}
inline bool Decoder::check_intermediate_bounds(u8 bit_depth, Intermediate value)
{
i32 maximum = (1 << (8 + bit_depth - 1)) - 1;
return value >= ~maximum && value <= maximum;
}
// (8.7.1.1) The function B( a, b, angle, 0 ) performs a butterfly rotation.
inline void Decoder::butterfly_rotation_in_place(u8 bit_depth, Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip)
inline void Decoder::butterfly_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip)
{
auto cos = cos64(angle);
auto sin = sin64(angle);
@ -1206,12 +1194,12 @@ inline void Decoder::butterfly_rotation_in_place(u8 bit_depth, Span<Intermediate
// It is a requirement of bitstream conformance that the values saved into the array T by this function are
// representable by a signed integer using 8 + BitDepth bits of precision.
VERIFY(check_intermediate_bounds(bit_depth, data[index_a]));
VERIFY(check_intermediate_bounds(bit_depth, data[index_b]));
// Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal
// to allow these bounds to be violated. Therefore, we can avoid the performance cost here.
}
// (8.7.1.1) The function H( a, b, 0 ) performs a Hadamard rotation.
inline void Decoder::hadamard_rotation_in_place(u8 bit_depth, Span<Intermediate> data, size_t index_a, size_t index_b, bool flip)
inline void Decoder::hadamard_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, bool flip)
{
// The function H( a, b, 1 ) performs a Hadamard rotation with flipped indices and is specified as follows:
// 1. The function H( b, a, 0 ) is invoked.
@ -1231,8 +1219,8 @@ inline void Decoder::hadamard_rotation_in_place(u8 bit_depth, Span<Intermediate>
// It is a requirement of bitstream conformance that the values saved into the array T by this function are
// representable by a signed integer using 8 + BitDepth bits of precision.
VERIFY(check_intermediate_bounds(bit_depth, data[index_a]));
VERIFY(check_intermediate_bounds(bit_depth, data[index_b]));
// Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal
// to allow these bounds to be violated. Therefore, we can avoid the performance cost here.
}
inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform_array_permutation(Span<Intermediate> data, u8 log2_of_block_size)
@ -1255,7 +1243,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform_array_per
return {};
}
inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size)
inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Intermediate> data, u8 log2_of_block_size)
{
// 2.1. The variable n0 is set equal to 1<<n.
u8 block_size = 1 << log2_of_block_size;
@ -1272,14 +1260,14 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
// 2.5 If n is equal to 2, invoke B( 0, 1, 16, 1 ), otherwise recursively invoke the inverse DCT defined in this
// section with the variable n set equal to n - 1.
if (log2_of_block_size == 2)
butterfly_rotation_in_place(bit_depth, data, 0, 1, 16, true);
butterfly_rotation_in_place(data, 0, 1, 16, true);
else
TRY(inverse_discrete_cosine_transform(bit_depth, data, log2_of_block_size - 1));
TRY(inverse_discrete_cosine_transform(data, log2_of_block_size - 1));
// 2.6 Invoke B( n1+i, n0-1-i, 32-brev( 5, n1+i), 0 ) for i = 0..(n2-1).
for (auto i = 0u; i < quarter_block_size; i++) {
auto index = half_block_size + i;
butterfly_rotation_in_place(bit_depth, data, index, block_size - 1 - i, 32 - brev(5, index), false);
butterfly_rotation_in_place(data, index, block_size - 1 - i, 32 - brev(5, index), false);
}
// 2.7 If n is greater than or equal to 3:
@ -1288,7 +1276,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
for (auto i = 0u; i < eighth_block_size; i++) {
for (auto j = 0u; j < 2; j++) {
auto index = half_block_size + (4 * i) + (2 * j);
hadamard_rotation_in_place(bit_depth, data, index, index + 1, j);
hadamard_rotation_in_place(data, index, index + 1, j);
}
}
}
@ -1301,7 +1289,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
auto index_a = block_size - log2_of_block_size + 3 - (quarter_block_size * j) - (4 * i);
auto index_b = half_block_size + log2_of_block_size - 4 + (quarter_block_size * j) + (4 * i);
auto angle = 28 - (16 * i) + (56 * j);
butterfly_rotation_in_place(bit_depth, data, index_a, index_b, angle, true);
butterfly_rotation_in_place(data, index_a, index_b, angle, true);
}
}
@ -1310,7 +1298,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
for (auto j = 0u; j < 4; j++) {
auto index_a = half_block_size + (eighth_block_size * j) + i;
auto index_b = half_block_size + quarter_block_size - 5 + (eighth_block_size * j) - i;
hadamard_rotation_in_place(bit_depth, data, index_a, index_b, (j & 1) != 0);
hadamard_rotation_in_place(data, index_a, index_b, (j & 1) != 0);
}
}
}
@ -1322,7 +1310,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
for (auto j = 0u; j < 2; j++) {
auto index_a = block_size - log2_of_block_size + 2 - i - (quarter_block_size * j);
auto index_b = half_block_size + log2_of_block_size - 3 + i + (quarter_block_size * j);
butterfly_rotation_in_place(bit_depth, data, index_a, index_b, 24 + (48 * j), true);
butterfly_rotation_in_place(data, index_a, index_b, 24 + (48 * j), true);
}
}
@ -1331,7 +1319,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
for (auto j = 0u; j < 2; j++) {
auto index_a = half_block_size + (quarter_block_size * j) + i;
auto index_b = half_block_size + quarter_block_size - 1 + (quarter_block_size * j) - i;
hadamard_rotation_in_place(bit_depth, data, index_a, index_b, (j & 1) != 0);
hadamard_rotation_in_place(data, index_a, index_b, (j & 1) != 0);
}
}
}
@ -1342,13 +1330,13 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_de
for (auto i = 0u; i < eighth_block_size; i++) {
auto index_a = block_size - eighth_block_size - 1 - i;
auto index_b = half_block_size + eighth_block_size + i;
butterfly_rotation_in_place(bit_depth, data, index_a, index_b, 16, true);
butterfly_rotation_in_place(data, index_a, index_b, 16, true);
}
}
// 7. Invoke H( i, n0-1-i, 0 ) for i = 0..(n1-1).
for (auto i = 0u; i < half_block_size; i++)
hadamard_rotation_in_place(bit_depth, data, i, block_size - 1 - i, false);
hadamard_rotation_in_place(data, i, block_size - 1 - i, false);
return {};
}
@ -1402,7 +1390,7 @@ inline void Decoder::inverse_asymmetric_discrete_sine_transform_output_array_per
}
}
inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(u8 bit_depth, Span<Intermediate> data)
inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(Span<Intermediate> data)
{
VERIFY(data.size() == 4);
const i64 sinpi_1_9 = 5283;
@ -1459,11 +1447,8 @@ inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(u8 bit_depth,
// (8.7.1.1) The inverse asymmetric discrete sine transforms also make use of an intermediate array named S.
// The values in this array require higher precision to avoid overflow. Using signed integers with 24 +
// BitDepth bits of precision is enough to avoid overflow.
const u8 bits = 24 + bit_depth;
VERIFY(check_bounds(data[0], bits));
VERIFY(check_bounds(data[1], bits));
VERIFY(check_bounds(data[2], bits));
VERIFY(check_bounds(data[3], bits));
// Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal
// to allow these bounds to be violated. Therefore, we can avoid the performance cost here.
}
// The function SB( a, b, angle, 0 ) performs a butterfly rotation.
@ -1503,12 +1488,14 @@ inline void Decoder::hadamard_rotation(Span<S> source, Span<D> destination, size
destination[index_b] = round_2(a - b, 14);
}
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_8(u8 bit_depth, Span<Intermediate> data)
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_8(Span<Intermediate> data)
{
VERIFY(data.size() == 8);
// This process does an in-place transform of the array T using:
// A higher precision array S for intermediate results.
// (8.7.1.1) NOTE - The values in array S require higher precision to avoid overflow. Using signed integers with
// 24 + BitDepth bits of precision is enough to avoid overflow.
Array<i64, 8> high_precision_temp;
// The following ordered steps apply:
@ -1520,11 +1507,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 2. Invoke SB( 2*i, 1+2*i, 30-8*i, 1 ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
butterfly_rotation(data, high_precision_temp.span(), 2 * i, 1 + (2 * i), 30 - (8 * i), true);
// (8.7.1.1) NOTE - The values in array S require higher precision to avoid overflow. Using signed integers with
// 24 + BitDepth bits of precision is enough to avoid overflow.
const u8 bits = 24 + bit_depth;
for (auto i = 0u; i < 8; i++)
VERIFY(check_bounds(high_precision_temp[i], bits));
// 3. Invoke SH( i, 4+i ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
hadamard_rotation(high_precision_temp.span(), data, i, 4 + i);
@ -1532,20 +1515,17 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 4. Invoke SB( 4+3*i, 5+i, 24-16*i, 1 ) for i = 0..1.
for (auto i = 0u; i < 2; i++)
butterfly_rotation(data, high_precision_temp.span(), 4 + (3 * i), 5 + i, 24 - (16 * i), true);
// Check again that we haven't exceeded the integer bounds.
for (auto i = 0u; i < 8; i++)
VERIFY(check_bounds(high_precision_temp[i], bits));
// 5. Invoke SH( 4+i, 6+i ) for i = 0..1.
for (auto i = 0u; i < 2; i++)
hadamard_rotation(high_precision_temp.span(), data, 4 + i, 6 + i);
// 6. Invoke H( i, 2+i, 0 ) for i = 0..1.
for (auto i = 0u; i < 2; i++)
hadamard_rotation_in_place(bit_depth, data, i, 2 + i, false);
hadamard_rotation_in_place(data, i, 2 + i, false);
// 7. Invoke B( 2+4*i, 3+4*i, 16, 1 ) for i = 0..1.
for (auto i = 0u; i < 2; i++)
butterfly_rotation_in_place(bit_depth, data, 2 + (4 * i), 3 + (4 * i), 16, true);
butterfly_rotation_in_place(data, 2 + (4 * i), 3 + (4 * i), 16, true);
// 8. Invoke the ADST output array permutation process specified in section 8.7.1.5 with the input variable n
// set equal to 3.
@ -1559,12 +1539,15 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
return {};
}
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_16(u8 bit_depth, Span<Intermediate> data)
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_16(Span<Intermediate> data)
{
VERIFY(data.size() == 16);
// This process does an in-place transform of the array T using:
// A higher precision array S for intermediate results.
// (8.7.1.1) The inverse asymmetric discrete sine transforms also make use of an intermediate array named S.
// The values in this array require higher precision to avoid overflow. Using signed integers with 24 +
// BitDepth bits of precision is enough to avoid overflow.
Array<i64, 16> high_precision_temp;
// The following ordered steps apply:
@ -1576,12 +1559,6 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 2. Invoke SB( 2*i, 1+2*i, 31-4*i, 1 ) for i = 0..7.
for (auto i = 0u; i < 8; i++)
butterfly_rotation(data, high_precision_temp.span(), 2 * i, 1 + (2 * i), 31 - (4 * i), true);
// (8.7.1.1) The inverse asymmetric discrete sine transforms also make use of an intermediate array named S.
// The values in this array require higher precision to avoid overflow. Using signed integers with 24 +
// BitDepth bits of precision is enough to avoid overflow.
const u8 bits = 24 + bit_depth;
for (auto i = 0u; i < 16; i++)
VERIFY(check_bounds(data[i], bits));
// 3. Invoke SH( i, 8+i ) for i = 0..7.
for (auto i = 0u; i < 8; i++)
hadamard_rotation(high_precision_temp.span(), data, i, 8 + i);
@ -1589,24 +1566,18 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 4. Invoke SB( 8+2*i, 9+2*i, 28-16*i, 1 ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
butterfly_rotation(data, high_precision_temp.span(), 8 + (2 * i), 9 + (2 * i), 128 + 28 - (16 * i), true);
// Check again that we haven't exceeded the integer bounds.
for (auto i = 0u; i < 16; i++)
VERIFY(check_bounds(data[i], bits));
// 5. Invoke SH( 8+i, 12+i ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
hadamard_rotation(high_precision_temp.span(), data, 8 + i, 12 + i);
// 6. Invoke H( i, 4+i, 0 ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
hadamard_rotation_in_place(bit_depth, data, i, 4 + i, false);
hadamard_rotation_in_place(data, i, 4 + i, false);
// 7. Invoke SB( 4+8*i+3*j, 5+8*i+j, 24-16*j, 1 ) for i = 0..1, for j = 0..1.
for (auto i = 0u; i < 2; i++)
for (auto j = 0u; j < 2; j++)
butterfly_rotation(data, high_precision_temp.span(), 4 + (8 * i) + (3 * j), 5 + (8 * i) + j, 24 - (16 * j), true);
// Check again that we haven't exceeded the integer bounds.
for (auto i = 0u; i < 16; i++)
VERIFY(check_bounds(data[i], bits));
// 8. Invoke SH( 4+8*j+i, 6+8*j+i ) for i = 0..1, j = 0..1.
for (auto i = 0u; i < 2; i++)
for (auto j = 0u; j < 2; j++)
@ -1615,11 +1586,11 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 9. Invoke H( 8*j+i, 2+8*j+i, 0 ) for i = 0..1, for j = 0..1.
for (auto i = 0u; i < 2; i++)
for (auto j = 0u; j < 2; j++)
hadamard_rotation_in_place(bit_depth, data, (8 * j) + i, 2 + (8 * j) + i, false);
hadamard_rotation_in_place(data, (8 * j) + i, 2 + (8 * j) + i, false);
// 10. Invoke B( 2+4*j+8*i, 3+4*j+8*i, 48+64*(i^j), 0 ) for i = 0..1, for j = 0..1.
for (auto i = 0u; i < 2; i++)
for (auto j = 0u; j < 2; j++)
butterfly_rotation_in_place(bit_depth, data, 2 + (4 * j) + (8 * i), 3 + (4 * j) + (8 * i), 48 + (64 * (i ^ j)), false);
butterfly_rotation_in_place(data, 2 + (4 * j) + (8 * i), 3 + (4 * j) + (8 * i), 48 + (64 * (i ^ j)), false);
// 11. Invoke the ADST output array permutation process specified in section 8.7.1.5 with the input variable n
// set equal to 4.
@ -1635,7 +1606,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
return {};
}
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size)
inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform(Span<Intermediate> data, u8 log2_of_block_size)
{
// 8.7.1.9 Inverse ADST Process
@ -1646,15 +1617,15 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform(
// The process to invoke depends on n as follows:
if (log2_of_block_size == 2) {
// If n is equal to 2, invoke the Inverse ADST4 process specified in section 8.7.1.6.
inverse_asymmetric_discrete_sine_transform_4(bit_depth, data);
inverse_asymmetric_discrete_sine_transform_4(data);
return {};
}
if (log2_of_block_size == 3) {
// Otherwise if n is equal to 3, invoke the Inverse ADST8 process specified in section 8.7.1.7.
return inverse_asymmetric_discrete_sine_transform_8(bit_depth, data);
return inverse_asymmetric_discrete_sine_transform_8(data);
}
// Otherwise (n is equal to 4), invoke the Inverse ADST16 process specified in section 8.7.1.8.
return inverse_asymmetric_discrete_sine_transform_16(bit_depth, data);
return inverse_asymmetric_discrete_sine_transform_16(data);
}
DecoderErrorOr<void> Decoder::inverse_transform_2d(BlockContext const& block_context, Span<Intermediate> dequantized, u8 log2_of_block_size, TransformSet transform_set)
@ -1687,12 +1658,12 @@ DecoderErrorOr<void> Decoder::inverse_transform_2d(BlockContext const& block_con
// 1. Invoke the inverse DCT permutation process as specified in section 8.7.1.2 with the input variable n.
TRY(inverse_discrete_cosine_transform_array_permutation(row, log2_of_block_size));
// 2. Invoke the inverse DCT process as specified in section 8.7.1.3 with the input variable n.
TRY(inverse_discrete_cosine_transform(block_context.frame_context.color_config.bit_depth, row, log2_of_block_size));
TRY(inverse_discrete_cosine_transform(row, log2_of_block_size));
break;
case TransformType::ADST:
// 4. Otherwise (TxType is equal to DCT_ADST or TxType is equal to ADST_ADST), invoke the inverse ADST
// process as specified in section 8.7.1.9 with input variable n.
TRY(inverse_asymmetric_discrete_sine_transform(block_context.frame_context.color_config.bit_depth, row, log2_of_block_size));
TRY(inverse_asymmetric_discrete_sine_transform(row, log2_of_block_size));
break;
default:
return DecoderError::corrupted("Unknown tx_type"sv);
@ -1725,12 +1696,12 @@ DecoderErrorOr<void> Decoder::inverse_transform_2d(BlockContext const& block_con
// 1. Invoke the inverse DCT permutation process as specified in section 8.7.1.2 with the input variable n.
TRY(inverse_discrete_cosine_transform_array_permutation(column, log2_of_block_size));
// 2. Invoke the inverse DCT process as specified in section 8.7.1.3 with the input variable n.
TRY(inverse_discrete_cosine_transform(block_context.frame_context.color_config.bit_depth, column, log2_of_block_size));
TRY(inverse_discrete_cosine_transform(column, log2_of_block_size));
break;
case TransformType::ADST:
// 4. Otherwise (TxType is equal to ADST_DCT or TxType is equal to ADST_ADST), invoke the inverse ADST
// process as specified in section 8.7.1.9 with input variable n.
TRY(inverse_asymmetric_discrete_sine_transform(block_context.frame_context.color_config.bit_depth, column, log2_of_block_size));
TRY(inverse_asymmetric_discrete_sine_transform(column, log2_of_block_size));
break;
default:
VERIFY_NOT_REACHED();

View file

@ -89,9 +89,9 @@ private:
inline i32 cos64(u8 angle);
inline i32 sin64(u8 angle);
// The function B( a, b, angle, 0 ) performs a butterfly rotation.
inline void butterfly_rotation_in_place(u8 bit_depth, Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip);
inline void butterfly_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip);
// The function H( a, b, 0 ) performs a Hadamard rotation.
inline void hadamard_rotation_in_place(u8 bit_depth, Span<Intermediate> data, size_t index_a, size_t index_b, bool flip);
inline void hadamard_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, bool flip);
// The function SB( a, b, angle, 0 ) performs a butterfly rotation.
// Spec defines the source as array T, and the destination array as S.
template<typename S, typename D>
@ -104,16 +104,13 @@ private:
template<typename T>
inline i32 round_2(T value, u8 bits);
// Checks whether the value is representable by a signed integer with (8 + bit_depth) bits.
inline bool check_intermediate_bounds(u8 bit_depth, Intermediate value);
// (8.7.1.10) This process does an in-place Walsh-Hadamard transform of the array T (of length 4).
inline DecoderErrorOr<void> inverse_walsh_hadamard_transform(Span<Intermediate> data, u8 log2_of_block_size, u8 shift);
// (8.7.1.2) Inverse DCT array permutation process
inline DecoderErrorOr<void> inverse_discrete_cosine_transform_array_permutation(Span<Intermediate> data, u8 log2_of_block_size);
// (8.7.1.3) Inverse DCT process
inline DecoderErrorOr<void> inverse_discrete_cosine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size);
inline DecoderErrorOr<void> inverse_discrete_cosine_transform(Span<Intermediate> data, u8 log2_of_block_size);
// (8.7.1.4) This process performs the in-place permutation of the array T of length 2 n which is required as the first step of
// the inverse ADST.
@ -123,15 +120,15 @@ private:
inline void inverse_asymmetric_discrete_sine_transform_output_array_permutation(Span<Intermediate> data, u8 log2_of_block_size);
// (8.7.1.6) This process does an in-place transform of the array T to perform an inverse ADST.
inline void inverse_asymmetric_discrete_sine_transform_4(u8 bit_depth, Span<Intermediate> data);
inline void inverse_asymmetric_discrete_sine_transform_4(Span<Intermediate> data);
// (8.7.1.7) This process does an in-place transform of the array T using a higher precision array S for intermediate
// results.
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_8(u8 bit_depth, Span<Intermediate> data);
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_8(Span<Intermediate> data);
// (8.7.1.8) This process does an in-place transform of the array T using a higher precision array S for intermediate
// results.
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_16(u8 bit_depth, Span<Intermediate> data);
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_16(Span<Intermediate> data);
// (8.7.1.9) This process performs an in-place inverse ADST process on the array T of size 2 n for 2 ≤ n ≤ 4.
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size);
inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform(Span<Intermediate> data, u8 log2_of_block_size);
/* (8.10) Reference Frame Update Process */
DecoderErrorOr<void> update_reference_frames(FrameContext const&);