Ver Fonte

LibVideo/VP9: Count syntax elements in TileContext, and sum at the end

Syntax element counters were previously accessed across tiles, which
would cause a race condition updating the counts in a tile-threaded
mode.
Zaggy1024 há 2 anos atrás
pai
commit
1fcac52e77

+ 24 - 6
Userland/Libraries/LibVideo/VP9/Context.h

@@ -21,6 +21,7 @@
 #include "Enums.h"
 #include "LookupTables.h"
 #include "MotionVector.h"
+#include "SyntaxElementCounter.h"
 #include "Utilities.h"
 
 namespace Video::VP9 {
@@ -33,20 +34,23 @@ enum class FrameShowMode {
 
 struct FrameContext {
 public:
-    FrameContext(ReadonlyBytes data,
+    static ErrorOr<FrameContext> create(ReadonlyBytes data,
         Vector2D<FrameBlockContext>& contexts)
-        : stream(data)
-        , bit_stream(MaybeOwned<Stream>(stream))
-        , m_block_contexts(contexts)
     {
+        return FrameContext(
+            TRY(try_make<FixedMemoryStream>(data)),
+            TRY(try_make<SyntaxElementCounter>()),
+            contexts);
     }
 
     FrameContext(FrameContext const&) = delete;
     FrameContext(FrameContext&&) = default;
 
-    FixedMemoryStream stream;
+    NonnullOwnPtr<FixedMemoryStream> stream;
     BigEndianInputBitStream bit_stream;
 
+    NonnullOwnPtr<SyntaxElementCounter> counter;
+
     u8 profile { 0 };
 
     FrameType type { FrameType::KeyFrame };
@@ -139,6 +143,16 @@ public:
 private:
     friend struct TileContext;
 
+    FrameContext(NonnullOwnPtr<FixedMemoryStream> stream,
+        NonnullOwnPtr<SyntaxElementCounter> counter,
+        Vector2D<FrameBlockContext>& contexts)
+        : stream(move(stream))
+        , bit_stream(MaybeOwned<Stream>(*this->stream))
+        , counter(move(counter))
+        , m_block_contexts(contexts)
+    {
+    }
+
     FrameShowMode m_frame_show_mode { FrameShowMode::CreateAndShowNewFrame };
     u8 m_existing_frame_index { 0 };
 
@@ -194,12 +208,13 @@ public:
         auto height = rows_end - rows_start;
         auto context_view = frame_context.m_block_contexts.view(rows_start, columns_start, height, width);
 
-        auto bit_stream = DECODER_TRY_ALLOC(try_make<BigEndianInputBitStream>(DECODER_TRY_ALLOC(try_make<FixedMemoryStream>(frame_context.stream))));
+        auto bit_stream = DECODER_TRY_ALLOC(try_make<BigEndianInputBitStream>(DECODER_TRY_ALLOC(try_make<FixedMemoryStream>(*frame_context.stream))));
         auto decoder = DECODER_TRY(DecoderErrorCategory::Corrupted, BooleanDecoder::initialize(move(bit_stream), tile_size));
 
         return TileContext {
             frame_context,
             move(decoder),
+            DECODER_TRY_ALLOC(try_make<SyntaxElementCounter>()),
             rows_start,
             rows_end,
             columns_start,
@@ -218,6 +233,7 @@ public:
 
     FrameContext const& frame_context;
     BooleanDecoder decoder;
+    NonnullOwnPtr<SyntaxElementCounter> counter;
     u32 rows_start { 0 };
     u32 rows_end { 0 };
     u32 columns_start { 0 };
@@ -250,6 +266,7 @@ struct BlockContext {
             .frame_context = tile_context.frame_context,
             .tile_context = tile_context,
             .decoder = tile_context.decoder,
+            .counter = *tile_context.counter,
             .row = row,
             .column = column,
             .size = size,
@@ -266,6 +283,7 @@ struct BlockContext {
     FrameContext const& frame_context;
     TileContext const& tile_context;
     BooleanDecoder& decoder;
+    SyntaxElementCounter& counter;
     u32 row { 0 };
     u32 column { 0 };
     BlockSubsize size;

+ 5 - 5
Userland/Libraries/LibVideo/VP9/Decoder.cpp

@@ -239,10 +239,10 @@ u32 Decoder::merge_probs(int const* tree, int index, u8* probs, u32* counts, u8
     return left_count + right_count;
 }
 
-DecoderErrorOr<void> Decoder::adapt_coef_probs(bool is_inter_predicted_frame)
+DecoderErrorOr<void> Decoder::adapt_coef_probs(FrameContext const& frame_context)
 {
     u8 update_factor;
-    if (!is_inter_predicted_frame || m_parser->m_previous_frame_type != FrameType::KeyFrame)
+    if (!frame_context.is_inter_predicted() || m_parser->m_previous_frame_type != FrameType::KeyFrame)
         update_factor = 112;
     else
         update_factor = 128;
@@ -255,10 +255,10 @@ DecoderErrorOr<void> Decoder::adapt_coef_probs(bool is_inter_predicted_frame)
                     for (size_t l = 0; l < max_l; l++) {
                         auto& coef_probs = m_parser->m_probability_tables->coef_probs()[t][i][j][k][l];
                         merge_probs(small_token_tree, 2, coef_probs,
-                            m_parser->m_syntax_element_counter->m_counts_token[t][i][j][k][l],
+                            frame_context.counter->m_counts_token[t][i][j][k][l],
                             24, update_factor);
                         merge_probs(binary_tree, 0, coef_probs,
-                            m_parser->m_syntax_element_counter->m_counts_more_coefs[t][i][j][k][l],
+                            frame_context.counter->m_counts_more_coefs[t][i][j][k][l],
                             24, update_factor);
                     }
                 }
@@ -287,7 +287,7 @@ DecoderErrorOr<void> Decoder::adapt_coef_probs(bool is_inter_predicted_frame)
 DecoderErrorOr<void> Decoder::adapt_non_coef_probs(FrameContext const& frame_context)
 {
     auto& probs = *m_parser->m_probability_tables;
-    auto& counter = *m_parser->m_syntax_element_counter;
+    auto& counter = *frame_context.counter;
     ADAPT_PROB_TABLE(is_inter, IS_INTER_CONTEXTS);
     ADAPT_PROB_TABLE(comp_mode, COMP_MODE_CONTEXTS);
     ADAPT_PROB_TABLE(comp_ref, REF_CONTEXTS);

+ 1 - 1
Userland/Libraries/LibVideo/VP9/Decoder.h

@@ -50,7 +50,7 @@ private:
     /* (8.4) Probability Adaptation Process */
     u8 merge_prob(u8 pre_prob, u32 count_0, u32 count_1, u8 count_sat, u8 max_update_factor);
     u32 merge_probs(int const* tree, int index, u8* probs, u32* counts, u8 count_sat, u8 max_update_factor);
-    DecoderErrorOr<void> adapt_coef_probs(bool is_inter_predicted_frame);
+    DecoderErrorOr<void> adapt_coef_probs(FrameContext const&);
     DecoderErrorOr<void> adapt_non_coef_probs(FrameContext const&);
     void adapt_probs(int const* tree, u8* probs, u32* counts);
     u8 adapt_prob(u8 prob, u32 counts[2]);

+ 32 - 33
Userland/Libraries/LibVideo/VP9/Parser.cpp

@@ -83,19 +83,17 @@ DecoderErrorOr<FrameContext> Parser::parse_frame(ReadonlyBytes frame_data)
 {
     if (!m_probability_tables)
         m_probability_tables = DECODER_TRY_ALLOC(try_make<ProbabilityTables>());
-    m_syntax_element_counter = make<SyntaxElementCounter>();
 
     // NOTE: m_reusable_frame_block_contexts does not need to retain any data between frame decodes.
     //       This is only stored so that we don't need to allocate a frame's block contexts on each
     //       call to this function, since it will rarely change sizes.
-    FrameContext frame_context { frame_data, m_reusable_frame_block_contexts };
+    auto frame_context = DECODER_TRY_ALLOC(FrameContext::create(frame_data, m_reusable_frame_block_contexts));
     TRY(uncompressed_header(frame_context));
     // FIXME: This should not be an error. Spec says that we consume padding bits until the end of the sample.
     if (frame_context.header_size_in_bytes == 0)
         return DecoderError::corrupted("Frame header is zero-sized"sv);
     m_probability_tables->load_probs(frame_context.probability_context_index);
     m_probability_tables->load_probs2(frame_context.probability_context_index);
-    m_syntax_element_counter->clear_counts();
 
     TRY(compressed_header(frame_context));
 
@@ -123,7 +121,7 @@ DecoderErrorOr<void> Parser::refresh_probs(FrameContext const& frame_context)
 {
     if (!frame_context.error_resilient_mode && !frame_context.parallel_decoding_mode) {
         m_probability_tables->load_probs(frame_context.probability_context_index);
-        TRY(m_decoder.adapt_coef_probs(frame_context.is_inter_predicted()));
+        TRY(m_decoder.adapt_coef_probs(frame_context));
         if (frame_context.is_inter_predicted()) {
             m_probability_tables->load_probs2(frame_context.probability_context_index);
             TRY(m_decoder.adapt_non_coef_probs(frame_context));
@@ -875,7 +873,7 @@ DecoderErrorOr<void> Parser::decode_tiles(FrameContext& frame_context)
             auto last_tile = (tile_row == tile_rows - 1) && (tile_col == tile_cols - 1);
             size_t tile_size;
             if (last_tile)
-                tile_size = frame_context.stream.remaining();
+                tile_size = frame_context.stream->remaining();
             else
                 tile_size = TRY_READ(frame_context.bit_stream.read_bits(32));
 
@@ -891,6 +889,7 @@ DecoderErrorOr<void> Parser::decode_tiles(FrameContext& frame_context)
 
             auto tile_context = TRY(TileContext::try_create(frame_context, tile_size, rows_start, rows_end, columns_start, columns_end, above_partition_context_for_tile, above_non_zero_tokens_view, above_segmentation_ids_for_tile));
             TRY(decode_tile(tile_context));
+            *frame_context.counter += *tile_context.counter;
             TRY_READ(frame_context.bit_stream.discard(tile_size));
         }
     }
@@ -927,7 +926,7 @@ DecoderErrorOr<void> Parser::decode_partition(TileContext& tile_context, u32 row
     bool has_cols = (column + half_block_8x8) < tile_context.frame_context.columns();
     u32 row_in_tile = row - tile_context.rows_start;
     u32 column_in_tile = column - tile_context.columns_start;
-    auto partition = TRY_READ(TreeParser::parse_partition(tile_context.decoder, *m_probability_tables, *m_syntax_element_counter, has_rows, has_cols, subsize, num_8x8, tile_context.above_partition_context, tile_context.left_partition_context.span(), row_in_tile, column_in_tile, !tile_context.frame_context.is_inter_predicted()));
+    auto partition = TRY_READ(TreeParser::parse_partition(tile_context.decoder, *m_probability_tables, *tile_context.counter, has_rows, has_cols, subsize, num_8x8, tile_context.above_partition_context, tile_context.left_partition_context.span(), row_in_tile, column_in_tile, !tile_context.frame_context.is_inter_predicted()));
 
     auto child_subsize = subsize_lookup[partition][subsize];
     if (child_subsize < Block_8x8 || partition == PartitionNone) {
@@ -1038,7 +1037,7 @@ DecoderErrorOr<bool> Parser::read_should_skip_residuals(BlockContext& block_cont
 {
     if (seg_feature_active(block_context, SEG_LVL_SKIP))
         return true;
-    return TRY_READ(TreeParser::parse_skip(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+    return TRY_READ(TreeParser::parse_skip(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context));
 }
 
 bool Parser::seg_feature_active(BlockContext const& block_context, u8 feature)
@@ -1050,7 +1049,7 @@ DecoderErrorOr<TransformSize> Parser::read_tx_size(BlockContext& block_context,
 {
     auto max_tx_size = max_txsize_lookup[block_context.size];
     if (allow_select && block_context.frame_context.transform_mode == TransformMode::Select && block_context.size >= Block_8x8)
-        return (TRY_READ(TreeParser::parse_tx_size(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, max_tx_size, above_context, left_context)));
+        return (TRY_READ(TreeParser::parse_tx_size(block_context.decoder, *m_probability_tables, block_context.counter, max_tx_size, above_context, left_context)));
     return min(max_tx_size, tx_mode_to_biggest_tx_size[to_underlying(block_context.frame_context.transform_mode)]);
 }
 
@@ -1120,7 +1119,7 @@ DecoderErrorOr<bool> Parser::read_is_inter(BlockContext& block_context, FrameBlo
 {
     if (seg_feature_active(block_context, SEG_LVL_REF_FRAME))
         return block_context.frame_context.segmentation_features[block_context.segment_id][SEG_LVL_REF_FRAME].value != ReferenceFrameType::None;
-    return TRY_READ(TreeParser::parse_block_is_inter_predicted(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+    return TRY_READ(TreeParser::parse_block_is_inter_predicted(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context));
 }
 
 DecoderErrorOr<void> Parser::intra_block_mode_info(BlockContext& block_context)
@@ -1129,14 +1128,14 @@ DecoderErrorOr<void> Parser::intra_block_mode_info(BlockContext& block_context)
     VERIFY(!block_context.is_inter_predicted());
     auto& sub_modes = block_context.sub_block_prediction_modes;
     if (block_context.size >= Block_8x8) {
-        auto mode = TRY_READ(TreeParser::parse_intra_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, block_context.size));
+        auto mode = TRY_READ(TreeParser::parse_intra_mode(block_context.decoder, *m_probability_tables, block_context.counter, block_context.size));
         for (auto& block_sub_mode : sub_modes)
             block_sub_mode = mode;
     } else {
         auto size_in_sub_blocks = block_context.get_size_in_sub_blocks();
         for (auto idy = 0; idy < 2; idy += size_in_sub_blocks.height()) {
             for (auto idx = 0; idx < 2; idx += size_in_sub_blocks.width()) {
-                auto sub_intra_mode = TRY_READ(TreeParser::parse_sub_intra_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter));
+                auto sub_intra_mode = TRY_READ(TreeParser::parse_sub_intra_mode(block_context.decoder, *m_probability_tables, block_context.counter));
                 for (auto y = 0; y < size_in_sub_blocks.height(); y++) {
                     for (auto x = 0; x < size_in_sub_blocks.width(); x++)
                         sub_modes[(idy + y) * 2 + idx + x] = sub_intra_mode;
@@ -1144,7 +1143,7 @@ DecoderErrorOr<void> Parser::intra_block_mode_info(BlockContext& block_context)
             }
         }
     }
-    block_context.uv_prediction_mode = TRY_READ(TreeParser::parse_uv_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, block_context.y_prediction_mode()));
+    block_context.uv_prediction_mode = TRY_READ(TreeParser::parse_uv_mode(block_context.decoder, *m_probability_tables, block_context.counter, block_context.y_prediction_mode()));
     return {};
 }
 
@@ -1166,17 +1165,17 @@ DecoderErrorOr<void> Parser::inter_block_mode_info(BlockContext& block_context,
     if (seg_feature_active(block_context, SEG_LVL_SKIP)) {
         block_context.y_prediction_mode() = PredictionMode::ZeroMv;
     } else if (block_context.size >= Block_8x8) {
-        block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, block_context.mode_context[block_context.reference_frame_types.primary]));
+        block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(block_context.decoder, *m_probability_tables, block_context.counter, block_context.mode_context[block_context.reference_frame_types.primary]));
     }
     if (block_context.frame_context.interpolation_filter == Switchable)
-        block_context.interpolation_filter = TRY_READ(TreeParser::parse_interpolation_filter(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+        block_context.interpolation_filter = TRY_READ(TreeParser::parse_interpolation_filter(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context));
     else
         block_context.interpolation_filter = block_context.frame_context.interpolation_filter;
     if (block_context.size < Block_8x8) {
         auto size_in_sub_blocks = block_context.get_size_in_sub_blocks();
         for (auto idy = 0; idy < 2; idy += size_in_sub_blocks.height()) {
             for (auto idx = 0; idx < 2; idx += size_in_sub_blocks.width()) {
-                block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, block_context.mode_context[block_context.reference_frame_types.primary]));
+                block_context.y_prediction_mode() = TRY_READ(TreeParser::parse_inter_mode(block_context.decoder, *m_probability_tables, block_context.counter, block_context.mode_context[block_context.reference_frame_types.primary]));
                 if (block_context.y_prediction_mode() == PredictionMode::NearestMv || block_context.y_prediction_mode() == PredictionMode::NearMv) {
                     select_best_sub_block_reference_motion_vectors(block_context, motion_vector_candidates, idy * 2 + idx, ReferenceIndex::Primary);
                     if (block_context.is_compound())
@@ -1209,7 +1208,7 @@ DecoderErrorOr<void> Parser::read_ref_frames(BlockContext& block_context, FrameB
     ReferenceMode compound_mode = block_context.frame_context.reference_mode;
     auto fixed_reference = block_context.frame_context.fixed_reference_type;
     if (compound_mode == ReferenceModeSelect)
-        compound_mode = TRY_READ(TreeParser::parse_comp_mode(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, fixed_reference, above_context, left_context));
+        compound_mode = TRY_READ(TreeParser::parse_comp_mode(block_context.decoder, *m_probability_tables, block_context.counter, fixed_reference, above_context, left_context));
     if (compound_mode == CompoundReference) {
         auto variable_references = block_context.frame_context.variable_reference_types;
 
@@ -1218,7 +1217,7 @@ DecoderErrorOr<void> Parser::read_ref_frames(BlockContext& block_context, FrameB
         if (block_context.frame_context.reference_frame_sign_biases[fixed_reference])
             swap(fixed_reference_index, variable_reference_index);
 
-        auto variable_reference_selection = TRY_READ(TreeParser::parse_comp_ref(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, fixed_reference, variable_references, variable_reference_index, above_context, left_context));
+        auto variable_reference_selection = TRY_READ(TreeParser::parse_comp_ref(block_context.decoder, *m_probability_tables, block_context.counter, fixed_reference, variable_references, variable_reference_index, above_context, left_context));
 
         block_context.reference_frame_types[fixed_reference_index] = fixed_reference;
         block_context.reference_frame_types[variable_reference_index] = variable_references[variable_reference_selection];
@@ -1227,9 +1226,9 @@ DecoderErrorOr<void> Parser::read_ref_frames(BlockContext& block_context, FrameB
 
     // FIXME: Maybe consolidate this into a tree. Context is different between part 1 and 2 but still, it would look nice here.
     ReferenceFrameType primary_type = ReferenceFrameType::LastFrame;
-    auto single_ref_p1 = TRY_READ(TreeParser::parse_single_ref_part_1(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+    auto single_ref_p1 = TRY_READ(TreeParser::parse_single_ref_part_1(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context));
     if (single_ref_p1) {
-        auto single_ref_p2 = TRY_READ(TreeParser::parse_single_ref_part_2(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, above_context, left_context));
+        auto single_ref_p2 = TRY_READ(TreeParser::parse_single_ref_part_2(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context));
         primary_type = single_ref_p2 ? ReferenceFrameType::AltRefFrame : ReferenceFrameType::GoldenFrame;
     }
     block_context.reference_frame_types = { primary_type, ReferenceFrameType::None };
@@ -1274,35 +1273,35 @@ DecoderErrorOr<MotionVector> Parser::read_motion_vector(BlockContext const& bloc
 {
     auto use_high_precision = block_context.frame_context.high_precision_motion_vectors_allowed && should_use_high_precision_motion_vector(candidates[reference_index].best_vector);
     MotionVector delta_vector;
-    auto joint = TRY_READ(TreeParser::parse_motion_vector_joint(block_context.decoder, *m_probability_tables, *m_syntax_element_counter));
+    auto joint = TRY_READ(TreeParser::parse_motion_vector_joint(block_context.decoder, *m_probability_tables, block_context.counter));
     if ((joint & MotionVectorNonZeroRow) != 0)
-        delta_vector.set_row(TRY(read_single_motion_vector_component(block_context.decoder, 0, use_high_precision)));
+        delta_vector.set_row(TRY(read_single_motion_vector_component(block_context.decoder, block_context.counter, 0, use_high_precision)));
     if ((joint & MotionVectorNonZeroColumn) != 0)
-        delta_vector.set_column(TRY(read_single_motion_vector_component(block_context.decoder, 1, use_high_precision)));
+        delta_vector.set_column(TRY(read_single_motion_vector_component(block_context.decoder, block_context.counter, 1, use_high_precision)));
 
     return candidates[reference_index].best_vector + delta_vector;
 }
 
 // read_mv_component( comp ) in the spec.
-DecoderErrorOr<i32> Parser::read_single_motion_vector_component(BooleanDecoder& decoder, u8 component, bool use_high_precision)
+DecoderErrorOr<i32> Parser::read_single_motion_vector_component(BooleanDecoder& decoder, SyntaxElementCounter& counter, u8 component, bool use_high_precision)
 {
-    auto mv_sign = TRY_READ(TreeParser::parse_motion_vector_sign(decoder, *m_probability_tables, *m_syntax_element_counter, component));
-    auto mv_class = TRY_READ(TreeParser::parse_motion_vector_class(decoder, *m_probability_tables, *m_syntax_element_counter, component));
+    auto mv_sign = TRY_READ(TreeParser::parse_motion_vector_sign(decoder, *m_probability_tables, counter, component));
+    auto mv_class = TRY_READ(TreeParser::parse_motion_vector_class(decoder, *m_probability_tables, counter, component));
     u32 magnitude;
     if (mv_class == MvClass0) {
-        auto mv_class0_bit = TRY_READ(TreeParser::parse_motion_vector_class0_bit(decoder, *m_probability_tables, *m_syntax_element_counter, component));
-        auto mv_class0_fr = TRY_READ(TreeParser::parse_motion_vector_class0_fr(decoder, *m_probability_tables, *m_syntax_element_counter, component, mv_class0_bit));
-        auto mv_class0_hp = TRY_READ(TreeParser::parse_motion_vector_class0_hp(decoder, *m_probability_tables, *m_syntax_element_counter, component, use_high_precision));
+        auto mv_class0_bit = TRY_READ(TreeParser::parse_motion_vector_class0_bit(decoder, *m_probability_tables, counter, component));
+        auto mv_class0_fr = TRY_READ(TreeParser::parse_motion_vector_class0_fr(decoder, *m_probability_tables, counter, component, mv_class0_bit));
+        auto mv_class0_hp = TRY_READ(TreeParser::parse_motion_vector_class0_hp(decoder, *m_probability_tables, counter, component, use_high_precision));
         magnitude = ((mv_class0_bit << 3) | (mv_class0_fr << 1) | mv_class0_hp) + 1;
     } else {
         u32 bits = 0;
         for (u8 i = 0; i < mv_class; i++) {
-            auto mv_bit = TRY_READ(TreeParser::parse_motion_vector_bit(decoder, *m_probability_tables, *m_syntax_element_counter, component, i));
+            auto mv_bit = TRY_READ(TreeParser::parse_motion_vector_bit(decoder, *m_probability_tables, counter, component, i));
             bits |= mv_bit << i;
         }
         magnitude = CLASS0_SIZE << (mv_class + 2);
-        auto mv_fr = TRY_READ(TreeParser::parse_motion_vector_fr(decoder, *m_probability_tables, *m_syntax_element_counter, component));
-        auto mv_hp = TRY_READ(TreeParser::parse_motion_vector_hp(decoder, *m_probability_tables, *m_syntax_element_counter, component, use_high_precision));
+        auto mv_fr = TRY_READ(TreeParser::parse_motion_vector_fr(decoder, *m_probability_tables, counter, component));
+        auto mv_hp = TRY_READ(TreeParser::parse_motion_vector_hp(decoder, *m_probability_tables, counter, component, use_high_precision));
         magnitude += ((bits << 3) | (mv_fr << 1) | mv_hp) + 1;
     }
     return (mv_sign ? -1 : 1) * static_cast<i32>(magnitude);
@@ -1452,10 +1451,10 @@ DecoderErrorOr<bool> Parser::tokens(BlockContext& block_context, size_t plane, u
         else
             tokens_context = TreeParser::get_context_for_other_tokens(token_cache, transform_size, transform_set, plane, token_position, block_context.is_inter_predicted(), band);
 
-        if (check_for_more_coefficients && !TRY_READ(TreeParser::parse_more_coefficients(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, tokens_context)))
+        if (check_for_more_coefficients && !TRY_READ(TreeParser::parse_more_coefficients(block_context.decoder, *m_probability_tables, block_context.counter, tokens_context)))
             break;
 
-        auto token = TRY_READ(TreeParser::parse_token(block_context.decoder, *m_probability_tables, *m_syntax_element_counter, tokens_context));
+        auto token = TRY_READ(TreeParser::parse_token(block_context.decoder, *m_probability_tables, block_context.counter, tokens_context));
         token_cache[token_position] = energy_class[token];
 
         i32 coef;

+ 1 - 2
Userland/Libraries/LibVideo/VP9/Parser.h

@@ -108,7 +108,7 @@ private:
     DecoderErrorOr<void> read_ref_frames(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<MotionVectorPair> get_motion_vector(BlockContext const&, BlockMotionVectorCandidates const&);
     DecoderErrorOr<MotionVector> read_motion_vector(BlockContext const&, BlockMotionVectorCandidates const&, ReferenceIndex);
-    DecoderErrorOr<i32> read_single_motion_vector_component(BooleanDecoder&, u8 component, bool use_high_precision);
+    DecoderErrorOr<i32> read_single_motion_vector_component(BooleanDecoder&, SyntaxElementCounter&, u8 component, bool use_high_precision);
     DecoderErrorOr<bool> residual(BlockContext&, bool has_block_above, bool has_block_left);
     DecoderErrorOr<bool> tokens(BlockContext&, size_t plane, u32 x, u32 y, TransformSize, TransformSet, Array<u8, 1024> token_cache);
     DecoderErrorOr<i32> read_coef(BooleanDecoder&, u8 bit_depth, Token token);
@@ -140,7 +140,6 @@ private:
     Vector2D<PersistentBlockContext> m_previous_block_contexts;
 
     OwnPtr<ProbabilityTables> m_probability_tables;
-    OwnPtr<SyntaxElementCounter> m_syntax_element_counter;
     Decoder& m_decoder;
 };
 

+ 52 - 1
Userland/Libraries/LibVideo/VP9/SyntaxElementCounter.cpp

@@ -5,10 +5,11 @@
  */
 
 #include "SyntaxElementCounter.h"
+#include <AK/Format.h>
 
 namespace Video::VP9 {
 
-void SyntaxElementCounter::clear_counts()
+SyntaxElementCounter::SyntaxElementCounter()
 {
     __builtin_memset(m_counts_intra_mode, 0, sizeof(m_counts_intra_mode));
     __builtin_memset(m_counts_uv_mode, 0, sizeof(m_counts_uv_mode));
@@ -34,4 +35,54 @@ void SyntaxElementCounter::clear_counts()
     __builtin_memset(m_counts_more_coefs, 0, sizeof(m_counts_more_coefs));
 }
 
+template<typename T, size_t size>
+static void sum_arrays(T (&destination)[size], const T (&left)[size], const T (&right)[size])
+{
+    for (size_t i = 0; i < size; i++) {
+        destination[i] = left[i] + right[i];
+    }
+}
+
+template<typename T, size_t size, size_t size_2>
+static void sum_arrays(T (&destination)[size][size_2], const T (&left)[size][size_2], const T (&right)[size][size_2])
+{
+    for (size_t i = 0; i < size; i++) {
+        sum_arrays(destination[i], left[i], right[i]);
+    }
+}
+
+SyntaxElementCounter SyntaxElementCounter::operator+(SyntaxElementCounter const& other) const
+{
+    SyntaxElementCounter result;
+    sum_arrays(result.m_counts_intra_mode, this->m_counts_intra_mode, other.m_counts_intra_mode);
+    sum_arrays(result.m_counts_uv_mode, this->m_counts_uv_mode, other.m_counts_uv_mode);
+    sum_arrays(result.m_counts_partition, this->m_counts_partition, other.m_counts_partition);
+    sum_arrays(result.m_counts_interp_filter, this->m_counts_interp_filter, other.m_counts_interp_filter);
+    sum_arrays(result.m_counts_inter_mode, this->m_counts_inter_mode, other.m_counts_inter_mode);
+    sum_arrays(result.m_counts_tx_size, this->m_counts_tx_size, other.m_counts_tx_size);
+    sum_arrays(result.m_counts_is_inter, this->m_counts_is_inter, other.m_counts_is_inter);
+    sum_arrays(result.m_counts_comp_mode, this->m_counts_comp_mode, other.m_counts_comp_mode);
+    sum_arrays(result.m_counts_single_ref, this->m_counts_single_ref, other.m_counts_single_ref);
+    sum_arrays(result.m_counts_comp_ref, this->m_counts_comp_ref, other.m_counts_comp_ref);
+    sum_arrays(result.m_counts_skip, this->m_counts_skip, other.m_counts_skip);
+    sum_arrays(result.m_counts_mv_joint, this->m_counts_mv_joint, other.m_counts_mv_joint);
+    sum_arrays(result.m_counts_mv_sign, this->m_counts_mv_sign, other.m_counts_mv_sign);
+    sum_arrays(result.m_counts_mv_class, this->m_counts_mv_class, other.m_counts_mv_class);
+    sum_arrays(result.m_counts_mv_class0_bit, this->m_counts_mv_class0_bit, other.m_counts_mv_class0_bit);
+    sum_arrays(result.m_counts_mv_class0_fr, this->m_counts_mv_class0_fr, other.m_counts_mv_class0_fr);
+    sum_arrays(result.m_counts_mv_class0_hp, this->m_counts_mv_class0_hp, other.m_counts_mv_class0_hp);
+    sum_arrays(result.m_counts_mv_bits, this->m_counts_mv_bits, other.m_counts_mv_bits);
+    sum_arrays(result.m_counts_mv_fr, this->m_counts_mv_fr, other.m_counts_mv_fr);
+    sum_arrays(result.m_counts_mv_hp, this->m_counts_mv_hp, other.m_counts_mv_hp);
+    sum_arrays(result.m_counts_token, this->m_counts_token, other.m_counts_token);
+    sum_arrays(result.m_counts_more_coefs, this->m_counts_more_coefs, other.m_counts_more_coefs);
+    return result;
+}
+
+SyntaxElementCounter& SyntaxElementCounter::operator+=(SyntaxElementCounter const& other)
+{
+    *this = *this + other;
+    return *this;
+}
+
 }

+ 5 - 0
Userland/Libraries/LibVideo/VP9/SyntaxElementCounter.h

@@ -13,6 +13,8 @@ namespace Video::VP9 {
 
 class SyntaxElementCounter final {
 public:
+    SyntaxElementCounter();
+
     /* (8.3) Clear Counts Process */
     void clear_counts();
 
@@ -38,6 +40,9 @@ public:
     u32 m_counts_mv_hp[2][2];
     u32 m_counts_token[TX_SIZES][BLOCK_TYPES][REF_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS][UNCONSTRAINED_NODES];
     u32 m_counts_more_coefs[TX_SIZES][BLOCK_TYPES][REF_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS][2];
+
+    SyntaxElementCounter operator+(SyntaxElementCounter const&) const;
+    SyntaxElementCounter& operator+=(SyntaxElementCounter const&);
 };
 
 }