Browse Source

LibVideo/VP9: Move more block fields into the BlockContext struct

This includes the segment IDs, transform block sizes, prediction modes,
sub-block counts, interpolation filters and sub-block motion vectors.
Zaggy1024 2 years ago
parent
commit
6533c5f6a8

+ 25 - 2
Userland/Libraries/LibVideo/VP9/Context.h

@@ -203,7 +203,7 @@ struct TokensContext {
 struct FrameBlockContext {
     bool is_intra_predicted() const { return ref_frames[0] == ReferenceFrameType::None; }
     bool is_single_reference() const { return ref_frames[1] == ReferenceFrameType::None; }
-    MotionVectorPair primary_motion_vector_pair() const { return { sub_block_motion_vectors[0][3], sub_block_motion_vectors[1][3] }; }
+    MotionVectorPair primary_motion_vector_pair() const { return sub_block_motion_vectors[3]; }
 
     bool is_available { false };
     bool skip_coefficients { false };
@@ -212,7 +212,7 @@ struct FrameBlockContext {
     Array<PredictionMode, 4> sub_modes { PredictionMode::DcPred, PredictionMode::DcPred, PredictionMode::DcPred, PredictionMode::DcPred };
     InterpolationFilter interpolation_filter { InterpolationFilter::EightTap };
     ReferenceFramePair ref_frames { ReferenceFrameType::None, ReferenceFrameType::None };
-    Array<Array<MotionVector, 4>, 2> sub_block_motion_vectors {};
+    Array<MotionVectorPair, 4> sub_block_motion_vectors;
     u8 segment_id { 0 };
 };
 
@@ -382,8 +382,31 @@ struct BlockContext {
     u32 row { 0 };
     u32 column { 0 };
     BlockSubsize size;
+    Gfx::Size<u8> get_size_in_4x4_blocks() const
+    {
+        auto width = num_4x4_blocks_wide_lookup[size];
+        auto height = num_4x4_blocks_high_lookup[size];
+        return Gfx::Size<u8>(width, height);
+    }
 
     Vector2DView<FrameBlockContext> contexts_view;
+
+    u8 segment_id { 0 };
+    bool should_skip_residuals { false };
+
+    TXSize tx_size { TXSize::TX_4x4 };
+
+    ReferenceFramePair reference_frame_types;
+    bool is_inter_predicted() const { return reference_frame_types[0] > ReferenceFrameType::None; }
+    bool is_compound() const { return reference_frame_types[1] > ReferenceFrameType::None; }
+
+    Array<PredictionMode, 4> sub_block_prediction_modes;
+    PredictionMode y_prediction_mode() const { return sub_block_prediction_modes.last(); }
+    PredictionMode& y_prediction_mode() { return sub_block_prediction_modes.last(); }
+    PredictionMode uv_prediction_mode { 0 };
+
+    InterpolationFilter interpolation_filter { EightTap };
+    Array<MotionVectorPair, 4> sub_block_motion_vectors;
 };
 
 }

+ 17 - 15
Userland/Libraries/LibVideo/VP9/Decoder.cpp

@@ -351,11 +351,11 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_
     //     3. Otherwise, mode is set equal to sub_modes[ blockIdx ].
     PredictionMode mode;
     if (plane > 0)
-        mode = m_parser->m_uv_mode;
+        mode = block_context.uv_prediction_mode;
     else if (block_context.size >= Block_8x8)
-        mode = m_parser->m_y_mode;
+        mode = block_context.y_prediction_mode();
     else
-        mode = m_parser->m_block_sub_modes[block_index];
+        mode = block_context.sub_block_prediction_modes[block_index];
 
     // The variable log2Size specifying the base 2 logarithm of the width of the transform block is set equal to txSz + 2.
     u8 log2_of_block_size = tx_size + 2;
@@ -700,31 +700,33 @@ MotionVector Decoder::select_motion_vector(u8 plane, BlockContext const& block_c
         };
     };
 
+    auto vectors = block_context.sub_block_motion_vectors;
+
     // The motion vector array mv is derived as follows:
     // − If plane is equal to 0, or MiSize is greater than or equal to BLOCK_8X8, mv is set equal to
     // BlockMvs[ refList ][ blockIdx ].
     if (plane == 0 || block_context.size >= Block_8x8)
-        return m_parser->m_block_mvs[ref_list][block_index];
+        return vectors[block_index][ref_list];
     // − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 0, mv is set equal to
     // BlockMvs[ refList ][ blockIdx ].
     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];
+        return vectors[block_index][ref_list];
     // − 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 (!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]);
+        return round_mv_comp_q2(vectors[block_index][ref_list] + vectors[block_index + 2][ref_list]);
     // − 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 (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]);
+        return round_mv_comp_q2(vectors[block_index][ref_list] + vectors[block_index + 1][ref_list]);
     // − 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(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]);
