Переглянути джерело

LibVideo/VP9: Add Frame, Tile and Block context structs

These are used to pass context needed for decoding, with mutability
scoped only to the sections that the function receiving the contexts
needs to modify. This allows lifetimes of data to be more explicit
rather than being stored in fields, as well as preventing tile threads
from modifying outside their allowed bounds.
Zaggy1024 2 роки тому
батько
коміт
befcd479ae

+ 99 - 4
Userland/Libraries/LibVideo/VP9/Context.h

@@ -12,9 +12,8 @@
 #include <LibGfx/Size.h>
 #include <LibVideo/Color/CodingIndependentCodePoints.h>
 
-#include <AK/Format.h>
-
 #include "Enums.h"
+#include "LookupTables.h"
 #include "MotionVector.h"
 
 namespace Video::VP9 {
@@ -153,7 +152,7 @@ public:
     }
 
     template<typename OtherT, typename Function>
-    void copy_to(Vector2D<OtherT>& other, Function function)
+    void copy_to(Vector2D<OtherT>& other, Function function) const
     {
         VERIFY(width() <= other.width());
         VERIFY(height() <= other.height());
@@ -163,7 +162,7 @@ public:
         }
     }
 
-    void copy_to(Vector2D<T>& other)
+    void copy_to(Vector2D<T>& other) const
     {
         VERIFY(width() <= other.width());
         VERIFY(height() <= other.height());
@@ -238,4 +237,100 @@ struct PersistentBlockContext {
     u8 segment_id { 0 };
 };
 
+struct FrameContext {
+public:
+    u8 profile { 0 };
+
+    bool shows_existing_frame() const { return m_show_existing_frame; }
+    u8 existing_frame_index() const { return m_existing_frame_index; }
+    void set_existing_frame_to_show(u8 index)
+    {
+        m_show_existing_frame = true;
+        m_existing_frame_index = index;
+    }
+
+    Gfx::Size<u32> size() const { return m_size; }
+    ErrorOr<void> set_size(Gfx::Size<u32> size)
+    {
+        m_size = size;
+
+        // From spec, compute_image_size( )
+        m_rows = (size.height() + 7u) >> 3u;
+        m_columns = (size.width() + 7u) >> 3u;
+        return m_block_contexts.try_resize(m_rows, m_columns);
+    }
+    u32 rows() const { return m_rows; }
+    u32 columns() const { return m_columns; }
+    u32 superblock_rows() const { return (rows() + 7u) >> 3u; }
+    u32 superblock_columns() const { return (columns() + 7u) >> 3u; }
+
+    Vector2D<FrameBlockContext> const& block_contexts() const { return m_block_contexts; }
+
+    Gfx::Size<u32> render_size { 0, 0 };
+
+    u16 header_size_in_bytes { 0 };
+
+private:
+    friend struct TileContext;
+
+    bool m_show_existing_frame { false };
+    u8 m_existing_frame_index { 0 };
+
+    Gfx::Size<u32> m_size { 0, 0 };
+    u32 m_rows { 0 };
+    u32 m_columns { 0 };
+    // 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.
+    Vector2D<FrameBlockContext> m_block_contexts;
+};
+
+struct TileContext {
+public:
+    TileContext(FrameContext& frame_context, u32 rows_start, u32 rows_end, u32 columns_start, u32 columns_end)
+        : frame_context(frame_context)
+        , rows_start(rows_start)
+        , rows_end(rows_end)
+        , columns_start(columns_start)
+        , columns_end(columns_end)
+        , block_contexts_view(frame_context.m_block_contexts.view(rows_start, columns_start, rows_end - rows_start, columns_end - columns_start))
+    {
+    }
+
+    Vector2D<FrameBlockContext> const& frame_block_contexts() const { return frame_context.block_contexts(); }
+
+    FrameContext const& frame_context;
+    u32 rows_start { 0 };
+    u32 rows_end { 0 };
+    u32 columns_start { 0 };
+    u32 columns_end { 0 };
+    Vector2DView<FrameBlockContext> block_contexts_view;
+};
+
+struct BlockContext {
+    BlockContext(TileContext& tile_context, u32 row, u32 column, BlockSubsize size)
+        : frame_context(tile_context.frame_context)
+        , tile_context(tile_context)
+        , row(row)
+        , column(column)
+        , size(size)
+        , contexts_view(tile_context.block_contexts_view.view(row - tile_context.rows_start, column - tile_context.columns_start,
+              min<u32>(num_8x8_blocks_high_lookup[size], tile_context.frame_context.rows() - row),
+              min<u32>(num_8x8_blocks_wide_lookup[size], tile_context.frame_context.columns() - column)))
+    {
+    }
+
+    Vector2D<FrameBlockContext> const& frame_block_contexts() const { return frame_context.block_contexts(); }
+
+    FrameContext const& frame_context;
+    TileContext const& tile_context;
+    u32 row { 0 };
+    u32 column { 0 };
+    BlockSubsize size;
+
+    Vector2DView<FrameBlockContext> contexts_view;
+};
+
 }

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

