Prechádzať zdrojové kódy

LibVideo/VP9: Store data used between decode_block calls in a struct

All state that needed to persist between calls to decode_block was
previously stored in plain Vector fields. This moves them into a struct
which sets a more explicit lifetime on that data. It may be possible to
store this data on the stack of a function with the appropriate
lifetime now that it is split into its own struct.
Zaggy1024 2 rokov pred
rodič
commit
44413c31a9

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

@@ -7,6 +7,8 @@
 
 #pragma once
 
+#include <AK/Array.h>
+
 #include "Enums.h"
 #include "MotionVector.h"
 
@@ -17,7 +19,7 @@ struct Pair {
     T a;
     T b;
 
-    T& operator[](size_t index)
+    T& operator[](u8 index)
     {
         if (index == 0)
             return a;
@@ -25,6 +27,11 @@ struct Pair {
             return b;
         VERIFY_NOT_REACHED();
     }
+
+    T const& operator[](u8 index) const
+    {
+        return const_cast<Pair<T>&>(*this)[index];
+    }
 };
 
 typedef Pair<ReferenceFrameType> ReferenceFramePair;
@@ -38,4 +45,21 @@ struct TokensContext {
     u8 m_context_index;
 };
 
+// Block context that is kept for the lifetime of a frame.
+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] }; }
+
+    bool is_available { false };
+    bool skip_coefficients { false };
+    TXSize tx_size { TXSize::TX_4x4 };
+    PredictionMode y_mode { PredictionMode::DcPred };
+    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 {};
+    u8 segment_id { 0 };
+};
+
 }

+ 9 - 7
Userland/Libraries/LibVideo/VP9/Decoder.cpp

@@ -75,7 +75,7 @@ DecoderErrorOr<void> Decoder::decode_frame(ReadonlyBytes frame_data)
         for (auto row = 0u; row < m_parser->m_mi_rows; row++) {
             for (auto column = 0u; column < m_parser->m_mi_cols; column++) {
                 auto index = index_from_row_and_column(row, column, m_parser->m_mi_rows);
-                m_parser->m_prev_segment_ids[index] = m_parser->m_segment_ids[index];
+                m_parser->m_prev_segment_ids[index] = m_parser->m_frame_block_contexts[index].segment_id;
             }
         }
     }
@@ -1813,16 +1813,18 @@ DecoderErrorOr<void> Decoder::update_reference_frames()
 
     // 2. If show_existing_frame is equal to 0, the following applies:
     if (!m_parser->m_show_existing_frame) {
-        VERIFY(m_parser->m_ref_frames.size() == m_parser->m_mi_rows * m_parser->m_mi_cols);
-        VERIFY(m_parser->m_mvs.size() == m_parser->m_mi_rows * m_parser->m_mi_cols);
         // − PrevRefFrames[ row ][ col ][ list ] is set equal to RefFrames[ row ][ col ][ list ] for row = 0..MiRows-1,
         // for col = 0..MiCols-1, for list = 0..1.
         // − PrevMvs[ row ][ col ][ list ][ comp ] is set equal to Mvs[ row ][ col ][ list ][ comp ] for row = 0..MiRows-1,
         // for col = 0..MiCols-1, for list = 0..1, for comp = 0..1.
-
-        // We can copy these.
-        m_parser->m_prev_ref_frames = m_parser->m_ref_frames;
-        m_parser->m_prev_mvs = m_parser->m_mvs;
+        size_t size = m_parser->m_frame_block_contexts.size();
+        m_parser->m_prev_ref_frames.resize_and_keep_capacity(size);
+        m_parser->m_prev_mvs.resize_and_keep_capacity(size);
+        for (size_t i = 0; i < size; i++) {
+            auto context = m_parser->m_frame_block_contexts[i];
+            m_parser->m_prev_ref_frames[i] = context.ref_frames;
+            m_parser->m_prev_mvs[i] = context.primary_motion_vector_pair();
+        }
     }
 
     return {};

+ 57 - 127
Userland/Libraries/LibVideo/VP9/Parser.cpp

@@ -332,8 +332,11 @@ void Parser::compute_image_size()
     bool first_invoke = !m_mi_cols && !m_mi_rows;
     bool same_size = m_mi_cols == new_cols && m_mi_rows == new_rows;
     if (first_invoke || !same_size) {
-        // m_segment_ids will be resized from decode_tiles() later.
-        m_segment_ids.clear_with_capacity();
+        // FIXME: Does this ever do anything? Segment IDs are already reset every frame. It's also suspicious
+        //        that spec refers to this as SegmentId rather than SegmentIds (plural). Is this supposed to
+        //        refer to PrevSegmentIds?
+        for (size_t i = 0; i < m_frame_block_contexts.size(); i++)
+            m_frame_block_contexts[i].segment_id = 0;
     }
 
     // 2. The variable UsePrevFrameMvs is set equal to 1 if all of the following conditions are true:
@@ -657,6 +660,8 @@ DecoderErrorOr<void> Parser::read_is_inter_probs()
 
 DecoderErrorOr<void> Parser::frame_reference_mode()
 {
+    // FIXME: These fields and the ones set in setup_compound_reference_mode should probably be contained by a field,
+    //        since they are all used to set the reference frames later in one function (I think).
     auto compound_reference_allowed = false;
     for (size_t i = 2; i <= REFS_PER_FRAME; i++) {
         if (m_ref_frame_sign_bias[i] != m_ref_frame_sign_bias[1])
@@ -798,36 +803,10 @@ void Parser::setup_compound_reference_mode()
     }
 }
 
-void Parser::cleanup_tile_allocations()
-{
-    // FIXME: Is this necessary? Data should be truncated and
-    //        overwritten by the next tile.
-    m_skips.clear_with_capacity();
-    m_tx_sizes.clear_with_capacity();
-    m_mi_sizes.clear_with_capacity();
-    m_y_modes.clear_with_capacity();
-    m_segment_ids.clear_with_capacity();
-    m_ref_frames.clear_with_capacity();
-    m_interp_filters.clear_with_capacity();
-    m_mvs.clear_with_capacity();
-    m_sub_mvs.clear_with_capacity();
-    m_sub_modes.clear_with_capacity();
-}
-
 DecoderErrorOr<void> Parser::allocate_tile_data()
 {
     auto dimensions = m_mi_rows * m_mi_cols;
-    cleanup_tile_allocations();
-    DECODER_TRY_ALLOC(m_skips.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_tx_sizes.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_mi_sizes.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_y_modes.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_segment_ids.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_ref_frames.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_interp_filters.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_mvs.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_sub_mvs.try_resize_and_keep_capacity(dimensions));
-    DECODER_TRY_ALLOC(m_sub_modes.try_resize_and_keep_capacity(dimensions));
+    DECODER_TRY_ALLOC(m_frame_block_contexts.try_resize_and_keep_capacity(dimensions));
     return {};
 }
 
@@ -946,7 +925,7 @@ DecoderErrorOr<void> Parser::decode_partition(u32 row, u32 column, BlockSubsize
     return {};
 }
 
