diff options
author | Zaggy1024 <zaggy1024@gmail.com> | 2022-11-22 19:15:38 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-11-30 08:28:30 +0100 |
commit | 40bc987fe330146f20d6950945c43cd068a927ca (patch) | |
tree | bbeed7b10c6282aab43e4559100264f4a959f10c /Userland | |
parent | 9f573264ea8f1175156c71d0524c29058946f232 (diff) | |
download | serenity-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.h | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibVideo/VP9/Decoder.cpp | 282 | ||||
-rw-r--r-- | Userland/Libraries/LibVideo/VP9/Decoder.h | 28 | ||||
-rw-r--r-- | Userland/Libraries/LibVideo/VP9/Parser.cpp | 102 | ||||
-rw-r--r-- | Userland/Libraries/LibVideo/VP9/Parser.h | 12 |
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 }; |