+    return round_mv_comp_q4(vectors[0][ref_list] + vectors[1][ref_list]
+        + vectors[2][ref_list] + vectors[3][ref_list]);
 }
 
 MotionVector Decoder::clamp_motion_vector(u8 plane, BlockContext const& block_context, u32 block_row, u32 block_column, MotionVector vector)
@@ -787,7 +789,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
 
     // A variable refIdx specifying which reference frame is being used is set equal to
     // ref_frame_idx[ ref_frame[ refList ] - LAST_FRAME ].
-    auto reference_frame_index = block_context.frame_context.reference_frame_indices[m_parser->m_ref_frame[ref_list] - LastFrame];
+    auto reference_frame_index = block_context.frame_context.reference_frame_indices[block_context.reference_frame_types[ref_list] - LastFrame];
 
     // It is a requirement of bitstream conformance that all the following conditions are satisfied:
     // − 2 * FrameWidth >= RefFrameWidth[ refIdx ]
@@ -907,7 +909,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
                 auto sample = reference_frame_buffer_at(
                     clip_3(0, scaled_bottom, (offset_scaled_block_y >> 4) + static_cast<i32>(row) - 3),
                     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;
+                accumulated_samples += subpel_filters[block_context.interpolation_filter][samples_start & 15][t] * sample;
             }
             intermediate_buffer_at(row, column) = clip_1(block_context.frame_context.color_config.bit_depth, round_2(accumulated_samples, 7));
         }
@@ -920,7 +922,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const&
             i32 accumulated_samples = 0;
             for (auto t = 0u; t < 8u; t++) {
                 auto sample = intermediate_buffer_at((samples_start >> 4) + t, column);
-                accumulated_samples += subpel_filters[m_parser->m_interp_filter][samples_start & 15][t] * sample;
+                accumulated_samples += subpel_filters[block_context.interpolation_filter][samples_start & 15][t] * sample;
             }
             block_buffer_at(row, column) = clip_1(block_context.frame_context.color_config.bit_depth, round_2(accumulated_samples, 7));
         }
@@ -942,7 +944,7 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, BlockContext const& block_
     // The outputs of this process are inter predicted samples in the current frame CurrFrame.
 
     // The variable isCompound is set equal to ref_frame[ 1 ] > NONE.
-    auto is_compound = m_parser->m_ref_frame[1] > None;
+    auto is_compound = block_context.reference_frame_types[1] > None;
     // The prediction arrays are formed by the following ordered steps:
     // 1. The variable refList is set equal to 0.
     // 2. through 5.