-size_t Parser::get_image_index(u32 row, u32 column)
+size_t Parser::get_image_index(u32 row, u32 column) const
 {
     VERIFY(row < m_mi_rows && column < m_mi_cols);
     return row * m_mi_cols + column;
@@ -975,26 +954,7 @@ DecoderErrorOr<void> Parser::decode_block(u32 row, u32 col, BlockSubsize subsize
     for (size_t y = 0; y < maximum_block_y; y++) {
         for (size_t x = 0; x < maximum_block_x; x++) {
             auto pos = get_image_index(row + y, col + x);
-            m_skips[pos] = m_skip;
-            m_tx_sizes[pos] = m_tx_size;
-            m_mi_sizes[pos] = m_mi_size;
-            m_y_modes[pos] = m_y_mode;
-            m_segment_ids[pos] = m_segment_id;
-            for (size_t ref_list = 0; ref_list < 2; ref_list++)
-                m_ref_frames[pos][ref_list] = m_ref_frame[ref_list];
-            if (m_is_inter) {
-                m_interp_filters[pos] = m_interp_filter;
-                for (size_t ref_list = 0; ref_list < 2; ref_list++) {
-                    // FIXME: Can we just store all the sub_mvs and then look up
-                    //        the main one by index 3?
-                    m_mvs[pos][ref_list] = m_block_mvs[ref_list][3];
-                    for (size_t b = 0; b < 4; b++)
-                        m_sub_mvs[pos][ref_list][b] = m_block_mvs[ref_list][b];
-                }
-            } else {
-                for (size_t b = 0; b < 4; b++)
-                    m_sub_modes[pos][b] = static_cast<PredictionMode>(m_block_sub_modes[b]);
-            }
+            m_frame_block_contexts[pos] = 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 };
         }
     }
     return {};
@@ -1019,16 +979,9 @@ DecoderErrorOr<void> Parser::intra_frame_mode_info()
     m_is_inter = false;
     // 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.
+    auto above_context = get_above_context();
+    auto left_context = get_left_context();
     if (m_mi_size >= Block_8x8) {
-        // FIXME: This context should be available in the block setup. Make a struct to store the context
-        //        that is needed to call the tree parses and set it in decode_block().
-        auto above_context = Optional<Array<PredictionMode, 4> const&>();
-        auto left_context = Optional<Array<PredictionMode, 4> const&>();
-        if (m_available_u)
-            above_context = m_sub_modes[get_image_index(m_mi_row - 1, m_mi_col)];
-        if (m_available_l)
-            left_context = m_sub_modes[get_image_index(m_mi_row, m_mi_col - 1)];
-
         m_y_mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, m_mi_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;
@@ -1037,13 +990,6 @@ DecoderErrorOr<void> Parser::intra_frame_mode_info()
         m_num_4x4_h = num_4x4_blocks_high_lookup[m_mi_size];
         for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
             for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
-                // FIXME: See the FIXME above.
-                auto above_context = Optional<Array<PredictionMode, 4> const&>();
-                auto left_context = Optional<Array<PredictionMode, 4> const&>();
-                if (m_available_u)
-                    above_context = m_sub_modes[get_image_index(m_mi_row - 1, m_mi_col)];
-                if (m_available_l)
-                    left_context = m_sub_modes[get_image_index(m_mi_row, m_mi_col - 1)];
                 auto sub_mode = TRY_READ(TreeParser::parse_default_intra_mode(*m_bit_stream, *m_probability_tables, m_mi_size, above_context, left_context, m_block_sub_modes, idx, idy));
 
                 for (auto y = 0; y < m_num_4x4_h; y++) {
@@ -1069,14 +1015,26 @@ DecoderErrorOr<void> Parser::intra_segment_id()
     return {};
 }
 
+FrameBlockContext Parser::get_above_context() const
+{
+    if (!m_available_u)
+        return FrameBlockContext { .is_available = false };
+    return m_frame_block_contexts[get_image_index(m_mi_row - 1, m_mi_col)];
+}
+
+FrameBlockContext Parser::get_left_context() const
+{
+    if (!m_available_l)
+        return FrameBlockContext { .is_available = false };
+    return m_frame_block_contexts[get_image_index(m_mi_row, m_mi_col - 1)];
+}
+
 DecoderErrorOr<void> Parser::read_skip()
 {
     if (seg_feature_active(SEG_LVL_SKIP)) {
         m_skip = true;
     } else {
-        Optional<bool> above_skip = m_available_u ? m_skips[get_image_index(m_mi_row - 1, m_mi_col)] : Optional<bool>();
-        Optional<bool> left_skip = m_available_l ? m_skips[get_image_index(m_mi_row, m_mi_col - 1)] : Optional<bool>();
-        m_skip = TRY_READ(TreeParser::parse_skip(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_skip, left_skip));
+        m_skip = TRY_READ(TreeParser::parse_skip(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, get_above_context(), get_left_context()));
     }
     return {};
 }
@@ -1089,28 +1047,15 @@ bool Parser::seg_feature_active(u8 feature)
 DecoderErrorOr<void> Parser::read_tx_size(bool allow_select)
 {
     m_max_tx_size = max_txsize_lookup[m_mi_size];
-    if (allow_select && m_tx_mode == TXModeSelect && m_mi_size >= Block_8x8) {
-        Optional<bool> above_skip = m_available_u ? m_skips[get_image_index(m_mi_row - 1, m_mi_col)] : Optional<bool>();
-        Optional<bool> left_skip = m_available_l ? m_skips[get_image_index(m_mi_row, m_mi_col - 1)] : Optional<bool>();
-        Optional<TXSize> above_tx_size = m_available_u ? m_tx_sizes[get_image_index(m_mi_row - 1, m_mi_col)] : Optional<TXSize>();
-        Optional<TXSize> left_tx_size = m_available_l ? m_tx_sizes[get_image_index(m_mi_row, m_mi_col - 1)] : Optional<TXSize>();
-        m_tx_size = TRY_READ(TreeParser::parse_tx_size(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_max_tx_size, above_skip, left_skip, above_tx_size, left_tx_size));
-    } else {
+    if (allow_select && m_tx_mode == TXModeSelect && m_mi_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, get_above_context(), get_left_context()));
+    else
         m_tx_size = min(m_max_tx_size, tx_mode_to_biggest_tx_size[m_tx_mode]);
-    }
     return {};
 }
 
 DecoderErrorOr<void> Parser::inter_frame_mode_info()
 {
-    m_left_ref_frame[0] = m_available_l ? m_ref_frames[get_image_index(m_mi_row, m_mi_col - 1)][0] : IntraFrame;
-    m_above_ref_frame[0] = m_available_u ? m_ref_frames[get_image_index(m_mi_row - 1, m_mi_col)][0] : IntraFrame;
-    m_left_ref_frame[1] = m_available_l ? m_ref_frames[get_image_index(m_mi_row, m_mi_col - 1)][1] : None;
-    m_above_ref_frame[1] = m_available_u ? m_ref_frames[get_image_index(m_mi_row - 1, m_mi_col)][1] : None;
-    m_left_intra = m_left_ref_frame[0] <= IntraFrame;
-    m_above_intra = m_above_ref_frame[0] <= IntraFrame;
-    m_left_single = m_left_ref_frame[1] <= None;
-    m_above_single = m_above_ref_frame[1] <= None;
     TRY(inter_segment_id());
     TRY(read_skip());
     TRY(read_is_inter());
@@ -1169,7 +1114,7 @@ u8 Parser::get_segment_id()
     u8 segment = 7;
     for (size_t y = 0; y < ymis; y++) {
         for (size_t x = 0; x < xmis; x++) {
-            segment = min(segment, m_prev_segment_ids[(m_mi_row + y) + (m_mi_col + x)]);
+            segment = min(segment, m_prev_segment_ids[get_image_index(m_mi_row + y, m_mi_col + x)]);
         }
     }
     return segment;
@@ -1177,13 +1122,10 @@ u8 Parser::get_segment_id()
 
 DecoderErrorOr<void> Parser::read_is_inter()
 {
-    if (seg_feature_active(SEG_LVL_REF_FRAME)) {
+    if (seg_feature_active(SEG_LVL_REF_FRAME))
         m_is_inter = m_feature_data[m_segment_id][SEG_LVL_REF_FRAME] != IntraFrame;
-    } else {
-        Optional<bool> above_intra = m_available_u ? m_above_intra : Optional<bool>();
-        Optional<bool> left_intra = m_available_l ? m_left_intra : Optional<bool>();
-        m_is_inter = TRY_READ(TreeParser::parse_is_inter(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_intra, left_intra));
-    }
+    else
+        m_is_inter = TRY_READ(TreeParser::parse_block_is_inter_predicted(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, get_above_context(), get_left_context()));
     return {};
 }
 
@@ -1229,15 +1171,10 @@ DecoderErrorOr<void> Parser::inter_block_mode_info()
     } else if (m_mi_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]]));
     }