@@ -55,7 +55,7 @@ DecoderErrorOr<void> Decoder::decode_frame(ReadonlyBytes frame_data)
 {
     // 1. The syntax elements for the coded frame are extracted as specified in sections 6 and 7. The syntax
     // tables include function calls indicating when the block decode processes should be triggered.
-    TRY(m_parser->parse_frame(frame_data));
+    auto frame_context = TRY(m_parser->parse_frame(frame_data));
 
     // 2. If loop_filter_level is not equal to 0, the loop filter process as specified in section 8.8 is invoked once the
     // coded frame has been decoded.
@@ -70,17 +70,17 @@ DecoderErrorOr<void> Decoder::decode_frame(ReadonlyBytes frame_data)
 
     // 4. The output process as specified in section 8.9 is invoked.
     if (m_parser->m_show_frame)
-        TRY(create_video_frame());
+        TRY(create_video_frame(frame_context));
 
     // 5. The reference frame update process as specified in section 8.10 is invoked.
-    TRY(update_reference_frames());
+    TRY(update_reference_frames(frame_context));
     return {};
 }
 
-DecoderErrorOr<void> Decoder::create_video_frame()
+DecoderErrorOr<void> Decoder::create_video_frame(FrameContext const& frame_context)
 {
-    u32 decoded_y_width = m_parser->m_mi_cols * 8;
-    Gfx::Size<u32> output_y_size = m_parser->m_frame_size;
+    u32 decoded_y_width = frame_context.columns() * 8;
+    Gfx::Size<u32> output_y_size = frame_context.size();
     auto decoded_uv_width = decoded_y_width >> m_parser->m_subsampling_x;
     Gfx::Size<u32> output_uv_size = {
         output_y_size.width() >> m_parser->m_subsampling_x,
@@ -125,10 +125,10 @@ inline size_t buffer_size(Gfx::Size<size_t> size)
     return buffer_size(size.width(), size.height());
 }
 
-DecoderErrorOr<void> Decoder::allocate_buffers()
+DecoderErrorOr<void> Decoder::allocate_buffers(FrameContext const& frame_context)
 {
     for (size_t plane = 0; plane < 3; plane++) {
-        auto size = m_parser->get_decoded_size_for_plane(plane);
+        auto size = m_parser->get_decoded_size_for_plane(frame_context, plane);
 
         auto& output_buffer = get_output_buffer(plane);
         output_buffer.clear_with_capacity();
@@ -329,7 +329,7 @@ u8 Decoder::adapt_prob(u8 prob, u8 counts[2])
     return merge_prob(prob, counts[0], counts[1], COUNT_SAT, MAX_UPDATE_FACTOR);
 }
 
-DecoderErrorOr<void> Decoder::predict_intra(u8 plane, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TXSize tx_size, u32 block_index)
+DecoderErrorOr<void> Decoder::predict_intra(u8 plane, BlockContext const& block_context, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TXSize tx_size, u32 block_index)
 {
     auto& frame_buffer = get_output_buffer(plane);
 
@@ -346,7 +346,7 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, u32 x, u32 y, bool have_le
     PredictionMode mode;
     if (plane > 0)
         mode = m_parser->m_uv_mode;
-    else if (m_parser->m_mi_size >= Block_8x8)
+    else if (block_context.size >= Block_8x8)
         mode = m_parser->m_y_mode;
     else
         mode = m_parser->m_block_sub_modes[block_index];
@@ -363,8 +363,8 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, u32 x, u32 y, bool have_le
     //  − maxY is set equal to ((MiRows * 8) >> subsampling_y) - 1.
     auto subsampling_x = plane > 0 ? m_parser->m_subsampling_x : false;
     auto subsampling_y = plane > 0 ? m_parser->m_subsampling_y : false;
-    auto max_x = ((m_parser->m_mi_cols * 8u) >> subsampling_x) - 1u;
-    auto max_y = ((m_parser->m_mi_rows * 8u) >> subsampling_y) - 1u;
+    auto max_x = ((block_context.frame_context.columns() * 8u) >> subsampling_x) - 1u;
+    auto max_y = ((block_context.frame_context.rows() * 8u) >> subsampling_y) - 1u;
 
     auto const frame_buffer_at = [&](u32 row, u32 column) -> u16& {
         const auto frame_stride = max_x + 1u;
@@ -665,7 +665,7 @@ DecoderErrorOr<void> Decoder::predict_intra(u8 plane, u32 x, u32 y, bool have_le
     return {};
 }
 
-MotionVector Decoder::select_motion_vector(u8 plane, u8 ref_list, u32 block_index)
+MotionVector Decoder::select_motion_vector(u8 plane, BlockContext const& block_context, u8 ref_list, u32 block_index)
 {
     // The inputs to this process are:
     // − a variable plane specifying which plane is being predicted,
@@ -697,7 +697,7 @@ MotionVector Decoder::select_motion_vector(u8 plane, u8 ref_list, u32 block_inde
     // The motion vector array mv is derived as follows:
     // − If plane is equal to 0, or MiSize is greater than or equal to BLOCK_8X8, mv is set equal to
     // BlockMvs[ refList ][ blockIdx ].
-    if (plane == 0 || m_parser->m_mi_size >= Block_8x8)
+    if (plane == 0 || block_context.size >= Block_8x8)
         return m_parser->m_block_mvs[ref_list][block_index];
     // − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 0, mv is set equal to
     // BlockMvs[ refList ][ blockIdx ].
@@ -721,7 +721,7 @@ MotionVector Decoder::select_motion_vector(u8 plane, u8 ref_list, u32 block_inde
         + m_parser->m_block_mvs[ref_list][2] + m_parser->m_block_mvs[ref_list][3]);
 }
 
-MotionVector Decoder::clamp_motion_vector(u8 plane, u32 block_row, u32 block_column, MotionVector vector)
+MotionVector Decoder::clamp_motion_vector(u8 plane, BlockContext const& block_context, u32 block_row, u32 block_column, MotionVector vector)
 {
     // FIXME: This function is named very similarly to Parser::clamp_mv. Rename one or the other?
 
@@ -734,14 +734,14 @@ MotionVector Decoder::clamp_motion_vector(u8 plane, u32 block_row, u32 block_col
     bool subsampling_y = plane > 0 ? m_parser->m_subsampling_y : false;
 
     // The output array clampedMv is specified by the following steps:
-    i32 blocks_high = num_8x8_blocks_high_lookup[m_parser->m_mi_size];
+    i32 blocks_high = num_8x8_blocks_high_lookup[block_context.size];
     // Casts must be done here to prevent subtraction underflow from wrapping the values.
     i32 mb_to_top_edge = -(static_cast<i32>(block_row * MI_SIZE) * 16) >> subsampling_y;
-    i32 mb_to_bottom_edge = (((static_cast<i32>(m_parser->m_mi_rows) - blocks_high - static_cast<i32>(block_row)) * MI_SIZE) * 16) >> subsampling_y;
+    i32 mb_to_bottom_edge = (((static_cast<i32>(block_context.frame_context.rows()) - blocks_high - static_cast<i32>(block_row)) * MI_SIZE) * 16) >> subsampling_y;
 
-    i32 blocks_wide = num_8x8_blocks_wide_lookup[m_parser->m_mi_size];
+    i32 blocks_wide = num_8x8_blocks_wide_lookup[block_context.size];
     i32 mb_to_left_edge = -(static_cast<i32>(block_column * MI_SIZE) * 16) >> subsampling_x;
-    i32 mb_to_right_edge = (((static_cast<i32>(m_parser->m_mi_cols) - blocks_wide - static_cast<i32>(block_column)) * MI_SIZE) * 16) >> subsampling_x;
+    i32 mb_to_right_edge = (((static_cast<i32>(block_context.frame_context.columns()) - blocks_wide - static_cast<i32>(block_column)) * MI_SIZE) * 16) >> subsampling_x;
 
     i32 subpel_left = (INTERP_EXTEND + ((blocks_wide * MI_SIZE) >> subsampling_x)) << SUBPEL_BITS;
     i32 subpel_right = subpel_left - SUBPEL_SHIFTS;
@@ -753,16 +753,16 @@ MotionVector Decoder::clamp_motion_vector(u8 plane, u32 block_row, u32 block_col
     };
 }
 
-DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, u8 ref_list, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span<u16> block_buffer)
+DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, BlockContext const& block_context, u8 ref_list, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span<u16> block_buffer)
 {
     VERIFY(width <= maximum_block_dimensions && height <= maximum_block_dimensions);
     // 2. The motion vector selection process in section 8.5.2.1 is invoked with plane, refList, blockIdx as inputs
     // and the output being the motion vector mv.
-    auto motion_vector = select_motion_vector(plane, ref_list, block_index);
+    auto motion_vector = select_motion_vector(plane, block_context, ref_list, block_index);
 
     // 3. The motion vector clamping process in section 8.5.2.2 is invoked with plane, mv as inputs and the output
     // being the clamped motion vector clampedMv
-    auto clamped_vector = clamp_motion_vector(plane, block_row, block_column, motion_vector);
+    auto clamped_vector = clamp_motion_vector(plane, block_context, block_row, block_column, motion_vector);
 
     // 4. The motion vector scaling process in section 8.5.2.3 is invoked with plane, refList, x, y, clampedMv as
     // inputs and the output being the initial location startX, startY, and the step sizes stepX, stepY.
@@ -791,10 +791,10 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, u8 ref_list, u32 blo
     if (m_parser->m_frame_store[reference_frame_index][plane].is_empty())
         return DecoderError::format(DecoderErrorCategory::Corrupted, "Attempted to use reference frame {} that has not been saved", reference_frame_index);
     auto ref_frame_size = m_parser->m_ref_frame_size[reference_frame_index];
-    auto double_frame_size = m_parser->m_frame_size.scaled_by(2);
+    auto double_frame_size = block_context.frame_context.size().scaled_by(2);
     if (double_frame_size.width() < ref_frame_size.width() || double_frame_size.height() < ref_frame_size.height())
         return DecoderError::format(DecoderErrorCategory::Corrupted, "Inter frame size is too small relative to reference frame {}", reference_frame_index);
-    if (!ref_frame_size.scaled_by(16).contains(m_parser->m_frame_size))
+    if (!ref_frame_size.scaled_by(16).contains(block_context.frame_context.size()))
         return DecoderError::format(DecoderErrorCategory::Corrupted, "Inter frame size is too large relative to reference frame {}", reference_frame_index);
 
     // FIXME: Convert all the operations in this function to vector operations supported by
@@ -804,8 +804,8 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, u8 ref_list, u32 blo
     // A variable yScale is set equal to (RefFrameHeight[ refIdx ] << REF_SCALE_SHIFT) / FrameHeight.
     // (xScale and yScale specify the size of the reference frame relative to the current frame in units where 16 is
     // equivalent to the reference frame having the same size.)
-    i32 x_scale = (ref_frame_size.width() << REF_SCALE_SHIFT) / m_parser->m_frame_size.width();
-    i32 y_scale = (ref_frame_size.height() << REF_SCALE_SHIFT) / m_parser->m_frame_size.height();
+    i32 x_scale = (ref_frame_size.width() << REF_SCALE_SHIFT) / block_context.frame_context.size().width();
+    i32 y_scale = (ref_frame_size.height() << REF_SCALE_SHIFT) / block_context.frame_context.size().height();
 
     // The variable baseX is set equal to (x * xScale) >> REF_SCALE_SHIFT.
     // The variable baseY is set equal to (y * yScale) >> REF_SCALE_SHIFT.
@@ -923,7 +923,7 @@ DecoderErrorOr<void> Decoder::predict_inter_block(u8 plane, u8 ref_list, u32 blo
     return {};
 }
 
-DecoderErrorOr<void> Decoder::predict_inter(u8 plane, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index)
+DecoderErrorOr<void> Decoder::predict_inter(u8 plane, BlockContext const& block_context, u32 x, u32 y, u32 width, u32 height, u32 block_index)
 {
     // The inter prediction process is invoked for inter coded blocks. When MiSize is smaller than BLOCK_8X8, the
     // prediction is done with a granularity of 4x4 samples, otherwise the whole plane is predicted at the same time.
@@ -942,7 +942,7 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, u32 block_row, u32 block_c
     // 2. through 5.
     Array<u16, maximum_block_size> predicted_buffer;
     auto predicted_span = predicted_buffer.span().trim(width * height);
-    TRY(predict_inter_block(plane, 0, block_row, block_column, x, y, width, height, block_index, predicted_span));
+    TRY(predict_inter_block(plane, block_context, 0, block_context.row, block_context.column, x, y, width, height, block_index, predicted_span));
     auto predicted_buffer_at = [&](Span<u16> buffer, u32 row, u32 column) -> u16& {
         return buffer[row * width + column];
     };
@@ -952,8 +952,8 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, u32 block_row, u32 block_c
     // The inter predicted samples are then derived as follows:
     auto& frame_buffer = get_output_buffer(plane);
     VERIFY(!frame_buffer.is_empty());
-    auto frame_width = (m_parser->m_mi_cols * 8u) >> (plane > 0 ? m_parser->m_subsampling_x : false);
-    auto frame_height = (m_parser->m_mi_rows * 8u) >> (plane > 0 ? m_parser->m_subsampling_y : false);
+    auto frame_width = (block_context.frame_context.columns() * 8u) >> (plane > 0 ? m_parser->m_subsampling_x : false);
+    auto frame_height = (block_context.frame_context.rows() * 8u) >> (plane > 0 ? m_parser->m_subsampling_y : false);
     auto frame_buffer_at = [&](u32 row, u32 column) -> u16& {
         return frame_buffer[row * frame_width + column];
     };
@@ -976,7 +976,7 @@ DecoderErrorOr<void> Decoder::predict_inter(u8 plane, u32 block_row, u32 block_c
     // for i = 0..h-1 and j = 0..w-1.
     Array<u16, maximum_block_size> second_predicted_buffer;
     auto second_predicted_span = second_predicted_buffer.span().trim(width * height);
-    TRY(predict_inter_block(plane, 1, block_row, block_column, x, y, width, height, block_index, second_predicted_span));
+    TRY(predict_inter_block(plane, block_context, 1, block_context.row, block_context.column, x, y, width, height, block_index, second_predicted_span));
 
     for (auto i = 0u; i < height_in_frame_buffer; i++) {
         for (auto j = 0u; j < width_in_frame_buffer; j++)
@@ -1055,7 +1055,7 @@ u16 Decoder::get_ac_quant(u8 plane)
     return ac_q(static_cast<u8>(get_qindex() + offset));
 }
 
-DecoderErrorOr<void> Decoder::reconstruct(u8 plane, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size)
+DecoderErrorOr<void> Decoder::reconstruct(u8 plane, BlockContext const& block_context, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size)
 {
     // 8.6.2 Reconstruct process
 
@@ -1096,8 +1096,8 @@ DecoderErrorOr<void> Decoder::reconstruct(u8 plane, u32 transform_block_x, u32 t
     auto& current_buffer = get_output_buffer(plane);
     auto subsampling_x = (plane > 0 ? m_parser->m_subsampling_x : 0);
     auto subsampling_y = (plane > 0 ? m_parser->m_subsampling_y : 0);
-    auto frame_width = (m_parser->m_mi_cols * 8) >> subsampling_x;
-    auto frame_height = (m_parser->m_mi_rows * 8) >> subsampling_y;
+    auto frame_width = (block_context.frame_context.columns() * 8) >> subsampling_x;
+    auto frame_height = (block_context.frame_context.rows() * 8) >> subsampling_y;
     auto width_in_frame_buffer = min(block_size, frame_width - transform_block_x);
     auto height_in_frame_buffer = min(block_size, frame_height - transform_block_y);
 
@@ -1742,7 +1742,7 @@ DecoderErrorOr<void> Decoder::inverse_transform_2d(Span<Intermediate> dequantize
     return {};
 }
 
-DecoderErrorOr<void> Decoder::update_reference_frames()
+DecoderErrorOr<void> Decoder::update_reference_frames(FrameContext const& frame_context)
 {
     // This process is invoked as the final step in decoding a frame.
     // The inputs to this process are the samples in the current frame CurrFrame[ plane ][ x ][ y ].
@@ -1756,7 +1756,7 @@ DecoderErrorOr<void> Decoder::update_reference_frames()
         if ((refresh_flags & 1) != 0) {
             // − RefFrameWidth[ i ] is set equal to FrameWidth.
             // − RefFrameHeight[ i ] is set equal to FrameHeight.
-            m_parser->m_ref_frame_size[i] = m_parser->m_frame_size;
+            m_parser->m_ref_frame_size[i] = frame_context.size();
             // − RefSubsamplingX[ i ] is set equal to subsampling_x.
             m_parser->m_ref_subsampling_x[i] = m_parser->m_subsampling_x;
             // − RefSubsamplingY[ i ] is set equal to subsampling_y.
@@ -1773,9 +1773,9 @@ DecoderErrorOr<void> Decoder::update_reference_frames()
             // FIXME: Frame width is not equal to the buffer's stride. If we store the stride of the buffer with the reference
             //        frame, we can just copy the framebuffer data instead. Alternatively, we should crop the output framebuffer.
             for (auto plane = 0u; plane < 3; plane++) {
-                auto width = m_parser->m_frame_size.width();
-                auto height = m_parser->m_frame_size.height();
-                auto stride = m_parser->m_mi_cols * 8;
+                auto width = frame_context.size().width();
+                auto height = frame_context.size().height();
+                auto stride = frame_context.columns() * 8;
 
                 if (plane > 0) {
                     width = (width + m_parser->m_subsampling_x) >> m_parser->m_subsampling_x;
@@ -1800,8 +1800,8 @@ 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) {
-        DECODER_TRY_ALLOC(m_parser->m_previous_block_contexts.try_resize_to_match_other_vector2d(m_parser->m_frame_block_contexts));
+    if (!frame_context.shows_existing_frame()) {
+        DECODER_TRY_ALLOC(m_parser->m_previous_block_contexts.try_resize_to_match_other_vector2d(frame_context.block_contexts()));
         // − 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,
@@ -1812,8 +1812,8 @@ DecoderErrorOr<void> Decoder::update_reference_frames()
         //   − show_existing_frame is equal to 0,
         //   − segmentation_enabled is equal to 1,
         //   − segmentation_update_map is equal to 1.
-        bool keep_segment_ids = !m_parser->m_show_existing_frame && m_parser->m_segmentation_enabled && m_parser->m_segmentation_update_map;
-        m_parser->m_frame_block_contexts.copy_to(m_parser->m_previous_block_contexts, [keep_segment_ids](FrameBlockContext context) {
+        bool keep_segment_ids = !frame_context.shows_existing_frame() && m_parser->m_segmentation_enabled && m_parser->m_segmentation_update_map;
+        frame_context.block_contexts().copy_to(m_parser->m_previous_block_contexts, [keep_segment_ids](FrameBlockContext context) {
             auto persistent_context = PersistentBlockContext(context);
             if (!keep_segment_ids)
                 persistent_context.segment_id = 0;

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

@@ -42,9 +42,9 @@ private:
     static constexpr size_t maximum_transform_size = 32ULL * 32ULL;
 
     DecoderErrorOr<void> decode_frame(ReadonlyBytes);
-    DecoderErrorOr<void> create_video_frame();
+    DecoderErrorOr<void> create_video_frame(FrameContext const&);
 
-    DecoderErrorOr<void> allocate_buffers();
+    DecoderErrorOr<void> allocate_buffers(FrameContext const&);
     Vector<Intermediate>& get_temp_buffer(u8 plane);
     Vector<u16>& get_output_buffer(u8 plane);
 
@@ -58,18 +58,18 @@ private:
 
     /* (8.5) Prediction Processes */
     // (8.5.1) Intra prediction process
-    DecoderErrorOr<void> predict_intra(u8 plane, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TXSize tx_size, u32 block_index);
+    DecoderErrorOr<void> predict_intra(u8 plane, BlockContext const& block_context, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TXSize tx_size, u32 block_index);
 
     // (8.5.1) Inter prediction process
-    DecoderErrorOr<void> predict_inter(u8 plane, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index);
+    DecoderErrorOr<void> predict_inter(u8 plane, BlockContext const& block_context, u32 x, u32 y, u32 width, u32 height, u32 block_index);
     // (8.5.2.1) Motion vector selection process
-    MotionVector select_motion_vector(u8 plane, u8 ref_list, u32 block_index);
+    MotionVector select_motion_vector(u8 plane, BlockContext const&, u8 ref_list, u32 block_index);
     // (8.5.2.2) Motion vector clamping process
-    MotionVector clamp_motion_vector(u8 plane, u32 block_row, u32 block_column, MotionVector vector);
+    MotionVector clamp_motion_vector(u8 plane, BlockContext const&, u32 block_row, u32 block_column, MotionVector vector);
     // (8.5.2.3) Motion vector scaling process
     DecoderErrorOr<MotionVector> scale_motion_vector(u8 plane, u8 ref_list, u32 x, u32 y, MotionVector vector);
     // From (8.5.1) Inter prediction process, steps 2-5
-    DecoderErrorOr<void> predict_inter_block(u8 plane, u8 ref_list, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span<u16> block_buffer);
+    DecoderErrorOr<void> predict_inter_block(u8 plane, BlockContext const&, u8 ref_list, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span<u16> block_buffer);
 
     /* (8.6) Reconstruction and Dequantization */
 
@@ -84,7 +84,7 @@ private:
     u16 get_ac_quant(u8 plane);
 
     // (8.6.2) Reconstruct process
-    DecoderErrorOr<void> reconstruct(u8 plane, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size);
+    DecoderErrorOr<void> reconstruct(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TXSize transform_block_size);
 
     // (8.7) Inverse transform process
     DecoderErrorOr<void> inverse_transform_2d(Span<Intermediate> dequantized, u8 log2_of_block_size);
@@ -140,7 +140,7 @@ private:
     inline DecoderErrorOr<void> inverse_asymmetric_discrete_sine_transform(Span<Intermediate> data, u8 log2_of_block_size);
 
     /* (8.10) Reference Frame Update Process */
-    DecoderErrorOr<void> update_reference_frames();
+    DecoderErrorOr<void> update_reference_frames(FrameContext const&);
 
     inline CodingIndependentCodePoints get_cicp_color_space();
 

Різницю між файлами не показано, бо вона завелика
+ 228 - 230
Userland/Libraries/LibVideo/VP9/Parser.cpp


+ 42 - 67
Userland/Libraries/LibVideo/VP9/Parser.h

@@ -34,7 +34,7 @@ class Parser {
 public:
     explicit Parser(Decoder&);
     ~Parser();
-    DecoderErrorOr<void> parse_frame(ReadonlyBytes);
+    DecoderErrorOr<FrameContext> parse_frame(ReadonlyBytes);
 
 private:
     /* Annex B: Superframes are a method of storing multiple coded frames into a single chunk
@@ -49,30 +49,29 @@ private:
     void clear_context(Vector<T>& context, size_t size);
     template<typename T>
     void clear_context(Vector<Vector<T>>& context, size_t outer_size, size_t inner_size);
-    DecoderErrorOr<void> allocate_tile_data();
 
     /* (6.1) Frame Syntax */
     bool trailing_bits();
     DecoderErrorOr<void> refresh_probs();
 
     /* (6.2) Uncompressed Header Syntax */
-    DecoderErrorOr<void> uncompressed_header();
+    DecoderErrorOr<FrameContext> uncompressed_header();
     DecoderErrorOr<void> frame_sync_code();
-    DecoderErrorOr<void> color_config();
+    DecoderErrorOr<void> color_config(FrameContext const&);
     DecoderErrorOr<void> set_frame_size_and_compute_image_size();
-    DecoderErrorOr<Gfx::Size<u32>> frame_size();
-    DecoderErrorOr<Gfx::Size<u32>> frame_size_with_refs();
-    DecoderErrorOr<Gfx::Size<u32>> render_size(Gfx::Size<u32> frame_size);
-    void compute_image_size();
+    DecoderErrorOr<Gfx::Size<u32>> parse_frame_size();
+    DecoderErrorOr<Gfx::Size<u32>> parse_frame_size_with_refs();
+    DecoderErrorOr<Gfx::Size<u32>> parse_render_size(Gfx::Size<u32> frame_size);
+    DecoderErrorOr<void> compute_image_size(FrameContext&);
     DecoderErrorOr<void> read_interpolation_filter();
     DecoderErrorOr<void> loop_filter_params();
     DecoderErrorOr<void> quantization_params();
     DecoderErrorOr<i8> read_delta_q();
     DecoderErrorOr<void> segmentation_params();
     DecoderErrorOr<u8> read_prob();
-    DecoderErrorOr<void> tile_info();
-    u16 calc_min_log2_tile_cols();
-    u16 calc_max_log2_tile_cols();
+    DecoderErrorOr<void> tile_info(FrameContext&);
+    u16 calc_min_log2_tile_cols(u32 superblock_columns);
+    u16 calc_max_log2_tile_cols(u32 superblock_columns);
     void setup_past_independence();
 
     /* (6.3) Compressed Header Syntax */
@@ -97,58 +96,53 @@ private:
     void setup_compound_reference_mode();
 
     /* (6.4) Decode Tiles Syntax */
-    DecoderErrorOr<void> decode_tiles();
-    void clear_above_context();
+    DecoderErrorOr<void> decode_tiles(FrameContext&);
+    void clear_above_context(FrameContext&);
     u32 get_tile_offset(u32 tile_num, u32 mis, u32 tile_size_log2);
-    DecoderErrorOr<void> decode_tile();
-    void clear_left_context();
-    DecoderErrorOr<void> decode_partition(u32 row, u32 column, BlockSubsize subsize);
-    DecoderErrorOr<void> decode_block(u32 row, u32 column, BlockSubsize subsize);
-    DecoderErrorOr<void> mode_info(u32 row, u32 column, FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> intra_frame_mode_info(FrameBlockContext above_context, FrameBlockContext left_context);
+    DecoderErrorOr<void> decode_tile(TileContext&);
+    void clear_left_context(TileContext&);
+    DecoderErrorOr<void> decode_partition(TileContext&, u32 row, u32 column, BlockSubsize subsize);
+    DecoderErrorOr<void> decode_block(TileContext&, u32 row, u32 column, BlockSubsize subsize);
+    DecoderErrorOr<void> mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
+    DecoderErrorOr<void> intra_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> intra_segment_id();
     DecoderErrorOr<void> read_skip(FrameBlockContext above_context, FrameBlockContext left_context);
     bool seg_feature_active(u8 feature);
-    DecoderErrorOr<void> read_tx_size(FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select);
-    DecoderErrorOr<void> inter_frame_mode_info(u32 row, u32 column, FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> inter_segment_id(u32 row, u32 column);
-    u8 get_segment_id(u32 row, u32 column);
+    DecoderErrorOr<void> read_tx_size(BlockContext const&, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select);
+    DecoderErrorOr<void> inter_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
+    DecoderErrorOr<void> inter_segment_id(BlockContext const&);
+    u8 get_segment_id(BlockContext const&);
     DecoderErrorOr<void> read_is_inter(FrameBlockContext above_context, FrameBlockContext left_context);
-    DecoderErrorOr<void> intra_block_mode_info();
-    DecoderErrorOr<void> inter_block_mode_info(u32 row, u32 column, FrameBlockContext above_context, FrameBlockContext left_context);
+    DecoderErrorOr<void> intra_block_mode_info(BlockContext&);
+    DecoderErrorOr<void> inter_block_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> read_ref_frames(FrameBlockContext above_context, FrameBlockContext left_context);
     DecoderErrorOr<void> assign_mv(bool is_compound);
     DecoderErrorOr<void> read_mv(u8 ref);
     DecoderErrorOr<i32> read_mv_component(u8 component);
-    DecoderErrorOr<bool> residual(u32 row, u32 column, bool has_block_above, bool has_block_left);
-    TXSize get_uv_tx_size();
+    DecoderErrorOr<bool> residual(BlockContext&, bool has_block_above, bool has_block_left);
+    TXSize get_uv_tx_size(BlockSubsize size);
     BlockSubsize get_plane_block_size(u32 subsize, u8 plane);
-    DecoderErrorOr<bool> tokens(size_t plane, u32 x, u32 y, TXSize tx_size, u32 block_index);
-    u32 const* get_scan(size_t plane, TXSize tx_size, u32 block_index);
+    DecoderErrorOr<bool> tokens(BlockContext&, size_t plane, u32 x, u32 y, TXSize tx_size, u32 block_index);
+    u32 const* get_scan(BlockContext const&, size_t plane, TXSize tx_size, u32 block_index);
     DecoderErrorOr<i32> read_coef(Token token);
 
     /* (6.5) Motion Vector Prediction */
-    void find_mv_refs(u32 row, u32 column, ReferenceFrameType, i32 block);
-    void find_best_ref_mvs(u32 row, u32 column, u8 ref_list);
+    void find_mv_refs(BlockContext&, ReferenceFrameType, i32 block);
+    void find_best_ref_mvs(BlockContext&, u8 ref_list);
     bool use_mv_hp(MotionVector const& delta_mv);
-    void append_sub8x8_mvs(u32 row, u32 column, i32 block, u8 ref_list);
-    bool is_inside(i32 row, i32 column);
-    void clamp_mv_ref(u32 row, u32 column, u8 i);
-    MotionVector clamp_mv(u32 row, u32 column, MotionVector mvec, i32 border);
-    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);
+    void append_sub8x8_mvs(BlockContext&, i32 block, u8 ref_list);
+    void clamp_mv_ref(BlockContext const&, u8 i);
+    MotionVector clamp_mv(BlockContext const&, MotionVector vector, i32 border);
+    size_t get_image_index(FrameContext const&, u32 row, u32 column) const;
+    void get_block_mv(BlockContext const&, MotionVector candidate_vector, u8 ref_list, bool use_prev);
+    void if_same_ref_frame_add_mv(BlockContext const&, MotionVector candidate_vector, ReferenceFrameType ref_frame, bool use_prev);
+    void if_diff_ref_frame_add_mv(BlockContext const&, MotionVector candidate_vector, ReferenceFrameType ref_frame, bool use_prev);
     void scale_mv(u8 ref_list, ReferenceFrameType ref_frame);
     void add_mv_ref_list(u8 ref_list);
 
-    Gfx::Point<size_t> get_decoded_point_for_plane(u32 row, u32 column, u8 plane);
-    Gfx::Size<size_t> get_decoded_size_for_plane(u8 plane);
+    Gfx::Point<size_t> get_decoded_point_for_plane(FrameContext const&, u32 row, u32 column, u8 plane);
+    Gfx::Size<size_t> get_decoded_size_for_plane(FrameContext const&, u8 plane);
 
-    u8 m_profile { 0 };
-    bool m_show_existing_frame { false };
-    u8 m_frame_to_show_map_index { 0 };
-    u16 m_header_size_in_bytes { 0 };
     u8 m_refresh_frame_flags { 0 };
     u8 m_loop_filter_level { 0 };
     u8 m_loop_filter_sharpness { 0 };
@@ -156,7 +150,6 @@ private:
     FrameType m_frame_type { FrameType::KeyFrame };
     FrameType m_last_frame_type { FrameType::KeyFrame };
     bool m_show_frame { false };
-    bool m_prev_show_frame { false };
     bool m_error_resilient_mode { false };
     bool m_frame_is_intra { false };
     u8 m_reset_frame_context { 0 };
@@ -171,13 +164,9 @@ private:
     ColorRange m_color_range;
     bool m_subsampling_x { false };
     bool m_subsampling_y { false };
-    Gfx::Size<u32> m_frame_size { 0, 0 };
-    Gfx::Size<u32> m_render_size { 0, 0 };
-    bool m_render_and_frame_size_different { false };
-    u32 m_mi_cols { 0 };
-    u32 m_mi_rows { 0 };
-    u32 m_sb64_cols { 0 };
-    u32 m_sb64_rows { 0 };
+    bool m_is_first_compute_image_size_invoke { true };
+    Gfx::Size<u32> m_previous_frame_size { 0, 0 };
+    bool m_previous_show_frame { false };
     InterpolationFilter m_interpolation_filter { 0xf };
     u8 m_base_q_idx { 0 };
     i8 m_delta_q_y_dc { 0 };
@@ -205,12 +194,6 @@ private:
     Vector<u8> m_above_partition_context;
     Vector<u8> m_left_partition_context;
 
-    // FIXME: Move (some?) mi_.. to an array of struct since they are usually used together.
-    u32 m_mi_row_start { 0 };
-    u32 m_mi_row_end { 0 };
-    u32 m_mi_col_start { 0 };
-    u32 m_mi_col_end { 0 };
-    BlockSubsize m_mi_size { 0 };
     u8 m_segment_id { 0 };
     // FIXME: Should this be an enum?
     // skip equal to 0 indicates that there may be some transform coefficients to read for this block; skip equal to 1
@@ -219,7 +202,6 @@ private:
     // skip may be set to 0 even if transform blocks contain immediate end of block markers.
     bool m_skip { false };
     TXSize m_max_tx_size { TX_4x4 };
-    BlockSubsize m_block_subsize { BlockSubsize::Block_4x4 };
     TXSize m_tx_size { TX_4x4 };
     ReferenceFramePair m_ref_frame;
     bool m_is_inter { false };
@@ -253,13 +235,6 @@ private:
     // FIXME: Use Array<MotionVectorPair, 4> instead.
     Array<Array<MotionVector, 4>, 2> m_block_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.
-    Vector2D<FrameBlockContext> m_frame_block_contexts;
-
     MotionVectorPair m_candidate_mv;
     ReferenceFramePair m_candidate_frame;
     u8 m_ref_mv_count { 0 };

Деякі файли не було показано, через те що забагато файлів було змінено