summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorZaggy1024 <zaggy1024@gmail.com>2022-11-22 19:15:38 -0600
committerAndreas Kling <kling@serenityos.org>2022-11-30 08:28:30 +0100
commit40bc987fe330146f20d6950945c43cd068a927ca (patch)
treebbeed7b10c6282aab43e4559100264f4a959f10c /Userland
parent9f573264ea8f1175156c71d0524c29058946f232 (diff)
downloadserenity-40bc987fe330146f20d6950945c43cd068a927ca.zip
LibVideo/VP9: Store color config in the frame context
The color config is reused for most inter predicted frames, so we use a struct ColorConfig to store the config from intra frames, and put it in a field in Parser to copy from when an inter frame without color config is encountered.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibVideo/VP9/Context.h10
-rw-r--r--Userland/Libraries/LibVideo/VP9/Decoder.cpp282
-rw-r--r--Userland/Libraries/LibVideo/VP9/Decoder.h28
-rw-r--r--Userland/Libraries/LibVideo/VP9/Parser.cpp102
-rw-r--r--Userland/Libraries/LibVideo/VP9/Parser.h12
5 files changed, 220 insertions, 214 deletions
diff --git a/Userland/Libraries/LibVideo/VP9/Context.h b/Userland/Libraries/LibVideo/VP9/Context.h
index ae468c9529..042ab1bef2 100644
--- a/Userland/Libraries/LibVideo/VP9/Context.h
+++ b/Userland/Libraries/LibVideo/VP9/Context.h
@@ -243,6 +243,14 @@ enum class FrameShowMode {
DoNotShowFrame,
};
+struct ColorConfig {
+ u8 bit_depth { 8 };
+ ColorSpace color_space { ColorSpace::Bt601 };
+ ColorRange color_range { ColorRange::Studio };
+ bool subsampling_x { true };
+ bool subsampling_y { true };
+};
+
struct FrameContext {
public:
u8 profile { 0 };
@@ -258,6 +266,8 @@ public:
}
u8 existing_frame_index() const { return m_existing_frame_index; }
+ ColorConfig color_config {};
+
Gfx::Size<u32> size() const { return m_size; }
ErrorOr<void> set_size(Gfx::Size<u32> size)
{
diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.cpp b/Userland/Libraries/LibVideo/VP9/Decoder.cpp
index a585e2779d..25a467ddf5 100644
--- a/Userland/Libraries/LibVideo/VP9/Decoder.cpp
+++ b/Userland/Libraries/LibVideo/VP9/Decoder.cpp
@@ -77,6 +77,65 @@ DecoderErrorOr<void> Decoder::decode_frame(ReadonlyBytes frame_data)
return {};
}
+inline CodingIndependentCodePoints get_cicp_color_space(FrameContext const& frame_context)
+{
+ ColorPrimaries color_primaries;
+ TransferCharacteristics transfer_characteristics;
+ MatrixCoefficients matrix_coefficients;
+
+ switch (frame_context.color_config.color_space) {
+ case ColorSpace::Unknown:
+ color_primaries = ColorPrimaries::Unspecified;
+ transfer_characteristics = TransferCharacteristics::Unspecified;
+ matrix_coefficients = MatrixCoefficients::Unspecified;
+ break;
+ case ColorSpace::Bt601:
+ color_primaries = ColorPrimaries::BT601;
+ transfer_characteristics = TransferCharacteristics::BT601;
+ matrix_coefficients = MatrixCoefficients::BT601;
+ break;
+ case ColorSpace::Bt709:
+ color_primaries = ColorPrimaries::BT709;
+ transfer_characteristics = TransferCharacteristics::BT709;
+ matrix_coefficients = MatrixCoefficients::BT709;
+ break;
+ case ColorSpace::Smpte170:
+ // https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/pixfmt-007.html#colorspace-smpte-170m-v4l2-colorspace-smpte170m
+ color_primaries = ColorPrimaries::BT601;
+ transfer_characteristics = TransferCharacteristics::BT709;
+ matrix_coefficients = MatrixCoefficients::BT601;
+ break;
+ case ColorSpace::Smpte240:
+ color_primaries = ColorPrimaries::SMPTE240;
+ transfer_characteristics = TransferCharacteristics::SMPTE240;
+ matrix_coefficients = MatrixCoefficients::SMPTE240;
+ break;
+ case ColorSpace::Bt2020:
+ color_primaries = ColorPrimaries::BT2020;
+ // Bit depth doesn't actually matter to our transfer functions since we
+ // convert in floats of range 0-1 (for now?), but just for correctness set
+ // the TC to match the bit depth here.
+ if (frame_context.color_config.bit_depth == 12)
+ transfer_characteristics = TransferCharacteristics::BT2020BitDepth12;
+ else if (frame_context.color_config.bit_depth == 10)
+ transfer_characteristics = TransferCharacteristics::BT2020BitDepth10;
+ else
+ transfer_characteristics = TransferCharacteristics::BT709;
+ matrix_coefficients = MatrixCoefficients::BT2020NonConstantLuminance;
+ break;
+ case ColorSpace::RGB:
+ color_primaries = ColorPrimaries::BT709;
+ transfer_characteristics = TransferCharacteristics::Linear;
+ matrix_coefficients = MatrixCoefficients::Identity;
+ break;
+ case ColorSpace::Reserved:
+ VERIFY_NOT_REACHED();
+ break;
+ }
+
+ return { color_primaries, transfer_characteristics, matrix_coefficients, frame_context.color_config.color_range };
+}
+
DecoderErrorOr<void> Decoder::create_video_frame(FrameContext const& frame_context)
{
// (8.9) Output process
@@ -87,10 +146,10 @@ DecoderErrorOr<void> Decoder::create_video_frame(FrameContext const& frame_conte
// sizes, as the spec seems to prefer that the halved sizes be ceiled.
u32 decoded_y_width = frame_context.columns() * 8;
Gfx::Size<u32> output_y_size = frame_context.size();
- auto decoded_uv_width = decoded_y_width >> m_parser->m_subsampling_x;
+ auto decoded_uv_width = decoded_y_width >> frame_context.color_config.subsampling_x;
Gfx::Size<u32> output_uv_size = {
- output_y_size.width() >> m_parser->m_subsampling_x,
- output_y_size.height() >> m_parser->m_subsampling_y,
+ output_y_size.width() >> frame_context.color_config.subsampling_x,
+ output_y_size.height() >> frame_context.color_config.subsampling_y,
};
Array<FixedArray<u16>, 3> output_buffers = {
DECODER_TRY_ALLOC(FixedArray<u16>::try_create(output_y_size.width() * output_y_size.height())),
@@ -113,8 +172,8 @@ DecoderErrorOr<void> Decoder::create_video_frame(FrameContext const& frame_conte
auto frame = DECODER_TRY_ALLOC(adopt_nonnull_own_or_enomem(new (nothrow) SubsampledYUVFrame(
{ output_y_size.width(), output_y_size.height() },
- m_parser->m_bit_depth, get_cicp_color_space(),
- m_parser->m_subsampling_x, m_parser->m_subsampling_y,
+ frame_context.color_config.bit_depth, get_cicp_color_space(frame_context),
+ frame_context.color_config.subsampling_x, frame_context.color_config.subsampling_y,
output_buffers[0], output_buffers[1], output_buffers[2])));
m_video_frame_queue.enqueue(move(frame));
@@ -148,65 +207,6 @@ Vector<u16>& Decoder::get_output_buffer(u8 plane)
return m_output_buffers[plane];
}
-inline CodingIndependentCodePoints Decoder::get_cicp_color_space()
-{
- ColorPrimaries color_primaries;
- TransferCharacteristics transfer_characteristics;
- MatrixCoefficients matrix_coefficients;
-
- switch (m_parser->m_color_space) {
- case ColorSpace::Unknown:
- color_primaries = ColorPrimaries::Unspecified;
- transfer_characteristics = TransferCharacteristics::Unspecified;
- matrix_coefficients = MatrixCoefficients::Unspecified;
- break;
- case ColorSpace::Bt601:
- color_primaries = ColorPrimaries::BT601;
- transfer_characteristics = TransferCharacteristics::BT601;
- matrix_coefficients = MatrixCoefficients::BT601;
- break;
- case ColorSpace::Bt709:
- color_primaries = ColorPrimaries::BT709;
- transfer_characteristics = TransferCharacteristics::BT709;
- matrix_coefficients = MatrixCoefficients::BT709;
- break;
- case ColorSpace::Smpte170:
- // https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/pixfmt-007.html#colorspace-smpte-170m-v4l2-colorspace-smpte170m
- color_primaries = ColorPrimaries::BT601;
- transfer_characteristics = TransferCharacteristics::BT709;
- matrix_coefficients = MatrixCoefficients::BT601;
- break;
- case ColorSpace::Smpte240:
- color_primaries = ColorPrimaries::SMPTE240;
- transfer_characteristics = TransferCharacteristics::SMPTE240;
- matrix_coefficients = MatrixCoefficients::SMPTE240;
- break;
- case ColorSpace::Bt2020:
- color_primaries = ColorPrimaries::BT2020;
- // Bit depth doesn't actually matter to our transfer functions since we
- // convert in floats of range 0-1 (for now?), but just for correctness set
- // the TC to match the bit depth here.
- if (m_parser->m_bit_depth == 12)
- transfer_characteristics = TransferCharacteristics::BT2020BitDepth12;
- else if (m_parser->m_bit_depth == 10)
- transfer_characteristics = TransferCharacteristics::BT2020BitDepth10;
- else
- transfer_characteristics = TransferCharacteristics::BT709;
- matrix_coefficients = MatrixCoefficients::BT2020NonConstantLuminance;
- break;
- case ColorSpace::RGB:
- color_primaries = ColorPrimaries::BT709;
- transfer_characteristics = TransferCharacteristics::Linear;
- matrix_coefficients = MatrixCoefficients::Identity;
- break;
- case ColorSpace::Reserved:
- VERIFY_NOT_REACHED();
- break;
- }
-
- return { color_primaries, transfer_characteristics, matrix_coefficients, m_parser->m_color_range };
-}
-
DecoderErrorOr<NonnullOwnPtr<VideoFrame>> Decoder::get_decoded_frame()
{
if (m_video_frame_queue.is_empty())
@@ -367,8 +367,8 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_
// If plane is greater than 0, then:
// − maxX is set equal to ((MiCols * 8) >> subsampling_x) - 1.
// − maxY is set equal to ((MiRows * 8) >> subsampling_y) - 1.
- auto subsampling_x = plane > 0 ? m_parser->m_subsampling_x : false;
- auto subsampling_y = plane > 0 ? m_parser->m_subsampling_y : false;
+ auto subsampling_x = plane > 0 ? block_context.frame_context.color_config.subsampling_x : false;
+ auto subsampling_y = plane > 0 ? block_context.frame_context.color_config.subsampling_y : false;
auto max_x = ((block_context.frame_context.columns() * 8u) >> subsampling_x) - 1u;
auto max_y = ((block_context.frame_context.rows() * 8u) >> subsampling_y) - 1u;
@@ -397,7 +397,7 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_
// NOTE: This value is pre-calculated since it is reused in spec below.
// Use this to replace spec text "(1<<(BitDepth-1))".
- Intermediate half_sample_value = (1 << (m_parser->m_bit_depth - 1));
+ Intermediate half_sample_value = (1 << (block_context.frame_context.color_config.bit_depth - 1));
// The array aboveRow[ i ] for i = 0..size-1 is specified by:
if (!have_above) {
@@ -594,7 +594,7 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_
// for i = 0..size-1, for j = 0..size-1.
for (auto i = 0u; i < block_size; i++) {
for (auto j = 0u; j < block_size; j++)
- predicted_sample_at(i, j) = clip_1(m_parser->m_bit_depth, above_row_at(j) + left_column[i] - above_row_at(-1));
+ predicted_sample_at(i, j) = clip_1(block_context.frame_context.color_config.bit_depth, above_row_at(j) + left_column[i] - above_row_at(-1));
}
break;
case PredictionMode::DcPred: {
@@ -643,7 +643,7 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_
} else {
// Otherwise (mode is DC_PRED),
// pred[ i ][ j ] is set equal to 1<<(BitDepth - 1) with i = 0..size-1 and j = 0..size-1.
- average = 1 << (m_parser->m_bit_depth - 1);
+ average = 1 << (block_context.frame_context.color_config.bit_depth - 1);
}
// pred[ i ][ j ] is set equal to avg with i = 0..size-1 and j = 0..size-1.
@@ -707,22 +707,22 @@ MotionVector Decoder::select_motion_vector(u8 plane, BlockContext const& block_c
return m_parser->m_block_mvs[ref_list][block_index];
// − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 0, mv is set equal to
// BlockMvs[ refList ][ blockIdx ].
- if (!m_parser->m_subsampling_x && !m_parser->m_subsampling_y)
+ if (!block_context.frame_context.color_config.subsampling_x && !block_context.frame_context.color_config.subsampling_y)
return m_parser->m_block_mvs[ref_list][block_index];
// − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 1, mv[ comp ] is set equal to
// round_mv_comp_q2( BlockMvs[ refList ][ blockIdx ][ comp ] + BlockMvs[ refList ][ blockIdx + 2 ][ comp ] )
// for comp = 0..1.
- if (!m_parser->m_subsampling_x && m_parser->m_subsampling_y)
+ if (!block_context.frame_context.color_config.subsampling_x && block_context.frame_context.color_config.subsampling_y)
return round_mv_comp_q2(m_parser->m_block_mvs[ref_list][block_index] + m_parser->m_block_mvs[ref_list][block_index + 2]);
// − Otherwise, if subsampling_x is equal to 1 and subsampling_y is equal to 0, mv[ comp ] is set equal to
// round_mv_comp_q2( BlockMvs[ refList ][ blockIdx ][ comp ] + BlockMvs[ refList ][ blockIdx + 1 ][ comp ] )
// for comp = 0..1.
- if (m_parser->m_subsampling_x && !m_parser->m_subsampling_y)
+ if (block_context.frame_context.color_config.subsampling_x && !block_context.frame_context.color_config.subsampling_y)
return round_mv_comp_q2(m_parser->m_block_mvs[ref_list][block_index] + m_parser->m_block_mvs[ref_list][block_index + 1]);
// − Otherwise, (subsampling_x is equal to 1 and subsampling_y is equal to 1), mv[ comp ] is set equal to
// round_mv_comp_q4( BlockMvs[ refList ][ 0 ][ comp ] + BlockMvs[ refList ][ 1 ][ comp ] +
// BlockMvs[ refList ][ 2 ][ comp ] + BlockMvs[ refList ][ 3 ][ comp ] ) for comp = 0..1.
- VERIFY(m_parser->m_subsampling_x && m_parser->m_subsampling_y);
+ VERIFY(block_context.frame_context.color_config.subsampling_x && block_context.frame_context.color_config.subsampling_y);
return round_mv_comp_q4(m_parser->m_block_mvs[ref_list][0] + m_parser->m_block_mvs[ref_list][1]
+ m_parser->m_block_mvs[ref_list][2] + m_parser->m_block_mvs[ref_list][3]);
}
@@ -736,8 +736,8 @@ MotionVector Decoder::clamp_motion_vector(u8 plane, BlockContext const& block_co
// The variables sx and sy are set equal to the subsampling for the current plane as follows:
// − If plane is equal to 0, sx is set equal to 0 and sy is set equal to 0.
// − Otherwise, sx is set equal to subsampling_x and sy is set equal to subsampling_y.
- bool subsampling_x = plane > 0 ? m_parser->m_subsampling_x : false;
- bool subsampling_y = plane > 0 ? m_parser->m_subsampling_y : false;
+ bool subsampling_x = plane > 0 ? block_context.frame_context.color_config.subsampling_x : false;
+ bool subsampling_y = plane > 0 ? block_context.frame_context.color_config.subsampling_y : false;
// The output array clampedMv is specified by the following steps:
i32 blocks_high = num_8x8_blocks_high_lookup[block_context.size];
@@ -823,8 +823,8 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
// The variable lumaY is set equal to (plane > 0) ? y << subsampling_y : y.
// (lumaX and lumaY specify the location of the block to be predicted in the current frame in units of luma
// samples.)
- bool subsampling_x = plane > 0 ? m_parser->m_subsampling_x : false;
- bool subsampling_y = plane > 0 ? m_parser->m_subsampling_y : false;
+ bool subsampling_x = plane > 0 ? block_context.frame_context.color_config.subsampling_x : false;
+ bool subsampling_y = plane > 0 ? block_context.frame_context.color_config.subsampling_y : false;
i32 luma_x = x << subsampling_x;
i32 luma_y = y << subsampling_y;
@@ -909,7 +909,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
clip_3(0, scaled_right, (samples_start >> 4) + static_cast<i32>(t) - 3));
accumulated_samples += subpel_filters[m_parser->m_interp_filter][samples_start & 15][t] * sample;
}
- intermediate_buffer_at(row, column) = clip_1(m_parser->m_bit_depth, round_2(accumulated_samples, 7));
+ intermediate_buffer_at(row, column) = clip_1(block_context.frame_context.color_config.bit_depth, round_2(accumulated_samples, 7));
}
}
@@ -922,7 +922,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
auto sample = intermediate_buffer_at((samples_start >> 4) + t, column);
accumulated_samples += subpel_filters[m_parser->m_interp_filter][samples_start & 15][t] * sample;
}
- block_buffer_at(row, column) = clip_1(m_parser->m_bit_depth, round_2(accumulated_samples, 7));
+ block_buffer_at(row, column) = clip_1(block_context.frame_context.color_config.bit_depth, round_2(accumulated_samples, 7));
}
}
@@ -958,8 +958,8 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, BlockContext const& block_
// The inter predicted samples are then derived as follows:
auto& frame_buffer = get_output_buffer(plane);
VERIFY(!frame_buffer.is_empty());
- auto frame_width = (block_context.frame_context.columns() * 8u) >> (plane > 0 ? m_parser->m_subsampling_x : false);
- auto frame_height = (block_context.frame_context.rows() * 8u) >> (plane > 0 ? m_parser->m_subsampling_y : false);
+ auto frame_width = (block_context.frame_context.columns() * 8u) >> (plane > 0 ? block_context.frame_context.color_config.subsampling_x : false);
+ auto frame_height = (block_context.frame_context.rows() * 8u) >> (plane > 0 ? block_context.frame_context.color_config.subsampling_y : false);
auto frame_buffer_at = [&](u32 row, u32 column) -> u16& {
return frame_buffer[row * frame_width + column];
};
@@ -992,7 +992,7 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, BlockContext const& block_
return {};
}
-u16 Decoder::dc_q(u8 b)
+u16 Decoder::dc_q(u8 bit_depth, u8 b)
{
// The function dc_q( b ) is specified as dc_qlookup[ (BitDepth-8) >> 1 ][ Clip3( 0, 255, b ) ] where dc_lookup is
// defined as follows:
@@ -1002,10 +1002,10 @@ u16 Decoder::dc_q(u8 b)
{ 4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91, 103, 115, 127, 140, 153, 166, 180, 194, 208, 222, 237, 251, 266, 281, 296, 312, 327, 343, 358, 374, 390, 405, 421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580, 596, 611, 627, 643, 659, 674, 690, 706, 721, 737, 752, 768, 783, 798, 814, 829, 844, 859, 874, 889, 904, 919, 934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122, 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234, 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, 1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741, 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199, 2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788, 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517, 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420, 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517, 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149, 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867, 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788, 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245, 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409, 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387 }
};
- return dc_qlookup[(m_parser->m_bit_depth - 8) >> 1][clip_3<u8>(0, 255, b)];
+ return dc_qlookup[(bit_depth - 8) >> 1][clip_3<u8>(0, 255, b)];
}
-u16 Decoder::ac_q(u8 b)
+u16 Decoder::ac_q(u8 bit_depth, u8 b)
{
// The function ac_q( b ) is specified as ac_qlookup[ (BitDepth-8) >> 1 ][ Clip3( 0, 255, b ) ] where ac_lookup is
// defined as follows:
@@ -1015,7 +1015,7 @@ u16 Decoder::ac_q(u8 b)
{ 4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99, 112, 126, 139, 154, 168, 183, 199, 214, 230, 247, 263, 280, 297, 314, 331, 349, 366, 384, 402, 420, 438, 456, 475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660, 679, 698, 716, 735, 753, 772, 791, 809, 828, 846, 865, 884, 902, 920, 939, 957, 976, 994, 1012, 1030, 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317, 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457, 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, 1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118, 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750, 2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619, 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791, 4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410, 6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635, 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, 11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565, 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806, 16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, 21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247 }
};
- return ac_qlookup[(m_parser->m_bit_depth - 8) >> 1][clip_3<u8>(0, 255, b)];
+ return ac_qlookup[(bit_depth - 8) >> 1][clip_3<u8>(0, 255, b)];
}
u8 Decoder::get_qindex()
@@ -1039,7 +1039,7 @@ u8 Decoder::get_qindex()
return m_parser->m_base_q_idx;
}
-u16 Decoder::get_dc_quant(u8 plane)
+u16 Decoder::get_dc_quant(u8 bit_depth, u8 plane)
{
// The function get_dc_quant( plane ) returns the quantizer value for the dc coefficient for a particular plane and
// is derived as follows:
@@ -1047,10 +1047,10 @@ u16 Decoder::get_dc_quant(u8 plane)
// − Otherwise, return dc_q( get_qindex( ) + delta_q_uv_dc ).
// Instead of if { return }, select the value to add and return.
i8 offset = plane == 0 ? m_parser->m_delta_q_y_dc : m_parser->m_delta_q_uv_dc;
- return dc_q(static_cast<u8>(get_qindex() + offset));
+ return dc_q(bit_depth, static_cast<u8>(get_qindex() + offset));
}
-u16 Decoder::get_ac_quant(u8 plane)
+u16 Decoder::get_ac_quant(u8 bit_depth, u8 plane)
{
// The function get_ac_quant( plane ) returns the quantizer value for the ac coefficient for a particular plane and
// is derived as follows:
@@ -1058,7 +1058,7 @@ u16 Decoder::get_ac_quant(u8 plane)
// − Otherwise, return ac_q( get_qindex( ) + delta_q_uv_ac ).
// Instead of if { return }, select the value to add and return.
i8 offset = plane == 0 ? 0 : m_parser->m_delta_q_uv_ac;
- return ac_q(static_cast<u8>(get_qindex() + offset));
+ return ac_q(bit_depth, static_cast<u8>(get_qindex() + offset));
}
DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_context, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size)
@@ -1075,7 +1075,7 @@ DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_co
// 1. Dequant[ i ][ j ] is set equal to ( Tokens[ i * n0 + j ] * get_ac_quant( plane ) ) / dqDenom
// for i = 0..(n0-1), for j = 0..(n0-1)
Array<Intermediate, maximum_transform_size> dequantized;
- Intermediate ac_quant = get_ac_quant(plane);
+ Intermediate ac_quant = get_ac_quant(block_context.frame_context.color_config.bit_depth, plane);
for (auto i = 0u; i < block_size; i++) {
for (auto j = 0u; j < block_size; j++) {
auto index = index_from_row_and_column(i, j, block_size);
@@ -1086,22 +1086,22 @@ DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_co
}
// 2. Dequant[ 0 ][ 0 ] is set equal to ( Tokens[ 0 ] * get_dc_quant( plane ) ) / dqDenom
- dequantized[0] = (m_parser->m_tokens[0] * get_dc_quant(plane)) / dq_denominator;
+ dequantized[0] = (m_parser->m_tokens[0] * get_dc_quant(block_context.frame_context.color_config.bit_depth, plane)) / dq_denominator;
// 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(dequantized[i]));
+ VERIFY(check_intermediate_bounds(block_context.frame_context.color_config.bit_depth, dequantized[i]));
// 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.
- TRY(inverse_transform_2d(dequantized, log2_of_block_size));
+ TRY(inverse_transform_2d(block_context.frame_context.color_config.bit_depth, dequantized, log2_of_block_size));
// 4. CurrFrame[ plane ][ y + i ][ x + j ] is set equal to Clip1( CurrFrame[ plane ][ y + i ][ x + j ] + Dequant[ i ][ j ] )
// for i = 0..(n0-1) and j = 0..(n0-1).
auto& current_buffer = get_output_buffer(plane);
- auto subsampling_x = (plane > 0 ? m_parser->m_subsampling_x : 0);
- auto subsampling_y = (plane > 0 ? m_parser->m_subsampling_y : 0);
+ auto subsampling_x = (plane > 0 ? block_context.frame_context.color_config.subsampling_x : 0);
+ auto subsampling_y = (plane > 0 ? block_context.frame_context.color_config.subsampling_y : 0);
auto frame_width = (block_context.frame_context.columns() * 8) >> subsampling_x;
auto frame_height = (block_context.frame_context.rows() * 8) >> subsampling_y;
auto width_in_frame_buffer = min(block_size, frame_width - transform_block_x);
@@ -1111,7 +1111,7 @@ DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_co
for (auto j = 0u; j < width_in_frame_buffer; j++) {
auto index = index_from_row_and_column(transform_block_y + i, transform_block_x + j, frame_width);
auto dequantized_value = dequantized[index_from_row_and_column(i, j, block_size)];
- current_buffer[index] = clip_1(m_parser->m_bit_depth, current_buffer[index] + dequantized_value);
+ current_buffer[index] = clip_1(block_context.frame_context.color_config.bit_depth, current_buffer[index] + dequantized_value);
}
}
@@ -1169,14 +1169,14 @@ inline bool check_bounds(i64 value, u8 bits)
return value >= ~maximum && value <= maximum;
}
-inline bool Decoder::check_intermediate_bounds(Intermediate value)
+inline bool Decoder::check_intermediate_bounds(u8 bit_depth, Intermediate value)
{
- i32 maximum = (1 << (8 + m_parser->m_bit_depth - 1)) - 1;
+ 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(Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip)
+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)
{
auto cos = cos64(angle);
auto sin = sin64(angle);
@@ -1197,12 +1197,12 @@ inline void Decoder::butterfly_rotation_in_place(Span<Intermediate> data, size_t
// 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(data[index_a]));
- VERIFY(check_intermediate_bounds(data[index_b]));
+ VERIFY(check_intermediate_bounds(bit_depth, data[index_a]));
+ VERIFY(check_intermediate_bounds(bit_depth, data[index_b]));
}
// (8.7.1.1) The function H( a, b, 0 ) performs a Hadamard rotation.
-inline void Decoder::hadamard_rotation_in_place(Span<Intermediate> data, size_t index_a, size_t index_b, bool flip)
+inline void Decoder::hadamard_rotation_in_place(u8 bit_depth, 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.
@@ -1222,8 +1222,8 @@ inline void Decoder::hadamard_rotation_in_place(Span<Intermediate> data, size_t
// 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(data[index_a]));
- VERIFY(check_intermediate_bounds(data[index_b]));
+ VERIFY(check_intermediate_bounds(bit_depth, data[index_a]));
+ VERIFY(check_intermediate_bounds(bit_depth, data[index_b]));
}
inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform_array_permutation(Span<Intermediate> data, u8 log2_of_block_size)
@@ -1246,7 +1246,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform_array_per
return {};
}
-inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Intermediate> data, u8 log2_of_block_size)
+inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(u8 bit_depth, 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;
@@ -1263,14 +1263,14 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
// 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(data, 0, 1, 16, true);
+ butterfly_rotation_in_place(bit_depth, data, 0, 1, 16, true);
else
- TRY(inverse_discrete_cosine_transform(data, log2_of_block_size - 1));
+ TRY(inverse_discrete_cosine_transform(bit_depth, 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(data, index, block_size - 1 - i, 32 - brev(5, index), false);
+ butterfly_rotation_in_place(bit_depth, data, index, block_size - 1 - i, 32 - brev(5, index), false);
}
// 2.7 If n is greater than or equal to 3:
@@ -1279,7 +1279,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index, index + 1, j);
+ hadamard_rotation_in_place(bit_depth, data, index, index + 1, j);
}
}
}
@@ -1292,7 +1292,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index_a, index_b, angle, true);
+ butterfly_rotation_in_place(bit_depth, data, index_a, index_b, angle, true);
}
}
@@ -1301,7 +1301,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index_a, index_b, (j & 1) != 0);
+ hadamard_rotation_in_place(bit_depth, data, index_a, index_b, (j & 1) != 0);
}
}
}
@@ -1313,7 +1313,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index_a, index_b, 24 + (48 * j), true);
+ butterfly_rotation_in_place(bit_depth, data, index_a, index_b, 24 + (48 * j), true);
}
}
@@ -1322,7 +1322,7 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index_a, index_b, (j & 1) != 0);
+ hadamard_rotation_in_place(bit_depth, data, index_a, index_b, (j & 1) != 0);
}
}
}
@@ -1333,13 +1333,13 @@ inline DecoderErrorOr<void> Decoder::inverse_discrete_cosine_transform(Span<Inte
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(data, index_a, index_b, 16, true);
+ butterfly_rotation_in_place(bit_depth, 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(data, i, block_size - 1 - i, false);
+ hadamard_rotation_in_place(bit_depth, data, i, block_size - 1 - i, false);
return {};
}
@@ -1393,7 +1393,7 @@ inline void Decoder::inverse_asymmetric_discrete_sine_transform_output_array_per
}
}
-inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(Span<Intermediate> data)
+inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(u8 bit_depth, Span<Intermediate> data)
{
VERIFY(data.size() == 4);
const i64 sinpi_1_9 = 5283;
@@ -1450,7 +1450,7 @@ inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(Span<Intermedi
// (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 + m_parser->m_bit_depth;
+ const u8 bits = 24 + bit_depth;
VERIFY(check_bounds(data[0], bits));
VERIFY(check_bounds(data[1], bits));
VERIFY(check_bounds(data[2], bits));
@@ -1494,7 +1494,7 @@ 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(Span<Intermediate> data)
+inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_8(u8 bit_depth, Span<Intermediate> data)
{
VERIFY(data.size() == 8);
// This process does an in-place transform of the array T using:
@@ -1513,7 +1513,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
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 + m_parser->m_bit_depth;
+ 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.
@@ -1532,11 +1532,11 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 6. Invoke H( i, 2+i, 0 ) for i = 0..1.
for (auto i = 0u; i < 2; i++)
- hadamard_rotation_in_place(data, i, 2 + i, false);
+ hadamard_rotation_in_place(bit_depth, 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(data, 2 + (4 * i), 3 + (4 * i), 16, true);
+ butterfly_rotation_in_place(bit_depth, 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.
@@ -1550,7 +1550,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
return {};
}
-inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_16(Span<Intermediate> data)
+inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_16(u8 bit_depth, Span<Intermediate> data)
{
VERIFY(data.size() == 16);
// This process does an in-place transform of the array T using:
@@ -1570,7 +1570,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// (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 + m_parser->m_bit_depth;
+ 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.
@@ -1589,7 +1589,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
// 6. Invoke H( i, 4+i, 0 ) for i = 0..3.
for (auto i = 0u; i < 4; i++)
- hadamard_rotation_in_place(data, i, 4 + i, false);
+ hadamard_rotation_in_place(bit_depth, 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++)
@@ -1606,11 +1606,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(data, (8 * j) + i, 2 + (8 * j) + i, false);
+ hadamard_rotation_in_place(bit_depth, 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(data, 2 + (4 * j) + (8 * i), 3 + (4 * j) + (8 * i), 48 + (64 * (i ^ j)), false);
+ butterfly_rotation_in_place(bit_depth, 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.
@@ -1626,7 +1626,7 @@ inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform_
return {};
}
-inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform(Span<Intermediate> data, u8 log2_of_block_size)
+inline DecoderErrorOr<void> Decoder::inverse_asymmetric_discrete_sine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size)
{
// 8.7.1.9 Inverse ADST Process
@@ -1637,18 +1637,18 @@ 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(data);
+ inverse_asymmetric_discrete_sine_transform_4(bit_depth, 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(data);
+ return inverse_asymmetric_discrete_sine_transform_8(bit_depth, 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(data);
+ return inverse_asymmetric_discrete_sine_transform_16(bit_depth, data);
}
-DecoderErrorOr<void> Decoder::inverse_transform_2d(Span<Intermediate> dequantized, u8 log2_of_block_size)
+DecoderErrorOr<void> Decoder::inverse_transform_2d(u8 bit_depth, Span<Intermediate> dequantized, u8 log2_of_block_size)
{
// This process performs a 2D inverse transform for an array of size 2^n by 2^n stored in the 2D array Dequant.
// The input to this process is a variable n (log2_of_block_size) that specifies the base 2 logarithm of the width of the transform.
@@ -1679,13 +1679,13 @@ DecoderErrorOr<void> Decoder::inverse_transform_2d(Span<Intermediate> dequantize
// 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(row, log2_of_block_size));
+ TRY(inverse_discrete_cosine_transform(bit_depth, row, log2_of_block_size));
break;
case DCT_ADST:
case ADST_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(row, log2_of_block_size));
+ TRY(inverse_asymmetric_discrete_sine_transform(bit_depth, row, log2_of_block_size));
break;
default:
return DecoderError::corrupted("Unknown tx_type"sv);
@@ -1719,13 +1719,13 @@ DecoderErrorOr<void> Decoder::inverse_transform_2d(Span<Intermediate> dequantize
// 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(column, log2_of_block_size));
+ TRY(inverse_discrete_cosine_transform(bit_depth, column, log2_of_block_size));
break;
case ADST_DCT:
case ADST_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(column, log2_of_block_size));
+ TRY(inverse_asymmetric_discrete_sine_transform(bit_depth, column, log2_of_block_size));
break;
default:
VERIFY_NOT_REACHED();
@@ -1764,11 +1764,11 @@ DecoderErrorOr<void> Decoder::update_reference_frames(FrameContext const& frame_
// − RefFrameHeight[ i ] is set equal to FrameHeight.
m_parser->m_ref_frame_size[i] = frame_context.size();
// − RefSubsamplingX[ i ] is set equal to subsampling_x.
- m_parser->m_ref_subsampling_x[i] = m_parser->m_subsampling_x;
+ m_parser->m_ref_subsampling_x[i] = frame_context.color_config.subsampling_x;
// − RefSubsamplingY[ i ] is set equal to subsampling_y.
- m_parser->m_ref_subsampling_y[i] = m_parser->m_subsampling_y;
+ m_parser->m_ref_subsampling_y[i] = frame_context.color_config.subsampling_y;
// − RefBitDepth[ i ] is set equal to BitDepth.
- m_parser->m_ref_bit_depth[i] = m_parser->m_bit_depth;
+ m_parser->m_ref_bit_depth[i] = frame_context.color_config.bit_depth;
// − FrameStore[ i ][ 0 ][ y ][ x ] is set equal to CurrFrame[ 0 ][ y ][ x ] for x = 0..FrameWidth-1, for y =
// 0..FrameHeight-1.
@@ -1784,9 +1784,9 @@ DecoderErrorOr<void> Decoder::update_reference_frames(FrameContext const& frame_
auto stride = frame_context.columns() * 8;
if (plane > 0) {
- width = (width + m_parser->m_subsampling_x) >> m_parser->m_subsampling_x;
- height = (height + m_parser->m_subsampling_y) >> m_parser->m_subsampling_y;
- stride >>= m_parser->m_subsampling_x;
+ width = (width + frame_context.color_config.subsampling_x) >> frame_context.color_config.subsampling_x;
+ height = (height + frame_context.color_config.subsampling_y) >> frame_context.color_config.subsampling_y;
+ stride >>= frame_context.color_config.subsampling_x;
}
auto original_buffer = get_output_buffer(plane);
diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.h b/Userland/Libraries/LibVideo/VP9/Decoder.h
index 94543a8ee9..6bf719b0cc 100644
--- a/Userland/Libraries/LibVideo/VP9/Decoder.h
+++ b/Userland/Libraries/LibVideo/VP9/Decoder.h
@@ -74,20 +74,20 @@ private:
/* (8.6) Reconstruction and Dequantization */
// FIXME: These should be inline or constexpr
- u16 dc_q(u8 b);
- u16 ac_q(u8 b);
+ u16 dc_q(u8 bit_depth, u8 b);
+ u16 ac_q(u8 bit_depth, u8 b);
// Returns the quantizer index for the current block
u8 get_qindex();
// Returns the quantizer value for the dc coefficient for a particular plane
- u16 get_dc_quant(u8 plane);
+ u16 get_dc_quant(u8 bit_depth, u8 plane);
// Returns the quantizer value for the ac coefficient for a particular plane
- u16 get_ac_quant(u8 plane);
+ u16 get_ac_quant(u8 bit_depth, u8 plane);
// (8.6.2) Reconstruct process
DecoderErrorOr<void> reconstruct(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size);
// (8.7) Inverse transform process
- DecoderErrorOr<void> inverse_transform_2d(Span<Intermediate> dequantized, u8 log2_of_block_size);
+ DecoderErrorOr<void> inverse_transform_2d(u8 bit_depth, Span<Intermediate> dequantized, u8 log2_of_block_size);
// (8.7.1) 1D Transforms
// (8.7.1.1) Butterfly functions
@@ -95,9 +95,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(Span<Intermediate> data, size_t index_a, size_t index_b, u8 angle, bool flip);
+ inline void butterfly_rotation_in_place(u8 bit_depth, 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(Span<Intermediate> data, size_t index_a, size_t index_b, bool flip);
+ inline void hadamard_rotation_in_place(u8 bit_depth, 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>
@@ -111,7 +111,7 @@ private:
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(Intermediate value);
+ 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);
@@ -119,7 +119,7 @@ private:
// (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(Span<Intermediate> data, u8 log2_of_block_size);
+ inline DecoderErrorOr<void> inverse_discrete_cosine_transform(u8 bit_depth, 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.
@@ -129,21 +129,19 @@ 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(Span<Intermediate> data);
+ inline void inverse_asymmetric_discrete_sine_transform_4(u8 bit_depth, 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(Span<Intermediate> data);
+ inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_8(u8 bit_depth, 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(Span<Intermediate> data);
+ inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform_16(u8 bit_depth, 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(Span<Intermediate> data, u8 log2_of_block_size);
+ inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform(u8 bit_depth, Span<Intermediate> data, u8 log2_of_block_size);
/* (8.10) Reference Frame Update Process */
DecoderErrorOr<void> update_reference_frames(FrameContext const&);
- inline CodingIndependentCodePoints get_cicp_color_space();
-
NonnullOwnPtr<Parser> m_parser;
Vector<u16> m_output_buffers[3];
diff --git a/Userland/Libraries/LibVideo/VP9/Parser.cpp b/Userland/Libraries/LibVideo/VP9/Parser.cpp
index fdd1dee990..08185617d0 100644
--- a/Userland/Libraries/LibVideo/VP9/Parser.cpp
+++ b/Userland/Libraries/LibVideo/VP9/Parser.cpp
@@ -105,6 +105,7 @@ DecoderErrorOr<FrameContext> Parser::parse_frame(ReadonlyBytes frame_data)
m_previous_frame_size = frame_context.size();
m_previous_show_frame = frame_context.shows_a_frame();
+ m_previous_color_config = frame_context.color_config;
return frame_context;
}
@@ -151,6 +152,7 @@ DecoderErrorOr<ColorRange> Parser::read_color_range()
DecoderErrorOr<FrameContext> Parser::uncompressed_header()
{
FrameContext frame_context;
+ frame_context.color_config = m_previous_color_config;
auto frame_marker = TRY_READ(m_bit_stream->read_bits(2));
if (frame_marker != 2)
@@ -180,7 +182,7 @@ DecoderErrorOr<FrameContext> Parser::uncompressed_header()
if (m_frame_type == KeyFrame) {
TRY(frame_sync_code());
- TRY(color_config(frame_context));
+ frame_context.color_config = TRY(parse_color_config(frame_context));
frame_size = TRY(parse_frame_size());
render_size = TRY(parse_render_size(frame_size));
m_refresh_frame_flags = 0xFF;
@@ -196,14 +198,8 @@ DecoderErrorOr<FrameContext> Parser::uncompressed_header()
if (m_frame_is_intra) {
TRY(frame_sync_code());
- if (frame_context.profile > 0) {
- TRY(color_config(frame_context));
- } else {
- m_color_space = Bt601;
- m_subsampling_x = true;
- m_subsampling_y = true;
- m_bit_depth = 8;
- }
+
+ frame_context.color_config = frame_context.profile > 0 ? TRY(parse_color_config(frame_context)) : ColorConfig();
m_refresh_frame_flags = TRY_READ(m_bit_stream->read_f8());
frame_size = TRY(parse_frame_size());
@@ -267,39 +263,47 @@ DecoderErrorOr<void> Parser::frame_sync_code()
return {};
}
-DecoderErrorOr<void> Parser::color_config(FrameContext const& frame_context)
+DecoderErrorOr<ColorConfig> Parser::parse_color_config(FrameContext const& frame_context)
{
+ // (6.2.2) color_config( )
+ u8 bit_depth;
if (frame_context.profile >= 2) {
- m_bit_depth = TRY_READ(m_bit_stream->read_bit()) ? 12 : 10;
+ bit_depth = TRY_READ(m_bit_stream->read_bit()) ? 12 : 10;
} else {
- m_bit_depth = 8;
+ bit_depth = 8;
}
- auto color_space = TRY_READ(m_bit_stream->read_bits(3));
- VERIFY(color_space <= RGB);
- m_color_space = static_cast<ColorSpace>(color_space);
+ auto color_space = static_cast<ColorSpace>(TRY_READ(m_bit_stream->read_bits(3)));
+ VERIFY(color_space <= ColorSpace::RGB);
+
+ ColorRange color_range;
+ bool subsampling_x, subsampling_y;
- if (color_space != RGB) {
- m_color_range = TRY(read_color_range());
+ if (color_space != ColorSpace::RGB) {
+ color_range = TRY(read_color_range());
if (frame_context.profile == 1 || frame_context.profile == 3) {
- m_subsampling_x = TRY_READ(m_bit_stream->read_bit());
- m_subsampling_y = TRY_READ(m_bit_stream->read_bit());
+ subsampling_x = TRY_READ(m_bit_stream->read_bit());
+ subsampling_y = TRY_READ(m_bit_stream->read_bit());
if (TRY_READ(m_bit_stream->read_bit()))
return DecoderError::corrupted("color_config: Subsampling reserved zero was set"sv);
} else {
- m_subsampling_x = true;
- m_subsampling_y = true;
+ subsampling_x = true;
+ subsampling_y = true;
}
} else {
- m_color_range = ColorRange::Full;
+ color_range = ColorRange::Full;
if (frame_context.profile == 1 || frame_context.profile == 3) {
- m_subsampling_x = false;
- m_subsampling_y = false;
+ subsampling_x = false;
+ subsampling_y = false;
if (TRY_READ(m_bit_stream->read_bit()))
return DecoderError::corrupted("color_config: RGB reserved zero was set"sv);
+ } else {
+ // FIXME: Spec does not specify the subsampling value here. Is this an error or should we set a default?
+ VERIFY_NOT_REACHED();
}
}
- return {};
+
+ return ColorConfig { bit_depth, color_space, color_range, subsampling_x, subsampling_y };
}
DecoderErrorOr<Gfx::Size<u32>> Parser::parse_frame_size()
@@ -1286,7 +1290,7 @@ Gfx::Point<size_t> Parser::get_decoded_point_for_plane(FrameContext const& frame
(void)frame_context;
if (plane == 0)
return { column * 8, row * 8 };
- return { (column * 8) >> m_subsampling_x, (row * 8) >> m_subsampling_y };
+ return { (column * 8) >> frame_context.color_config.subsampling_x, (row * 8) >> frame_context.color_config.subsampling_y };
}
Gfx::Size<size_t> Parser::get_decoded_size_for_plane(FrameContext const& frame_context, u8 plane)
@@ -1295,18 +1299,32 @@ Gfx::Size<size_t> Parser::get_decoded_size_for_plane(FrameContext const& frame_c
return { point.x(), point.y() };
}
+static BlockSubsize get_plane_block_size(bool subsampling_x, bool subsampling_y, u32 subsize, u8 plane)
+{
+ auto sub_x = (plane > 0) ? subsampling_x : 0;
+ auto sub_y = (plane > 0) ? subsampling_y : 0;
+ return ss_size_lookup[subsize][sub_x][sub_y];
+}
+
+static TXSize get_uv_tx_size(bool subsampling_x, bool subsampling_y, TXSize tx_size, BlockSubsize size)
+{
+ if (size < Block_8x8)
+ return TX_4x4;
+ return min(tx_size, max_txsize_lookup[get_plane_block_size(subsampling_x, subsampling_y, size, 1)]);
+}
+
DecoderErrorOr<bool> Parser::residual(BlockContext& block_context, bool has_block_above, bool has_block_left)
{
bool had_residual_tokens = false;
auto block_size = block_context.size < Block_8x8 ? Block_8x8 : block_context.size;
for (u8 plane = 0; plane < 3; plane++) {
- auto tx_size = (plane > 0) ? get_uv_tx_size(block_context.size) : m_tx_size;
+ auto tx_size = (plane > 0) ? get_uv_tx_size(block_context.frame_context.color_config.subsampling_x, block_context.frame_context.color_config.subsampling_y, m_tx_size, block_context.size) : m_tx_size;
auto step = 1 << tx_size;
- auto plane_size = get_plane_block_size(block_size, plane);
+ auto plane_size = get_plane_block_size(block_context.frame_context.color_config.subsampling_x, block_context.frame_context.color_config.subsampling_y, block_size, plane);
auto num_4x4_w = num_4x4_blocks_wide_lookup[plane_size];
auto num_4x4_h = num_4x4_blocks_high_lookup[plane_size];
- auto sub_x = (plane > 0) ? m_subsampling_x : 0;
- auto sub_y = (plane > 0) ? m_subsampling_y : 0;
+ auto sub_x = (plane > 0) ? block_context.frame_context.color_config.subsampling_x : 0;
+ auto sub_y = (plane > 0) ? block_context.frame_context.color_config.subsampling_y : 0;
auto base_x = (block_context.column * 8) >> sub_x;
auto base_y = (block_context.row * 8) >> sub_y;
if (m_is_inter) {
@@ -1357,20 +1375,6 @@ DecoderErrorOr<bool> Parser::residual(BlockContext& block_context, bool has_bloc
return had_residual_tokens;
}
-TXSize Parser::get_uv_tx_size(BlockSubsize size)
-{
- if (size < Block_8x8)
- return TX_4x4;
- return min(m_tx_size, max_txsize_lookup[get_plane_block_size(size, 1)]);
-}
-
-BlockSubsize Parser::get_plane_block_size(u32 subsize, u8 plane)
-{
- auto sub_x = (plane > 0) ? m_subsampling_x : 0;
- auto sub_y = (plane > 0) ? m_subsampling_y : 0;
- return ss_size_lookup[subsize][sub_x][sub_y];
-}
-
DecoderErrorOr<bool> Parser::tokens(BlockContext& block_context, size_t plane, u32 start_x, u32 start_y, TXSize tx_size, u32 block_index)
{
u32 segment_eob = 16 << (tx_size << 1);
@@ -1380,7 +1384,7 @@ DecoderErrorOr<bool> Parser::tokens(BlockContext& block_context, size_t plane, u
for (; c < segment_eob; c++) {
auto pos = scan[c];
auto band = (tx_size == TX_4x4) ? coefband_4x4[c] : coefband_8x8plus[c];
- auto tokens_context = TreeParser::get_tokens_context(m_subsampling_x, m_subsampling_y, block_context.frame_context.rows(), block_context.frame_context.columns(), m_above_nonzero_context, m_left_nonzero_context, m_token_cache, tx_size, m_tx_type, plane, start_x, start_y, pos, m_is_inter, band, c);
+ auto tokens_context = TreeParser::get_tokens_context(block_context.frame_context.color_config.subsampling_x, block_context.frame_context.color_config.subsampling_y, block_context.frame_context.rows(), block_context.frame_context.columns(), m_above_nonzero_context, m_left_nonzero_context, m_token_cache, tx_size, m_tx_type, plane, start_x, start_y, pos, m_is_inter, band, c);
if (check_eob) {
auto more_coefs = TRY_READ(TreeParser::parse_more_coefficients(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, tokens_context));
if (!more_coefs)
@@ -1392,7 +1396,7 @@ DecoderErrorOr<bool> Parser::tokens(BlockContext& block_context, size_t plane, u
m_tokens[pos] = 0;
check_eob = false;
} else {
- i32 coef = TRY(read_coef(token));
+ i32 coef = TRY(read_coef(block_context.frame_context.color_config.bit_depth, token));
bool sign_bit = TRY_READ(m_bit_stream->read_literal(1));
m_tokens[pos] = sign_bit ? -coef : coef;
check_eob = true;
@@ -1439,15 +1443,15 @@ u32 const* Parser::get_scan(BlockContext const& block_context, size_t plane, TXS
return default_scan_32x32;
}
-DecoderErrorOr<i32> Parser::read_coef(Token token)
+DecoderErrorOr<i32> Parser::read_coef(u8 bit_depth, Token token)
{
auto cat = extra_bits[token][0];
auto num_extra = extra_bits[token][1];
u32 coef = extra_bits[token][2];
if (token == DctValCat6) {
- for (size_t e = 0; e < (u8)(m_bit_depth - 8); e++) {
+ for (size_t e = 0; e < (u8)(bit_depth - 8); e++) {
auto high_bit = TRY_READ(m_bit_stream->read_bool(255));
- coef += high_bit << (5 + m_bit_depth - e);
+ coef += high_bit << (5 + bit_depth - e);
}
}
for (size_t e = 0; e < num_extra; e++) {
diff --git a/Userland/Libraries/LibVideo/VP9/Parser.h b/Userland/Libraries/LibVideo/VP9/Parser.h
index 901cf77f57..70fe837e21 100644
--- a/Userland/Libraries/LibVideo/VP9/Parser.h
+++ b/Userland/Libraries/LibVideo/VP9/Parser.h
@@ -57,7 +57,7 @@ private:
/* (6.2) Uncompressed Header Syntax */
DecoderErrorOr<FrameContext> uncompressed_header();
DecoderErrorOr<void> frame_sync_code();
- DecoderErrorOr<void> color_config(FrameContext const&);
+ DecoderErrorOr<ColorConfig> parse_color_config(FrameContext const&);
DecoderErrorOr<void> set_frame_size_and_compute_image_size();
DecoderErrorOr<Gfx::Size<u32>> parse_frame_size();
DecoderErrorOr<Gfx::Size<u32>> parse_frame_size_with_refs();
@@ -120,11 +120,9 @@ private:
DecoderErrorOr<void> read_mv(u8 ref);
DecoderErrorOr<i32> read_mv_component(u8 component);
DecoderErrorOr<bool> residual(BlockContext&, bool has_block_above, bool has_block_left);
- TXSize get_uv_tx_size(BlockSubsize size);
- BlockSubsize get_plane_block_size(u32 subsize, u8 plane);
DecoderErrorOr<bool> tokens(BlockContext&, size_t plane, u32 x, u32 y, TXSize tx_size, u32 block_index);
u32 const* get_scan(BlockContext const&, size_t plane, TXSize tx_size, u32 block_index);
- DecoderErrorOr<i32> read_coef(Token token);
+ DecoderErrorOr<i32> read_coef(u8 bit_depth, Token token);
/* (6.5) Motion Vector Prediction */
void find_mv_refs(BlockContext&, ReferenceFrameType, i32 block);
@@ -158,14 +156,10 @@ private:
bool m_refresh_frame_context { false };
bool m_frame_parallel_decoding_mode { false };
u8 m_frame_context_idx { 0 };
- u8 m_bit_depth { 0 };
- ColorSpace m_color_space;
- ColorRange m_color_range;
- bool m_subsampling_x { false };
- bool m_subsampling_y { false };
bool m_is_first_compute_image_size_invoke { true };
Gfx::Size<u32> m_previous_frame_size { 0, 0 };
bool m_previous_show_frame { false };
+ ColorConfig m_previous_color_config;
InterpolationFilter m_interpolation_filter { 0xf };
u8 m_base_q_idx { 0 };
i8 m_delta_q_y_dc { 0 };