-    if (m_interpolation_filter == Switchable) {
-        Optional<ReferenceFrameType> above_ref_frame = m_available_u ? m_ref_frames[get_image_index(m_mi_row - 1, m_mi_col)][0] : Optional<ReferenceFrameType>();
-        Optional<ReferenceFrameType> left_ref_frame = m_available_l ? m_ref_frames[get_image_index(m_mi_row, m_mi_col - 1)][0] : Optional<ReferenceFrameType>();
-        Optional<InterpolationFilter> above_interpolation_filter = m_available_u ? m_interp_filters[get_image_index(m_mi_row - 1, m_mi_col)] : Optional<InterpolationFilter>();
-        Optional<InterpolationFilter> left_interpolation_filter = m_available_l ? m_interp_filters[get_image_index(m_mi_row, m_mi_col - 1)] : Optional<InterpolationFilter>();
-        m_interp_filter = TRY_READ(TreeParser::parse_interpolation_filter(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, above_ref_frame, left_ref_frame, above_interpolation_filter, left_interpolation_filter));
-    } else {
+    if (m_interpolation_filter == Switchable)
+        m_interp_filter = TRY_READ(TreeParser::parse_interpolation_filter(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, get_above_context(), get_left_context()));
+    else
         m_interp_filter = m_interpolation_filter;
-    }
     if (m_mi_size < Block_8x8) {
         m_num_4x4_w = num_4x4_blocks_wide_lookup[m_mi_size];
         m_num_4x4_h = num_4x4_blocks_high_lookup[m_mi_size];
@@ -1278,36 +1215,28 @@ DecoderErrorOr<void> Parser::read_ref_frames()
         return {};
     }
     ReferenceMode comp_mode;
-    Optional<bool> above_single = m_available_u ? m_above_single : Optional<bool>();
-    Optional<bool> left_single = m_available_l ? m_left_single : Optional<bool>();
-    Optional<bool> above_intra = m_available_u ? m_above_intra : Optional<bool>();
-    Optional<bool> left_intra = m_available_l ? m_left_intra : Optional<bool>();
-    Optional<ReferenceFrameType> above_ref_frame_0 = m_available_u ? m_above_ref_frame[0] : Optional<ReferenceFrameType>();
-    Optional<ReferenceFrameType> left_ref_frame_0 = m_available_l ? m_left_ref_frame[0] : Optional<ReferenceFrameType>();
-    Optional<ReferenceFramePair> above_ref_frame = m_available_u ? m_above_ref_frame : Optional<ReferenceFramePair>();
-    Optional<ReferenceFramePair> left_ref_frame = m_available_l ? m_left_ref_frame : Optional<ReferenceFramePair>();
-    if (m_reference_mode == ReferenceModeSelect) {
-        comp_mode = TRY_READ(TreeParser::parse_comp_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_comp_fixed_ref, above_single, left_single, above_intra, left_intra, above_ref_frame_0, left_ref_frame_0));
-    } else {
+    auto above_context = get_above_context();
+    auto left_context = get_left_context();
+    if (m_reference_mode == ReferenceModeSelect)
+        comp_mode = TRY_READ(TreeParser::parse_comp_mode(*m_bit_stream, *m_probability_tables, *m_syntax_element_counter, m_comp_fixed_ref, above_context, left_context));
+    else
         comp_mode = m_reference_mode;
-    }
     if (comp_mode == CompoundReference) {
-        auto biased_reference_index = m_ref_frame_sign_bias[m_comp_fixed_ref];
-        auto inverse_biased_reference_index = biased_reference_index == 0 ? 1 : 0;
+        // FIXME: Make reference frame pairs be indexed by an enum of FixedReference or VariableReference?
+        auto fixed_reference_index = m_ref_frame_sign_bias[m_comp_fixed_ref];
+        auto variable_reference_index = fixed_reference_index == 0 ? 1 : 0;
 
-        Optional<ReferenceFrameType> above_ref_frame_biased = m_available_u ? m_above_ref_frame[inverse_biased_reference_index] : Optional<ReferenceFrameType>();
-        Optional<ReferenceFrameType> left_ref_frame_biased = m_available_l ? m_left_ref_frame[inverse_biased_reference_index] : Optional<ReferenceFrameType>();
         // 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, above_single, left_single, above_intra, left_intra, above_ref_frame_0, left_ref_frame_0, above_ref_frame_biased, left_ref_frame_biased));
+        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[biased_reference_index] = m_comp_fixed_ref;
-        m_ref_frame[inverse_biased_reference_index] = m_comp_var_ref[comp_ref];
+        m_ref_frame[fixed_reference_index] = m_comp_fixed_ref;
+        m_ref_frame[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_single, left_single, above_intra, left_intra, above_ref_frame, left_ref_frame));
+    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_single, left_single, above_intra, left_intra, above_ref_frame, left_ref_frame));
+        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;
     } else {
         m_ref_frame[0] = LastFrame;
@@ -1577,8 +1506,9 @@ void Parser::get_block_mv(u32 candidate_row, u32 candidate_column, u8 ref_list,
         m_candidate_mv[ref_list] = m_prev_mvs[index][ref_list];
         m_candidate_frame[ref_list] = m_prev_ref_frames[index][ref_list];
     } else {
-        m_candidate_mv[ref_list] = m_mvs[index][ref_list];
-        m_candidate_frame[ref_list] = m_ref_frames[index][ref_list];
+        auto current_context = m_frame_block_contexts[index];
+        m_candidate_mv[ref_list] = current_context.primary_motion_vector_pair()[ref_list];
+        m_candidate_frame[ref_list] = current_context.ref_frames[ref_list];
     }
 }
 
