From f4e835635f3117d192d0c16c8f1499d750507df5 Mon Sep 17 00:00:00 2001 From: Zaggy1024 Date: Wed, 23 Nov 2022 06:26:02 -0600 Subject: [PATCH] LibVideo/VP9: Move quantizer indices into FrameContext This also renames (most?) of the related quantizer functions and variables to make more sense. I haven't determined what AC/DC stands for here, but it may be just an arbitrary naming scheme for the first and subsequent coefficients used to quantize the residuals for a block. --- Userland/Libraries/LibVideo/VP9/Context.h | 10 +++++ Userland/Libraries/LibVideo/VP9/Decoder.cpp | 44 +++++++++++---------- Userland/Libraries/LibVideo/VP9/Decoder.h | 8 ++-- Userland/Libraries/LibVideo/VP9/Parser.cpp | 21 +++++----- Userland/Libraries/LibVideo/VP9/Parser.h | 9 +---- 5 files changed, 50 insertions(+), 42 deletions(-) diff --git a/Userland/Libraries/LibVideo/VP9/Context.h b/Userland/Libraries/LibVideo/VP9/Context.h index f0808bd509..403f204324 100644 --- a/Userland/Libraries/LibVideo/VP9/Context.h +++ b/Userland/Libraries/LibVideo/VP9/Context.h @@ -311,6 +311,16 @@ public: Array loop_filter_reference_deltas; Array loop_filter_mode_deltas; + u8 base_quantizer_index { 0 }; + i8 y_dc_quantizer_index_delta { 0 }; + i8 uv_dc_quantizer_index_delta { 0 }; + i8 uv_ac_quantizer_index_delta { 0 }; + bool is_lossless() const + { + // From quantization_params( ) in the spec. + return base_quantizer_index == 0 && y_dc_quantizer_index_delta == 0 && uv_dc_quantizer_index_delta == 0 && uv_ac_quantizer_index_delta == 0; + } + u16 header_size_in_bytes { 0 }; private: diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.cpp b/Userland/Libraries/LibVideo/VP9/Decoder.cpp index d40f441feb..2168646ebc 100644 --- a/Userland/Libraries/LibVideo/VP9/Decoder.cpp +++ b/Userland/Libraries/LibVideo/VP9/Decoder.cpp @@ -1018,7 +1018,7 @@ u16 Decoder::ac_q(u8 bit_depth, u8 b) return ac_qlookup[(bit_depth - 8) >> 1][clip_3(0, 255, b)]; } -u8 Decoder::get_qindex() +u8 Decoder::get_base_quantizer_index(BlockContext const& block_context) { // The function get_qindex( ) returns the quantizer index for the current block and is specified by the following: // − If seg_feature_active( SEG_LVL_ALT_Q ) is equal to 1 the following ordered steps apply: @@ -1028,7 +1028,7 @@ u8 Decoder::get_qindex() // 2. If segmentation_abs_or_delta_update is equal to 0, set data equal to base_q_idx + data if (!m_parser->m_segmentation_abs_or_delta_update) { - data += m_parser->m_base_q_idx; + data += block_context.frame_context.base_quantizer_index; } // 3. Return Clip3( 0, 255, data ). @@ -1036,29 +1036,33 @@ u8 Decoder::get_qindex() } // − Otherwise, return base_q_idx. - return m_parser->m_base_q_idx; + return block_context.frame_context.base_quantizer_index; } -u16 Decoder::get_dc_quant(u8 bit_depth, u8 plane) +u16 Decoder::get_dc_quantizer(BlockContext const& block_context, u8 plane) { + // FIXME: The result of this function can be cached. This does not change per frame. + // The function get_dc_quant( plane ) returns the quantizer value for the dc coefficient for a particular plane and // is derived as follows: // − If plane is equal to 0, return dc_q( get_qindex( ) + delta_q_y_dc ). // − 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(bit_depth, static_cast(get_qindex() + offset)); + i8 offset = plane == 0 ? block_context.frame_context.y_dc_quantizer_index_delta : block_context.frame_context.uv_dc_quantizer_index_delta; + return dc_q(block_context.frame_context.color_config.bit_depth, static_cast(get_base_quantizer_index(block_context) + offset)); } -u16 Decoder::get_ac_quant(u8 bit_depth, u8 plane) +u16 Decoder::get_ac_quantizer(BlockContext const& block_context, u8 plane) { + // FIXME: The result of this function can be cached. This does not change per frame. + // The function get_ac_quant( plane ) returns the quantizer value for the ac coefficient for a particular plane and // is derived as follows: // − If plane is equal to 0, return ac_q( get_qindex( ) ). // − 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(bit_depth, static_cast(get_qindex() + offset)); + i8 offset = plane == 0 ? 0 : block_context.frame_context.uv_ac_quantizer_index_delta; + return ac_q(block_context.frame_context.color_config.bit_depth, static_cast(get_base_quantizer_index(block_context) + offset)); } DecoderErrorOr Decoder::reconstruct(u8 plane, BlockContext const& block_context, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size) @@ -1075,7 +1079,7 @@ DecoderErrorOr 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 dequantized; - Intermediate ac_quant = get_ac_quant(block_context.frame_context.color_config.bit_depth, plane); + Intermediate ac_quant = get_ac_quantizer(block_context, 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,7 +1090,7 @@ DecoderErrorOr 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(block_context.frame_context.color_config.bit_depth, plane)) / dq_denominator; + dequantized[0] = (m_parser->m_tokens[0] * get_dc_quantizer(block_context, 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. @@ -1095,7 +1099,7 @@ DecoderErrorOr Decoder::reconstruct(u8 plane, BlockContext const& block_co // 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(block_context.frame_context.color_config.bit_depth, dequantized, log2_of_block_size)); + TRY(inverse_transform_2d(block_context, 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). @@ -1648,7 +1652,7 @@ inline DecoderErrorOr Decoder::inverse_asymmetric_discrete_sine_transform( return inverse_asymmetric_discrete_sine_transform_16(bit_depth, data); } -DecoderErrorOr Decoder::inverse_transform_2d(u8 bit_depth, Span dequantized, u8 log2_of_block_size) +DecoderErrorOr Decoder::inverse_transform_2d(BlockContext const& block_context, Span 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. @@ -1667,7 +1671,7 @@ DecoderErrorOr Decoder::inverse_transform_2d(u8 bit_depth, Spanm_lossless) { + if (block_context.frame_context.is_lossless()) { TRY(inverse_walsh_hadamard_transform(row, log2_of_block_size, 2)); continue; } @@ -1679,13 +1683,13 @@ DecoderErrorOr Decoder::inverse_transform_2d(u8 bit_depth, Span Decoder::inverse_transform_2d(u8 bit_depth, Spanm_lossless) { + if (block_context.frame_context.is_lossless()) { TRY(inverse_walsh_hadamard_transform(column, log2_of_block_size, 2)); continue; } @@ -1719,13 +1723,13 @@ DecoderErrorOr Decoder::inverse_transform_2d(u8 bit_depth, Span Decoder::inverse_transform_2d(u8 bit_depth, Spanm_lossless) { + if (!block_context.frame_context.is_lossless()) { for (auto i = 0u; i < block_size; i++) { auto index = index_from_row_and_column(i, j, block_size); dequantized[index] = round_2(dequantized[index], min(6, log2_of_block_size + 2)); diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.h b/Userland/Libraries/LibVideo/VP9/Decoder.h index 8e33f14025..8c076db312 100644 --- a/Userland/Libraries/LibVideo/VP9/Decoder.h +++ b/Userland/Libraries/LibVideo/VP9/Decoder.h @@ -77,17 +77,17 @@ private: 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(); + u8 get_base_quantizer_index(BlockContext const&); // Returns the quantizer value for the dc coefficient for a particular plane - u16 get_dc_quant(u8 bit_depth, u8 plane); + u16 get_dc_quantizer(BlockContext const&, u8 plane); // Returns the quantizer value for the ac coefficient for a particular plane - u16 get_ac_quant(u8 bit_depth, u8 plane); + u16 get_ac_quantizer(BlockContext const&, u8 plane); // (8.6.2) Reconstruct process DecoderErrorOr reconstruct(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size); // (8.7) Inverse transform process - DecoderErrorOr inverse_transform_2d(u8 bit_depth, Span dequantized, u8 log2_of_block_size); + DecoderErrorOr inverse_transform_2d(BlockContext const&, Span dequantized, u8 log2_of_block_size); // (8.7.1) 1D Transforms // (8.7.1.1) Butterfly functions diff --git a/Userland/Libraries/LibVideo/VP9/Parser.cpp b/Userland/Libraries/LibVideo/VP9/Parser.cpp index b77b6217f7..fba379a2f2 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.cpp +++ b/Userland/Libraries/LibVideo/VP9/Parser.cpp @@ -261,7 +261,7 @@ DecoderErrorOr Parser::uncompressed_header() frame_context.probability_context_index = probability_context_index; TRY(loop_filter_params(frame_context)); - TRY(quantization_params()); + TRY(quantization_params(frame_context)); TRY(segmentation_params()); TRY(tile_info(frame_context)); @@ -418,13 +418,12 @@ DecoderErrorOr Parser::loop_filter_params(FrameContext& frame_context) return {}; } -DecoderErrorOr Parser::quantization_params() +DecoderErrorOr Parser::quantization_params(FrameContext& frame_context) { - m_base_q_idx = TRY_READ(m_bit_stream->read_f8()); - m_delta_q_y_dc = TRY(read_delta_q()); - m_delta_q_uv_dc = TRY(read_delta_q()); - m_delta_q_uv_ac = TRY(read_delta_q()); - m_lossless = m_base_q_idx == 0 && m_delta_q_y_dc == 0 && m_delta_q_uv_dc == 0 && m_delta_q_uv_ac == 0; + frame_context.base_quantizer_index = TRY_READ(m_bit_stream->read_f8()); + frame_context.y_dc_quantizer_index_delta = TRY(read_delta_q()); + frame_context.uv_dc_quantizer_index_delta = TRY(read_delta_q()); + frame_context.uv_ac_quantizer_index_delta = TRY(read_delta_q()); return {}; } @@ -538,7 +537,7 @@ void Parser::setup_past_independence() DecoderErrorOr Parser::compressed_header(FrameContext& frame_context) { - TRY(read_tx_mode()); + TRY(read_tx_mode(frame_context)); if (m_tx_mode == TXModeSelect) TRY(tx_mode_probs()); TRY(read_coef_probs()); @@ -557,9 +556,9 @@ DecoderErrorOr Parser::compressed_header(FrameContext& frame_context) return {}; } -DecoderErrorOr Parser::read_tx_mode() +DecoderErrorOr Parser::read_tx_mode(FrameContext const& frame_context) { - if (m_lossless) { + if (frame_context.is_lossless()) { m_tx_mode = Only_4x4; } else { auto tx_mode = TRY_READ(m_bit_stream->read_literal(2)); @@ -1429,7 +1428,7 @@ u32 const* Parser::get_scan(BlockContext const& block_context, size_t plane, TXS if (plane > 0 || tx_size == TX_32x32) { m_tx_type = DCT_DCT; } else if (tx_size == TX_4x4) { - if (m_lossless || m_is_inter) + if (block_context.frame_context.is_lossless() || m_is_inter) m_tx_type = DCT_DCT; else m_tx_type = mode_to_txfm_map[to_underlying(block_context.size < Block_8x8 ? m_block_sub_modes[block_index] : m_y_mode)]; diff --git a/Userland/Libraries/LibVideo/VP9/Parser.h b/Userland/Libraries/LibVideo/VP9/Parser.h index d5f3d06c25..bfe3812135 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.h +++ b/Userland/Libraries/LibVideo/VP9/Parser.h @@ -65,7 +65,7 @@ private: DecoderErrorOr compute_image_size(FrameContext&); DecoderErrorOr read_interpolation_filter(); DecoderErrorOr loop_filter_params(FrameContext&); - DecoderErrorOr quantization_params(); + DecoderErrorOr quantization_params(FrameContext&); DecoderErrorOr read_delta_q(); DecoderErrorOr segmentation_params(); DecoderErrorOr read_prob(); @@ -76,7 +76,7 @@ private: /* (6.3) Compressed Header Syntax */ DecoderErrorOr compressed_header(FrameContext&); - DecoderErrorOr read_tx_mode(); + DecoderErrorOr read_tx_mode(FrameContext const&); DecoderErrorOr tx_mode_probs(); DecoderErrorOr diff_update_prob(u8 prob); DecoderErrorOr decode_term_subexp(); @@ -148,11 +148,6 @@ private: FrameType m_previous_frame_type { FrameType::KeyFrame }; Array m_previous_loop_filter_ref_deltas; Array m_previous_loop_filter_mode_deltas; - u8 m_base_q_idx { 0 }; - i8 m_delta_q_y_dc { 0 }; - i8 m_delta_q_uv_dc { 0 }; - i8 m_delta_q_uv_ac { 0 }; - bool m_lossless { false }; u8 m_segmentation_tree_probs[7]; u8 m_segmentation_pred_prob[3]; bool m_feature_enabled[8][4];