From 44413c31a92e3d143c11799b38151cb03d39b98d Mon Sep 17 00:00:00 2001 From: Zaggy1024 Date: Fri, 18 Nov 2022 13:56:14 -0600 Subject: [PATCH] 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. --- Userland/Libraries/LibVideo/VP9/Context.h | 26 +- Userland/Libraries/LibVideo/VP9/Decoder.cpp | 16 +- Userland/Libraries/LibVideo/VP9/Parser.cpp | 184 ++++------- Userland/Libraries/LibVideo/VP9/Parser.h | 38 +-- .../Libraries/LibVideo/VP9/TreeParser.cpp | 292 +++++++++--------- Userland/Libraries/LibVideo/VP9/TreeParser.h | 18 +- 6 files changed, 258 insertions(+), 316 deletions(-) diff --git a/Userland/Libraries/LibVideo/VP9/Context.h b/Userland/Libraries/LibVideo/VP9/Context.h index 0408f372f1..38548485b0 100644 --- a/Userland/Libraries/LibVideo/VP9/Context.h +++ b/Userland/Libraries/LibVideo/VP9/Context.h @@ -7,6 +7,8 @@ #pragma once +#include + #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&>(*this)[index]; + } }; typedef Pair 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 sub_modes { PredictionMode::DcPred, PredictionMode::DcPred, PredictionMode::DcPred, PredictionMode::DcPred }; + InterpolationFilter interpolation_filter { InterpolationFilter::EightTap }; + ReferenceFramePair ref_frames { ReferenceFrameType::None, ReferenceFrameType::None }; + Array, 2> sub_block_motion_vectors {}; + u8 segment_id { 0 }; +}; + } diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.cpp b/Userland/Libraries/LibVideo/VP9/Decoder.cpp index 79bc0dd704..6e004c02ef 100644 --- a/Userland/Libraries/LibVideo/VP9/Decoder.cpp +++ b/Userland/Libraries/LibVideo/VP9/Decoder.cpp @@ -75,7 +75,7 @@ DecoderErrorOr 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 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 {}; diff --git a/Userland/Libraries/LibVideo/VP9/Parser.cpp b/Userland/Libraries/LibVideo/VP9/Parser.cpp index 71c2fb926f..4d013e9507 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.cpp +++ b/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 Parser::read_is_inter_probs() DecoderErrorOr 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 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 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 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(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 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 const&>(); - auto left_context = Optional 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 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 const&>(); - auto left_context = Optional 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 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 Parser::read_skip() { if (seg_feature_active(SEG_LVL_SKIP)) { m_skip = true; } else { - Optional above_skip = m_available_u ? m_skips[get_image_index(m_mi_row - 1, m_mi_col)] : Optional(); - Optional left_skip = m_available_l ? m_skips[get_image_index(m_mi_row, m_mi_col - 1)] : Optional(); - 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 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 above_skip = m_available_u ? m_skips[get_image_index(m_mi_row - 1, m_mi_col)] : Optional(); - Optional left_skip = m_available_l ? m_skips[get_image_index(m_mi_row, m_mi_col - 1)] : Optional(); - Optional above_tx_size = m_available_u ? m_tx_sizes[get_image_index(m_mi_row - 1, m_mi_col)] : Optional(); - Optional left_tx_size = m_available_l ? m_tx_sizes[get_image_index(m_mi_row, m_mi_col - 1)] : Optional(); - 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 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 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 above_intra = m_available_u ? m_above_intra : Optional(); - Optional left_intra = m_available_l ? m_left_intra : Optional(); - 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 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 above_ref_frame = m_available_u ? m_ref_frames[get_image_index(m_mi_row - 1, m_mi_col)][0] : Optional(); - Optional left_ref_frame = m_available_l ? m_ref_frames[get_image_index(m_mi_row, m_mi_col - 1)][0] : Optional(); - Optional above_interpolation_filter = m_available_u ? m_interp_filters[get_image_index(m_mi_row - 1, m_mi_col)] : Optional(); - Optional left_interpolation_filter = m_available_l ? m_interp_filters[get_image_index(m_mi_row, m_mi_col - 1)] : Optional(); - 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 Parser::read_ref_frames() return {}; } ReferenceMode comp_mode; - Optional above_single = m_available_u ? m_above_single : Optional(); - Optional left_single = m_available_l ? m_left_single : Optional(); - Optional above_intra = m_available_u ? m_above_intra : Optional(); - Optional left_intra = m_available_l ? m_left_intra : Optional(); - Optional above_ref_frame_0 = m_available_u ? m_above_ref_frame[0] : Optional(); - Optional left_ref_frame_0 = m_available_l ? m_left_ref_frame[0] : Optional(); - Optional above_ref_frame = m_available_u ? m_above_ref_frame : Optional(); - Optional left_ref_frame = m_available_l ? m_left_ref_frame : Optional(); - 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 above_ref_frame_biased = m_available_u ? m_above_ref_frame[inverse_biased_reference_index] : Optional(); - Optional left_ref_frame_biased = m_available_l ? m_left_ref_frame[inverse_biased_reference_index] : Optional(); // 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; diff --git a/Userland/Libraries/LibVideo/VP9/Parser.h b/Userland/Libraries/LibVideo/VP9/Parser.h index 5cefff816c..57a9cf4e77 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.h +++ b/Userland/Libraries/LibVideo/VP9/Parser.h @@ -51,7 +51,6 @@ private: template void clear_context(Vector>& context, size_t outer_size, size_t inner_size); DecoderErrorOr 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 read_coef_probs(); + FrameBlockContext get_above_context() const; + FrameBlockContext get_left_context() const; DecoderErrorOr read_skip_prob(); DecoderErrorOr read_inter_mode_probs(); DecoderErrorOr 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> 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 instead. + Array, 2> m_block_mvs; Vector m_prev_segment_ids; - Vector m_skips; - Vector m_tx_sizes; - Vector m_mi_sizes; - Vector m_y_modes; - Vector m_segment_ids; - Vector m_ref_frames; - Vector m_prev_ref_frames; - Vector m_mvs; - Vector 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 m_frame_block_contexts; + MotionVectorPair m_candidate_mv; ReferenceFramePair m_candidate_frame; - Vector, 2>> m_sub_mvs; u8 m_ref_mv_count { 0 }; MotionVectorPair m_ref_list_mv; bool m_use_prev_frame_mvs; - Vector m_interp_filters; + Vector m_prev_ref_frames; + Vector m_prev_mvs; // Indexed by ReferenceFrame enum. u8 m_mode_context[4] { INVALID_CASE }; diff --git a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp index c6ecf5b384..01ca9301e6 100644 --- a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp +++ b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp @@ -80,7 +80,7 @@ ErrorOr TreeParser::parse_partition(BitStream& bit_stream, Probabilit return value; } -ErrorOr TreeParser::parse_default_intra_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, BlockSubsize mi_size, Optional const&> above_context, Optional const&> left_context, Array const& block_sub_modes, u8 index_x, u8 index_y) +ErrorOr TreeParser::parse_default_intra_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, BlockSubsize mi_size, FrameBlockContext above, FrameBlockContext left, Array 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 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 TreeParser::parse_inter_mode(BitStream& bit_stream, Prob return value; } -ErrorOr TreeParser::parse_interpolation_filter(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional above_ref_frame, Optional left_ref_frame, Optional above_interpolation_filter, Optional left_interpolation_filter) +ErrorOr 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 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 TreeParser::parse_interpolation_filter(BitStream& b return value; } -ErrorOr TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional const& above_skip, Optional const& left_skip) +ErrorOr TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left) { // Probabilities u8 context = 0; - context += static_cast(above_skip.value_or(false)); - context += static_cast(left_skip.value_or(false)); + context += static_cast(above.skip_coefficients); + context += static_cast(left.skip_coefficients); u8 probability = probability_table.skip_prob()[context]; auto value = TRY(parse_tree(bit_stream, { binary_tree }, [&](u8) { return probability; })); @@ -233,7 +229,7 @@ ErrorOr TreeParser::parse_skip(BitStream& bit_stream, ProbabilityTables co return value; } -ErrorOr TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TXSize max_tx_size, Optional above_skip, Optional left_skip, Optional above_tx_size, Optional left_tx_size) +ErrorOr 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 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(bit_stream, tree, [&](u8 node) { return probabilities[node]; })); @@ -265,16 +260,16 @@ ErrorOr TreeParser::parse_tx_size(BitStream& bit_stream, ProbabilityTabl return value; } -ErrorOr TreeParser::parse_is_inter(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional above_intra, Optional left_intra) +ErrorOr 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(above_intra.value() || left_intra.value()); - else if (above_intra.has_value() || left_intra.has_value()) - context = 2 * static_cast(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(above.is_intra_predicted() || left.is_intra_predicted()); + else if (above.is_available || left.is_available) + context = 2 * static_cast(above.is_available ? above.is_intra_predicted() : left.is_intra_predicted()); u8 probability = probability_table.is_inter_prob()[context]; auto value = TRY(parse_tree(bit_stream, { binary_tree }, [&](u8) { return probability; })); @@ -282,34 +277,34 @@ ErrorOr TreeParser::parse_is_inter(BitStream& bit_stream, ProbabilityTable return value; } -ErrorOr TreeParser::parse_comp_mode(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame_0, Optional left_ref_frame_0) +ErrorOr 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(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(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(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(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(left_ref_frame_0.value() == comp_fixed_ref); + } else if (left.is_available) { + if (left.is_single_reference()) + context = static_cast(left.ref_frames[0] == comp_fixed_ref); else context = 3; } else { @@ -322,33 +317,34 @@ ErrorOr TreeParser::parse_comp_mode(BitStream& bit_stream, Probab return value; } -ErrorOr TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame_0, Optional left_ref_frame_0, Optional above_ref_frame_biased, Optional left_ref_frame_biased) +ErrorOr 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 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 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(above_ref_frame_0.value() != comp_var_ref[1]); + if (above.is_single_reference()) { + context = 3 * static_cast(above.ref_frames[0] != comp_var_ref[1]); } else { - context = 4 * static_cast(above_ref_frame_biased.value() != comp_var_ref[1]); + context = 4 * static_cast(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(left_ref_frame_0.value() != comp_var_ref[1]); + if (left.is_single_reference()) { + context = 3 * static_cast(left.ref_frames[0] != comp_var_ref[1]); } else { - context = 4 * static_cast(left_ref_frame_biased != comp_var_ref[1]); + context = 4 * static_cast(left.ref_frames[variable_reference_index] != comp_var_ref[1]); } } } else { @@ -404,61 +400,61 @@ ErrorOr TreeParser::parse_comp_ref(BitStream& bit_stream, ProbabilityTable return value; } -ErrorOr TreeParser::parse_single_ref_part_1(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame, Optional left_ref_frame) +ErrorOr 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 TreeParser::parse_single_ref_part_1(BitStream& bit_stream, Probabi return value; } -ErrorOr TreeParser::parse_single_ref_part_2(BitStream& bit_stream, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame, Optional left_ref_frame) +ErrorOr 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; diff --git a/Userland/Libraries/LibVideo/VP9/TreeParser.h b/Userland/Libraries/LibVideo/VP9/TreeParser.h index 6bc7db4d59..70261573f5 100644 --- a/Userland/Libraries/LibVideo/VP9/TreeParser.h +++ b/Userland/Libraries/LibVideo/VP9/TreeParser.h @@ -49,7 +49,7 @@ public: }; static ErrorOr parse_partition(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, bool has_rows, bool has_columns, BlockSubsize block_subsize, u8 num_8x8, Vector const& above_partition_context, Vector const& left_partition_context, u32 row, u32 column, bool frame_is_intra); - static ErrorOr parse_default_intra_mode(BitStream&, ProbabilityTables const&, BlockSubsize mi_size, Optional const&> above_context, Optional const&> left_context, Array const& block_sub_modes, u8 index_x, u8 index_y); + static ErrorOr parse_default_intra_mode(BitStream&, ProbabilityTables const&, BlockSubsize mi_size, FrameBlockContext above, FrameBlockContext left, Array const& block_sub_modes, u8 index_x, u8 index_y); static ErrorOr parse_default_uv_mode(BitStream&, ProbabilityTables const&, PredictionMode y_mode); static ErrorOr parse_intra_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, BlockSubsize mi_size); static ErrorOr parse_sub_intra_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&); @@ -57,14 +57,14 @@ public: static ErrorOr parse_segment_id(BitStream&, u8 const probabilities[7]); static ErrorOr parse_segment_id_predicted(BitStream&, u8 const probabilities[3], u8 above_seg_pred_context, u8 left_seg_pred_context); static ErrorOr parse_inter_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, u8 mode_context_for_ref_frame_0); - static ErrorOr parse_interpolation_filter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional above_ref_frame, Optional left_ref_frame, Optional above_interpolation_filter, Optional left_interpolation_filter); - static ErrorOr parse_skip(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional const& above_skip, Optional const& left_skip); - static ErrorOr parse_tx_size(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, TXSize max_tx_size, Optional above_skip, Optional left_skip, Optional above_tx_size, Optional left_tx_size); - static ErrorOr parse_is_inter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional above_intra, Optional left_intra); - static ErrorOr parse_comp_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame_0, Optional left_ref_frame_0); - static ErrorOr parse_comp_ref(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame_0, Optional left_ref_frame_0, Optional above_ref_frame_biased, Optional left_ref_frame_biased); - static ErrorOr parse_single_ref_part_1(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame, Optional left_ref_frame); - static ErrorOr parse_single_ref_part_2(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, Optional above_single, Optional left_single, Optional above_intra, Optional left_intra, Optional above_ref_frame, Optional left_ref_frame); + static ErrorOr parse_interpolation_filter(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); + static ErrorOr parse_skip(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); + static ErrorOr parse_tx_size(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, TXSize max_tx_size, FrameBlockContext above, FrameBlockContext left); + static ErrorOr parse_block_is_inter_predicted(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); + static ErrorOr parse_comp_mode(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, FrameBlockContext above, FrameBlockContext left); + static ErrorOr 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 parse_single_ref_part_1(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); + static ErrorOr parse_single_ref_part_2(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); static ErrorOr parse_motion_vector_joint(BitStream&, ProbabilityTables const&, SyntaxElementCounter&); static ErrorOr parse_motion_vector_sign(BitStream&, ProbabilityTables const&, SyntaxElementCounter&, u8 component);