@@ -1022,9 +1024,9 @@ 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:
-    if (m_parser->seg_feature_active(SEG_LVL_ALT_Q)) {
+    if (m_parser->seg_feature_active(block_context, SEG_LVL_ALT_Q)) {
         // 1. Set the variable data equal to FeatureData[ segment_id ][ SEG_LVL_ALT_Q ].
-        auto data = m_parser->m_feature_data[m_parser->m_segment_id][SEG_LVL_ALT_Q];
+        auto data = m_parser->m_feature_data[block_context.segment_id][SEG_LVL_ALT_Q];
 
         // 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) {

+ 125 - 143
Userland/Libraries/LibVideo/VP9/Parser.cpp

@@ -632,8 +632,8 @@ u8 Parser::inv_recenter_nonneg(u8 v, u8 m)
 
 DecoderErrorOr<void> Parser::read_coef_probs()
 {
-    m_max_tx_size = tx_mode_to_biggest_tx_size[m_tx_mode];
-    for (u8 tx_size = 0; tx_size <= m_max_tx_size; tx_size++) {
+    auto max_tx_size = tx_mode_to_biggest_tx_size[m_tx_mode];
+    for (u8 tx_size = 0; tx_size <= max_tx_size; tx_size++) {
         auto update_probs = TRY_READ(m_bit_stream->read_literal(1));
         if (update_probs == 1) {
             for (auto i = 0; i < 2; i++) {
@@ -963,12 +963,12 @@ DecoderErrorOr<void> Parser::decode_block(TileContext& tile_context, u32 row, u3
 
     TRY(mode_info(block_context, above_context, left_context));
     auto had_residual_tokens = TRY(residual(block_context, above_context.is_available, left_context.is_available));
-    if (m_is_inter && subsize >= Block_8x8 && !had_residual_tokens)
-        m_skip = true;
+    if (block_context.is_inter_predicted() && subsize >= Block_8x8 && !had_residual_tokens)
+        block_context.should_skip_residuals = true;
 
     for (size_t y = 0; y < block_context.contexts_view.height(); y++) {
         for (size_t x = 0; x < block_context.contexts_view.width(); x++) {
-            auto sub_block_context = FrameBlockContext { true, m_skip, m_tx_size, m_y_mode, m_block_sub_modes, m_interp_filter, m_ref_frame, m_block_mvs, m_segment_id };
+            auto sub_block_context = FrameBlockContext { true, block_context.should_skip_residuals, block_context.tx_size, block_context.y_prediction_mode(), block_context.sub_block_prediction_modes, block_context.interpolation_filter, block_context.reference_frame_types, block_context.sub_block_motion_vectors, block_context.segment_id };
             block_context.contexts_view.at(y, x) = sub_block_context;
             VERIFY(block_context.frame_block_contexts().at(row + y, column + x).tx_size == sub_block_context.tx_size);
         }
@@ -987,81 +987,72 @@ DecoderErrorOr<void> Parser::mode_info(BlockContext& block_context, FrameBlockCo
 
 DecoderErrorOr<void> Parser::intra_frame_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
-    TRY(intra_segment_id());
-    TRY(read_skip(above_context, left_context));
-    TRY(read_tx_size(block_context, above_context, left_context, true));
-    m_ref_frame[0] = IntraFrame;
-    m_ref_frame[1] = None;
-    m_is_inter = false;
+    block_context.reference_frame_types = { ReferenceFrameType::None, ReferenceFrameType::None };
+    VERIFY(!block_context.is_inter_predicted());
+    TRY(set_intra_segment_id(block_context));
+    block_context.should_skip_residuals = TRY(read_should_skip_residuals(block_context, above_context, left_context));
+    block_context.tx_size = TRY(read_tx_size(block_context, above_context, left_context, true));
     // FIXME: This if statement is also present in parse_default_intra_mode. The selection of parameters for
     //        the probability table lookup should be inlined here.
     if (block_context.size >= Block_8x8) {
-        m_y_mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, block_context.size, above_context, left_context, m_block_sub_modes, 0, 0));
-        for (auto& block_sub_mode : m_block_sub_modes)
-            block_sub_mode = m_y_mode;
+        auto mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, block_context.size, above_context, left_context, block_context.sub_block_prediction_modes, 0, 0));
+        for (auto& block_sub_mode : block_context.sub_block_prediction_modes)
+            block_sub_mode = mode;
     } else {
-        m_num_4x4_w = num_4x4_blocks_wide_lookup[block_context.size];
-        m_num_4x4_h = num_4x4_blocks_high_lookup[block_context.size];
-        for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
-            for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
-                auto sub_mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, block_context.size, above_context, left_context, m_block_sub_modes, idx, idy));
-
-                for (auto y = 0; y < m_num_4x4_h; y++) {
-                    for (auto x = 0; x < m_num_4x4_w; x++) {
+        auto size_in_4x4_blocks = block_context.get_size_in_4x4_blocks();
+        for (auto idy = 0; idy < 2; idy += size_in_4x4_blocks.height()) {
+            for (auto idx = 0; idx < 2; idx += size_in_4x4_blocks.width()) {
+                auto sub_mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, block_context.size, above_context, left_context, block_context.sub_block_prediction_modes, idx, idy));
+
+                for (auto y = 0; y < size_in_4x4_blocks.height(); y++) {
+                    for (auto x = 0; x < size_in_4x4_blocks.width(); x++) {
                         auto index = (idy + y) * 2 + idx + x;
-                        m_block_sub_modes[index] = sub_mode;
+                        block_context.sub_block_prediction_modes[index] = sub_mode;
                     }
                 }
             }
         }
-        m_y_mode = m_block_sub_modes.last();
     }
-    m_uv_mode = TRY_READ(TreeParser::parse_default_uv_mode(*m_bit_stream, *m_probability_tables, m_y_mode));
+    block_context.uv_prediction_mode = TRY_READ(TreeParser::parse_default_uv_mode(*m_bit_stream, *m_probability_tables, block_context.y_prediction_mode()));
     return {};
 }
 
-DecoderErrorOr<void> Parser::intra_segment_id()
+DecoderErrorOr<void> Parser::set_intra_segment_id(BlockContext& block_context)
 {
     if (m_segmentation_enabled && m_segmentation_update_map)
-        m_segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
+        block_context.segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
     else
-        m_segment_id = 0;
+        block_context.segment_id = 0;
     return {};
 }
 
-DecoderErrorOr<void> Parser::read_skip(FrameBlockContext above_context, FrameBlockContext left_context)
+DecoderErrorOr<bool> Parser::read_should_skip_residuals(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
-    if (seg_feature_active(SEG_LVL_SKIP)) {
-        m_skip = true;
-    } else {
-        m_skip = TRY_READ(TreeParser::parse_skip(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
-    }
-    return {};
+    if (seg_feature_active(block_context, SEG_LVL_SKIP))
+        return true;
+    return TRY_READ(TreeParser::parse_skip(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
 }
 
-bool Parser::seg_feature_active(u8 feature)
+bool Parser::seg_feature_active(BlockContext const& block_context, u8 feature)
 {
-    return m_segmentation_enabled && m_feature_enabled[m_segment_id][feature];
+    return m_segmentation_enabled && m_feature_enabled[block_context.segment_id][feature];
 }
 
-DecoderErrorOr<void> Parser::read_tx_size(BlockContext const& block_context, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select)
+DecoderErrorOr<TXSize> Parser::read_tx_size(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select)
 {
-    // FIXME: This probably doesn't need to set max_tx_size, and can also return the TXSize it reads.
-    m_max_tx_size = max_txsize_lookup[block_context.size];
+    auto max_tx_size = max_txsize_lookup[block_context.size];
     if (allow_select && m_tx_mode == TXModeSelect && block_context.size >= Block_8x8)
-        m_tx_size = TRY_READ(TreeParser::parse_tx_size(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_max_tx_size, above_context, left_context));
-    else
-        m_tx_size = min(m_max_tx_size, tx_mode_to_biggest_tx_size[m_tx_mode]);
-    return {};
+        return (TRY_READ(TreeParser::parse_tx_size(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, max_tx_size, above_context, left_context)));
+    return min(max_tx_size, tx_mode_to_biggest_tx_size[m_tx_mode]);
 }
 
 DecoderErrorOr<void> Parser::inter_frame_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
-    TRY(inter_segment_id(block_context));
-    TRY(read_skip(above_context, left_context));
-    TRY(read_is_inter(above_context, left_context));
-    TRY(read_tx_size(block_context, above_context, left_context, !m_skip || !m_is_inter));
-    if (m_is_inter) {
+    TRY(set_inter_segment_id(block_context));
+    block_context.should_skip_residuals = TRY(read_should_skip_residuals(block_context, above_context, left_context));
+    auto is_inter = TRY(read_is_inter(block_context, above_context, left_context));
+    block_context.tx_size = TRY(read_tx_size(block_context, above_context, left_context, !block_context.should_skip_residuals || !is_inter));
+    if (is_inter) {
         TRY(inter_block_mode_info(block_context, above_context, left_context));
     } else {
         TRY(intra_block_mode_info(block_context));
@@ -1069,27 +1060,27 @@ DecoderErrorOr<void> Parser::inter_frame_mode_info(BlockContext& block_context,
     return {};
 }
 
-DecoderErrorOr<void> Parser::inter_segment_id(BlockContext const& block_context)
+DecoderErrorOr<void> Parser::set_inter_segment_id(BlockContext& block_context)
 {
     if (!m_segmentation_enabled) {
-        m_segment_id = 0;
+        block_context.segment_id = 0;
         return {};
     }
     auto predicted_segment_id = get_segment_id(block_context);
     if (!m_segmentation_update_map) {
-        m_segment_id = predicted_segment_id;
+        block_context.segment_id = predicted_segment_id;
         return {};
     }
     if (!m_segmentation_temporal_update) {
-        m_segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
+        block_context.segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
         return {};
     }
 
     auto seg_id_predicted = TRY_READ(TreeParser::parse_segment_id_predicted(*m_bit_stream, m_segmentation_pred_prob, m_left_seg_pred_context[block_context.row], m_above_seg_pred_context[block_context.column]));
     if (seg_id_predicted)
-        m_segment_id = predicted_segment_id;
+        block_context.segment_id = predicted_segment_id;
     else
-        m_segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
+        block_context.segment_id = TRY_READ(TreeParser::parse_segment_id(*m_bit_stream, m_segmentation_tree_probs));
 
     for (size_t i = 0; i < num_8x8_blocks_wide_lookup[block_context.size]; i++) {
         auto index = block_context.column + i;
@@ -1121,98 +1112,87 @@ u8 Parser::get_segment_id(BlockContext const& block_context)
     return segment;
 }
 
-DecoderErrorOr<void> Parser::read_is_inter(FrameBlockContext above_context, FrameBlockContext left_context)
+DecoderErrorOr<bool> Parser::read_is_inter(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
-    if (seg_feature_active(SEG_LVL_REF_FRAME))
-        m_is_inter = m_feature_data[m_segment_id][SEG_LVL_REF_FRAME] != IntraFrame;
-    else
-        m_is_inter = TRY_READ(TreeParser::parse_block_is_inter_predicted(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
-    return {};
+    if (seg_feature_active(block_context, SEG_LVL_REF_FRAME))
+        return m_feature_data[block_context.segment_id][SEG_LVL_REF_FRAME] != IntraFrame;
+    return TRY_READ(TreeParser::parse_block_is_inter_predicted(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
 }
 
 DecoderErrorOr<void> Parser::intra_block_mode_info(BlockContext& block_context)
 {
-    m_ref_frame[0] = IntraFrame;
-    m_ref_frame[1] = None;
+    block_context.reference_frame_types = { ReferenceFrameType::None, ReferenceFrameType::None };
+    VERIFY(!block_context.is_inter_predicted());
+    auto& sub_modes = block_context.sub_block_prediction_modes;
     if (block_context.size >= Block_8x8) {
-        m_y_mode = TRY_READ(TreeParser::parse_intra_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, block_context.size));
-        for (auto& block_sub_mode : m_block_sub_modes)
-            block_sub_mode = m_y_mode;
+        auto mode = TRY_READ(TreeParser::parse_intra_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, block_context.size));
+        for (auto& block_sub_mode : sub_modes)
+            block_sub_mode = mode;
     } else {
-        m_num_4x4_w = num_4x4_blocks_wide_lookup[block_context.size];
-        m_num_4x4_h = num_4x4_blocks_high_lookup[block_context.size];
-        PredictionMode sub_intra_mode;
-        for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
-            for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
-                sub_intra_mode = TRY_READ(TreeParser::parse_sub_intra_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter));
-                for (auto y = 0; y < m_num_4x4_h; y++) {
-                    for (auto x = 0; x < m_num_4x4_w; x++)
-                        m_block_sub_modes[(idy + y) * 2 + idx + x] = sub_intra_mode;
+        auto size_in_4x4_blocks = block_context.get_size_in_4x4_blocks();
+        for (auto idy = 0; idy < 2; idy += size_in_4x4_blocks.height()) {
+            for (auto idx = 0; idx < 2; idx += size_in_4x4_blocks.width()) {
+                auto sub_intra_mode = TRY_READ(TreeParser::parse_sub_intra_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter));
+                for (auto y = 0; y < size_in_4x4_blocks.height(); y++) {
+                    for (auto x = 0; x < size_in_4x4_blocks.width(); x++)
+                        sub_modes[(idy + y) * 2 + idx + x] = sub_intra_mode;
                 }
             }
         }
-        m_y_mode = sub_intra_mode;
     }
-    m_uv_mode = TRY_READ(TreeParser::parse_uv_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_y_mode));
+    block_context.uv_prediction_mode = TRY_READ(TreeParser::parse_uv_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, block_context.y_prediction_mode()));
     return {};
 }
 
 DecoderErrorOr<void> Parser::inter_block_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
     TRY(read_ref_frames(block_context, above_context, left_context));
+    VERIFY(block_context.is_inter_predicted());
     for (auto j = 0; j < 2; j++) {
-        if (m_ref_frame[j] > IntraFrame) {
-            find_mv_refs(block_context, m_ref_frame[j], -1);
+        if (block_context.reference_frame_types[j] > IntraFrame) {
+            find_mv_refs(block_context, block_context.reference_frame_types[j], -1);
             find_best_ref_mvs(block_context, j);
         }
     }
-    auto is_compound = m_ref_frame[1] > IntraFrame;
-    if (seg_feature_active(SEG_LVL_SKIP)) {
-        m_y_mode = PredictionMode::ZeroMv;
+    if (seg_feature_active(block_context, SEG_LVL_SKIP)) {
+        block_context.y_prediction_mode() = PredictionMode::ZeroMv;
     } else if (block_context.size >= Block_8x8) {
-        m_y_mode = TRY_READ(TreeParser::parse_inter_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_mode_context[m_ref_frame[0]]));
+        block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_mode_context[block_context.reference_frame_types[0]]));
     }
     if (block_context.frame_context.interpolation_filter == Switchable)
-        m_interp_filter = TRY_READ(TreeParser::parse_interpolation_filter(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+        block_context.interpolation_filter = TRY_READ(TreeParser::parse_interpolation_filter(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
     else
-        m_interp_filter = block_context.frame_context.interpolation_filter;
+        block_context.interpolation_filter = block_context.frame_context.interpolation_filter;
     if (block_context.size < Block_8x8) {
-        m_num_4x4_w = num_4x4_blocks_wide_lookup[block_context.size];
-        m_num_4x4_h = num_4x4_blocks_high_lookup[block_context.size];
-        for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
-            for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
-                m_y_mode = TRY_READ(TreeParser::parse_inter_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_mode_context[m_ref_frame[0]]));
-                if (m_y_mode == PredictionMode::NearestMv || m_y_mode == PredictionMode::NearMv) {
-                    for (auto j = 0; j < 1 + is_compound; j++)
+        auto size_in_4x4_blocks = block_context.get_size_in_4x4_blocks();
+        for (auto idy = 0; idy < 2; idy += size_in_4x4_blocks.height()) {
+            for (auto idx = 0; idx < 2; idx += size_in_4x4_blocks.width()) {
+                block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_mode_context[block_context.reference_frame_types[0]]));
+                if (block_context.y_prediction_mode() == PredictionMode::NearestMv || block_context.y_prediction_mode() == PredictionMode::NearMv) {
+                    for (auto j = 0; j < 1 + block_context.is_compound(); j++)
                         append_sub8x8_mvs(block_context, idy * 2 + idx, j);
                 }
-                TRY(assign_mv(block_context, is_compound));
-                for (auto y = 0; y < m_num_4x4_h; y++) {
-                    for (auto x = 0; x < m_num_4x4_w; x++) {
-                        auto block = (idy + y) * 2 + idx + x;
-                        for (auto ref_list = 0; ref_list < 1 + is_compound; ref_list++) {
-                            m_block_mvs[ref_list][block] = m_mv[ref_list];
-                        }
+                auto new_motion_vector_pair = TRY(assign_mv(block_context));
+                for (auto y = 0; y < size_in_4x4_blocks.height(); y++) {
+                    for (auto x = 0; x < size_in_4x4_blocks.width(); x++) {
+                        auto sub_block_index = (idy + y) * 2 + idx + x;
+                        block_context.sub_block_motion_vectors[sub_block_index] = new_motion_vector_pair;
                     }
                 }
             }
         }
         return {};
     }
-    TRY(assign_mv(block_context, is_compound));
-    for (auto ref_list = 0; ref_list < 1 + is_compound; ref_list++) {
-        for (auto block = 0; block < 4; block++) {
-            m_block_mvs[ref_list][block] = m_mv[ref_list];
-        }
-    }
+    auto new_motion_vector_pair = TRY(assign_mv(block_context));
+    for (auto block = 0; block < 4; block++)
+        block_context.sub_block_motion_vectors[block] = new_motion_vector_pair;
     return {};
 }
 
 DecoderErrorOr<void> Parser::read_ref_frames(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context)
 {
-    if (seg_feature_active(SEG_LVL_REF_FRAME)) {
-        m_ref_frame[0] = static_cast<ReferenceFrameType>(m_feature_data[m_segment_id][SEG_LVL_REF_FRAME]);
-        m_ref_frame[1] = None;
+    if (seg_feature_active(block_context, SEG_LVL_REF_FRAME)) {
+        block_context.reference_frame_types = { static_cast<ReferenceFrameType>(m_feature_data[block_context.segment_id][SEG_LVL_REF_FRAME]), None };
         return {};
     }
     ReferenceMode comp_mode;
@@ -1228,40 +1208,45 @@ DecoderErrorOr<void> Parser::read_ref_frames(BlockContext& block_context, FrameB
         // FIXME: Create an enum for compound frame references using names Primary and Secondary.
         auto comp_ref = TRY_READ(TreeParser::parse_comp_ref(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_comp_fixed_ref, m_comp_var_ref, variable_reference_index, above_context, left_context));
 
-        m_ref_frame[fixed_reference_index] = m_comp_fixed_ref;
-        m_ref_frame[variable_reference_index] = m_comp_var_ref[comp_ref];
+        block_context.reference_frame_types[fixed_reference_index] = m_comp_fixed_ref;
+        block_context.reference_frame_types[variable_reference_index] = m_comp_var_ref[comp_ref];
         return {};
     }
     // FIXME: Maybe consolidate this into a tree. Context is different between part 1 and 2 but still, it would look nice here.
     auto single_ref_p1 = TRY_READ(TreeParser::parse_single_ref_part_1(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
     if (single_ref_p1) {
         auto single_ref_p2 = TRY_READ(TreeParser::parse_single_ref_part_2(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
-        m_ref_frame[0] = single_ref_p2 ? AltRefFrame : GoldenFrame;
+        block_context.reference_frame_types[0] = single_ref_p2 ? AltRefFrame : GoldenFrame;
     } else {
-        m_ref_frame[0] = LastFrame;
+        block_context.reference_frame_types[0] = LastFrame;
     }
-    m_ref_frame[1] = None;
+    block_context.reference_frame_types[1] = None;
     return {};
 }
 
-DecoderErrorOr<void> Parser::assign_mv(BlockContext const& block_context, bool is_compound)
+DecoderErrorOr<MotionVectorPair> Parser::assign_mv(BlockContext const& block_context)
 {
-    m_mv[1] = {};
-    for (auto i = 0; i < 1 + is_compound; i++) {
-        if (m_y_mode == PredictionMode::NewMv) {
-            TRY(read_mv(block_context, i));
-        } else if (m_y_mode == PredictionMode::NearestMv) {
-            m_mv[i] = m_nearest_mv[i];
-        } else if (m_y_mode == PredictionMode::NearMv) {
-            m_mv[i] = m_near_mv[i];
-        } else {
-            m_mv[i] = {};
+    MotionVectorPair result;
+    for (auto i = 0; i < 1 + block_context.is_compound(); i++) {
+        switch (block_context.y_prediction_mode()) {
+        case PredictionMode::NewMv:
+            result[i] = TRY(read_mv(block_context, i));
+            break;
+        case PredictionMode::NearestMv:
+            result[i] = m_nearest_mv[i];
+            break;
+        case PredictionMode::NearMv:
+            result[i] = m_near_mv[i];
+            break;
+        default:
+            result[i] = {};
+            break;
         }
     }
-    return {};
+    return result;
 }
 
-DecoderErrorOr<void> Parser::read_mv(BlockContext const& block_context, u8 ref)
+DecoderErrorOr<MotionVector> Parser::read_mv(BlockContext const& block_context, u8 ref)
 {
     m_use_hp = block_context.frame_context.high_precision_motion_vectors_allowed && use_mv_hp(m_best_mv[ref]);
     MotionVector diff_mv;
@@ -1271,10 +1256,7 @@ DecoderErrorOr<void> Parser::read_mv(BlockContext const& block_context, u8 ref)
     if (mv_joint == MvJointHnzvz || mv_joint == MvJointHnzvnz)
         diff_mv.set_column(TRY(read_mv_component(1)));
 
-    // FIXME: We probably don't need to assign MVs to a field, these can just
-    //        be returned and assigned where they are requested.
-    m_mv[ref] = m_best_mv[ref] + diff_mv;
-    return {};
+    return m_best_mv[ref] + diff_mv;
 }
 
 DecoderErrorOr<i32> Parser::read_mv_component(u8 component)
@@ -1334,7 +1316,7 @@ DecoderErrorOr<bool> Parser::residual(BlockContext& block_context, bool has_bloc
     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.frame_context.color_config.subsampling_x, block_context.frame_context.color_config.subsampling_y, m_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, block_context.tx_size, block_context.size) : block_context.tx_size;
         auto step = 1 << tx_size;
         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];
@@ -1343,7 +1325,7 @@ DecoderErrorOr<bool> Parser::residual(BlockContext& block_context, bool has_bloc
         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) {
+        if (block_context.is_inter_predicted()) {
             if (block_context.size < Block_8x8) {
                 for (auto y = 0; y < num_4x4_h; y++) {
                     for (auto x = 0; x < num_4x4_w; x++) {
@@ -1363,9 +1345,9 @@ DecoderErrorOr<bool> Parser::residual(BlockContext& block_context, bool has_bloc
                 auto start_y = base_y + (4 * y);
                 auto non_zero = false;
                 if (start_x < max_x && start_y < max_y) {
-                    if (!m_is_inter)
+                    if (!block_context.is_inter_predicted())
                         TRY(m_decoder.predict_intra(plane, block_context, start_x, start_y, has_block_left || x > 0, has_block_above || y > 0, (x + step) < num_4x4_w, tx_size, block_index));
-                    if (!m_skip) {
+                    if (!block_context.should_skip_residuals) {
                         non_zero = TRY(tokens(block_context, plane, start_x, start_y, tx_size, block_index));
                         had_residual_tokens = had_residual_tokens || non_zero;
                         TRY(m_decoder.reconstruct(plane, block_context, start_x, start_y, tx_size));
@@ -1400,7 +1382,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(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);
+        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, block_context.is_inter_predicted(), 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)
@@ -1428,12 +1410,12 @@ 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 (block_context.frame_context.is_lossless() || m_is_inter)
+        if (block_context.frame_context.is_lossless() || block_context.is_inter_predicted())
             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)];
+            m_tx_type = mode_to_txfm_map[to_underlying(block_context.size < Block_8x8 ? block_context.sub_block_prediction_modes[block_index] : block_context.y_prediction_mode())];
     } else {
-        m_tx_type = mode_to_txfm_map[to_underlying(m_y_mode)];
+        m_tx_type = mode_to_txfm_map[to_underlying(block_context.y_prediction_mode())];
     }
     if (tx_size == TX_4x4) {
         if (m_tx_type == ADST_DCT)
@@ -1600,7 +1582,7 @@ void Parser::find_mv_refs(BlockContext& block_context, ReferenceFrameType refere
                         { 3, 3 }
                     };
                     auto index = block >= 0 ? idx_n_column_to_subblock[block][offset_vector.column() == 0] : 3;
-                    m_candidate_mv[ref_list] = context.sub_block_motion_vectors[ref_list][index];
+                    m_candidate_mv[ref_list] = context.sub_block_motion_vectors[index][ref_list];
 
                     add_mv_ref_list(ref_list);
                     break;
@@ -1663,17 +1645,17 @@ void Parser::find_best_ref_mvs(BlockContext& block_context, u8 ref_list)
 void Parser::append_sub8x8_mvs(BlockContext& block_context, i32 block, u8 ref_list)
 {
     MotionVector sub_8x8_mvs[2];
-    find_mv_refs(block_context, m_ref_frame[ref_list], block);
+    find_mv_refs(block_context, block_context.reference_frame_types[ref_list], block);
     auto destination_index = 0;
     if (block == 0) {
         for (auto i = 0u; i < 2; i++)
             sub_8x8_mvs[destination_index++] = m_ref_list_mv[i];
     } else if (block <= 2) {
-        sub_8x8_mvs[destination_index++] = m_block_mvs[ref_list][0];
+        sub_8x8_mvs[destination_index++] = block_context.sub_block_motion_vectors[0][ref_list];
     } else {
-        sub_8x8_mvs[destination_index++] = m_block_mvs[ref_list][2];
+        sub_8x8_mvs[destination_index++] = block_context.sub_block_motion_vectors[2][ref_list];
         for (auto index = 1; index >= 0 && destination_index < 2; index--) {
-            auto block_vector = m_block_mvs[ref_list][index];
+            auto block_vector = block_context.sub_block_motion_vectors[index][ref_list];
             if (block_vector != sub_8x8_mvs[0])
                 sub_8x8_mvs[destination_index++] = block_vector;
         }

+ 8 - 29
Userland/Libraries/LibVideo/VP9/Parser.h

@@ -105,19 +105,19 @@ private:
     DecoderErrorOr<void> decode_block(TileContext&, u32 row, u32 column, BlockSubsize subsize);
     DecoderErrorOr<void> mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> intra_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> intra_segment_id();
-    DecoderErrorOr<void> read_skip(FrameBlockContext above_context, FrameBlockContext left_context);
-    bool seg_feature_active(u8 feature);
-    DecoderErrorOr<void> read_tx_size(BlockContext const&, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select);
+    DecoderErrorOr<void> set_intra_segment_id(BlockContext&);
+    DecoderErrorOr<bool> read_should_skip_residuals(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
+    bool seg_feature_active(BlockContext const&, u8 feature);
+    DecoderErrorOr<TXSize> read_tx_size(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select);
     DecoderErrorOr<void> inter_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> inter_segment_id(BlockContext const&);
+    DecoderErrorOr<void> set_inter_segment_id(BlockContext&);
     u8 get_segment_id(BlockContext const&);
-    DecoderErrorOr<void> read_is_inter(FrameBlockContext above_context, FrameBlockContext left_context);
+    DecoderErrorOr<bool> read_is_inter(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> intra_block_mode_info(BlockContext&);
     DecoderErrorOr<void> inter_block_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> read_ref_frames(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> assign_mv(BlockContext const&, bool is_compound);
-    DecoderErrorOr<void> read_mv(BlockContext const&, u8 ref);
+    DecoderErrorOr<MotionVectorPair> assign_mv(BlockContext const&);
+    DecoderErrorOr<MotionVector> read_mv(BlockContext const&, u8 ref);
     DecoderErrorOr<i32> read_mv_component(u8 component);
     DecoderErrorOr<bool> residual(BlockContext&, bool has_block_above, bool has_block_left);
     DecoderErrorOr<bool> tokens(BlockContext&, size_t plane, u32 x, u32 y, TXSize tx_size, u32 block_index);
@@ -167,25 +167,6 @@ private:
     Vector<u8> m_above_partition_context;
     Vector<u8> m_left_partition_context;
 
-    u8 m_segment_id { 0 };
-    // FIXME: Should this be an enum?
-    // skip equal to 0 indicates that there may be some transform coefficients to read for this block; skip equal to 1
-    // indicates that there are no transform coefficients.
-    //
-    // skip may be set to 0 even if transform blocks contain immediate end of block markers.
-    bool m_skip { false };
-    TXSize m_max_tx_size { TX_4x4 };
-    TXSize m_tx_size { TX_4x4 };
-    ReferenceFramePair m_ref_frame;
-    bool m_is_inter { false };
-    PredictionMode m_y_mode { 0 };
-    Array<PredictionMode, 4> m_block_sub_modes;
-    u8 m_num_4x4_w { 0 };
-    u8 m_num_4x4_h { 0 };
-    PredictionMode m_uv_mode { 0 }; // FIXME: Is u8 the right size?
-    // The current block's interpolation filter.
-    InterpolationFilter m_interp_filter { EightTap };
-    MotionVectorPair m_mv;
     MotionVectorPair m_near_mv;
     MotionVectorPair m_nearest_mv;
     MotionVectorPair m_best_mv;
@@ -205,8 +186,6 @@ private:
     ReferenceMode m_reference_mode;
     ReferenceFrameType m_comp_fixed_ref;
     ReferenceFramePair m_comp_var_ref;
-    // FIXME: Use Array<MotionVectorPair, 4> instead.
-    Array<Array<MotionVector, 4>, 2> m_block_mvs;
 
     MotionVectorPair m_candidate_mv;
     ReferenceFramePair m_candidate_frame;