@@ -1656,12 +1586,12 @@ void Parser::find_mv_refs(ReferenceFrameType reference_frame, i32 block)
 
         if (is_inside(candidate.row(), candidate.column())) {
             auto candidate_index = get_image_index(candidate.row(), candidate.column());
-            auto index = get_image_index(candidate.row(), candidate.column());
             different_ref_found = true;
-            context_counter += mode_2_counter[to_underlying(m_y_modes[index])];
+            auto context = m_frame_block_contexts[candidate_index];
+            context_counter += mode_2_counter[to_underlying(context.y_mode)];
 
             for (auto ref_list = 0u; ref_list < 2; ref_list++) {
-                if (m_ref_frames[candidate_index][ref_list] == reference_frame) {
+                if (context.ref_frames[ref_list] == reference_frame) {
                     // This section up until add_mv_ref_list() is defined in spec as get_sub_block_mv().
                     constexpr u8 idx_n_column_to_subblock[4][2] = {
                         { 1, 2 },
@@ -1670,7 +1600,7 @@ void Parser::find_mv_refs(ReferenceFrameType reference_frame, i32 block)
                         { 3, 3 }
                     };
                     auto index = block >= 0 ? idx_n_column_to_subblock[block][offset_vector.column() == 0] : 3;
-                    m_candidate_mv[ref_list] = m_sub_mvs[candidate_index][ref_list][index];
+                    m_candidate_mv[ref_list] = context.sub_block_motion_vectors[ref_list][index];
 
                     add_mv_ref_list(ref_list);
                     break;

+ 14 - 24
Userland/Libraries/LibVideo/VP9/Parser.h

@@ -51,7 +51,6 @@ private:
     template<typename T>
     void clear_context(Vector<Vector<T>>& context, size_t outer_size, size_t inner_size);
     DecoderErrorOr<void> allocate_tile_data();
-    void cleanup_tile_allocations();
 
     /* (6.1) Frame Syntax */
     bool trailing_bits();
@@ -86,6 +85,8 @@ private:
     u8 inv_remap_prob(u8 delta_prob, u8 prob);
     u8 inv_recenter_nonneg(u8 v, u8 m);
     DecoderErrorOr<void> read_coef_probs();
+    FrameBlockContext get_above_context() const;
+    FrameBlockContext get_left_context() const;
     DecoderErrorOr<void> read_skip_prob();
     DecoderErrorOr<void> read_inter_mode_probs();
     DecoderErrorOr<void> read_interp_filter_probs();
@@ -137,7 +138,7 @@ private:
     bool is_inside(i32 row, i32 column);
     void clamp_mv_ref(u8 i);
     MotionVector clamp_mv(MotionVector mvec, i32 border);
-    size_t get_image_index(u32 row, u32 column);
+    size_t get_image_index(u32 row, u32 column) const;
     void get_block_mv(u32 candidate_row, u32 candidate_column, u8 ref_list, bool use_prev);
     void if_same_ref_frame_add_mv(u32 candidate_row, u32 candidate_column, ReferenceFrameType ref_frame, bool use_prev);
     void if_diff_ref_frame_add_mv(u32 candidate_row, u32 candidate_column, ReferenceFrameType ref_frame, bool use_prev);
@@ -234,16 +235,6 @@ private:
     u8 m_num_4x4_w { 0 };
     u8 m_num_4x4_h { 0 };
     PredictionMode m_uv_mode { 0 }; // FIXME: Is u8 the right size?
-    // FIXME: From spec: NOTE – We are using a 2D array to store the SubModes for clarity. It is possible to reduce memory
-    // consumption by only storing one intra mode for each 8x8 horizontal and vertical position, i.e. to use two 1D
-    // arrays instead.
-    Vector<Array<PredictionMode, 4>> m_sub_modes;
-    ReferenceFramePair m_left_ref_frame;
-    ReferenceFramePair m_above_ref_frame;
-    bool m_left_intra { false };
-    bool m_above_intra { false };
-    bool m_left_single { false };
-    bool m_above_single { false };
     // The current block's interpolation filter.
     InterpolationFilter m_interp_filter { EightTap };
     MotionVectorPair m_mv;
@@ -267,25 +258,24 @@ private:
     ReferenceMode m_reference_mode;
     ReferenceFrameType m_comp_fixed_ref;
     ReferenceFramePair m_comp_var_ref;
-    MotionVector m_block_mvs[2][4];
+    // FIXME: Use Array<MotionVectorPair, 4> instead.
+    Array<Array<MotionVector, 4>, 2> m_block_mvs;
     Vector<u8> m_prev_segment_ids;
 
-    Vector<bool> m_skips;
-    Vector<TXSize> m_tx_sizes;
-    Vector<u32> m_mi_sizes;
-    Vector<PredictionMode> m_y_modes;
-    Vector<u8> m_segment_ids;
-    Vector<ReferenceFramePair> m_ref_frames;
-    Vector<ReferenceFramePair> m_prev_ref_frames;
-    Vector<MotionVectorPair> m_mvs;
-    Vector<MotionVectorPair> m_prev_mvs;
+    // FIXME: From spec: NOTE – We are using a 2D array to store the SubModes for clarity. It is possible to reduce memory
+    //        consumption by only storing one intra mode for each 8x8 horizontal and vertical position, i.e. to use two 1D
+    //        arrays instead.
+    //        I think should also apply to other fields that are only accessed relative to the current block. Worth looking
+    //        into how much of this context needs to be stored for the whole frame vs a row or column from the current tile.
+    Vector<FrameBlockContext> m_frame_block_contexts;
+
     MotionVectorPair m_candidate_mv;
     ReferenceFramePair m_candidate_frame;
-    Vector<Array<Array<MotionVector, 4>, 2>> m_sub_mvs;
     u8 m_ref_mv_count { 0 };
     MotionVectorPair m_ref_list_mv;
     bool m_use_prev_frame_mvs;
-    Vector<InterpolationFilter> m_interp_filters;
+    Vector<ReferenceFramePair> m_prev_ref_frames;
+    Vector<MotionVectorPair> m_prev_mvs;
     // Indexed by ReferenceFrame enum.
     u8 m_mode_context[4] { INVALID_CASE };
 

+ 144 - 148
Userland/Libraries/LibVideo/VP9/TreeParser.cpp

@@ -80,7 +80,7 @@ ErrorOr<Partition> TreeParser::parse_partition(BitStream& bit_stream, Probabilit
     return value;
 }
 
-ErrorOr<PredictionMode> TreeParser::parse_default_intra_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, BlockSubsize mi_size, Optional<Array<PredictionMode, 4> const&> above_context, Optional<Array<PredictionMode, 4> const&> left_context, Array<PredictionMode, 4> const& block_sub_modes, u8 index_x, u8 index_y)
+ErrorOr<PredictionMode> TreeParser::parse_default_intra_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, BlockSubsize mi_size, FrameBlockContext above, FrameBlockContext left, Array<PredictionMode, 4> const& block_sub_modes, u8 index_x, u8 index_y)
 {
     // FIXME: This should use a struct for the above and left contexts.
 
@@ -90,18 +90,18 @@ ErrorOr<PredictionMode> TreeParser::parse_default_intra_mode(BitStream& bit_stre
     // Probabilities
     PredictionMode above_mode, left_mode;
     if (mi_size >= Block_8x8) {
-        above_mode = above_context.has_value() ? above_context.value()[2] : PredictionMode::DcPred;
-        left_mode = left_context.has_value() ? left_context.value()[1] : PredictionMode::DcPred;
+        above_mode = above.sub_modes[2];
+        left_mode = left.sub_modes[1];
     } else {
         if (index_y > 0)
             above_mode = block_sub_modes[index_x];
         else
-            above_mode = above_context.has_value() ? above_context.value()[2 + index_x] : PredictionMode::DcPred;
+            above_mode = above.sub_modes[2 + index_x];
 
         if (index_x > 0)
             left_mode = block_sub_modes[index_y << 1];
         else
-            left_mode = left_context.has_value() ? left_context.value()[1 + (index_y << 1)] : PredictionMode::DcPred;
+            left_mode = left.sub_modes[1 + (index_y << 1)];
     }
     u8 const* probabilities = probability_table.kf_y_mode_probs()[to_underlying(above_mode)][to_underlying(left_mode)];
 
@@ -191,7 +191,7 @@ ErrorOr<PredictionMode> TreeParser::parse_inter_mode(BitStream& bit_stream, Prob
     return value;
 }
 
-ErrorOr<InterpolationFilter> TreeParser::parse_interpolation_filter(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional<ReferenceFrameType> above_ref_frame, Optional<ReferenceFrameType> left_ref_frame, Optional<InterpolationFilter> above_interpolation_filter, Optional<InterpolationFilter> left_interpolation_filter)
+ErrorOr<InterpolationFilter> TreeParser::parse_interpolation_filter(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left context should be provided by a struct.
 
@@ -202,12 +202,8 @@ ErrorOr<InterpolationFilter> TreeParser::parse_interpolation_filter(BitStream& b
     // NOTE: SWITCHABLE_FILTERS is not used in the spec for this function. Therefore, the number
     //       was demystified by referencing the reference codec libvpx:
     //       https://github.com/webmproject/libvpx/blob/705bf9de8c96cfe5301451f1d7e5c90a41c64e5f/vp9/common/vp9_pred_common.h#L69
-    u8 left_interp = (left_ref_frame.has_value() && left_ref_frame.value() > IntraFrame)
-        ? left_interpolation_filter.value()
-        : SWITCHABLE_FILTERS;
-    u8 above_interp = (above_ref_frame.has_value() && above_ref_frame.value() > IntraFrame)
-        ? above_interpolation_filter.value()
-        : SWITCHABLE_FILTERS;
+    u8 left_interp = left.ref_frames[0] > ReferenceFrameType::None ? left.interpolation_filter : SWITCHABLE_FILTERS;
+    u8 above_interp = above.ref_frames[0] > ReferenceFrameType::None ? above.interpolation_filter : SWITCHABLE_FILTERS;
     u8 context = SWITCHABLE_FILTERS;
     if (above_interp == left_interp || above_interp == SWITCHABLE_FILTERS)
         context = left_interp;
@@ -220,12 +216,12 @@ ErrorOr<InterpolationFilter> TreeParser::parse_interpolation_filter(BitStream& b
     return value;
 }
 
-ErrorOr<bool> TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional<bool> const& above_skip, Optional<bool> const& left_skip)
+ErrorOr<bool> TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left)
 {
     // Probabilities
     u8 context = 0;
-    context += static_cast<u8>(above_skip.value_or(false));
-    context += static_cast<u8>(left_skip.value_or(false));
+    context += static_cast<u8>(above.skip_coefficients);
+    context += static_cast<u8>(left.skip_coefficients);
     u8 probability = probability_table.skip_prob()[context];
 
     auto value = TRY(parse_tree<bool>(bit_stream, { binary_tree }, [&](u8) { return probability; }));
@@ -233,7 +229,7 @@ ErrorOr<bool> TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables co
     return value;
 }
 
-ErrorOr<TXSize> TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TXSize max_tx_size, Optional<bool> above_skip, Optional<bool> left_skip, Optional<TXSize> above_tx_size, Optional<TXSize> left_tx_size)
+ErrorOr<TXSize> TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TXSize max_tx_size, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
@@ -245,19 +241,18 @@ ErrorOr<TXSize> TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTabl
         tree = { tx_size_32_tree };
 
     // Probabilities
-    auto above = max_tx_size;
-    auto left = max_tx_size;
-    if (above_skip.has_value() && !above_skip.value()) {
-        above = above_tx_size.value();
-    }
-    if (left_skip.has_value() && !left_skip.value()) {
-        left = left_tx_size.value();
-    }
-    if (!left_skip.has_value())
-        left = above;
-    if (!above_skip.has_value())
-        above = left;
-    auto context = (above + left) > max_tx_size;
+    auto above_context = max_tx_size;
+    auto left_context = max_tx_size;
+    if (above.is_available && !above.skip_coefficients)
+        above_context = above.tx_size;
+    if (left.is_available && !left.skip_coefficients)
+        left_context = left.tx_size;
+    if (!left.is_available)
+        left_context = above_context;
+    if (!above.is_available)
+        above_context = left_context;
+    auto context = (above_context + left_context) > max_tx_size;
+
     u8 const* probabilities = probability_table.tx_probs()[max_tx_size][context];
 
     auto value = TRY(parse_tree<TXSize>(bit_stream, tree, [&](u8 node) { return probabilities[node]; }));
@@ -265,16 +260,16 @@ ErrorOr<TXSize> TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTabl
     return value;
 }
 
-ErrorOr<bool> TreeParser::parse_is_inter(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional<bool> above_intra, Optional<bool> left_intra)
+ErrorOr<bool> TreeParser::parse_block_is_inter_predicted(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
     // Probabilities
     u8 context = 0;
-    if (above_intra.has_value() && left_intra.has_value())
-        context = (left_intra.value() && above_intra.value()) ? 3 : static_cast<u8>(above_intra.value() || left_intra.value());
-    else if (above_intra.has_value() || left_intra.has_value())
-        context = 2 * static_cast<u8>(above_intra.has_value() ? above_intra.value() : left_intra.value());
+    if (above.is_available && left.is_available)
+        context = (left.is_intra_predicted() && above.is_intra_predicted()) ? 3 : static_cast<u8>(above.is_intra_predicted() || left.is_intra_predicted());
+    else if (above.is_available || left.is_available)
+        context = 2 * static_cast<u8>(above.is_available ? above.is_intra_predicted() : left.is_intra_predicted());
     u8 probability = probability_table.is_inter_prob()[context];
 
     auto value = TRY(parse_tree<bool>(bit_stream, { binary_tree }, [&](u8) { return probability; }));
@@ -282,34 +277,34 @@ ErrorOr<bool> TreeParser::parse_is_inter(BitStream& bit_stream, ProbabilityTable
     return value;
 }
 
-ErrorOr<ReferenceMode> TreeParser::parse_comp_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFrameType> above_ref_frame_0, Optional<ReferenceFrameType> left_ref_frame_0)
+ErrorOr<ReferenceMode> TreeParser::parse_comp_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
     // Probabilities
     u8 context;
-    if (above_single.has_value() && left_single.has_value()) {
-        if (above_single.value() && left_single.value()) {
-            auto is_above_fixed = above_ref_frame_0.value() == comp_fixed_ref;
-            auto is_left_fixed = left_ref_frame_0.value() == comp_fixed_ref;
+    if (above.is_available && left.is_available) {
+        if (above.is_single_reference() && left.is_single_reference()) {
+            auto is_above_fixed = above.ref_frames[0] == comp_fixed_ref;
+            auto is_left_fixed = left.ref_frames[0] == comp_fixed_ref;
             context = is_above_fixed ^ is_left_fixed;
-        } else if (above_single.value()) {
-            auto is_above_fixed = above_ref_frame_0.value() == comp_fixed_ref;
-            context = 2 + static_cast<u8>(is_above_fixed || above_intra.value());
-        } else if (left_single.value()) {
-            auto is_left_fixed = left_ref_frame_0.value() == comp_fixed_ref;
-            context = 2 + static_cast<u8>(is_left_fixed || left_intra.value());
+        } else if (above.is_single_reference()) {
+            auto is_above_fixed = above.ref_frames[0] == comp_fixed_ref;
+            context = 2 + static_cast<u8>(is_above_fixed || above.is_intra_predicted());
+        } else if (left.is_single_reference()) {
+            auto is_left_fixed = left.ref_frames[0] == comp_fixed_ref;
+            context = 2 + static_cast<u8>(is_left_fixed || left.is_intra_predicted());
         } else {
             context = 4;
         }
-    } else if (above_single.has_value()) {
-        if (above_single.value())
-            context = above_ref_frame_0.value() == comp_fixed_ref;
+    } else if (above.is_available) {
+        if (above.is_single_reference())
+            context = above.ref_frames[0] == comp_fixed_ref;
         else
             context = 3;
-    } else if (left_single.has_value()) {
-        if (left_single.value())
-            context = static_cast<u8>(left_ref_frame_0.value() == comp_fixed_ref);
+    } else if (left.is_available) {
+        if (left.is_single_reference())
+            context = static_cast<u8>(left.ref_frames[0] == comp_fixed_ref);
         else
             context = 3;
     } else {
@@ -322,33 +317,34 @@ ErrorOr<ReferenceMode> TreeParser::parse_comp_mode(BitStream& bit_stream, Probab
     return value;
 }
 
-ErrorOr<bool> TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFrameType> above_ref_frame_0, Optional<ReferenceFrameType> left_ref_frame_0, Optional<ReferenceFrameType> above_ref_frame_biased, Optional<ReferenceFrameType> left_ref_frame_biased)
+ErrorOr<bool> TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, u8 variable_reference_index, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
     // Probabilities
     u8 context;
-    if (above_intra.has_value() && left_intra.has_value()) {
-        if (above_intra.value() && left_intra.value()) {
+
+    if (above.is_available && left.is_available) {
+        if (above.is_intra_predicted() && left.is_intra_predicted()) {
             context = 2;
-        } else if (left_intra.value()) {
-            if (above_single.value()) {
-                context = 1 + 2 * (above_ref_frame_0.value() != comp_var_ref[1]);
+        } else if (left.is_intra_predicted()) {
+            if (above.is_single_reference()) {
+                context = 1 + 2 * (above.ref_frames[0] != comp_var_ref[1]);
             } else {
-                context = 1 + 2 * (above_ref_frame_biased.value() != comp_var_ref[1]);
+                context = 1 + 2 * (above.ref_frames[variable_reference_index] != comp_var_ref[1]);
             }
-        } else if (above_intra.value()) {
-            if (left_single.value()) {
-                context = 1 + 2 * (left_ref_frame_0.value() != comp_var_ref[1]);
+        } else if (above.is_intra_predicted()) {
+            if (left.is_single_reference()) {
+                context = 1 + 2 * (left.ref_frames[0] != comp_var_ref[1]);
             } else {
-                context = 1 + 2 * (left_ref_frame_biased != comp_var_ref[1]);
+                context = 1 + 2 * (left.ref_frames[variable_reference_index] != comp_var_ref[1]);
             }
         } else {
-            auto var_ref_above = above_single.value() ? above_ref_frame_0 : above_ref_frame_biased;
-            auto var_ref_left = left_single.value() ? left_ref_frame_0 : left_ref_frame_biased;
+            auto var_ref_above = above.is_single_reference() ? above.ref_frames[0] : above.ref_frames[variable_reference_index];
+            auto var_ref_left = left.is_single_reference() ? left.ref_frames[0] : left.ref_frames[variable_reference_index];
             if (var_ref_above == var_ref_left && comp_var_ref[1] == var_ref_above) {
                 context = 0;
-            } else if (left_single.value() && above_single.value()) {
+            } else if (left.is_single_reference() && above.is_single_reference()) {
                 if ((var_ref_above == comp_fixed_ref && var_ref_left == comp_var_ref[0])
                     || (var_ref_left == comp_fixed_ref && var_ref_above == comp_var_ref[0])) {
                     context = 4;
@@ -357,9 +353,9 @@ ErrorOr<bool> TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTable
                 } else {
                     context = 1;
                 }
-            } else if (left_single.value() || above_single.value()) {
-                auto vrfc = left_single.value() ? var_ref_above : var_ref_left;
-                auto rfs = above_single.value() ? var_ref_above : var_ref_left;
+            } else if (left.is_single_reference() || above.is_single_reference()) {
+                auto vrfc = left.is_single_reference() ? var_ref_above : var_ref_left;
+                auto rfs = above.is_single_reference() ? var_ref_above : var_ref_left;
                 if (vrfc == comp_var_ref[1] && rfs != comp_var_ref[1]) {
                     context = 1;
                 } else if (rfs == comp_var_ref[1] && vrfc != comp_var_ref[1]) {
@@ -373,24 +369,24 @@ ErrorOr<bool> TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTable
                 context = 2;
             }
         }
-    } else if (above_intra.has_value()) {
-        if (above_intra.value()) {
+    } else if (above.is_available) {
+        if (above.is_intra_predicted()) {
             context = 2;
         } else {
-            if (above_single.value()) {
-                context = 3 * static_cast<u8>(above_ref_frame_0.value() != comp_var_ref[1]);
+            if (above.is_single_reference()) {
+                context = 3 * static_cast<u8>(above.ref_frames[0] != comp_var_ref[1]);
             } else {
-                context = 4 * static_cast<u8>(above_ref_frame_biased.value() != comp_var_ref[1]);
+                context = 4 * static_cast<u8>(above.ref_frames[variable_reference_index] != comp_var_ref[1]);
             }
         }
-    } else if (left_intra.has_value()) {
-        if (left_intra.value()) {
+    } else if (left.is_available) {
+        if (left.is_intra_predicted()) {
             context = 2;
         } else {
-            if (left_single.value()) {
-                context = 3 * static_cast<u8>(left_ref_frame_0.value() != comp_var_ref[1]);
+            if (left.is_single_reference()) {
+                context = 3 * static_cast<u8>(left.ref_frames[0] != comp_var_ref[1]);
             } else {
-                context = 4 * static_cast<u8>(left_ref_frame_biased != comp_var_ref[1]);
+                context = 4 * static_cast<u8>(left.ref_frames[variable_reference_index] != comp_var_ref[1]);
             }
         }
     } else {
@@ -404,61 +400,61 @@ ErrorOr<bool> TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTable
     return value;
 }
 
-ErrorOr<bool> TreeParser::parse_single_ref_part_1(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFramePair> above_ref_frame, Optional<ReferenceFramePair> left_ref_frame)
+ErrorOr<bool> TreeParser::parse_single_ref_part_1(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
     // Probabilities
     u8 context;
-    if (above_single.has_value() && left_single.has_value()) {
-        if (above_intra.value() && left_intra.value()) {
+    if (above.is_available && left.is_available) {
+        if (above.is_intra_predicted() && left.is_intra_predicted()) {
             context = 2;
-        } else if (left_intra.value()) {
-            if (above_single.value()) {
-                context = 4 * (above_ref_frame.value()[0] == LastFrame);
+        } else if (left.is_intra_predicted()) {
+            if (above.is_single_reference()) {
+                context = 4 * (above.ref_frames[0] == LastFrame);
             } else {
-                context = 1 + (above_ref_frame.value()[0] == LastFrame || above_ref_frame.value()[1] == LastFrame);
+                context = 1 + (above.ref_frames[0] == LastFrame || above.ref_frames[1] == LastFrame);
             }
-        } else if (above_intra.value()) {
-            if (left_single.value()) {
-                context = 4 * (left_ref_frame.value()[0] == LastFrame);
+        } else if (above.is_intra_predicted()) {
+            if (left.is_single_reference()) {
+                context = 4 * (left.ref_frames[0] == LastFrame);
             } else {
-                context = 1 + (left_ref_frame.value()[0] == LastFrame || left_ref_frame.value()[1] == LastFrame);
+                context = 1 + (left.ref_frames[0] == LastFrame || left.ref_frames[1] == LastFrame);
             }
         } else {
-            if (left_single.value() && above_single.value()) {
-                context = 2 * (above_ref_frame.value()[0] == LastFrame) + 2 * (left_ref_frame.value()[0] == LastFrame);
-            } else if (!left_single.value() && !above_single.value()) {
-                auto above_is_last = above_ref_frame.value()[0] == LastFrame || above_ref_frame.value()[1] == LastFrame;
-                auto left_is_last = left_ref_frame.value()[0] == LastFrame || left_ref_frame.value()[1] == LastFrame;
-                context = 1 + (above_is_last || left_is_last);
+            if (left.is_single_reference() && above.is_single_reference()) {
+                context = 2 * (above.ref_frames[0] == LastFrame) + 2 * (left.ref_frames[0] == LastFrame);
+            } else if (!left.is_single_reference() && !above.is_single_reference()) {
+                auto above_used_last_frame = above.ref_frames[0] == LastFrame || above.ref_frames[1] == LastFrame;
+                auto left_used_last_frame = left.ref_frames[0] == LastFrame || left.ref_frames[1] == LastFrame;
+                context = 1 + (above_used_last_frame || left_used_last_frame);
             } else {
-                auto rfs = above_single.value() ? above_ref_frame.value()[0] : left_ref_frame.value()[0];
-                auto crf1 = above_single.value() ? left_ref_frame.value()[0] : above_ref_frame.value()[0];
-                auto crf2 = above_single.value() ? left_ref_frame.value()[1] : above_ref_frame.value()[1];
-                context = crf1 == LastFrame || crf2 == LastFrame;
-                if (rfs == LastFrame)
+                auto single_reference_type = above.is_single_reference() ? above.ref_frames[0] : left.ref_frames[0];
+                auto compound_reference_a_type = above.is_single_reference() ? left.ref_frames[0] : above.ref_frames[0];
+                auto compound_reference_b_type = above.is_single_reference() ? left.ref_frames[1] : above.ref_frames[1];
+                context = compound_reference_a_type == LastFrame || compound_reference_b_type == LastFrame;
+                if (single_reference_type == LastFrame)
                     context += 3;
             }
         }
-    } else if (above_single.has_value()) {
-        if (above_intra.value()) {
+    } else if (above.is_available) {
+        if (above.is_intra_predicted()) {
             context = 2;
         } else {
-            if (above_single.value()) {
-                context = 4 * (above_ref_frame.value()[0] == LastFrame);
+            if (above.is_single_reference()) {
+                context = 4 * (above.ref_frames[0] == LastFrame);
             } else {
-                context = 1 + (above_ref_frame.value()[0] == LastFrame || above_ref_frame.value()[1] == LastFrame);
+                context = 1 + (above.ref_frames[0] == LastFrame || above.ref_frames[1] == LastFrame);
             }
         }
-    } else if (left_single.has_value()) {
-        if (left_intra.value()) {
+    } else if (left.is_available) {
+        if (left.is_intra_predicted()) {
             context = 2;
         } else {
-            if (left_single.value()) {
-                context = 4 * (left_ref_frame.value()[0] == LastFrame);
+            if (left.is_single_reference()) {
+                context = 4 * (left.ref_frames[0] == LastFrame);
             } else {
-                context = 1 + (left_ref_frame.value()[0] == LastFrame || left_ref_frame.value()[1] == LastFrame);
+                context = 1 + (left.ref_frames[0] == LastFrame || left.ref_frames[1] == LastFrame);
             }
         }
     } else {
@@ -471,81 +467,81 @@ ErrorOr<bool> TreeParser::parse_single_ref_part_1(BitStream& bit_stream, Probabi
     return value;
 }
 
-ErrorOr<bool> TreeParser::parse_single_ref_part_2(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFramePair> above_ref_frame, Optional<ReferenceFramePair> left_ref_frame)
+ErrorOr<bool> TreeParser::parse_single_ref_part_2(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left)
 {
     // FIXME: Above and left contexts should be in structs.
 
     // Probabilities
     u8 context;
-    if (above_single.has_value() && left_single.has_value()) {
-        if (above_intra.value() && left_intra.value()) {
+    if (above.is_available && left.is_available) {
+        if (above.is_intra_predicted() && left.is_intra_predicted()) {
             context = 2;
-        } else if (left_intra.value()) {
-            if (above_single.value()) {
-                if (above_ref_frame.value()[0] == LastFrame) {
+        } else if (left.is_intra_predicted()) {
+            if (above.is_single_reference()) {
+                if (above.ref_frames[0] == LastFrame) {
                     context = 3;
                 } else {
-                    context = 4 * (above_ref_frame.value()[0] == GoldenFrame);
+                    context = 4 * (above.ref_frames[0] == GoldenFrame);
                 }
             } else {
-                context = 1 + 2 * (above_ref_frame.value()[0] == GoldenFrame || above_ref_frame.value()[1] == GoldenFrame);
+                context = 1 + 2 * (above.ref_frames[0] == GoldenFrame || above.ref_frames[1] == GoldenFrame);
             }
-        } else if (above_intra.value()) {
-            if (left_single.value()) {
-                if (left_ref_frame.value()[0] == LastFrame) {
+        } else if (above.is_intra_predicted()) {
+            if (left.is_single_reference()) {
+                if (left.ref_frames[0] == LastFrame) {
                     context = 3;
                 } else {
-                    context = 4 * (left_ref_frame.value()[0] == GoldenFrame);
+                    context = 4 * (left.ref_frames[0] == GoldenFrame);
                 }
             } else {
-                context = 1 + 2 * (left_ref_frame.value()[0] == GoldenFrame || left_ref_frame.value()[1] == GoldenFrame);
+                context = 1 + 2 * (left.ref_frames[0] == GoldenFrame || left.ref_frames[1] == GoldenFrame);
             }
         } else {
-            if (left_single.value() && above_single.value()) {
-                auto above_last = above_ref_frame.value()[0] == LastFrame;
-                auto left_last = left_ref_frame.value()[0] == LastFrame;
+            if (left.is_single_reference() && above.is_single_reference()) {
+                auto above_last = above.ref_frames[0] == LastFrame;
+                auto left_last = left.ref_frames[0] == LastFrame;
                 if (above_last && left_last) {
                     context = 3;
                 } else if (above_last) {
-                    context = 4 * (left_ref_frame.value()[0] == GoldenFrame);
+                    context = 4 * (left.ref_frames[0] == GoldenFrame);
                 } else if (left_last) {
-                    context = 4 * (above_ref_frame.value()[0] == GoldenFrame);
+                    context = 4 * (above.ref_frames[0] == GoldenFrame);
                 } else {
-                    context = 2 * (above_ref_frame.value()[0] == GoldenFrame) + 2 * (left_ref_frame.value()[0] == GoldenFrame);
+                    context = 2 * (above.ref_frames[0] == GoldenFrame) + 2 * (left.ref_frames[0] == GoldenFrame);
                 }
-            } else if (!left_single.value() && !above_single.value()) {
-                if (above_ref_frame.value()[0] == left_ref_frame.value()[0] && above_ref_frame.value()[1] == left_ref_frame.value()[1]) {
-                    context = 3 * (above_ref_frame.value()[0] == GoldenFrame || above_ref_frame.value()[1] == GoldenFrame);
+            } else if (!left.is_single_reference() && !above.is_single_reference()) {
+                if (above.ref_frames[0] == left.ref_frames[0] && above.ref_frames[1] == left.ref_frames[1]) {
+                    context = 3 * (above.ref_frames[0] == GoldenFrame || above.ref_frames[1] == GoldenFrame);
                 } else {
                     context = 2;
                 }
             } else {
-                auto rfs = above_single.value() ? above_ref_frame.value()[0] : left_ref_frame.value()[0];
-                auto crf1 = above_single.value() ? left_ref_frame.value()[0] : above_ref_frame.value()[0];
-                auto crf2 = above_single.value() ? left_ref_frame.value()[1] : above_ref_frame.value()[1];
-                context = crf1 == GoldenFrame || crf2 == GoldenFrame;
-                if (rfs == GoldenFrame) {
+                auto single_reference_type = above.is_single_reference() ? above.ref_frames[0] : left.ref_frames[0];
+                auto compound_reference_a_type = above.is_single_reference() ? left.ref_frames[0] : above.ref_frames[0];
+                auto compound_reference_b_type = above.is_single_reference() ? left.ref_frames[1] : above.ref_frames[1];
+                context = compound_reference_a_type == GoldenFrame || compound_reference_b_type == GoldenFrame;
+                if (single_reference_type == GoldenFrame) {
                     context += 3;
-                } else if (rfs != AltRefFrame) {
+                } else if (single_reference_type != AltRefFrame) {
                     context = 1 + (2 * context);
                 }
             }
         }
-    } else if (above_single.has_value()) {
-        if (above_intra.value() || (above_ref_frame.value()[0] == LastFrame && above_single.value())) {
+    } else if (above.is_available) {
+        if (above.is_intra_predicted() || (above.ref_frames[0] == LastFrame && above.is_single_reference())) {
             context = 2;
-        } else if (above_single.value()) {
-            context = 4 * (above_ref_frame.value()[0] == GoldenFrame);
+        } else if (above.is_single_reference()) {
+            context = 4 * (above.ref_frames[0] == GoldenFrame);
         } else {
-            context = 3 * (above_ref_frame.value()[0] == GoldenFrame || above_ref_frame.value()[1] == GoldenFrame);
+            context = 3 * (above.ref_frames[0] == GoldenFrame || above.ref_frames[1] == GoldenFrame);
         }
-    } else if (left_single.has_value()) {
-        if (left_intra.value() || (left_ref_frame.value()[0] == LastFrame && left_single.value())) {
+    } else if (left.is_available) {
+        if (left.is_intra_predicted() || (left.ref_frames[0] == LastFrame && left.is_single_reference())) {
             context = 2;
-        } else if (left_single.value()) {
-            context = 4 * (left_ref_frame.value()[0] == GoldenFrame);
+        } else if (left.is_single_reference()) {
+            context = 4 * (left.ref_frames[0] == GoldenFrame);
         } else {
-            context = 3 * (left_ref_frame.value()[0] == GoldenFrame || left_ref_frame.value()[1] == GoldenFrame);
+            context = 3 * (left.ref_frames[0] == GoldenFrame || left.ref_frames[1] == GoldenFrame);
         }
     } else {
         context = 2;

+ 9 - 9
Userland/Libraries/LibVideo/VP9/TreeParser.h

@@ -49,7 +49,7 @@ public:
     };
 
     static ErrorOr<Partition> parse_partition(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, bool has_rows, bool has_columns, BlockSubsize block_subsize, u8 num_8x8, Vector<u8> const& above_partition_context, Vector<u8> const& left_partition_context, u32 row, u32 column, bool frame_is_intra);
-    static ErrorOr<PredictionMode> parse_default_intra_mode(BitStream&, ProbabilityTables const&, BlockSubsize mi_size, Optional<Array<PredictionMode, 4> const&> above_context, Optional<Array<PredictionMode, 4> const&> left_context, Array<PredictionMode, 4> const& block_sub_modes, u8 index_x, u8 index_y);
+    static ErrorOr<PredictionMode> parse_default_intra_mode(BitStream&, ProbabilityTables const&, BlockSubsize mi_size, FrameBlockContext above, FrameBlockContext left, Array<PredictionMode, 4> const& block_sub_modes, u8 index_x, u8 index_y);
     static ErrorOr<PredictionMode> parse_default_uv_mode(BitStream&, ProbabilityTables const&, PredictionMode y_mode);
     static ErrorOr<PredictionMode> parse_intra_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, BlockSubsize mi_size);
     static ErrorOr<PredictionMode> parse_sub_intra_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&);
@@ -57,14 +57,14 @@ public:
     static ErrorOr<u8> parse_segment_id(BitStream&, u8 const probabilities[7]);
     static ErrorOr<bool> parse_segment_id_predicted(BitStream&, u8 const probabilities[3], u8 above_seg_pred_context, u8 left_seg_pred_context);
     static ErrorOr<PredictionMode> parse_inter_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, u8 mode_context_for_ref_frame_0);
-    static ErrorOr<InterpolationFilter> parse_interpolation_filter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional<ReferenceFrameType> above_ref_frame, Optional<ReferenceFrameType> left_ref_frame, Optional<InterpolationFilter> above_interpolation_filter, Optional<InterpolationFilter> left_interpolation_filter);
-    static ErrorOr<bool> parse_skip(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional<bool> const& above_skip, Optional<bool> const& left_skip);
-    static ErrorOr<TXSize> parse_tx_size(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, TXSize max_tx_size, Optional<bool> above_skip, Optional<bool> left_skip, Optional<TXSize> above_tx_size, Optional<TXSize> left_tx_size);
-    static ErrorOr<bool> parse_is_inter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional<bool> above_intra, Optional<bool> left_intra);
-    static ErrorOr<ReferenceMode> parse_comp_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFrameType> above_ref_frame_0, Optional<ReferenceFrameType> left_ref_frame_0);
-    static ErrorOr<bool> parse_comp_ref(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFrameType> above_ref_frame_0, Optional<ReferenceFrameType> left_ref_frame_0, Optional<ReferenceFrameType> above_ref_frame_biased, Optional<ReferenceFrameType> left_ref_frame_biased);
-    static ErrorOr<bool> parse_single_ref_part_1(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFramePair> above_ref_frame, Optional<ReferenceFramePair> left_ref_frame);
-    static ErrorOr<bool> parse_single_ref_part_2(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional<bool> above_single, Optional<bool> left_single, Optional<bool> above_intra, Optional<bool> left_intra, Optional<ReferenceFramePair> above_ref_frame, Optional<ReferenceFramePair> left_ref_frame);
+    static ErrorOr<InterpolationFilter> parse_interpolation_filter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<bool> parse_skip(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<TXSize> parse_tx_size(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, TXSize max_tx_size, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<bool> parse_block_is_inter_predicted(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<ReferenceMode> parse_comp_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<bool> parse_comp_ref(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, u8 variable_reference_index, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<bool> parse_single_ref_part_1(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left);
+    static ErrorOr<bool> parse_single_ref_part_2(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left);
 
     static ErrorOr<MvJoint> parse_motion_vector_joint(BitStream&, ProbabilityTables const&, SyntaxElementCounter&);
     static ErrorOr<bool> parse_motion_vector_sign(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, u8 component);