From c4c91f02b3d80b3beb1ba08268d94195ca8f783c Mon Sep 17 00:00:00 2001 From: Zaggy1024 Date: Thu, 20 Jun 2024 23:11:08 -0500 Subject: [PATCH] LibMedia: Remove the home-grown VP9 decoder --- Meta/Lagom/Fuzzers/FuzzVP9Decoder.cpp | 16 - Meta/Lagom/Fuzzers/fuzzers.cmake | 2 - Tests/LibMedia/CMakeLists.txt | 4 - Tests/LibMedia/TestVP9Decode.cpp | 23 +- Tests/LibMedia/oss-fuzz-testcase-52630.vp9 | Bin 75 -> 0 bytes Tests/LibMedia/oss-fuzz-testcase-53977.vp9 | Bin 64 -> 0 bytes Tests/LibMedia/oss-fuzz-testcase-62054.vp9 | 1 - Tests/LibMedia/oss-fuzz-testcase-63182.vp9 | Bin 32 -> 0 bytes Userland/Libraries/LibMedia/CMakeLists.txt | 5 - .../LibMedia/Video/VP9/BooleanDecoder.h | 15 - .../Libraries/LibMedia/Video/VP9/Context.h | 380 ---- .../LibMedia/Video/VP9/ContextStorage.h | 290 --- .../Libraries/LibMedia/Video/VP9/Decoder.cpp | 2015 ----------------- .../Libraries/LibMedia/Video/VP9/Decoder.h | 153 -- Userland/Libraries/LibMedia/Video/VP9/Enums.h | 177 -- .../LibMedia/Video/VP9/LookupTables.h | 406 ---- .../LibMedia/Video/VP9/MotionVector.h | 62 - .../Libraries/LibMedia/Video/VP9/Parser.cpp | 1782 --------------- .../Libraries/LibMedia/Video/VP9/Parser.h | 147 -- .../LibMedia/Video/VP9/ProbabilityTables.cpp | 1219 ---------- .../LibMedia/Video/VP9/ProbabilityTables.h | 127 -- .../Libraries/LibMedia/Video/VP9/Symbols.h | 81 - .../Video/VP9/SyntaxElementCounter.cpp | 88 - .../LibMedia/Video/VP9/SyntaxElementCounter.h | 48 - .../LibMedia/Video/VP9/TreeParser.cpp | 733 ------ .../Libraries/LibMedia/Video/VP9/TreeParser.h | 79 - .../Libraries/LibMedia/Video/VP9/Utilities.h | 133 -- 27 files changed, 3 insertions(+), 7983 deletions(-) delete mode 100644 Meta/Lagom/Fuzzers/FuzzVP9Decoder.cpp delete mode 100644 Tests/LibMedia/oss-fuzz-testcase-52630.vp9 delete mode 100644 Tests/LibMedia/oss-fuzz-testcase-53977.vp9 delete mode 100644 Tests/LibMedia/oss-fuzz-testcase-62054.vp9 delete mode 100644 Tests/LibMedia/oss-fuzz-testcase-63182.vp9 delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/BooleanDecoder.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Context.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/ContextStorage.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Decoder.cpp delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Decoder.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Enums.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/LookupTables.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/MotionVector.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Parser.cpp delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Parser.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.cpp delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Symbols.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.cpp delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/TreeParser.cpp delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/TreeParser.h delete mode 100644 Userland/Libraries/LibMedia/Video/VP9/Utilities.h diff --git a/Meta/Lagom/Fuzzers/FuzzVP9Decoder.cpp b/Meta/Lagom/Fuzzers/FuzzVP9Decoder.cpp deleted file mode 100644 index b2e0512e900..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzVP9Decoder.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(u8 const* data, size_t size) -{ - AK::set_debug_enabled(false); - Media::Video::VP9::Decoder vp9_decoder; - (void)vp9_decoder.receive_sample(Duration::zero(), { data, size }); - return 0; -} diff --git a/Meta/Lagom/Fuzzers/fuzzers.cmake b/Meta/Lagom/Fuzzers/fuzzers.cmake index a541901a805..57550252d8d 100644 --- a/Meta/Lagom/Fuzzers/fuzzers.cmake +++ b/Meta/Lagom/Fuzzers/fuzzers.cmake @@ -39,7 +39,6 @@ set(FUZZER_TARGETS TTF TinyVGLoader URL - VP9Decoder WasmParser WAVLoader WebPLoader @@ -94,7 +93,6 @@ set(FUZZER_DEPENDENCIES_TIFFLoader LibGfx) set(FUZZER_DEPENDENCIES_TTF LibGfx) set(FUZZER_DEPENDENCIES_TinyVGLoader LibGfx) set(FUZZER_DEPENDENCIES_URL LibURL) -set(FUZZER_DEPENDENCIES_VP9Decoder LibMedia) set(FUZZER_DEPENDENCIES_WasmParser LibWasm) set(FUZZER_DEPENDENCIES_WAVLoader LibAudio) set(FUZZER_DEPENDENCIES_WebPLoader LibGfx) diff --git a/Tests/LibMedia/CMakeLists.txt b/Tests/LibMedia/CMakeLists.txt index 6faee303106..23f0f3aa9f7 100644 --- a/Tests/LibMedia/CMakeLists.txt +++ b/Tests/LibMedia/CMakeLists.txt @@ -14,7 +14,3 @@ install(FILES vp9_4k.webm DESTINATION usr/Tests/LibMedia) install(FILES vp9_clamp_reference_mvs.webm DESTINATION usr/Tests/LibMedia) install(FILES vp9_oob_blocks.webm DESTINATION usr/Tests/LibMedia) install(FILES master_elements_containing_crc32.mkv DESTINATION usr/Tests/LibMedia) -install(FILES oss-fuzz-testcase-52630.vp9 DESTINATION usr/Tests/LibMedia) -install(FILES oss-fuzz-testcase-53977.vp9 DESTINATION usr/Tests/LibMedia) -install(FILES oss-fuzz-testcase-62054.vp9 DESTINATION usr/Tests/LibMedia) -install(FILES oss-fuzz-testcase-63182.vp9 DESTINATION usr/Tests/LibMedia) diff --git a/Tests/LibMedia/TestVP9Decode.cpp b/Tests/LibMedia/TestVP9Decode.cpp index c0bbd316ce4..f818eef88ce 100644 --- a/Tests/LibMedia/TestVP9Decode.cpp +++ b/Tests/LibMedia/TestVP9Decode.cpp @@ -4,13 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include "TestMediaCommon.h" -static NonnullOwnPtr make_decoder(Media::Matroska::SampleIterator const&) +static NonnullOwnPtr make_decoder(Media::Matroska::SampleIterator const& iterator) { - return make(); + return MUST(Media::FFmpeg::FFmpegVideoDecoder::try_create(Media::CodecID::VP9, iterator.track().codec_private_data())); } TEST_CASE(webm_in_vp9) @@ -23,23 +23,6 @@ TEST_CASE(vp9_oob_blocks) decode_video("./vp9_oob_blocks.webm"sv, 240, make_decoder); } -TEST_CASE(vp9_malformed_frame) -{ - Array test_inputs = { - "./oss-fuzz-testcase-52630.vp9"sv, - "./oss-fuzz-testcase-53977.vp9"sv, - "./oss-fuzz-testcase-62054.vp9"sv, - "./oss-fuzz-testcase-63182.vp9"sv - }; - - for (auto test_input : test_inputs) { - auto file = MUST(Core::MappedFile::map(test_input)); - Media::Video::VP9::Decoder vp9_decoder; - auto maybe_decoder_error = vp9_decoder.receive_sample(Duration::zero(), file->bytes()); - EXPECT(maybe_decoder_error.is_error()); - } -} - BENCHMARK_CASE(vp9_4k) { decode_video("./vp9_4k.webm"sv, 2, make_decoder); diff --git a/Tests/LibMedia/oss-fuzz-testcase-52630.vp9 b/Tests/LibMedia/oss-fuzz-testcase-52630.vp9 deleted file mode 100644 index 7d6c1dabfe01ee6cfcb1e243b037e81d2b9a4f04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmdnE - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Media::Video::VP9 { - -using BooleanDecoder = Gfx::BooleanDecoder; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Context.h b/Userland/Libraries/LibMedia/Video/VP9/Context.h deleted file mode 100644 index cc5ae5c71df..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Context.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "BooleanDecoder.h" -#include "ContextStorage.h" -#include "Enums.h" -#include "LookupTables.h" -#include "MotionVector.h" -#include "SyntaxElementCounter.h" -#include "Utilities.h" - -namespace Media::Video::VP9 { - -enum class FrameShowMode { - CreateAndShowNewFrame, - ShowExistingFrame, - DoNotShowFrame, -}; - -struct Quantizers { - u16 y_ac_quantizer { 0 }; - u16 uv_ac_quantizer { 0 }; - - u16 y_dc_quantizer { 0 }; - u16 uv_dc_quantizer { 0 }; -}; - -struct FrameContext { -public: - static ErrorOr create(ReadonlyBytes data, - Vector2D& contexts) - { - return FrameContext( - data, - TRY(try_make(data)), - TRY(try_make()), - contexts); - } - - FrameContext(FrameContext const&) = delete; - FrameContext(FrameContext&&) = default; - - ReadonlyBytes stream_data; - NonnullOwnPtr stream; - BigEndianInputBitStream bit_stream; - - DecoderErrorOr create_range_decoder(size_t size) - { - if (size > stream->remaining()) - return DecoderError::corrupted("Range decoder size invalid"sv); - - auto compressed_header_data = ReadonlyBytes(stream_data.data() + stream->offset(), size); - - // 9.2.1: The Boolean decoding process specified in section 9.2.2 is invoked to read a marker syntax element from the - // bitstream. It is a requirement of bitstream conformance that the value read is equal to 0. - auto decoder = DECODER_TRY(DecoderErrorCategory::Corrupted, BooleanDecoder::initialize(compressed_header_data)); - if (decoder.read_bool(128)) - return DecoderError::corrupted("Range decoder marker was non-zero"sv); - - DECODER_TRY(DecoderErrorCategory::Corrupted, bit_stream.discard(size)); - return decoder; - } - - NonnullOwnPtr counter; - - u8 profile { 0 }; - - FrameType type { FrameType::KeyFrame }; - bool is_inter_predicted() const { return type == FrameType::InterFrame; } - - bool error_resilient_mode { false }; - bool parallel_decoding_mode { false }; - bool should_replace_probability_context { false }; - - bool shows_a_frame() const { return m_frame_show_mode != FrameShowMode::DoNotShowFrame; } - bool shows_a_new_frame() const { return m_frame_show_mode == FrameShowMode::CreateAndShowNewFrame; } - bool shows_existing_frame() const { return m_frame_show_mode == FrameShowMode::ShowExistingFrame; } - void set_frame_hidden() { m_frame_show_mode = FrameShowMode::DoNotShowFrame; } - void set_existing_frame_to_show(u8 index) - { - m_frame_show_mode = FrameShowMode::ShowExistingFrame; - m_existing_frame_index = index; - } - u8 existing_frame_index() const { return m_existing_frame_index; } - - bool use_previous_frame_motion_vectors { false }; - - ColorConfig color_config {}; - - u8 reference_frames_to_update_flags { 0 }; - bool should_update_reference_frame_at_index(u8 index) const { return (reference_frames_to_update_flags & (1 << index)) != 0; } - - u8 probability_context_index { 0 }; - - Gfx::Size size() const { return m_size; } - ErrorOr set_size(Gfx::Size size) - { - m_size = size; - - // From spec, compute_image_size( ) - m_rows = pixels_to_blocks(size.height() + 7u); - m_columns = pixels_to_blocks(size.width() + 7u); - 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 blocks_ceiled_to_superblocks(rows()); } - u32 superblock_columns() const { return blocks_ceiled_to_superblocks(columns()); } - // Calculates the output size for each plane in the frame. - Gfx::Size decoded_size(bool uv) const - { - if (uv) { - return { - Subsampling::subsampled_size(color_config.subsampling_y, blocks_to_pixels(columns())), - Subsampling::subsampled_size(color_config.subsampling_y, blocks_to_pixels(rows())), - }; - } - return { - blocks_to_pixels(columns()), - blocks_to_pixels(rows()), - }; - } - - Vector2D const& block_contexts() const { return m_block_contexts; } - - Gfx::Size render_size { 0, 0 }; - Gfx::Size log2_of_tile_counts { 0, 0 }; - - // This group of fields is only needed for inter-predicted frames. - Array reference_frame_indices; - Array reference_frame_sign_biases; - bool high_precision_motion_vectors_allowed { false }; - InterpolationFilter interpolation_filter { InterpolationFilter::Switchable }; - - u8 loop_filter_level { 0 }; - u8 loop_filter_sharpness { 0 }; - bool loop_filter_delta_enabled { false }; - Array loop_filter_reference_deltas; - Array loop_filter_mode_deltas; - - // Set based on quantization_params( ) in the spec. - bool lossless { false }; - Array segment_quantizers; - - bool segmentation_enabled { false }; - // Note: We can use Optional> for these tree probabilities, but unfortunately it seems to have measurable performance overhead. - bool use_full_segment_id_tree { false }; - Array full_segment_id_tree_probabilities; - bool use_predicted_segment_id_tree { false }; - Array predicted_segment_id_tree_probabilities; - bool should_use_absolute_segment_base_quantizer { false }; - SegmentationFeatures segmentation_features; - SegmentFeatureStatus get_segment_feature(u8 segment_id, SegmentFeature feature) const - { - return segmentation_features[segment_id][to_underlying(feature)]; - } - - u16 header_size_in_bytes { 0 }; - - TransformMode transform_mode; - - // This group also is only needed for inter-predicted frames. - ReferenceMode reference_mode; - ReferenceFrameType fixed_reference_type; - ReferenceFramePair variable_reference_types; - -private: - friend struct TileContext; - - FrameContext(ReadonlyBytes data, - NonnullOwnPtr stream, - NonnullOwnPtr counter, - Vector2D& contexts) - : stream_data(data) - , stream(move(stream)) - , bit_stream(MaybeOwned(*this->stream)) - , counter(move(counter)) - , m_block_contexts(contexts) - { - } - - FrameShowMode m_frame_show_mode { FrameShowMode::CreateAndShowNewFrame }; - u8 m_existing_frame_index { 0 }; - - Gfx::Size 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& m_block_contexts; -}; - -static ErrorOr create_non_zero_tokens(u32 size_in_sub_blocks, bool subsampling) -{ - return NonZeroTokens { - TRY(FixedArray::create(size_in_sub_blocks)), - TRY(FixedArray::create(size_in_sub_blocks >>= subsampling)), - TRY(FixedArray::create(size_in_sub_blocks)), - }; -} - -template -static Span safe_slice(Span span, u32 start, u32 size) -{ - return span.slice(start, min(size, span.size() - start)); -} - -static NonZeroTokensView create_non_zero_tokens_view(NonZeroTokensView non_zero_tokens, u32 start_in_sub_blocks, u32 size_in_sub_blocks, bool subsampling) -{ - NonZeroTokensView result; - // Y plane - result[0] = safe_slice(non_zero_tokens[0], start_in_sub_blocks, size_in_sub_blocks); - // UV planes - start_in_sub_blocks >>= subsampling; - size_in_sub_blocks >>= subsampling; - result[1] = safe_slice(non_zero_tokens[1], start_in_sub_blocks, size_in_sub_blocks); - result[2] = safe_slice(non_zero_tokens[2], start_in_sub_blocks, size_in_sub_blocks); - return result; -} - -static NonZeroTokensView create_non_zero_tokens_view(NonZeroTokens& non_zero_tokens, u32 start_in_sub_blocks, u32 size_in_sub_blocks, bool subsampling) -{ - return create_non_zero_tokens_view({ non_zero_tokens[0].span(), non_zero_tokens[1].span(), non_zero_tokens[2].span() }, start_in_sub_blocks, size_in_sub_blocks, subsampling); -} - -struct TileContext { -public: - static DecoderErrorOr try_create(FrameContext& frame_context, u32 tile_size, u32 rows_start, u32 rows_end, u32 columns_start, u32 columns_end, PartitionContextView above_partition_context, NonZeroTokensView above_non_zero_tokens, SegmentationPredictionContextView above_segmentation_ids) - { - auto width = columns_end - columns_start; - auto height = rows_end - rows_start; - auto context_view = frame_context.m_block_contexts.view(rows_start, columns_start, height, width); - - return TileContext { - frame_context, - TRY(frame_context.create_range_decoder(tile_size)), - DECODER_TRY_ALLOC(try_make()), - rows_start, - rows_end, - columns_start, - columns_end, - context_view, - above_partition_context, - above_non_zero_tokens, - above_segmentation_ids, - DECODER_TRY_ALLOC(PartitionContext::create(superblocks_to_blocks(blocks_ceiled_to_superblocks(height)))), - DECODER_TRY_ALLOC(create_non_zero_tokens(blocks_to_sub_blocks(height), frame_context.color_config.subsampling_y)), - DECODER_TRY_ALLOC(SegmentationPredictionContext::create(height)), - }; - } - - Vector2D const& frame_block_contexts() const { return frame_context.block_contexts(); } - - FrameContext const& frame_context; - BooleanDecoder decoder; - NonnullOwnPtr counter; - u32 rows_start { 0 }; - u32 rows_end { 0 }; - u32 columns_start { 0 }; - u32 columns_end { 0 }; - u32 rows() const { return rows_end - rows_start; } - u32 columns() const { return columns_end - columns_start; } - Vector2DView block_contexts_view; - - PartitionContextView above_partition_context; - NonZeroTokensView above_non_zero_tokens; - SegmentationPredictionContextView above_segmentation_ids; - PartitionContext left_partition_context; - NonZeroTokens left_non_zero_tokens; - SegmentationPredictionContext left_segmentation_ids; -}; - -struct BlockContext { - static BlockContext create(TileContext& tile_context, u32 row, u32 column, BlockSubsize size) - { - auto contexts_view = tile_context.block_contexts_view.view( - row - tile_context.rows_start, - column - tile_context.columns_start, - min(num_8x8_blocks_high_lookup[size], tile_context.frame_context.rows() - row), - min(num_8x8_blocks_wide_lookup[size], tile_context.frame_context.columns() - column)); - - auto size_in_blocks = block_size_to_blocks(size); - auto size_in_sub_blocks = block_size_to_sub_blocks(get_subsampled_block_size(size, false, false)); - - return 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, - .contexts_view = contexts_view, - .above_non_zero_tokens = create_non_zero_tokens_view(tile_context.above_non_zero_tokens, blocks_to_sub_blocks(column - tile_context.columns_start), size_in_sub_blocks.width(), tile_context.frame_context.color_config.subsampling_x), - .above_segmentation_ids = safe_slice(tile_context.above_segmentation_ids, column - tile_context.columns_start, size_in_blocks.width()), - .left_non_zero_tokens = create_non_zero_tokens_view(tile_context.left_non_zero_tokens, blocks_to_sub_blocks(row - tile_context.rows_start), size_in_sub_blocks.height(), tile_context.frame_context.color_config.subsampling_y), - .left_segmentation_ids = safe_slice(tile_context.left_segmentation_ids.span(), row - tile_context.rows_start, size_in_blocks.height()), - }; - } - - Vector2D const& frame_block_contexts() const { return frame_context.block_contexts(); } - - FrameContext const& frame_context; - TileContext const& tile_context; - BooleanDecoder& decoder; - SyntaxElementCounter& counter; - u32 row { 0 }; - u32 column { 0 }; - BlockSubsize size; - Gfx::Size get_size_in_sub_blocks() const - { - return block_size_to_sub_blocks(size); - } - - Vector2DView contexts_view; - - u8 segment_id { 0 }; - bool should_skip_residuals { false }; - - TransformSize transform_size { Transform_4x4 }; - - ReferenceFramePair reference_frame_types {}; - bool is_inter_predicted() const { return reference_frame_types.primary != ReferenceFrameType::None; } - bool is_compound() const { return reference_frame_types.secondary != ReferenceFrameType::None; } - - Array sub_block_prediction_modes {}; - PredictionMode y_prediction_mode() const { return sub_block_prediction_modes.last(); } - PredictionMode& y_prediction_mode() { return sub_block_prediction_modes.last(); } - PredictionMode uv_prediction_mode { 0 }; - - InterpolationFilter interpolation_filter { EightTap }; - Array sub_block_motion_vectors {}; - - Array residual_tokens {}; - - // Indexed by ReferenceFrame enum. - Array mode_context {}; - - NonZeroTokensView above_non_zero_tokens; - SegmentationPredictionContextView above_segmentation_ids; - NonZeroTokensView left_non_zero_tokens; - SegmentationPredictionContextView left_segmentation_ids; - - SegmentFeatureStatus get_segment_feature(SegmentFeature feature) const - { - return frame_context.get_segment_feature(segment_id, feature); - } -}; - -struct BlockMotionVectorCandidateSet { - MotionVector near_vector; - MotionVector nearest_vector; - MotionVector best_vector; -}; - -struct MotionVectorCandidate { - ReferenceFrameType type; - MotionVector vector; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/ContextStorage.h b/Userland/Libraries/LibMedia/Video/VP9/ContextStorage.h deleted file mode 100644 index 06f04453883..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/ContextStorage.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "Enums.h" -#include "LookupTables.h" -#include "MotionVector.h" - -namespace Media::Video::VP9 { - -template -struct ReferencePair { - T primary; - T secondary; - - T& operator[](ReferenceIndex index) - { - switch (index) { - case ReferenceIndex::Primary: - return primary; - case ReferenceIndex::Secondary: - return secondary; - default: - VERIFY_NOT_REACHED(); - } - } - - T const& operator[](ReferenceIndex index) const - { - return const_cast&>(*this)[index]; - } -}; - -typedef ReferencePair ReferenceFramePair; -typedef ReferencePair MotionVectorPair; - -template -class Vector2D; - -template -class Vector2DView { -public: - u32 top() const { return m_top; } - u32 left() const { return m_left; } - u32 height() const { return m_height; } - u32 width() const { return m_width; } - - T const& operator[](size_t index) const { return m_storage[index]; } - size_t size() const { return m_storage->size(); } - - T& at(u32 relative_row, u32 relative_column) - { - VERIFY(relative_row < height()); - VERIFY(relative_column < width()); - return m_storage->at(top() + relative_row, left() + relative_column); - } - T const& at(u32 relative_row, u32 relative_column) const - { - VERIFY(relative_row < height()); - VERIFY(relative_column < width()); - return m_storage->at(top() + relative_row, left() + relative_column); - } - - Vector2DView view(u32 top, u32 left, u32 height, u32 width) - { - VERIFY(top + height <= this->height()); - VERIFY(left + width <= this->width()); - return Vector2DView(m_storage, this->top() + top, this->left() + left, height, width); - } - -private: - friend class Vector2D; - - Vector2DView(Vector2D* const storage, u32 top, u32 left, u32 height, u32 width) - : m_storage(storage) - , m_top(top) - , m_left(left) - , m_height(height) - , m_width(width) - { - } - - Vector2D* const m_storage; - u32 const m_top { 0 }; - u32 const m_left { 0 }; - u32 const m_height { 0 }; - u32 const m_width { 0 }; -}; - -template -class Vector2D { -public: - ~Vector2D() - { - clear_storage(); - } - - ErrorOr try_resize(u32 height, u32 width) - { - if (height != m_height && width != m_width) { - clear_storage(); - - size_t size = height * width; - auto* new_storage = new (nothrow) T[size]; - if (!new_storage) - return Error::from_errno(ENOMEM); - m_storage = new_storage; - m_height = height; - m_width = width; - } - - return {}; - } - - u32 height() const { return m_height; } - u32 width() const { return m_width; } - - size_t index_at(u32 row, u32 column) const - { - VERIFY(row < height()); - VERIFY(column < width()); - return row * width() + column; - } - - T& operator[](size_t index) { return m_storage[index]; } - T const& operator[](size_t index) const { return m_storage[index]; } - size_t size() const { return m_height * m_width; } - - T& at(u32 row, u32 column) - { - return m_storage[index_at(row, column)]; - } - T const& at(u32 row, u32 column) const - { - return m_storage[index_at(row, column)]; - } - - void assign(u32 row, u32 column, T&& value) - { - new (&m_storage[index_at(row, column)]) T(move(value)); - } - - template - void copy_to(Vector2D& other, Function function) const - { - VERIFY(width() <= other.width()); - VERIFY(height() <= other.height()); - for (u32 row = 0; row < height(); row++) { - for (u32 column = 0; column < width(); column++) - other.at(row, column) = function(at(row, column)); - } - } - - void copy_to(Vector2D& other) const - { - VERIFY(width() <= other.width()); - VERIFY(height() <= other.height()); - for (u32 row = 0; row < height(); row++) { - auto other_index = other.index_at(row, 0); - AK::TypedTransfer::copy(&m_storage[index_at(row, 0)], &other[other_index], width()); - } - } - - template - ErrorOr try_resize_to_match_other_vector2d(Vector2D const& other) - { - return try_resize(other.height(), other.width()); - } - - void reset() - { - for (size_t i = 0; i < size(); i++) - m_storage[i] = T(); - } - - Vector2DView view(u32 top, u32 left, u32 height, u32 width) - { - VERIFY(top + height <= this->height()); - VERIFY(left + width <= this->width()); - return Vector2DView(this, top, left, height, width); - } - -private: - void clear_storage() - { - delete[] m_storage; - m_storage = nullptr; - m_width = 0; - m_height = 0; - } - - u32 m_height { 0 }; - u32 m_width { 0 }; - T* m_storage { nullptr }; -}; - -// Block context that is kept for the lifetime of a frame. -struct FrameBlockContext { - bool is_intra_predicted() const { return ref_frames.primary == ReferenceFrameType::None; } - bool is_single_reference() const { return ref_frames.secondary == ReferenceFrameType::None; } - MotionVectorPair primary_motion_vector_pair() const { return sub_block_motion_vectors[3]; } - - bool is_available { false }; - bool skip_coefficients { false }; - TransformSize transform_size { Transform_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 sub_block_motion_vectors; - u8 segment_id { 0 }; -}; - -// Block context that is kept between frames until explicitly cleared. -struct PersistentBlockContext { - PersistentBlockContext() - : available(false) - { - } - - PersistentBlockContext(FrameBlockContext const& frame_context) - : available(frame_context.is_available) - , ref_frames(frame_context.ref_frames) - , primary_motion_vector_pair(frame_context.primary_motion_vector_pair()) - , segment_id(frame_context.segment_id) - { - } - - bool available { false }; - ReferenceFramePair ref_frames { ReferenceFrameType::None, ReferenceFrameType::None }; - MotionVectorPair primary_motion_vector_pair {}; - u8 segment_id { 0 }; -}; - -struct SegmentFeatureStatus { - bool enabled { false }; - u8 value { 0 }; -}; - -using SegmentFeatures = Array; -using SegmentationFeatures = Array; - -struct ColorConfig { - u8 bit_depth { 8 }; - ColorSpace color_space { ColorSpace::Bt601 }; - VideoFullRangeFlag color_range { VideoFullRangeFlag::Studio }; - bool subsampling_x { true }; - bool subsampling_y { true }; -}; - -struct BlockMotionVectorCandidateSet; -using BlockMotionVectorCandidates = ReferencePair; - -using NonZeroTokens = Array, 3>; -using NonZeroTokensView = Array, 3>; - -using SegmentationPredictionContext = FixedArray; -using SegmentationPredictionContextView = Span; - -using PartitionContext = FixedArray; -using PartitionContextView = Span; - -struct ReferenceFrame { - Gfx::Size size { 0, 0 }; - bool subsampling_x { false }; - bool subsampling_y { false }; - u8 bit_depth { 0 }; - Array, 3> frame_planes {}; - - bool is_valid() const { return bit_depth > 0; } - - // These values are set at the start of each inter frame to be used during prediction. - i32 x_scale { 0 }; - i32 y_scale { 0 }; - i32 scaled_step_x { 0 }; - i32 scaled_step_y { 0 }; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Decoder.cpp b/Userland/Libraries/LibMedia/Video/VP9/Decoder.cpp deleted file mode 100644 index b343708f88f..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Decoder.cpp +++ /dev/null @@ -1,2015 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -#include "Context.h" -#include "Decoder.h" -#include "Utilities.h" - -#if defined(AK_COMPILER_GCC) -# pragma GCC optimize("O3") -#endif - -namespace Media::Video::VP9 { - -Decoder::Decoder() - : m_parser(make(*this)) -{ -} - -DecoderErrorOr Decoder::receive_sample(Duration timestamp, ReadonlyBytes chunk_data) -{ - auto superframe_sizes = m_parser->parse_superframe_sizes(chunk_data); - - if (superframe_sizes.is_empty()) { - return decode_frame(timestamp, chunk_data); - } - - size_t offset = 0; - - for (auto superframe_size : superframe_sizes) { - auto checked_size = Checked(superframe_size); - checked_size += offset; - if (checked_size.has_overflow() || checked_size.value() > chunk_data.size()) - return DecoderError::with_description(DecoderErrorCategory::Corrupted, "Superframe size invalid"sv); - auto frame_data = chunk_data.slice(offset, superframe_size); - TRY(decode_frame(timestamp, frame_data)); - offset = checked_size.value(); - } - - return {}; -} - -DecoderErrorOr Decoder::decode_frame(Duration timestamp, 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. - 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. - // FIXME: Implement loop filtering. - - // 3. If all of the following conditions are true, PrevSegmentIds[ row ][ col ] is set equal to - // SegmentIds[ row ][ col ] for row = 0..MiRows-1, for col = 0..MiCols-1: - // − show_existing_frame is equal to 0, - // − segmentation_enabled is equal to 1, - // − segmentation_update_map is equal to 1. - // This is handled by update_reference_frames. - - // 4. The output process as specified in section 8.9 is invoked. - if (frame_context.shows_a_frame()) { - switch (frame_context.color_config.bit_depth) { - case 8: - TRY(create_video_frame(timestamp, frame_context)); - break; - case 10: - case 12: - TRY(create_video_frame(timestamp, frame_context)); - break; - } - } - - // 5. The reference frame update process as specified in section 8.10 is invoked. - TRY(update_reference_frames(frame_context)); - return {}; -} - -inline CodingIndependentCodePoints get_cicp_color_space(FrameContext const& frame_context) -{ - ColorPrimaries color_primaries; - TransferCharacteristics transfer_characteristics; - MatrixCoefficients matrix_coefficients; - - switch (frame_context.color_config.color_space) { - case ColorSpace::Unknown: - color_primaries = ColorPrimaries::Unspecified; - transfer_characteristics = TransferCharacteristics::Unspecified; - matrix_coefficients = MatrixCoefficients::Unspecified; - break; - case ColorSpace::Bt601: - color_primaries = ColorPrimaries::BT601; - transfer_characteristics = TransferCharacteristics::BT601; - matrix_coefficients = MatrixCoefficients::BT601; - break; - case ColorSpace::Bt709: - color_primaries = ColorPrimaries::BT709; - transfer_characteristics = TransferCharacteristics::BT709; - matrix_coefficients = MatrixCoefficients::BT709; - break; - case ColorSpace::Smpte170: - // https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/pixfmt-007.html#colorspace-smpte-170m-v4l2-colorspace-smpte170m - color_primaries = ColorPrimaries::BT601; - transfer_characteristics = TransferCharacteristics::BT709; - matrix_coefficients = MatrixCoefficients::BT601; - break; - case ColorSpace::Smpte240: - color_primaries = ColorPrimaries::SMPTE240; - transfer_characteristics = TransferCharacteristics::SMPTE240; - matrix_coefficients = MatrixCoefficients::SMPTE240; - break; - case ColorSpace::Bt2020: - color_primaries = ColorPrimaries::BT2020; - // Bit depth doesn't actually matter to our transfer functions since we - // convert in floats of range 0-1 (for now?), but just for correctness set - // the TC to match the bit depth here. - if (frame_context.color_config.bit_depth == 12) - transfer_characteristics = TransferCharacteristics::BT2020BitDepth12; - else if (frame_context.color_config.bit_depth == 10) - transfer_characteristics = TransferCharacteristics::BT2020BitDepth10; - else - transfer_characteristics = TransferCharacteristics::BT709; - matrix_coefficients = MatrixCoefficients::BT2020NonConstantLuminance; - break; - case ColorSpace::RGB: - color_primaries = ColorPrimaries::BT709; - transfer_characteristics = TransferCharacteristics::Linear; - matrix_coefficients = MatrixCoefficients::Identity; - break; - case ColorSpace::Reserved: - VERIFY_NOT_REACHED(); - break; - } - - return { color_primaries, transfer_characteristics, matrix_coefficients, frame_context.color_config.color_range }; -} - -template -DecoderErrorOr Decoder::create_video_frame(Duration timestamp, FrameContext const& frame_context) -{ - // (8.9) Output process - - // FIXME: If show_existing_frame is set, output from FrameStore[frame_to_show_map_index] here instead. - if (frame_context.shows_existing_frame()) { - dbgln("FIXME: Show an existing reference frame."); - } - - // FIXME: The math isn't entirely accurate to spec. output_uv_size is probably incorrect for certain - // sizes, as the spec seems to prefer that the halved sizes be ceiled. - u32 decoded_y_width = frame_context.decoded_size(false).width(); - auto decoded_uv_width = frame_context.decoded_size(true).width(); - - Subsampling subsampling { frame_context.color_config.subsampling_x, frame_context.color_config.subsampling_y }; - auto output_y_size = frame_context.size().to_type(); - auto output_uv_size = subsampling.subsampled_size(output_y_size); - - auto frame = DECODER_TRY_ALLOC(SubsampledYUVFrame::try_create( - timestamp, - { output_y_size.width(), output_y_size.height() }, - frame_context.color_config.bit_depth, get_cicp_color_space(frame_context), - subsampling)); - for (u32 plane = 0; plane < 3; plane++) { - auto* buffer = frame->get_plane_data(plane); - auto decoded_width = plane == 0 ? decoded_y_width : decoded_uv_width; - auto output_size = plane == 0 ? output_y_size : output_uv_size; - auto const* decoded_buffer = get_output_buffer(plane).data(); - - for (u32 row = 0; row < output_size.height(); row++) { - for (u32 column = 0; column < output_size.width(); column++) - buffer[row * output_size.width() + column] = static_cast(decoded_buffer[row * decoded_width + column]); - } - } - - m_video_frame_queue.enqueue(move(frame)); - - return {}; -} - -DecoderErrorOr Decoder::allocate_buffers(FrameContext const& frame_context) -{ - for (size_t plane = 0; plane < 3; plane++) { - auto size = frame_context.decoded_size(plane > 0); - - auto& output_buffer = get_output_buffer(plane); - output_buffer.clear_with_capacity(); - DECODER_TRY_ALLOC(output_buffer.try_resize_and_keep_capacity(size.width() * size.height())); - } - return {}; -} - -Vector& Decoder::get_output_buffer(u8 plane) -{ - return m_output_buffers[plane]; -} - -DecoderErrorOr> Decoder::get_decoded_frame() -{ - if (m_video_frame_queue.is_empty()) - return DecoderError::format(DecoderErrorCategory::NeedsMoreInput, "No video frame in queue."); - - return m_video_frame_queue.dequeue(); -} - -void Decoder::flush() -{ - m_video_frame_queue.clear(); -} - -template -static inline i32 rounded_right_shift(T value, u8 bits) -{ - value = (value + static_cast(1u << (bits - 1u))) >> bits; - return static_cast(value); -} - -u8 Decoder::merge_prob(u8 pre_prob, u32 count_0, u32 count_1, u8 count_sat, u8 max_update_factor) -{ - auto total_decode_count = count_0 + count_1; - u8 prob = 128; - if (total_decode_count != 0) { - prob = static_cast(clip_3(1u, 255u, (count_0 * 256 + (total_decode_count >> 1)) / total_decode_count)); - } - auto count = min(total_decode_count, count_sat); - auto factor = (max_update_factor * count) / count_sat; - return rounded_right_shift(pre_prob * (256 - factor) + (prob * factor), 8); -} - -u32 Decoder::merge_probs(int const* tree, int index, u8* probs, u32* counts, u8 count_sat, u8 max_update_factor) -{ - auto s = tree[index]; - auto left_count = (s <= 0) ? counts[-s] : merge_probs(tree, s, probs, counts, count_sat, max_update_factor); - auto r = tree[index + 1]; - auto right_count = (r <= 0) ? counts[-r] : merge_probs(tree, r, probs, counts, count_sat, max_update_factor); - probs[index >> 1] = merge_prob(probs[index >> 1], left_count, right_count, count_sat, max_update_factor); - return left_count + right_count; -} - -DecoderErrorOr Decoder::adapt_coef_probs(FrameContext const& frame_context) -{ - u8 update_factor; - if (!frame_context.is_inter_predicted() || m_parser->m_previous_frame_type != FrameType::KeyFrame) - update_factor = 112; - else - update_factor = 128; - - for (size_t t = 0; t < 4; t++) { - for (size_t i = 0; i < 2; i++) { - for (size_t j = 0; j < 2; j++) { - for (size_t k = 0; k < 6; k++) { - size_t max_l = (k == 0) ? 3 : 6; - 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, - frame_context.counter->m_counts_token[t][i][j][k][l], - 24, update_factor); - merge_probs(binary_tree, 0, coef_probs, - frame_context.counter->m_counts_more_coefs[t][i][j][k][l], - 24, update_factor); - } - } - } - } - } - - return {}; -} - -#define ADAPT_PROB_TABLE(name, size) \ - do { \ - for (size_t i = 0; i < (size); i++) { \ - auto table = probs.name##_prob(); \ - table[i] = adapt_prob(table[i], counter.m_counts_##name[i]); \ - } \ - } while (0) - -#define ADAPT_TREE(tree_name, prob_name, count_name, size) \ - do { \ - for (size_t i = 0; i < (size); i++) { \ - adapt_probs(tree_name##_tree, probs.prob_name##_probs()[i], counter.m_counts_##count_name[i]); \ - } \ - } while (0) - -DecoderErrorOr Decoder::adapt_non_coef_probs(FrameContext const& frame_context) -{ - auto& probs = *m_parser->m_probability_tables; - 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); - for (size_t i = 0; i < REF_CONTEXTS; i++) { - for (size_t j = 0; j < 2; j++) - probs.single_ref_prob()[i][j] = adapt_prob(probs.single_ref_prob()[i][j], counter.m_counts_single_ref[i][j]); - } - ADAPT_TREE(inter_mode, inter_mode, inter_mode, INTER_MODE_CONTEXTS); - ADAPT_TREE(intra_mode, y_mode, intra_mode, BLOCK_SIZE_GROUPS); - ADAPT_TREE(intra_mode, uv_mode, uv_mode, INTRA_MODES); - ADAPT_TREE(partition, partition, partition, PARTITION_CONTEXTS); - ADAPT_PROB_TABLE(skip, SKIP_CONTEXTS); - if (frame_context.interpolation_filter == Switchable) { - ADAPT_TREE(interp_filter, interp_filter, interp_filter, INTERP_FILTER_CONTEXTS); - } - if (frame_context.transform_mode == TransformMode::Select) { - for (size_t i = 0; i < TX_SIZE_CONTEXTS; i++) { - auto& tx_probs = probs.tx_probs(); - auto& tx_counts = counter.m_counts_tx_size; - adapt_probs(tx_size_8_tree, tx_probs[Transform_8x8][i], tx_counts[Transform_8x8][i]); - adapt_probs(tx_size_16_tree, tx_probs[Transform_16x16][i], tx_counts[Transform_16x16][i]); - adapt_probs(tx_size_32_tree, tx_probs[Transform_32x32][i], tx_counts[Transform_32x32][i]); - } - } - adapt_probs(mv_joint_tree, probs.mv_joint_probs(), counter.m_counts_mv_joint); - for (size_t i = 0; i < 2; i++) { - probs.mv_sign_prob()[i] = adapt_prob(probs.mv_sign_prob()[i], counter.m_counts_mv_sign[i]); - adapt_probs(mv_class_tree, probs.mv_class_probs()[i], counter.m_counts_mv_class[i]); - probs.mv_class0_bit_prob()[i] = adapt_prob(probs.mv_class0_bit_prob()[i], counter.m_counts_mv_class0_bit[i]); - for (size_t j = 0; j < MV_OFFSET_BITS; j++) - probs.mv_bits_prob()[i][j] = adapt_prob(probs.mv_bits_prob()[i][j], counter.m_counts_mv_bits[i][j]); - for (size_t j = 0; j < CLASS0_SIZE; j++) - adapt_probs(mv_fr_tree, probs.mv_class0_fr_probs()[i][j], counter.m_counts_mv_class0_fr[i][j]); - adapt_probs(mv_fr_tree, probs.mv_fr_probs()[i], counter.m_counts_mv_fr[i]); - if (frame_context.high_precision_motion_vectors_allowed) { - probs.mv_class0_hp_prob()[i] = adapt_prob(probs.mv_class0_hp_prob()[i], counter.m_counts_mv_class0_hp[i]); - probs.mv_hp_prob()[i] = adapt_prob(probs.mv_hp_prob()[i], counter.m_counts_mv_hp[i]); - } - } - return {}; -} - -void Decoder::adapt_probs(int const* tree, u8* probs, u32* counts) -{ - merge_probs(tree, 0, probs, counts, COUNT_SAT, MAX_UPDATE_FACTOR); -} - -u8 Decoder::adapt_prob(u8 prob, u32 counts[2]) -{ - return merge_prob(prob, counts[0], counts[1], COUNT_SAT, MAX_UPDATE_FACTOR); -} - -DecoderErrorOr Decoder::predict_intra(u8 plane, BlockContext const& block_context, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TransformSize tx_size, u32 block_index) -{ - auto& frame_buffer = get_output_buffer(plane); - - // 8.5.1 Intra prediction process - - // The intra prediction process is invoked for intra coded blocks to predict a part of the block corresponding to a - // transform block. When the transform size is smaller than the block size, this process can be invoked multiple - // times within a single block for the same plane, and the invocations are in raster order within the block. - - // The variable mode is specified by: - // 1. If plane is greater than 0, mode is set equal to uv_mode. - // 2. Otherwise, if MiSize is greater than or equal to BLOCK_8X8, mode is set equal to y_mode. - // 3. Otherwise, mode is set equal to sub_modes[ blockIdx ]. - PredictionMode mode; - if (plane > 0) - mode = block_context.uv_prediction_mode; - else if (block_context.size >= Block_8x8) - mode = block_context.y_prediction_mode(); - else - mode = block_context.sub_block_prediction_modes[block_index]; - - // The variable log2Size specifying the base 2 logarithm of the width of the transform block is set equal to txSz + 2. - u8 log2_of_block_size = tx_size + 2; - // The variable size is set equal to 1 << log2Size. - u8 block_size = 1 << log2_of_block_size; - - // The variable maxX is set equal to (MiCols * 8) - 1. - // The variable maxY is set equal to (MiRows * 8) - 1. - // If plane is greater than 0, then: - // − maxX is set equal to ((MiCols * 8) >> subsampling_x) - 1. - // − maxY is set equal to ((MiRows * 8) >> subsampling_y) - 1. - auto output_size = block_context.frame_context.decoded_size(plane > 0); - auto max_x = output_size.width() - 1; - auto max_y = output_size.height() - 1; - - auto const frame_buffer_at = [&](u32 row, u32 column) -> u16& { - return frame_buffer[row * output_size.width() + column]; - }; - - // The array aboveRow[ i ] for i = 0..size-1 is specified by: - // .. - // The array aboveRow[ i ] for i = size..2*size-1 is specified by: - // .. - // The array aboveRow[ i ] for i = -1 is specified by: - // .. - - // NOTE: above_row is an array ranging from 0 to (2*block_size). - // There are three sections to the array: - // - [0] - // - [1 .. block_size] - // - [block_size + 1 .. block_size * 2] - // The array indices must be offset by 1 to accommodate index -1. - Array above_row; - auto above_row_at = [&](i32 index) -> Intermediate& { - return above_row[index + 1]; - }; - - // NOTE: This value is pre-calculated since it is reused in spec below. - // Use this to replace spec text "(1<<(BitDepth-1))". - Intermediate half_sample_value = (1 << (block_context.frame_context.color_config.bit_depth - 1)); - - // The array aboveRow[ i ] for i = 0..size-1 is specified by: - if (!have_above) { - // 1. If haveAbove is equal to 0, aboveRow[ i ] is set equal to (1<<(BitDepth-1)) - 1. - // FIXME: Use memset? - for (auto i = 0u; i < block_size; i++) - above_row_at(i) = half_sample_value - 1; - } else { - // 2. Otherwise, aboveRow[ i ] is set equal to CurrFrame[ plane ][ y-1 ][ Min(maxX, x+i) ]. - for (auto i = 0u; i < block_size; i++) - above_row_at(i) = frame_buffer_at(y - 1, min(max_x, x + i)); - } - - // The array aboveRow[ i ] for i = size..2*size-1 is specified by: - if (have_above && not_on_right && tx_size == Transform_4x4) { - // 1. If haveAbove is equal to 1 and notOnRight is equal to 1 and txSz is equal to 0, - // aboveRow[ i ] is set equal to CurrFrame[ plane ][ y-1 ][ Min(maxX, x+i) ]. - for (auto i = block_size; i < block_size * 2; i++) - above_row_at(i) = frame_buffer_at(y - 1, min(max_x, x + i)); - } else { - // 2. Otherwise, aboveRow[ i ] is set equal to aboveRow[ size-1 ]. - for (auto i = block_size; i < block_size * 2; i++) - above_row_at(i) = above_row_at(block_size - 1); - } - - // The array aboveRow[ i ] for i = -1 is specified by: - if (have_above && have_left) { - // 1. If haveAbove is equal to 1 and haveLeft is equal to 1, aboveRow[ -1 ] is set equal to - // CurrFrame[ plane ][ y-1 ][ Min(maxX, x-1) ]. - above_row_at(-1) = frame_buffer_at(y - 1, min(max_x, x - 1)); - } else if (have_above) { - // 2. Otherwise if haveAbove is equal to 1, aboveRow[ -1] is set equal to (1<<(BitDepth-1)) + 1. - above_row_at(-1) = half_sample_value + 1; - } else { - // 3. Otherwise, aboveRow[ -1 ] is set equal to (1<<(BitDepth-1)) - 1 - above_row_at(-1) = half_sample_value - 1; - } - - // The array leftCol[ i ] for i = 0..size-1 is specified by: - Array left_column; - if (have_left) { - // − If haveLeft is equal to 1, leftCol[ i ] is set equal to CurrFrame[ plane ][ Min(maxY, y+i) ][ x-1 ]. - for (auto i = 0u; i < block_size; i++) - left_column[i] = frame_buffer_at(min(max_y, y + i), x - 1); - } else { - // − Otherwise, leftCol[ i ] is set equal to (1<<(BitDepth-1)) + 1. - for (auto i = 0u; i < block_size; i++) - left_column[i] = half_sample_value + 1; - } - - // A 2D array named pred containing the intra predicted samples is constructed as follows: - Array predicted_samples; - auto const predicted_sample_at = [&](u32 row, u32 column) -> Intermediate& { - return predicted_samples[row * block_size + column]; - }; - - // FIXME: One of the two below should be a simple memcpy of 1D arrays. - switch (mode) { - case PredictionMode::VPred: - // − If mode is equal to V_PRED, pred[ i ][ j ] is set equal to aboveRow[ j ] with j = 0..size-1 and i = 0..size-1 - // (each row of the block is filled with a copy of aboveRow). - for (auto j = 0u; j < block_size; j++) { - for (auto i = 0u; i < block_size; i++) - predicted_sample_at(i, j) = above_row_at(j); - } - break; - case PredictionMode::HPred: - // − Otherwise if mode is equal to H_PRED, pred[ i ][ j ] is set equal to leftCol[ i ] with j = 0..size-1 and i = - // 0..size-1 (each column of the block is filled with a copy of leftCol). - for (auto j = 0u; j < block_size; j++) { - for (auto i = 0u; i < block_size; i++) - predicted_sample_at(i, j) = left_column[i]; - } - break; - case PredictionMode::D207Pred: - // − Otherwise if mode is equal to D207_PRED, the following applies: - // 1. pred[ size - 1 ][ j ] = leftCol[ size - 1] for j = 0..size-1 - for (auto j = 0u; j < block_size; j++) - predicted_sample_at(block_size - 1, j) = left_column[block_size - 1]; - // 2. pred[ i ][ 0 ] = Round2( leftCol[ i ] + leftCol[ i + 1 ], 1 ) for i = 0..size-2 - for (auto i = 0u; i < block_size - 1u; i++) - predicted_sample_at(i, 0) = rounded_right_shift(left_column[i] + left_column[i + 1], 1); - // 3. pred[ i ][ 1 ] = Round2( leftCol[ i ] + 2 * leftCol[ i + 1 ] + leftCol[ i + 2 ], 2 ) for i = 0..size-3 - for (auto i = 0u; i < block_size - 2u; i++) - predicted_sample_at(i, 1) = rounded_right_shift(left_column[i] + (2 * left_column[i + 1]) + left_column[i + 2], 2); - // 4. pred[ size - 2 ][ 1 ] = Round2( leftCol[ size - 2 ] + 3 * leftCol[ size - 1 ], 2 ) - predicted_sample_at(block_size - 2, 1) = rounded_right_shift(left_column[block_size - 2] + (3 * left_column[block_size - 1]), 2); - // 5. pred[ i ][ j ] = pred[ i + 1 ][ j - 2 ] for i = (size-2)..0, for j = 2..size-1 - // NOTE – In the last step i iterates in reverse order. - for (auto i = block_size - 2u;;) { - for (auto j = 2u; j < block_size; j++) - predicted_sample_at(i, j) = predicted_sample_at(i + 1, j - 2); - if (i == 0) - break; - i--; - } - break; - case PredictionMode::D45Pred: - // Otherwise if mode is equal to D45_PRED, - // for i = 0..size-1, for j = 0..size-1. - for (auto i = 0u; i < block_size; i++) { - for (auto j = 0; j < block_size; j++) { - // pred[ i ][ j ] is set equal to (i + j + 2 < size * 2) ? - if (i + j + 2 < block_size * 2) - // Round2( aboveRow[ i + j ] + aboveRow[ i + j + 1 ] * 2 + aboveRow[ i + j + 2 ], 2 ) : - predicted_sample_at(i, j) = rounded_right_shift(above_row_at(i + j) + above_row_at(i + j + 1) * 2 + above_row_at(i + j + 2), 2); - else - // aboveRow[ 2 * size - 1 ] - predicted_sample_at(i, j) = above_row_at(2 * block_size - 1); - } - } - break; - case PredictionMode::D63Pred: - // Otherwise if mode is equal to D63_PRED, - for (auto i = 0u; i < block_size; i++) { - for (auto j = 0u; j < block_size; j++) { - // i/2 + j - auto row_index = (i / 2) + j; - // pred[ i ][ j ] is set equal to (i & 1) ? - if (i & 1) - // Round2( aboveRow[ i/2 + j ] + aboveRow[ i/2 + j + 1 ] * 2 + aboveRow[ i/2 + j + 2 ], 2 ) : - predicted_sample_at(i, j) = rounded_right_shift(above_row_at(row_index) + above_row_at(row_index + 1) * 2 + above_row_at(row_index + 2), 2); - else - // Round2( aboveRow[ i/2 + j ] + aboveRow[ i/2 + j + 1 ], 1 ) for i = 0..size-1, for j = 0..size-1. - predicted_sample_at(i, j) = rounded_right_shift(above_row_at(row_index) + above_row_at(row_index + 1), 1); - } - } - break; - case PredictionMode::D117Pred: - // Otherwise if mode is equal to D117_PRED, the following applies: - // 1. pred[ 0 ][ j ] = Round2( aboveRow[ j - 1 ] + aboveRow[ j ], 1 ) for j = 0..size-1 - for (auto j = 0; j < block_size; j++) - predicted_sample_at(0, j) = rounded_right_shift(above_row_at(j - 1) + above_row_at(j), 1); - // 2. pred[ 1 ][ 0 ] = Round2( leftCol[ 0 ] + 2 * aboveRow[ -1 ] + aboveRow[ 0 ], 2 ) - predicted_sample_at(1, 0) = rounded_right_shift(left_column[0] + 2 * above_row_at(-1) + above_row_at(0), 2); - // 3. pred[ 1 ][ j ] = Round2( aboveRow[ j - 2 ] + 2 * aboveRow[ j - 1 ] + aboveRow[ j ], 2 ) for j = 1..size-1 - for (auto j = 1; j < block_size; j++) - predicted_sample_at(1, j) = rounded_right_shift(above_row_at(j - 2) + 2 * above_row_at(j - 1) + above_row_at(j), 2); - // 4. pred[ 2 ][ 0 ] = Round2( aboveRow[ -1 ] + 2 * leftCol[ 0 ] + leftCol[ 1 ], 2 ) - predicted_sample_at(2, 0) = rounded_right_shift(above_row_at(-1) + 2 * left_column[0] + left_column[1], 2); - // 5. pred[ i ][ 0 ] = Round2( leftCol[ i - 3 ] + 2 * leftCol[ i - 2 ] + leftCol[ i - 1 ], 2 ) for i = 3..size-1 - for (auto i = 3u; i < block_size; i++) - predicted_sample_at(i, 0) = rounded_right_shift(left_column[i - 3] + 2 * left_column[i - 2] + left_column[i - 1], 2); - // 6. pred[ i ][ j ] = pred[ i - 2 ][ j - 1 ] for i = 2..size-1, for j = 1..size-1 - for (auto i = 2u; i < block_size; i++) { - for (auto j = 1u; j < block_size; j++) - predicted_sample_at(i, j) = predicted_sample_at(i - 2, j - 1); - } - break; - case PredictionMode::D135Pred: - // Otherwise if mode is equal to D135_PRED, the following applies: - // 1. pred[ 0 ][ 0 ] = Round2( leftCol[ 0 ] + 2 * aboveRow[ -1 ] + aboveRow[ 0 ], 2 ) - predicted_sample_at(0, 0) = rounded_right_shift(left_column[0] + 2 * above_row_at(-1) + above_row_at(0), 2); - // 2. pred[ 0 ][ j ] = Round2( aboveRow[ j - 2 ] + 2 * aboveRow[ j - 1 ] + aboveRow[ j ], 2 ) for j = 1..size-1 - for (auto j = 1; j < block_size; j++) - predicted_sample_at(0, j) = rounded_right_shift(above_row_at(j - 2) + 2 * above_row_at(j - 1) + above_row_at(j), 2); - // 3. pred[ 1 ][ 0 ] = Round2( aboveRow [ -1 ] + 2 * leftCol[ 0 ] + leftCol[ 1 ], 2 ) for i = 1..size-1 - predicted_sample_at(1, 0) = rounded_right_shift(above_row_at(-1) + 2 * left_column[0] + left_column[1], 2); - // 4. pred[ i ][ 0 ] = Round2( leftCol[ i - 2 ] + 2 * leftCol[ i - 1 ] + leftCol[ i ], 2 ) for i = 2..size-1 - for (auto i = 2u; i < block_size; i++) - predicted_sample_at(i, 0) = rounded_right_shift(left_column[i - 2] + 2 * left_column[i - 1] + left_column[i], 2); - // 5. pred[ i ][ j ] = pred[ i - 1 ][ j - 1 ] for i = 1..size-1, for j = 1..size-1 - for (auto i = 1u; i < block_size; i++) { - for (auto j = 1; j < block_size; j++) - predicted_sample_at(i, j) = predicted_sample_at(i - 1, j - 1); - } - break; - case PredictionMode::D153Pred: - // Otherwise if mode is equal to D153_PRED, the following applies: - // 1. pred[ 0 ][ 0 ] = Round2( leftCol[ 0 ] + aboveRow[ -1 ], 1 ) - predicted_sample_at(0, 0) = rounded_right_shift(left_column[0] + above_row_at(-1), 1); - // 2. pred[ i ][ 0 ] = Round2( leftCol[ i - 1] + leftCol[ i ], 1 ) for i = 1..size-1 - for (auto i = 1u; i < block_size; i++) - predicted_sample_at(i, 0) = rounded_right_shift(left_column[i - 1] + left_column[i], 1); - // 3. pred[ 0 ][ 1 ] = Round2( leftCol[ 0 ] + 2 * aboveRow[ -1 ] + aboveRow[ 0 ], 2 ) - predicted_sample_at(0, 1) = rounded_right_shift(left_column[0] + 2 * above_row_at(-1) + above_row_at(0), 2); - // 4. pred[ 1 ][ 1 ] = Round2( aboveRow[ -1 ] + 2 * leftCol [ 0 ] + leftCol [ 1 ], 2 ) - predicted_sample_at(1, 1) = rounded_right_shift(above_row_at(-1) + 2 * left_column[0] + left_column[1], 2); - // 5. pred[ i ][ 1 ] = Round2( leftCol[ i - 2 ] + 2 * leftCol[ i - 1 ] + leftCol[ i ], 2 ) for i = 2..size-1 - for (auto i = 2u; i < block_size; i++) - predicted_sample_at(i, 1) = rounded_right_shift(left_column[i - 2] + 2 * left_column[i - 1] + left_column[i], 2); - // 6. pred[ 0 ][ j ] = Round2( aboveRow[ j - 3 ] + 2 * aboveRow[ j - 2 ] + aboveRow[ j - 1 ], 2 ) for j = 2..size-1 - for (auto j = 2; j < block_size; j++) - predicted_sample_at(0, j) = rounded_right_shift(above_row_at(j - 3) + 2 * above_row_at(j - 2) + above_row_at(j - 1), 2); - // 7. pred[ i ][ j ] = pred[ i - 1 ][ j - 2 ] for i = 1..size-1, for j = 2..size-1 - for (auto i = 1u; i < block_size; i++) { - for (auto j = 2u; j < block_size; j++) - predicted_sample_at(i, j) = predicted_sample_at(i - 1, j - 2); - } - break; - case PredictionMode::TmPred: - // Otherwise if mode is equal to TM_PRED, - // pred[ i ][ j ] is set equal to Clip1( aboveRow[ j ] + leftCol[ i ] - aboveRow[ -1 ] ) - // for i = 0..size-1, for j = 0..size-1. - for (auto i = 0u; i < block_size; i++) { - for (auto j = 0u; j < block_size; j++) - predicted_sample_at(i, j) = clip_1(block_context.frame_context.color_config.bit_depth, above_row_at(j) + left_column[i] - above_row_at(-1)); - } - break; - case PredictionMode::DcPred: { - Intermediate average = 0; - - if (have_left && have_above) { - // Otherwise if mode is equal to DC_PRED and haveLeft is equal to 1 and haveAbove is equal to 1, - // The variable avg (the average of the samples in union of aboveRow and leftCol) - // is specified as follows: - // sum = 0 - // for ( k = 0; k < size; k++ ) { - // sum += leftCol[ k ] - // sum += aboveRow[ k ] - // } - // avg = (sum + size) >> (log2Size + 1) - Intermediate sum = 0; - for (auto k = 0u; k < block_size; k++) { - sum += left_column[k]; - sum += above_row_at(k); - } - average = (sum + block_size) >> (log2_of_block_size + 1); - } else if (have_left && !have_above) { - // Otherwise if mode is equal to DC_PRED and haveLeft is equal to 1 and haveAbove is equal to 0, - // The variable leftAvg is specified as follows: - // sum = 0 - // for ( k = 0; k < size; k++ ) { - // sum += leftCol[ k ] - // } - // leftAvg = (sum + (1 << (log2Size - 1) ) ) >> log2Size - Intermediate sum = 0; - for (auto k = 0u; k < block_size; k++) - sum += left_column[k]; - average = (sum + (1 << (log2_of_block_size - 1))) >> log2_of_block_size; - } else if (!have_left && have_above) { - // Otherwise if mode is equal to DC_PRED and haveLeft is equal to 0 and haveAbove is equal to 1, - // The variable aboveAvg is specified as follows: - // sum = 0 - // for ( k = 0; k < size; k++ ) { - // sum += aboveRow[ k ] - // } - // aboveAvg = (sum + (1 << (log2Size - 1) ) ) >> log2Size - Intermediate sum = 0; - for (auto k = 0u; k < block_size; k++) - sum += above_row_at(k); - average = (sum + (1 << (log2_of_block_size - 1))) >> log2_of_block_size; - } else { - // Otherwise (mode is DC_PRED), - // pred[ i ][ j ] is set equal to 1<<(BitDepth - 1) with i = 0..size-1 and j = 0..size-1. - average = 1 << (block_context.frame_context.color_config.bit_depth - 1); - } - - // pred[ i ][ j ] is set equal to avg with i = 0..size-1 and j = 0..size-1. - for (auto i = 0u; i < block_size; i++) { - for (auto j = 0u; j < block_size; j++) - predicted_sample_at(i, j) = average; - } - break; - } - default: - dbgln("Unknown prediction mode {}", static_cast(mode)); - VERIFY_NOT_REACHED(); - } - - // The current frame is updated as follows: - // − CurrFrame[ plane ][ y + i ][ x + j ] is set equal to pred[ i ][ j ] for i = 0..size-1 and j = 0..size-1. - auto width_in_frame_buffer = min(static_cast(block_size), max_x - x + 1); - auto height_in_frame_buffer = min(static_cast(block_size), max_y - y + 1); - - for (auto i = 0u; i < height_in_frame_buffer; i++) { - for (auto j = 0u; j < width_in_frame_buffer; j++) - frame_buffer_at(y + i, x + j) = predicted_sample_at(i, j); - } - - return {}; -} - -MotionVector Decoder::select_motion_vector(u8 plane, BlockContext const& block_context, ReferenceIndex reference_index, u32 block_index) -{ - // The inputs to this process are: - // − a variable plane specifying which plane is being predicted, - // − a variable refList specifying that we should select the motion vector from BlockMvs[ refList ], - // − a variable blockIdx, specifying how much of the block has already been predicted in units of 4x4 samples. - // The output of this process is a 2 element array called mv containing the motion vector for this block. - - // The purpose of this process is to find the motion vector for this block. Motion vectors are specified for each - // luma block, but a chroma block may cover more than one luma block due to subsampling. In this case, an - // average motion vector is constructed for the chroma block. - - // The functions round_mv_comp_q2 and round_mv_comp_q4 perform division with rounding to the nearest - // integer and are specified as: - auto round_mv_comp_q2 = [&](MotionVector in) { - // return (value < 0 ? value - 1 : value + 1) / 2 - return MotionVector { - (in.row() < 0 ? in.row() - 1 : in.row() + 1) / 2, - (in.column() < 0 ? in.column() - 1 : in.column() + 1) / 2 - }; - }; - auto round_mv_comp_q4 = [&](MotionVector in) { - // return (value < 0 ? value - 2 : value + 2) / 4 - return MotionVector { - (in.row() < 0 ? in.row() - 2 : in.row() + 2) / 4, - (in.column() < 0 ? in.column() - 2 : in.column() + 2) / 4 - }; - }; - - auto vectors = block_context.sub_block_motion_vectors; - - // The motion vector array mv is derived as follows: - // − If plane is equal to 0, or MiSize is greater than or equal to BLOCK_8X8, mv is set equal to - // BlockMvs[ refList ][ blockIdx ]. - if (plane == 0 || block_context.size >= Block_8x8) - return vectors[block_index][reference_index]; - // − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 0, mv is set equal to - // BlockMvs[ refList ][ blockIdx ]. - if (!block_context.frame_context.color_config.subsampling_x && !block_context.frame_context.color_config.subsampling_y) - return vectors[block_index][reference_index]; - // − Otherwise, if subsampling_x is equal to 0 and subsampling_y is equal to 1, mv[ comp ] is set equal to - // round_mv_comp_q2( BlockMvs[ refList ][ blockIdx ][ comp ] + BlockMvs[ refList ][ blockIdx + 2 ][ comp ] ) - // for comp = 0..1. - if (!block_context.frame_context.color_config.subsampling_x && block_context.frame_context.color_config.subsampling_y) - return round_mv_comp_q2(vectors[block_index][reference_index] + vectors[block_index + 2][reference_index]); - // − Otherwise, if subsampling_x is equal to 1 and subsampling_y is equal to 0, mv[ comp ] is set equal to - // round_mv_comp_q2( BlockMvs[ refList ][ blockIdx ][ comp ] + BlockMvs[ refList ][ blockIdx + 1 ][ comp ] ) - // for comp = 0..1. - if (block_context.frame_context.color_config.subsampling_x && !block_context.frame_context.color_config.subsampling_y) - return round_mv_comp_q2(vectors[block_index][reference_index] + vectors[block_index + 1][reference_index]); - // − Otherwise, (subsampling_x is equal to 1 and subsampling_y is equal to 1), mv[ comp ] is set equal to - // round_mv_comp_q4( BlockMvs[ refList ][ 0 ][ comp ] + BlockMvs[ refList ][ 1 ][ comp ] + - // BlockMvs[ refList ][ 2 ][ comp ] + BlockMvs[ refList ][ 3 ][ comp ] ) for comp = 0..1. - VERIFY(block_context.frame_context.color_config.subsampling_x && block_context.frame_context.color_config.subsampling_y); - return round_mv_comp_q4(vectors[0][reference_index] + vectors[1][reference_index] - + vectors[2][reference_index] + vectors[3][reference_index]); -} - -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? - - // The purpose of this process is to change the motion vector into the appropriate precision for the current plane - // and to clamp motion vectors that go too far off the edge of the frame. - // The variables sx and sy are set equal to the subsampling for the current plane as follows: - // − If plane is equal to 0, sx is set equal to 0 and sy is set equal to 0. - // − Otherwise, sx is set equal to subsampling_x and sy is set equal to subsampling_y. - bool subsampling_x = plane > 0 ? block_context.frame_context.color_config.subsampling_x : false; - bool subsampling_y = plane > 0 ? block_context.frame_context.color_config.subsampling_y : false; - - // The output array clampedMv is specified by the following steps: - 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(block_row * MI_SIZE) * 16) >> subsampling_y; - i32 mb_to_bottom_edge = (((static_cast(block_context.frame_context.rows()) - blocks_high - static_cast(block_row)) * MI_SIZE) * 16) >> subsampling_y; - - i32 blocks_wide = num_8x8_blocks_wide_lookup[block_context.size]; - i32 mb_to_left_edge = -(static_cast(block_column * MI_SIZE) * 16) >> subsampling_x; - i32 mb_to_right_edge = (((static_cast(block_context.frame_context.columns()) - blocks_wide - static_cast(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; - i32 subpel_top = (INTERP_EXTEND + ((blocks_high * MI_SIZE) >> subsampling_y)) << SUBPEL_BITS; - i32 subpel_bottom = subpel_top - SUBPEL_SHIFTS; - return { - clip_3(mb_to_top_edge - subpel_top, mb_to_bottom_edge + subpel_bottom, (2 * vector.row()) >> subsampling_y), - clip_3(mb_to_left_edge - subpel_left, mb_to_right_edge + subpel_right, (2 * vector.column()) >> subsampling_x) - }; -} - -static constexpr i32 maximum_scaled_step = 80; - -DecoderErrorOr Decoder::prepare_referenced_frame(Gfx::Size frame_size, u8 reference_frame_index) -{ - ReferenceFrame& reference_frame = m_parser->m_reference_frames[reference_frame_index]; - - // 8.5.2.3 Motion vector scaling process - // The inputs to this process are: - // − a variable plane specifying which plane is being predicted, - // − a variable refList specifying that we should scale to match reference frame ref_frame[ refList ], - // − variables x and y specifying the location of the top left sample in the CurrFrame[ plane ] array of the region - // to be predicted, - // − a variable clampedMv specifying the clamped motion vector. - // The outputs of this process are the variables startX and startY giving the reference block location in units of - // 1/16 th of a sample, and variables xStep and yStep giving the step size in units of 1/16 th of a sample. - // This process is responsible for computing the sampling locations in the reference frame based on the motion - // vector. The sampling locations are also adjusted to compensate for any difference in the size of the reference - // frame compared to the current frame. - - // It is a requirement of bitstream conformance that all the following conditions are satisfied: - // − 2 * FrameWidth >= RefFrameWidth[ refIdx ] - // − 2 * FrameHeight >= RefFrameHeight[ refIdx ] - // − FrameWidth <= 16 * RefFrameWidth[ refIdx ] - // − FrameHeight <= 16 * RefFrameHeight[ refIdx ] - if (!reference_frame.is_valid()) - return DecoderError::format(DecoderErrorCategory::Corrupted, "Attempted to use reference frame {} that has not been saved", reference_frame_index); - auto double_frame_size = frame_size.scaled(2); - if (double_frame_size.width() < reference_frame.size.width() || double_frame_size.height() < reference_frame.size.height()) - return DecoderError::format(DecoderErrorCategory::Corrupted, "Inter frame size is too small relative to reference frame {}", reference_frame_index); - if (!reference_frame.size.scaled(16).contains(frame_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 - // MotionVector. - - // A variable xScale is set equal to (RefFrameWidth[ refIdx ] << REF_SCALE_SHIFT) / FrameWidth. - // 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.) - // NOTE: This spec note above seems to be incorrect. The 1:1 scale value would be 16,384. - i32 x_scale = (reference_frame.size.width() << REF_SCALE_SHIFT) / frame_size.width(); - i32 y_scale = (reference_frame.size.height() << REF_SCALE_SHIFT) / frame_size.height(); - - // The output variable stepX is set equal to (16 * xScale) >> REF_SCALE_SHIFT. - // The output variable stepY is set equal to (16 * yScale) >> REF_SCALE_SHIFT. - i32 scaled_step_x = (16 * x_scale) >> REF_SCALE_SHIFT; - i32 scaled_step_y = (16 * y_scale) >> REF_SCALE_SHIFT; - - // 5. The block inter prediction process in section 8.5.2.4 is invoked with plane, refList, startX, startY, stepX, - // stepY, w, h as inputs and the output is assigned to the 2D array preds[ refList ]. - - // 8.5.2.4 Block inter prediction process - // The inputs to this process are: - // − a variable plane, - // − a variable refList specifying that we should predict from ref_frame[ refList ], - // − variables x and y giving the block location in units of 1/16 th of a sample, - // − variables xStep and yStep giving the step size in units of 1/16 th of a sample. (These will be at most equal - // to 80 due to the restrictions on scaling between reference frames.) - VERIFY(scaled_step_x <= maximum_scaled_step && scaled_step_y <= maximum_scaled_step); - // − variables w and h giving the width and height of the block in units of samples - // The output from this process is the 2D array named pred containing inter predicted samples. - - reference_frame.x_scale = x_scale; - reference_frame.y_scale = x_scale; - reference_frame.scaled_step_x = scaled_step_x; - reference_frame.scaled_step_y = scaled_step_y; - - return {}; -} - -DecoderErrorOr Decoder::predict_inter_block(u8 plane, BlockContext const& block_context, ReferenceIndex reference_index, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span 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, block_context, reference_index, 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_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. - - // 8.5.2.3 Motion vector scaling process - // The inputs to this process are: - // − a variable plane specifying which plane is being predicted, - // − a variable refList specifying that we should scale to match reference frame ref_frame[ refList ], - // − variables x and y specifying the location of the top left sample in the CurrFrame[ plane ] array of the region - // to be predicted, - // − a variable clampedMv specifying the clamped motion vector. - // The outputs of this process are the variables startX and startY giving the reference block location in units of - // 1/16 th of a sample, and variables xStep and yStep giving the step size in units of 1/16 th of a sample. - // This process is responsible for computing the sampling locations in the reference frame based on the motion - // vector. The sampling locations are also adjusted to compensate for any difference in the size of the reference - // frame compared to the current frame. - - // NOTE: Some of this is done in advance by Decoder::prepare_referenced_frame(). - - // A variable refIdx specifying which reference frame is being used is set equal to - // ref_frame_idx[ ref_frame[ refList ] - LAST_FRAME ]. - auto reference_frame_index = block_context.frame_context.reference_frame_indices[block_context.reference_frame_types[reference_index] - ReferenceFrameType::LastFrame]; - auto const& reference_frame = m_parser->m_reference_frames[reference_frame_index]; - - // Scale values range from 8192 to 262144. - // 16384 = 1:1, higher values indicate the reference frame is larger than the current frame. - auto x_scale = reference_frame.x_scale; - auto y_scale = reference_frame.y_scale; - - // The amount of subpixels between each sample of this block. Non-16 values will cause the output to be scaled. - auto scaled_step_x = reference_frame.scaled_step_x; - auto scaled_step_y = reference_frame.scaled_step_y; - - // The variable baseX is set equal to (x * xScale) >> REF_SCALE_SHIFT. - // The variable baseY is set equal to (y * yScale) >> REF_SCALE_SHIFT. - // (baseX and baseY specify the location of the block in the reference frame if a zero motion vector is used). - i32 base_x = (x * x_scale) >> REF_SCALE_SHIFT; - i32 base_y = (y * y_scale) >> REF_SCALE_SHIFT; - - // The variable lumaX is set equal to (plane > 0) ? x << subsampling_x : x. - // The variable lumaY is set equal to (plane > 0) ? y << subsampling_y : y. - // (lumaX and lumaY specify the location of the block to be predicted in the current frame in units of luma - // samples.) - bool subsampling_x = plane > 0 ? block_context.frame_context.color_config.subsampling_x : false; - bool subsampling_y = plane > 0 ? block_context.frame_context.color_config.subsampling_y : false; - i32 luma_x = x << subsampling_x; - i32 luma_y = y << subsampling_y; - - // The variable fracX is set equal to ( (16 * lumaX * xScale) >> REF_SCALE_SHIFT) & SUBPEL_MASK. - // The variable fracY is set equal to ( (16 * lumaY * yScale) >> REF_SCALE_SHIFT) & SUBPEL_MASK. - i32 frac_x = ((16 * luma_x * x_scale) >> REF_SCALE_SHIFT) & SUBPEL_MASK; - i32 frac_y = ((16 * luma_y * y_scale) >> REF_SCALE_SHIFT) & SUBPEL_MASK; - - // The variable dX is set equal to ( (clampedMv[ 1 ] * xScale) >> REF_SCALE_SHIFT) + fracX. - // The variable dY is set equal to ( (clampedMv[ 0 ] * yScale) >> REF_SCALE_SHIFT) + fracY. - // (dX and dY specify a scaled motion vector.) - i32 scaled_vector_x = ((clamped_vector.column() * x_scale) >> REF_SCALE_SHIFT) + frac_x; - i32 scaled_vector_y = ((clamped_vector.row() * y_scale) >> REF_SCALE_SHIFT) + frac_y; - - // The output variable startX is set equal to (baseX << SUBPEL_BITS) + dX. - // The output variable startY is set equal to (baseY << SUBPEL_BITS) + dY. - i32 offset_scaled_block_x = (base_x << SUBPEL_BITS) + scaled_vector_x; - i32 offset_scaled_block_y = (base_y << SUBPEL_BITS) + scaled_vector_y; - - // A variable ref specifying the reference frame contents is set equal to FrameStore[ refIdx ]. - auto& reference_frame_buffer = reference_frame.frame_planes[plane]; - auto reference_frame_width = Subsampling::subsampled_size(subsampling_x, reference_frame.size.width()) + MV_BORDER * 2; - - // The variable lastX is set equal to ( (RefFrameWidth[ refIdx ] + subX) >> subX) - 1. - // The variable lastY is set equal to ( (RefFrameHeight[ refIdx ] + subY) >> subY) - 1. - // (lastX and lastY specify the coordinates of the bottom right sample of the reference plane.) - // Ad-hoc: These variables are not needed, since the reference frame is expanded to contain the samples that - // may be referenced by motion vectors on the edge of the frame. - - // The sub-sample interpolation is effected via two one-dimensional convolutions. First a horizontal filter is used - // to build up a temporary array, and then this array is vertically filtered to obtain the final prediction. The - // fractional parts of the motion vectors determine the filtering process. If the fractional part is zero, then the - // filtering is equivalent to a straight sample copy. - // The filtering is applied as follows: - - constexpr auto sample_offset = 3; - - auto subpixel_row_from_reference_row = [offset_scaled_block_y](u32 row) { - return (offset_scaled_block_y >> SUBPEL_BITS) + static_cast(row); - }; - auto reference_index_for_row = [reference_frame_width](i32 row) { - return static_cast(MV_BORDER + row) * reference_frame_width; - }; - - // The variable intermediateHeight specifying the height required for the intermediate array is set equal to (((h - - // 1) * yStep + 15) >> 4) + 8. - static constexpr auto maximum_intermediate_height = (((maximum_block_dimensions - 1) * maximum_scaled_step + 15) >> 4) + 8; - auto const intermediate_height = (((height - 1) * scaled_step_y + 15) >> 4) + 8; - VERIFY(intermediate_height <= maximum_intermediate_height); - // Check our reference frame bounds before starting the loop. - auto const last_possible_reference_index = reference_index_for_row(subpixel_row_from_reference_row(intermediate_height - sample_offset)); - VERIFY(reference_frame_buffer.size() >= last_possible_reference_index); - - VERIFY(block_buffer.size() >= static_cast(width) * height); - - auto const reference_block_x = MV_BORDER + (offset_scaled_block_x >> SUBPEL_BITS); - auto const reference_block_y = MV_BORDER + (offset_scaled_block_y >> SUBPEL_BITS); - auto const reference_subpixel_x = offset_scaled_block_x & SUBPEL_MASK; - auto const reference_subpixel_y = offset_scaled_block_y & SUBPEL_MASK; - - // OPTIMIZATION: If the fractional part of a component of the motion vector is 0, we want to do a fast path - // skipping one or both of the convolutions. - bool const copy_x = reference_subpixel_x == 0; - bool const copy_y = reference_subpixel_y == 0; - bool const unscaled_x = scaled_step_x == 16; - bool const unscaled_y = scaled_step_y == 16; - - // The array intermediate is specified as follows: - // Note: Height is specified by `intermediate_height`, width is specified by `width` - Array intermediate_buffer; - auto const bit_depth = block_context.frame_context.color_config.bit_depth; - auto const* reference_start = reference_frame_buffer.data() + reference_block_y * reference_frame_width + reference_block_x; - - // FIXME: We are using 16-bit products to vectorize the filter loops, but when filtering in a high bit-depth video, they will truncate. - // Instead of hardcoding them, we should have the bit depth as a template parameter, and the accumulators can select a size based - // on whether the bit depth > 8. - // Note that we only get a benefit from this on the default CPU target. If we enable AVX2 here, we may want to specialize the - // function for the CPU target and remove the cast to i16 so that it doesn't have to truncate on AVX2, where it can do the full - // unrolled 32-bit product loops in one vector. - - if (unscaled_x && unscaled_y && bit_depth == 8) { - if (copy_x && copy_y) { - // We can memcpy here to avoid doing any real work. - auto const* reference_scan_line = &reference_frame_buffer[reference_block_y * reference_frame_width + reference_block_x]; - auto* destination_scan_line = block_buffer.data(); - - for (auto row = 0u; row < height; row++) { - memcpy(destination_scan_line, reference_scan_line, width * sizeof(*destination_scan_line)); - reference_scan_line += reference_frame_width; - destination_scan_line += width; - } - - return {}; - } - - auto horizontal_convolution_unscaled = [](auto bit_depth, auto* destination, auto width, auto height, auto const* source, auto source_stride, auto filter, auto subpixel_x) { - source -= sample_offset; - auto const source_end_skip = source_stride - width; - - for (auto row = 0u; row < height; row++) { - for (auto column = 0u; column < width; column++) { - i32 accumulated_samples = 0; - for (auto t = 0; t < 8; t++) { - auto sample = source[t]; - accumulated_samples += static_cast(subpel_filters[filter][subpixel_x][t] * sample); - } - - *destination = clip_1(bit_depth, rounded_right_shift(accumulated_samples, 7)); - source++; - destination++; - } - source += source_end_skip; - } - }; - - if (copy_y) { - horizontal_convolution_unscaled(bit_depth, block_buffer.data(), width, height, reference_start, reference_frame_width, block_context.interpolation_filter, reference_subpixel_x); - return {}; - } - - auto vertical_convolution_unscaled = [](auto bit_depth, auto* destination, auto width, auto height, auto const* source, auto source_stride, auto filter, auto subpixel_y) { - auto const source_end_skip = source_stride - width; - - for (auto row = 0u; row < height; row++) { - for (auto column = 0u; column < width; column++) { - auto const* scan_column = source; - i32 accumulated_samples = 0; - for (auto t = 0; t < 8; t++) { - auto sample = *scan_column; - accumulated_samples += static_cast(subpel_filters[filter][subpixel_y][t] * sample); - scan_column += source_stride; - } - *destination = clip_1(bit_depth, rounded_right_shift(accumulated_samples, 7)); - source++; - destination++; - } - source += source_end_skip; - } - }; - - if (copy_x) { - vertical_convolution_unscaled(bit_depth, block_buffer.data(), width, height, reference_start - (sample_offset * reference_frame_width), reference_frame_width, block_context.interpolation_filter, reference_subpixel_y); - return {}; - } - - horizontal_convolution_unscaled(bit_depth, intermediate_buffer.data(), width, intermediate_height, reference_start - (sample_offset * reference_frame_width), reference_frame_width, block_context.interpolation_filter, reference_subpixel_x); - vertical_convolution_unscaled(bit_depth, block_buffer.data(), width, height, intermediate_buffer.data(), width, block_context.interpolation_filter, reference_subpixel_y); - return {}; - } - - // NOTE: Accumulators below are 32-bit to allow high bit-depth videos to decode without overflows. - // These should be changed when the accumulators above are. - - auto horizontal_convolution_scaled = [](auto bit_depth, auto* destination, auto width, auto height, auto const* source, auto source_stride, auto filter, auto subpixel_x, auto scale_x) { - source -= sample_offset; - - for (auto row = 0u; row < height; row++) { - auto scan_subpixel = subpixel_x; - for (auto column = 0u; column < width; column++) { - auto const* scan_line = source + (scan_subpixel >> 4); - i32 accumulated_samples = 0; - for (auto t = 0; t < 8; t++) { - auto sample = scan_line[t]; - accumulated_samples += subpel_filters[filter][scan_subpixel & SUBPEL_MASK][t] * sample; - } - - *destination = clip_1(bit_depth, rounded_right_shift(accumulated_samples, 7)); - destination++; - scan_subpixel += scale_x; - } - source += source_stride; - } - }; - - auto vertical_convolution_scaled = [](auto bit_depth, auto* destination, auto width, auto height, auto const* source, auto source_stride, auto filter, auto subpixel_y, auto scale_y) { - for (auto row = 0u; row < height; row++) { - auto const* source_column_base = source + (subpixel_y >> SUBPEL_BITS) * source_stride; - - for (auto column = 0u; column < width; column++) { - auto const* scan_column = source_column_base + column; - i32 accumulated_samples = 0; - for (auto t = 0; t < 8; t++) { - auto sample = *scan_column; - accumulated_samples += subpel_filters[filter][subpixel_y & SUBPEL_MASK][t] * sample; - scan_column += source_stride; - } - - *destination = clip_1(bit_depth, rounded_right_shift(accumulated_samples, 7)); - destination++; - } - subpixel_y += scale_y; - } - }; - - horizontal_convolution_scaled(bit_depth, intermediate_buffer.data(), width, intermediate_height, reference_start - (sample_offset * reference_frame_width), reference_frame_width, block_context.interpolation_filter, offset_scaled_block_x & SUBPEL_MASK, scaled_step_x); - vertical_convolution_scaled(bit_depth, block_buffer.data(), width, height, intermediate_buffer.data(), width, block_context.interpolation_filter, reference_subpixel_y, scaled_step_y); - - return {}; -} - -DecoderErrorOr 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. - // The inputs to this process are: - // − a variable plane specifying which plane is being predicted, - // − variables x and y specifying the location of the top left sample in the CurrFrame[ plane ] array of the region - // to be predicted, - // − variables w and h specifying the width and height of the region to be predicted, - // − a variable blockIdx, specifying how much of the block has already been predicted in units of 4x4 samples. - // The outputs of this process are inter predicted samples in the current frame CurrFrame. - - // The prediction arrays are formed by the following ordered steps: - // 1. The variable refList is set equal to 0. - // 2. through 5. - Array predicted_buffer; - auto predicted_span = predicted_buffer.span().trim(width * height); - TRY(predict_inter_block(plane, block_context, ReferenceIndex::Primary, block_context.row, block_context.column, x, y, width, height, block_index, predicted_span)); - auto predicted_buffer_at = [&](Span buffer, u32 row, u32 column) -> u16& { - return buffer[row * width + column]; - }; - - // 6. If isCompound is equal to 1, then the variable refList is set equal to 1 and steps 2, 3, 4 and 5 are repeated - // to form the prediction for the second reference. - // The inter predicted samples are then derived as follows: - auto& frame_buffer = get_output_buffer(plane); - VERIFY(!frame_buffer.is_empty()); - auto frame_size = block_context.frame_context.decoded_size(plane > 0); - auto frame_buffer_at = [&](u32 row, u32 column) -> u16& { - return frame_buffer[row * frame_size.width() + column]; - }; - - auto width_in_frame_buffer = min(width, frame_size.width() - x); - auto height_in_frame_buffer = min(height, frame_size.height() - y); - - // The variable isCompound is set equal to ref_frame[ 1 ] > NONE. - // − If isCompound is equal to 0, CurrFrame[ plane ][ y + i ][ x + j ] is set equal to preds[ 0 ][ i ][ j ] for i = 0..h-1 - // and j = 0..w-1. - if (!block_context.is_compound()) { - for (auto i = 0u; i < height_in_frame_buffer; i++) { - for (auto j = 0u; j < width_in_frame_buffer; j++) - frame_buffer_at(y + i, x + j) = predicted_buffer_at(predicted_span, i, j); - } - - return {}; - } - - // − Otherwise, CurrFrame[ plane ][ y + i ][ x + j ] is set equal to Round2( preds[ 0 ][ i ][ j ] + preds[ 1 ][ i ][ j ], 1 ) - // for i = 0..h-1 and j = 0..w-1. - Array second_predicted_buffer; - auto second_predicted_span = second_predicted_buffer.span().trim(width * height); - TRY(predict_inter_block(plane, block_context, ReferenceIndex::Secondary, 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++) - frame_buffer_at(y + i, x + j) = rounded_right_shift(predicted_buffer_at(predicted_span, i, j) + predicted_buffer_at(second_predicted_span, i, j), 1); - } - - return {}; -} - -inline u16 dc_q(u8 bit_depth, u8 b) -{ - // The function dc_q( b ) is specified as dc_qlookup[ (BitDepth-8) >> 1 ][ Clip3( 0, 255, b ) ] where dc_lookup is - // defined as follows: - constexpr u16 dc_qlookup[3][256] = { - { 4, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 53, 54, 55, 56, 57, 57, 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 70, 71, 72, 73, 74, 74, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 87, 88, 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 114, 116, 117, 118, 120, 121, 123, 125, 127, 129, 131, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 161, 164, 166, 169, 172, 174, 177, 180, 182, 185, 187, 190, 192, 195, 199, 202, 205, 208, 211, 214, 217, 220, 223, 226, 230, 233, 237, 240, 243, 247, 250, 253, 257, 261, 265, 269, 272, 276, 280, 284, 288, 292, 296, 300, 304, 309, 313, 317, 322, 326, 330, 335, 340, 344, 349, 354, 359, 364, 369, 374, 379, 384, 389, 395, 400, 406, 411, 417, 423, 429, 435, 441, 447, 454, 461, 467, 475, 482, 489, 497, 505, 513, 522, 530, 539, 549, 559, 569, 579, 590, 602, 614, 626, 640, 654, 668, 684, 700, 717, 736, 755, 775, 796, 819, 843, 869, 896, 925, 955, 988, 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336 }, - { 4, 9, 10, 13, 15, 17, 20, 22, 25, 28, 31, 34, 37, 40, 43, 47, 50, 53, 57, 60, 64, 68, 71, 75, 78, 82, 86, 90, 93, 97, 101, 105, 109, 113, 116, 120, 124, 128, 132, 136, 140, 143, 147, 151, 155, 159, 163, 166, 170, 174, 178, 182, 185, 189, 193, 197, 200, 204, 208, 212, 215, 219, 223, 226, 230, 233, 237, 241, 244, 248, 251, 255, 259, 262, 266, 269, 273, 276, 280, 283, 287, 290, 293, 297, 300, 304, 307, 310, 314, 317, 321, 324, 327, 331, 334, 337, 343, 350, 356, 362, 369, 375, 381, 387, 394, 400, 406, 412, 418, 424, 430, 436, 442, 448, 454, 460, 466, 472, 478, 484, 490, 499, 507, 516, 525, 533, 542, 550, 559, 567, 576, 584, 592, 601, 609, 617, 625, 634, 644, 655, 666, 676, 687, 698, 708, 718, 729, 739, 749, 759, 770, 782, 795, 807, 819, 831, 844, 856, 868, 880, 891, 906, 920, 933, 947, 961, 975, 988, 1001, 1015, 1030, 1045, 1061, 1076, 1090, 1105, 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236, 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379, 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537, 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717, 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929, 1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197, 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561, 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102, 3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953, 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347 }, - { 4, 12, 18, 25, 33, 41, 50, 60, 70, 80, 91, 103, 115, 127, 140, 153, 166, 180, 194, 208, 222, 237, 251, 266, 281, 296, 312, 327, 343, 358, 374, 390, 405, 421, 437, 453, 469, 484, 500, 516, 532, 548, 564, 580, 596, 611, 627, 643, 659, 674, 690, 706, 721, 737, 752, 768, 783, 798, 814, 829, 844, 859, 874, 889, 904, 919, 934, 949, 964, 978, 993, 1008, 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122, 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234, 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342, 1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544, 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741, 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933, 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199, 2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467, 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788, 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127, 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517, 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951, 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420, 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942, 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517, 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149, 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867, 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715, 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788, 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245, 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409, 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812, 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387 } - }; - - return dc_qlookup[(bit_depth - 8) >> 1][clip_3(0, 255, b)]; -} - -inline u16 ac_q(u8 bit_depth, u8 b) -{ - // The function ac_q( b ) is specified as ac_qlookup[ (BitDepth-8) >> 1 ][ Clip3( 0, 255, b ) ] where ac_lookup is - // defined as follows: - constexpr u16 ac_qlookup[3][256] = { - { 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 311, 317, 323, 329, 335, 341, 347, 353, 359, 366, 373, 380, 387, 394, 401, 408, 416, 424, 432, 440, 448, 456, 465, 474, 483, 492, 501, 510, 520, 530, 540, 550, 560, 571, 582, 593, 604, 615, 627, 639, 651, 663, 676, 689, 702, 715, 729, 743, 757, 771, 786, 801, 816, 832, 848, 864, 881, 898, 915, 933, 951, 969, 988, 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567, 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828 }, - { 4, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 37, 40, 44, 48, 51, 55, 59, 63, 67, 71, 75, 79, 83, 88, 92, 96, 100, 105, 109, 114, 118, 122, 127, 131, 136, 140, 145, 149, 154, 158, 163, 168, 172, 177, 181, 186, 190, 195, 199, 204, 208, 213, 217, 222, 226, 231, 235, 240, 244, 249, 253, 258, 262, 267, 271, 275, 280, 284, 289, 293, 297, 302, 306, 311, 315, 319, 324, 328, 332, 337, 341, 345, 349, 354, 358, 362, 367, 371, 375, 379, 384, 388, 392, 396, 401, 409, 417, 425, 433, 441, 449, 458, 466, 474, 482, 490, 498, 506, 514, 523, 531, 539, 547, 555, 563, 571, 579, 588, 596, 604, 616, 628, 640, 652, 664, 676, 688, 700, 713, 725, 737, 749, 761, 773, 785, 797, 809, 825, 841, 857, 873, 889, 905, 922, 938, 954, 970, 986, 1002, 1018, 1038, 1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198, 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386, 1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603, 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859, 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159, 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507, 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915, 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391, 3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952, 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604, 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372, 5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268, 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312 }, - { 4, 13, 19, 27, 35, 44, 54, 64, 75, 87, 99, 112, 126, 139, 154, 168, 183, 199, 214, 230, 247, 263, 280, 297, 314, 331, 349, 366, 384, 402, 420, 438, 456, 475, 493, 511, 530, 548, 567, 586, 604, 623, 642, 660, 679, 698, 716, 735, 753, 772, 791, 809, 828, 846, 865, 884, 902, 920, 939, 957, 976, 994, 1012, 1030, 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175, 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317, 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457, 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595, 1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856, 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118, 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378, 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750, 2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137, 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619, 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149, 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791, 4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544, 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410, 6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435, 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635, 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028, 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661, 11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565, 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806, 16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414, 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486, 21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070, 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247 } - }; - - return ac_qlookup[(bit_depth - 8) >> 1][clip_3(0, 255, b)]; -} - -u8 Decoder::get_base_quantizer_index(SegmentFeatureStatus alternative_quantizer_feature, bool should_use_absolute_segment_base_quantizer, u8 base_quantizer_index) -{ - // The function get_qindex( ) returns the quantizer index for the current block and is specified by the following: - // − If seg_feature_active( SEG_LVL_ALT_Q ) is equal to 1 the following ordered steps apply: - if (alternative_quantizer_feature.enabled) { - // 1. Set the variable data equal to FeatureData[ segment_id ][ SEG_LVL_ALT_Q ]. - auto data = alternative_quantizer_feature.value; - - // 2. If segmentation_abs_or_delta_update is equal to 0, set data equal to base_q_idx + data - if (!should_use_absolute_segment_base_quantizer) { - data += base_quantizer_index; - } - - // 3. Return Clip3( 0, 255, data ). - return clip_3(0, 255, data); - } - - // − Otherwise, return base_q_idx. - return base_quantizer_index; -} - -u16 Decoder::get_dc_quantizer(u8 bit_depth, u8 base, i8 delta) -{ - // NOTE: Delta is selected by the caller based on whether it is for the Y or UV planes. - - // The function get_dc_quant( plane ) returns the quantizer value for the dc coefficient for a particular plane and - // is derived as follows: - // − If plane is equal to 0, return dc_q( get_qindex( ) + delta_q_y_dc ). - // − Otherwise, return dc_q( get_qindex( ) + delta_q_uv_dc ). - return dc_q(bit_depth, static_cast(base + delta)); -} - -u16 Decoder::get_ac_quantizer(u8 bit_depth, u8 base, i8 delta) -{ - // NOTE: Delta is selected by the caller based on whether it is for the Y or UV planes. - - // The function get_ac_quant( plane ) returns the quantizer value for the ac coefficient for a particular plane and - // is derived as follows: - // − If plane is equal to 0, return ac_q( get_qindex( ) ). - // − Otherwise, return ac_q( get_qindex( ) + delta_q_uv_ac ). - return ac_q(bit_depth, static_cast(base + delta)); -} - -DecoderErrorOr Decoder::reconstruct(u8 plane, BlockContext const& block_context, u32 transform_block_x, u32 transform_block_y, TransformSize transform_block_size, TransformSet transform_set) -{ - // 8.6.2 Reconstruct process - - // The variable n (specifying the base 2 logarithm of the width of the transform block) is set equal to 2 + txSz. - u8 log2_of_block_size = 2u + transform_block_size; - switch (log2_of_block_size) { - case 2: - return reconstruct_templated<2>(plane, block_context, transform_block_x, transform_block_y, transform_set); - break; - case 3: - return reconstruct_templated<3>(plane, block_context, transform_block_x, transform_block_y, transform_set); - break; - case 4: - return reconstruct_templated<4>(plane, block_context, transform_block_x, transform_block_y, transform_set); - break; - case 5: - return reconstruct_templated<5>(plane, block_context, transform_block_x, transform_block_y, transform_set); - break; - default: - VERIFY_NOT_REACHED(); - } -} - -template -DecoderErrorOr Decoder::reconstruct_templated(u8 plane, BlockContext const& block_context, u32 transform_block_x, u32 transform_block_y, TransformSet transform_set) -{ - // 8.6.2 Reconstruct process, continued: - - // The variable dqDenom is set equal to 2 if txSz is equal to Transform_32X32, otherwise dqDenom is set equal to 1. - constexpr Intermediate dq_denominator = log2_of_block_size == 5 ? 2 : 1; - // The variable n0 (specifying the width of the transform block) is set equal to 1 << n. - constexpr auto block_size = 1u << log2_of_block_size; - - // 1. Dequant[ i ][ j ] is set equal to ( Tokens[ i * n0 + j ] * get_ac_quant( plane ) ) / dqDenom - // for i = 0..(n0-1), for j = 0..(n0-1) - Array dequantized; - auto quantizers = block_context.frame_context.segment_quantizers[block_context.segment_id]; - Intermediate ac_quant = plane == 0 ? quantizers.y_ac_quantizer : quantizers.uv_ac_quantizer; - auto const* tokens_raw = block_context.residual_tokens.data(); - for (u32 i = 0; i < dequantized.size(); i++) { - dequantized[i] = (tokens_raw[i] * ac_quant) / dq_denominator; - } - - // 2. Dequant[ 0 ][ 0 ] is set equal to ( Tokens[ 0 ] * get_dc_quant( plane ) ) / dqDenom - dequantized[0] = (block_context.residual_tokens[0] * (plane == 0 ? quantizers.y_dc_quantizer : quantizers.uv_dc_quantizer)) / dq_denominator; - - // It is a requirement of bitstream conformance that the values written into the Dequant array in steps 1 and 2 - // are representable by a signed integer with 8 + BitDepth bits. - // Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal - // to allow these bounds to be violated. Therefore, we can avoid the performance cost here. - - // 3. Invoke the 2D inverse transform block process defined in section 8.7.2 with the variable n as input. - // The inverse transform outputs are stored back to the Dequant buffer. - TRY(inverse_transform_2d(block_context, dequantized, transform_set)); - - // 4. CurrFrame[ plane ][ y + i ][ x + j ] is set equal to Clip1( CurrFrame[ plane ][ y + i ][ x + j ] + Dequant[ i ][ j ] ) - // for i = 0..(n0-1) and j = 0..(n0-1). - auto& current_buffer = get_output_buffer(plane); - auto frame_size = block_context.frame_context.decoded_size(plane > 0); - auto width_in_frame_buffer = min(block_size, frame_size.width() - transform_block_x); - auto height_in_frame_buffer = min(block_size, frame_size.height() - transform_block_y); - - for (auto i = 0u; i < height_in_frame_buffer; i++) { - for (auto j = 0u; j < width_in_frame_buffer; j++) { - auto index = (transform_block_y + i) * frame_size.width() + transform_block_x + j; - auto dequantized_value = dequantized[i * block_size + j]; - current_buffer[index] = clip_1(block_context.frame_context.color_config.bit_depth, current_buffer[index] + dequantized_value); - } - } - - return {}; -} - -inline DecoderErrorOr Decoder::inverse_walsh_hadamard_transform(Span data, u8 log2_of_block_size, u8 shift) -{ - // The input to this process is a variable shift that specifies the amount of pre-scaling. - // This process does an in-place transform of the array T (of length 4) by the following ordered steps: - if (1 << log2_of_block_size != 4) - return DecoderError::corrupted("Block size was not 4"sv); - - auto a = data[0] >> shift; - auto c = data[1] >> shift; - auto d = data[2] >> shift; - auto b = data[3] >> shift; - a += c; - d -= b; - auto average_of_a_and_d = (a - d) >> 1; - b = average_of_a_and_d - b; - c = average_of_a_and_d - c; - a -= b; - d += c; - data[0] = a; - data[1] = b; - data[2] = c; - data[3] = d; - return {}; -} - -inline i32 Decoder::cos64(u8 angle) -{ - i32 const cos64_lookup[33] = { 16384, 16364, 16305, 16207, 16069, 15893, 15679, 15426, 15137, 14811, 14449, 14053, 13623, 13160, 12665, 12140, 11585, 11003, 10394, 9760, 9102, 8423, 7723, 7005, 6270, 5520, 4756, 3981, 3196, 2404, 1606, 804, 0 }; - - // 1. Set a variable angle2 equal to angle & 127. - angle &= 127; - // 2. If angle2 is greater than or equal to 0 and less than or equal to 32, return cos64_lookup[ angle2 ]. - if (angle <= 32) - return cos64_lookup[angle]; - // 3. If angle2 is greater than 32 and less than or equal to 64, return cos64_lookup[ 64 - angle2 ] * -1. - if (angle <= 64) - return -cos64_lookup[64 - angle]; - // 4. If angle2 is greater than 64 and less than or equal to 96, return cos64_lookup[ angle2 - 64 ] * -1. - if (angle <= 96) - return -cos64_lookup[angle - 64]; - // 5. Otherwise (if angle2 is greater than 96 and less than 128), return cos64_lookup[ 128 - angle2 ]. - return cos64_lookup[128 - angle]; -} - -inline i32 Decoder::sin64(u8 angle) -{ - if (angle < 32) - angle += 128; - return cos64(angle - 32u); -} - -// (8.7.1.1) The function B( a, b, angle, 0 ) performs a butterfly rotation. -inline void Decoder::butterfly_rotation_in_place(Span data, size_t index_a, size_t index_b, u8 angle, bool flip) -{ - auto cos = cos64(angle); - auto sin = sin64(angle); - // 1. The variable x is set equal to T[ a ] * cos64( angle ) - T[ b ] * sin64( angle ). - i64 rotated_a = static_cast(data[index_a]) * cos - static_cast(data[index_b]) * sin; - // 2. The variable y is set equal to T[ a ] * sin64( angle ) + T[ b ] * cos64( angle ). - i64 rotated_b = static_cast(data[index_a]) * sin + static_cast(data[index_b]) * cos; - // 3. T[ a ] is set equal to Round2( x, 14 ). - data[index_a] = rounded_right_shift(rotated_a, 14); - // 4. T[ b ] is set equal to Round2( y, 14 ). - data[index_b] = rounded_right_shift(rotated_b, 14); - - // The function B( a ,b, angle, 1 ) performs a butterfly rotation and flip specified by the following ordered steps: - // 1. The function B( a, b, angle, 0 ) is invoked. - // 2. The contents of T[ a ] and T[ b ] are exchanged. - if (flip) - swap(data[index_a], data[index_b]); - - // It is a requirement of bitstream conformance that the values saved into the array T by this function are - // representable by a signed integer using 8 + BitDepth bits of precision. - // Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal - // to allow these bounds to be violated. Therefore, we can avoid the performance cost here. -} - -// (8.7.1.1) The function H( a, b, 0 ) performs a Hadamard rotation. -inline void Decoder::hadamard_rotation_in_place(Span data, size_t index_a, size_t index_b, bool flip) -{ - // The function H( a, b, 1 ) performs a Hadamard rotation with flipped indices and is specified as follows: - // 1. The function H( b, a, 0 ) is invoked. - if (flip) - swap(index_a, index_b); - - // The function H( a, b, 0 ) performs a Hadamard rotation specified by the following ordered steps: - - // 1. The variable x is set equal to T[ a ]. - auto a_value = data[index_a]; - // 2. The variable y is set equal to T[ b ]. - auto b_value = data[index_b]; - // 3. T[ a ] is set equal to x + y. - data[index_a] = a_value + b_value; - // 4. T[ b ] is set equal to x - y. - data[index_b] = a_value - b_value; - - // It is a requirement of bitstream conformance that the values saved into the array T by this function are - // representable by a signed integer using 8 + BitDepth bits of precision. - // Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal - // to allow these bounds to be violated. Therefore, we can avoid the performance cost here. -} - -template -inline DecoderErrorOr Decoder::inverse_discrete_cosine_transform_array_permutation(Span data) -{ - static_assert(log2_of_block_size >= 2 && log2_of_block_size <= 5, "Block size out of range."); - - constexpr u8 block_size = 1 << log2_of_block_size; - - // This process performs an in-place permutation of the array T of length 2^n for 2 ≤ n ≤ 5 which is required before - // execution of the inverse DCT process. - if (log2_of_block_size < 2 || log2_of_block_size > 5) - return DecoderError::corrupted("Block size was out of range"sv); - - // 1.1. A temporary array named copyT is set equal to T. - Array data_copy; - AK::TypedTransfer::copy(data_copy.data(), data.data(), block_size); - - // 1.2. T[ i ] is set equal to copyT[ brev( n, i ) ] for i = 0..((1<(i)]; - - return {}; -} - -template -ALWAYS_INLINE DecoderErrorOr Decoder::inverse_discrete_cosine_transform(Span data) -{ - static_assert(log2_of_block_size >= 2 && log2_of_block_size <= 5, "Block size out of range."); - - // 2.1. The variable n0 is set equal to 1<> 1; - // 2.3 The variable n2 is set equal to 1<<(n-2). - constexpr u8 quarter_block_size = half_block_size >> 1; - // 2.4 The variable n3 is set equal to 1<<(n-3). - constexpr u8 eighth_block_size = quarter_block_size >> 1; - - // 2.5 If n is equal to 2, invoke B( 0, 1, 16, 1 ), otherwise recursively invoke the inverse DCT defined in this - // section with the variable n set equal to n - 1. - if constexpr (log2_of_block_size == 2) - butterfly_rotation_in_place(data, 0, 1, 16, true); - else - TRY(inverse_discrete_cosine_transform(data)); - - // 2.6 Invoke B( n1+i, n0-1-i, 32-brev( 5, n1+i), 0 ) for i = 0..(n2-1). - for (auto i = 0u; i < quarter_block_size; i++) { - auto index = half_block_size + i; - butterfly_rotation_in_place(data, index, block_size - 1 - i, 32 - brev<5>(index), false); - } - - // 2.7 If n is greater than or equal to 3: - if constexpr (log2_of_block_size >= 3) { - // a. Invoke H( n1+4*i+2*j, n1+1+4*i+2*j, j ) for i = 0..(n3-1), j = 0..1. - for (auto i = 0u; i < eighth_block_size; i++) { - for (auto j = 0u; j < 2; j++) { - auto index = half_block_size + (4 * i) + (2 * j); - hadamard_rotation_in_place(data, index, index + 1, j); - } - } - } - - // 4. If n is equal to 5: - if constexpr (log2_of_block_size == 5) { - // a. Invoke B( n0-n+3-n2*j-4*i, n1+n-4+n2*j+4*i, 28-16*i+56*j, 1 ) for i = 0..1, j = 0..1. - for (auto i = 0u; i < 2; i++) { - for (auto j = 0u; j < 2; j++) { - auto index_a = block_size - log2_of_block_size + 3 - (quarter_block_size * j) - (4 * i); - auto index_b = half_block_size + log2_of_block_size - 4 + (quarter_block_size * j) + (4 * i); - auto angle = 28 - (16 * i) + (56 * j); - butterfly_rotation_in_place(data, index_a, index_b, angle, true); - } - } - - // b. Invoke H( n1+n3*j+i, n1+n2-5+n3*j-i, j&1 ) for i = 0..1, j = 0..3. - for (auto i = 0u; i < 2; i++) { - for (auto j = 0u; j < 4; j++) { - auto index_a = half_block_size + (eighth_block_size * j) + i; - auto index_b = half_block_size + quarter_block_size - 5 + (eighth_block_size * j) - i; - hadamard_rotation_in_place(data, index_a, index_b, (j & 1) != 0); - } - } - } - - // 5. If n is greater than or equal to 4: - if constexpr (log2_of_block_size >= 4) { - // a. Invoke B( n0-n+2-i-n2*j, n1+n-3+i+n2*j, 24+48*j, 1 ) for i = 0..(n==5), j = 0..1. - for (auto i = 0u; i <= (log2_of_block_size == 5); i++) { - for (auto j = 0u; j < 2; j++) { - auto index_a = block_size - log2_of_block_size + 2 - i - (quarter_block_size * j); - auto index_b = half_block_size + log2_of_block_size - 3 + i + (quarter_block_size * j); - butterfly_rotation_in_place(data, index_a, index_b, 24 + (48 * j), true); - } - } - - // b. Invoke H( n1+n2*j+i, n1+n2-1+n2*j-i, j&1 ) for i = 0..(2n-7), j = 0..1. - for (auto i = 0u; i < (2 * log2_of_block_size) - 6u; i++) { - for (auto j = 0u; j < 2; j++) { - auto index_a = half_block_size + (quarter_block_size * j) + i; - auto index_b = half_block_size + quarter_block_size - 1 + (quarter_block_size * j) - i; - hadamard_rotation_in_place(data, index_a, index_b, (j & 1) != 0); - } - } - } - - // 6. If n is greater than or equal to 3: - if constexpr (log2_of_block_size >= 3) { - // a. Invoke B( n0-n3-1-i, n1+n3+i, 16, 1 ) for i = 0..(n3-1). - for (auto i = 0u; i < eighth_block_size; i++) { - auto index_a = block_size - eighth_block_size - 1 - i; - auto index_b = half_block_size + eighth_block_size + i; - butterfly_rotation_in_place(data, index_a, index_b, 16, true); - } - } - - // 7. Invoke H( i, n0-1-i, 0 ) for i = 0..(n1-1). - for (auto i = 0u; i < half_block_size; i++) - hadamard_rotation_in_place(data, i, block_size - 1 - i, false); - - return {}; -} - -template -inline void Decoder::inverse_asymmetric_discrete_sine_transform_input_array_permutation(Span data) -{ - // The variable n0 is set equal to 1< data_copy; - AK::TypedTransfer::copy(data_copy.data(), data.data(), block_size); - - // The values at even locations T[ 2 * i ] are set equal to copyT[ n0 - 1 - 2 * i ] for i = 0..(n1-1). - // The values at odd locations T[ 2 * i + 1 ] are set equal to copyT[ 2 * i ] for i = 0..(n1-1). - for (auto i = 0u; i < block_size; i += 2) { - data[i] = data_copy[block_size - 1 - i]; - data[i + 1] = data_copy[i]; - } -} - -template -inline void Decoder::inverse_asymmetric_discrete_sine_transform_output_array_permutation(Span data) -{ - auto block_size = 1u << log2_of_block_size; - - // A temporary array named copyT is set equal to T. - Array data_copy; - AK::TypedTransfer::copy(data_copy.data(), data.data(), block_size); - - // The permutation depends on n as follows: - if (log2_of_block_size == 4) { - // − If n is equal to 4, - // T[ 8*a + 4*b + 2*c + d ] is set equal to copyT[ 8*(d^c) + 4*(c^b) + 2*(b^a) + a ] for a = 0..1 - // and b = 0..1 and c = 0..1 and d = 0..1. - for (auto a = 0u; a < 2; a++) - for (auto b = 0u; b < 2; b++) - for (auto c = 0u; c < 2; c++) - for (auto d = 0u; d < 2; d++) - data[(8 * a) + (4 * b) + (2 * c) + d] = data_copy[8 * (d ^ c) + 4 * (c ^ b) + 2 * (b ^ a) + a]; - } else { - VERIFY(log2_of_block_size == 3); - // − Otherwise (n is equal to 3), - // T[ 4*a + 2*b + c ] is set equal to copyT[ 4*(c^b) + 2*(b^a) + a ] for a = 0..1 and - // b = 0..1 and c = 0..1. - for (auto a = 0u; a < 2; a++) - for (auto b = 0u; b < 2; b++) - for (auto c = 0u; c < 2; c++) - data[4 * a + 2 * b + c] = data_copy[4 * (c ^ b) + 2 * (b ^ a) + a]; - } -} - -inline void Decoder::inverse_asymmetric_discrete_sine_transform_4(Span data) -{ - VERIFY(data.size() == 4); - i64 const sinpi_1_9 = 5283; - i64 const sinpi_2_9 = 9929; - i64 const sinpi_3_9 = 13377; - i64 const sinpi_4_9 = 15212; - - // Steps are derived from pseudocode in (8.7.1.6): - // s0 = SINPI_1_9 * T[ 0 ] - i64 s0 = sinpi_1_9 * data[0]; - // s1 = SINPI_2_9 * T[ 0 ] - i64 s1 = sinpi_2_9 * data[0]; - // s2 = SINPI_3_9 * T[ 1 ] - i64 s2 = sinpi_3_9 * data[1]; - // s3 = SINPI_4_9 * T[ 2 ] - i64 s3 = sinpi_4_9 * data[2]; - // s4 = SINPI_1_9 * T[ 2 ] - i64 s4 = sinpi_1_9 * data[2]; - // s5 = SINPI_2_9 * T[ 3 ] - i64 s5 = sinpi_2_9 * data[3]; - // s6 = SINPI_4_9 * T[ 3 ] - i64 s6 = sinpi_4_9 * data[3]; - // v = T[ 0 ] - T[ 2 ] + T[ 3 ] - // s7 = SINPI_3_9 * v - i64 s7 = sinpi_3_9 * (data[0] - data[2] + data[3]); - - // x0 = s0 + s3 + s5 - auto x0 = s0 + s3 + s5; - // x1 = s1 - s4 - s6 - auto x1 = s1 - s4 - s6; - // x2 = s7 - auto x2 = s7; - // x3 = s2 - auto x3 = s2; - - // s0 = x0 + x3 - s0 = x0 + x3; - // s1 = x1 + x3 - s1 = x1 + x3; - // s2 = x2 - s2 = x2; - // s3 = x0 + x1 - x3 - s3 = x0 + x1 - x3; - - // T[ 0 ] = Round2( s0, 14 ) - data[0] = rounded_right_shift(s0, 14); - // T[ 1 ] = Round2( s1, 14 ) - data[1] = rounded_right_shift(s1, 14); - // T[ 2 ] = Round2( s2, 14 ) - data[2] = rounded_right_shift(s2, 14); - // T[ 3 ] = Round2( s3, 14 ) - data[3] = rounded_right_shift(s3, 14); - - // (8.7.1.1) The inverse asymmetric discrete sine transforms also make use of an intermediate array named S. - // The values in this array require higher precision to avoid overflow. Using signed integers with 24 + - // BitDepth bits of precision is enough to avoid overflow. - // Note: Since bounds checks just ensure that we will not have resulting values that will overflow, it's non-fatal - // to allow these bounds to be violated. Therefore, we can avoid the performance cost here. -} - -// The function SB( a, b, angle, 0 ) performs a butterfly rotation. -// Spec defines the source as array T, and the destination array as S. -template -inline void Decoder::butterfly_rotation(Span source, Span destination, size_t index_a, size_t index_b, u8 angle, bool flip) -{ - // The function SB( a, b, angle, 0 ) performs a butterfly rotation according to the following ordered steps: - auto cos = cos64(angle); - auto sin = sin64(angle); - // Expand to the destination buffer's precision. - D a = source[index_a]; - D b = source[index_b]; - // 1. S[ a ] is set equal to T[ a ] * cos64( angle ) - T[ b ] * sin64( angle ). - destination[index_a] = a * cos - b * sin; - // 2. S[ b ] is set equal to T[ a ] * sin64( angle ) + T[ b ] * cos64( angle ). - destination[index_b] = a * sin + b * cos; - - // The function SB( a, b, angle, 1 ) performs a butterfly rotation and flip according to the following ordered steps: - // 1. The function SB( a, b, angle, 0 ) is invoked. - // 2. The contents of S[ a ] and S[ b ] are exchanged. - if (flip) - swap(destination[index_a], destination[index_b]); -} - -// The function SH( a, b ) performs a Hadamard rotation and rounding. -// Spec defines the source array as S, and the destination array as T. -template -inline void Decoder::hadamard_rotation(Span source, Span destination, size_t index_a, size_t index_b) -{ - // Keep the source buffer's precision until rounding. - S a = source[index_a]; - S b = source[index_b]; - // 1. T[ a ] is set equal to Round2( S[ a ] + S[ b ], 14 ). - destination[index_a] = rounded_right_shift(a + b, 14); - // 2. T[ b ] is set equal to Round2( S[ a ] - S[ b ], 14 ). - destination[index_b] = rounded_right_shift(a - b, 14); -} - -inline DecoderErrorOr Decoder::inverse_asymmetric_discrete_sine_transform_8(Span data) -{ - VERIFY(data.size() == 8); - // This process does an in-place transform of the array T using: - - // A higher precision array S for intermediate results. - // (8.7.1.1) NOTE - The values in array S require higher precision to avoid overflow. Using signed integers with - // 24 + BitDepth bits of precision is enough to avoid overflow. - Array high_precision_temp; - - // The following ordered steps apply: - - // 1. Invoke the ADST input array permutation process specified in section 8.7.1.4 with the input variable n set - // equal to 3. - inverse_asymmetric_discrete_sine_transform_input_array_permutation<3>(data); - - // 2. Invoke SB( 2*i, 1+2*i, 30-8*i, 1 ) for i = 0..3. - for (auto i = 0u; i < 4; i++) - butterfly_rotation(data, high_precision_temp.span(), 2 * i, 1 + (2 * i), 30 - (8 * i), true); - - // 3. Invoke SH( i, 4+i ) for i = 0..3. - for (auto i = 0u; i < 4; i++) - hadamard_rotation(high_precision_temp.span(), data, i, 4 + i); - - // 4. Invoke SB( 4+3*i, 5+i, 24-16*i, 1 ) for i = 0..1. - for (auto i = 0u; i < 2; i++) - butterfly_rotation(data, high_precision_temp.span(), 4 + (3 * i), 5 + i, 24 - (16 * i), true); - // 5. Invoke SH( 4+i, 6+i ) for i = 0..1. - for (auto i = 0u; i < 2; i++) - hadamard_rotation(high_precision_temp.span(), data, 4 + i, 6 + i); - - // 6. Invoke H( i, 2+i, 0 ) for i = 0..1. - for (auto i = 0u; i < 2; i++) - hadamard_rotation_in_place(data, i, 2 + i, false); - - // 7. Invoke B( 2+4*i, 3+4*i, 16, 1 ) for i = 0..1. - for (auto i = 0u; i < 2; i++) - butterfly_rotation_in_place(data, 2 + (4 * i), 3 + (4 * i), 16, true); - - // 8. Invoke the ADST output array permutation process specified in section 8.7.1.5 with the input variable n - // set equal to 3. - inverse_asymmetric_discrete_sine_transform_output_array_permutation<3>(data); - - // 9. Set T[ 1+2*i ] equal to -T[ 1+2*i ] for i = 0..3. - for (auto i = 0u; i < 4; i++) { - auto index = 1 + (2 * i); - data[index] = -data[index]; - } - return {}; -} - -inline DecoderErrorOr Decoder::inverse_asymmetric_discrete_sine_transform_16(Span data) -{ - VERIFY(data.size() == 16); - // This process does an in-place transform of the array T using: - - // A higher precision array S for intermediate results. - // (8.7.1.1) The inverse asymmetric discrete sine transforms also make use of an intermediate array named S. - // The values in this array require higher precision to avoid overflow. Using signed integers with 24 + - // BitDepth bits of precision is enough to avoid overflow. - Array high_precision_temp; - - // The following ordered steps apply: - - // 1. Invoke the ADST input array permutation process specified in section 8.7.1.4 with the input variable n set - // equal to 4. - inverse_asymmetric_discrete_sine_transform_input_array_permutation<4>(data); - - // 2. Invoke SB( 2*i, 1+2*i, 31-4*i, 1 ) for i = 0..7. - for (auto i = 0u; i < 8; i++) - butterfly_rotation(data, high_precision_temp.span(), 2 * i, 1 + (2 * i), 31 - (4 * i), true); - // 3. Invoke SH( i, 8+i ) for i = 0..7. - for (auto i = 0u; i < 8; i++) - hadamard_rotation(high_precision_temp.span(), data, i, 8 + i); - - // 4. Invoke SB( 8+2*i, 9+2*i, 28-16*i, 1 ) for i = 0..3. - for (auto i = 0u; i < 4; i++) - butterfly_rotation(data, high_precision_temp.span(), 8 + (2 * i), 9 + (2 * i), 128 + 28 - (16 * i), true); - // 5. Invoke SH( 8+i, 12+i ) for i = 0..3. - for (auto i = 0u; i < 4; i++) - hadamard_rotation(high_precision_temp.span(), data, 8 + i, 12 + i); - - // 6. Invoke H( i, 4+i, 0 ) for i = 0..3. - for (auto i = 0u; i < 4; i++) - hadamard_rotation_in_place(data, i, 4 + i, false); - - // 7. Invoke SB( 4+8*i+3*j, 5+8*i+j, 24-16*j, 1 ) for i = 0..1, for j = 0..1. - for (auto i = 0u; i < 2; i++) - for (auto j = 0u; j < 2; j++) - butterfly_rotation(data, high_precision_temp.span(), 4 + (8 * i) + (3 * j), 5 + (8 * i) + j, 24 - (16 * j), true); - // 8. Invoke SH( 4+8*j+i, 6+8*j+i ) for i = 0..1, j = 0..1. - for (auto i = 0u; i < 2; i++) - for (auto j = 0u; j < 2; j++) - hadamard_rotation(high_precision_temp.span(), data, 4 + (8 * j) + i, 6 + (8 * j) + i); - - // 9. Invoke H( 8*j+i, 2+8*j+i, 0 ) for i = 0..1, for j = 0..1. - for (auto i = 0u; i < 2; i++) - for (auto j = 0u; j < 2; j++) - hadamard_rotation_in_place(data, (8 * j) + i, 2 + (8 * j) + i, false); - // 10. Invoke B( 2+4*j+8*i, 3+4*j+8*i, 48+64*(i^j), 0 ) for i = 0..1, for j = 0..1. - for (auto i = 0u; i < 2; i++) - for (auto j = 0u; j < 2; j++) - butterfly_rotation_in_place(data, 2 + (4 * j) + (8 * i), 3 + (4 * j) + (8 * i), 48 + (64 * (i ^ j)), false); - - // 11. Invoke the ADST output array permutation process specified in section 8.7.1.5 with the input variable n - // set equal to 4. - inverse_asymmetric_discrete_sine_transform_output_array_permutation<4>(data); - - // 12. Set T[ 1+12*j+2*i ] equal to -T[ 1+12*j+2*i ] for i = 0..1, for j = 0..1. - for (auto i = 0u; i < 2; i++) { - for (auto j = 0u; j < 2; j++) { - auto index = 1 + (12 * j) + (2 * i); - data[index] = -data[index]; - } - } - return {}; -} - -template -inline DecoderErrorOr Decoder::inverse_asymmetric_discrete_sine_transform(Span data) -{ - // 8.7.1.9 Inverse ADST Process - - // This process performs an in-place inverse ADST process on the array T of size 2^n for 2 ≤ n ≤ 4. - if constexpr (log2_of_block_size < 2 || log2_of_block_size > 4) - return DecoderError::corrupted("Block size was out of range"sv); - - // The process to invoke depends on n as follows: - if constexpr (log2_of_block_size == 2) { - // − If n is equal to 2, invoke the Inverse ADST4 process specified in section 8.7.1.6. - inverse_asymmetric_discrete_sine_transform_4(data); - return {}; - } - if constexpr (log2_of_block_size == 3) { - // − Otherwise if n is equal to 3, invoke the Inverse ADST8 process specified in section 8.7.1.7. - return inverse_asymmetric_discrete_sine_transform_8(data); - } - // − Otherwise (n is equal to 4), invoke the Inverse ADST16 process specified in section 8.7.1.8. - return inverse_asymmetric_discrete_sine_transform_16(data); -} - -template -ALWAYS_INLINE DecoderErrorOr Decoder::inverse_transform_2d(BlockContext const& block_context, Span dequantized, TransformSet transform_set) -{ - static_assert(log2_of_block_size >= 2 && log2_of_block_size <= 5); - - // This process performs a 2D inverse transform for an array of size 2^n by 2^n stored in the 2D array Dequant. - // The input to this process is a variable n (log2_of_block_size) that specifies the base 2 logarithm of the width of the transform. - - // 1. Set the variable n0 (block_size) equal to 1 << n. - constexpr auto block_size = 1u << log2_of_block_size; - - Array row_array; - Span row = row_array.span().trim(block_size); - - // 2. The row transforms with i = 0..(n0-1) are applied as follows: - for (auto i = 0u; i < block_size; i++) { - // 1. Set T[ j ] equal to Dequant[ i ][ j ] for j = 0..(n0-1). - for (auto j = 0u; j < block_size; j++) - row[j] = dequantized[i * block_size + j]; - - // 2. If Lossless is equal to 1, invoke the Inverse WHT process as specified in section 8.7.1.10 with shift equal - // to 2. - if (block_context.frame_context.lossless) { - TRY(inverse_walsh_hadamard_transform(row, log2_of_block_size, 2)); - } else { - switch (transform_set.second_transform) { - case TransformType::DCT: - // Otherwise, if TxType is equal to DCT_DCT or TxType is equal to ADST_DCT, apply an inverse DCT as - // follows: - // 1. Invoke the inverse DCT permutation process as specified in section 8.7.1.2 with the input variable n. - TRY(inverse_discrete_cosine_transform_array_permutation(row)); - // 2. Invoke the inverse DCT process as specified in section 8.7.1.3 with the input variable n. - TRY(inverse_discrete_cosine_transform(row)); - break; - case TransformType::ADST: - // 4. Otherwise (TxType is equal to DCT_ADST or TxType is equal to ADST_ADST), invoke the inverse ADST - // process as specified in section 8.7.1.9 with input variable n. - TRY(inverse_asymmetric_discrete_sine_transform(row)); - break; - default: - return DecoderError::corrupted("Unknown tx_type"sv); - } - } - - // 5. Set Dequant[ i ][ j ] equal to T[ j ] for j = 0..(n0-1). - for (auto j = 0u; j < block_size; j++) - dequantized[i * block_size + j] = row[j]; - } - - Array column_array; - auto column = column_array.span().trim(block_size); - - // 3. The column transforms with j = 0..(n0-1) are applied as follows: - for (auto j = 0u; j < block_size; j++) { - // 1. Set T[ i ] equal to Dequant[ i ][ j ] for i = 0..(n0-1). - for (auto i = 0u; i < block_size; i++) - column[i] = dequantized[i * block_size + j]; - - // 2. If Lossless is equal to 1, invoke the Inverse WHT process as specified in section 8.7.1.10 with shift equal - // to 0. - if (block_context.frame_context.lossless) { - TRY(inverse_walsh_hadamard_transform(column, log2_of_block_size, 0)); - } else { - switch (transform_set.first_transform) { - case TransformType::DCT: - // Otherwise, if TxType is equal to DCT_DCT or TxType is equal to DCT_ADST, apply an inverse DCT as - // follows: - // 1. Invoke the inverse DCT permutation process as specified in section 8.7.1.2 with the input variable n. - TRY(inverse_discrete_cosine_transform_array_permutation(column)); - // 2. Invoke the inverse DCT process as specified in section 8.7.1.3 with the input variable n. - TRY(inverse_discrete_cosine_transform(column)); - break; - case TransformType::ADST: - // 4. Otherwise (TxType is equal to ADST_DCT or TxType is equal to ADST_ADST), invoke the inverse ADST - // process as specified in section 8.7.1.9 with input variable n. - TRY(inverse_asymmetric_discrete_sine_transform(column)); - break; - default: - VERIFY_NOT_REACHED(); - } - } - - // 5. If Lossless is equal to 1, set Dequant[ i ][ j ] equal to T[ i ] for i = 0..(n0-1). - for (auto i = 0u; i < block_size; i++) - dequantized[i * block_size + j] = column[i]; - - // 6. Otherwise (Lossless is equal to 0), set Dequant[ i ][ j ] equal to Round2( T[ i ], Min( 6, n + 2 ) ) - // for i = 0..(n0-1). - if (!block_context.frame_context.lossless) { - for (auto i = 0u; i < block_size; i++) { - auto index = i * block_size + j; - dequantized[index] = rounded_right_shift(dequantized[index], min(6, log2_of_block_size + 2)); - } - } - } - - return {}; -} - -DecoderErrorOr 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 ]. - // The output from this process is an updated set of reference frames and previous motion vectors. - // The following ordered steps apply: - - // 1. For each value of i from 0 to NUM_REF_FRAMES - 1, the following applies if bit i of refresh_frame_flags - // is equal to 1 (i.e. if (refresh_frame_flags>>i)&1 is equal to 1): - for (u8 i = 0; i < NUM_REF_FRAMES; i++) { - if (frame_context.should_update_reference_frame_at_index(i)) { - auto& reference_frame = m_parser->m_reference_frames[i]; - - // − RefFrameWidth[ i ] is set equal to FrameWidth. - // − RefFrameHeight[ i ] is set equal to FrameHeight. - reference_frame.size = frame_context.size(); - // − RefSubsamplingX[ i ] is set equal to subsampling_x. - reference_frame.subsampling_x = frame_context.color_config.subsampling_x; - // − RefSubsamplingY[ i ] is set equal to subsampling_y. - reference_frame.subsampling_y = frame_context.color_config.subsampling_y; - // − RefBitDepth[ i ] is set equal to BitDepth. - reference_frame.bit_depth = frame_context.color_config.bit_depth; - - // − FrameStore[ i ][ 0 ][ y ][ x ] is set equal to CurrFrame[ 0 ][ y ][ x ] for x = 0..FrameWidth-1, for y = - // 0..FrameHeight-1. - // − FrameStore[ i ][ plane ][ y ][ x ] is set equal to CurrFrame[ plane ][ y ][ x ] for plane = 1..2, for x = - // 0..((FrameWidth+subsampling_x) >> subsampling_x)-1, for y = 0..((FrameHeight+subsampling_y) >> - // subsampling_y)-1. - - // 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 = frame_context.size().width(); - auto height = frame_context.size().height(); - auto stride = frame_context.decoded_size(plane > 0).width(); - if (plane > 0) { - width = Subsampling::subsampled_size(frame_context.color_config.subsampling_x, width); - height = Subsampling::subsampled_size(frame_context.color_config.subsampling_y, height); - } - - auto const& original_buffer = get_output_buffer(plane); - auto& frame_store_buffer = reference_frame.frame_planes[plane]; - auto frame_store_width = width + MV_BORDER * 2; - auto frame_store_height = height + MV_BORDER * 2; - frame_store_buffer.resize_and_keep_capacity(frame_store_width * frame_store_height); - - VERIFY(original_buffer.size() >= width * height); - for (auto destination_y = 0u; destination_y < frame_store_height; destination_y++) { - // Offset the source row by the motion vector border and then clamp it to the range of 0...height. - // This will create an extended border on the top and bottom of the reference frame to avoid having to bounds check - // inter-prediction. - auto source_y = min(destination_y >= MV_BORDER ? destination_y - MV_BORDER : 0, height - 1); - auto const* source = &original_buffer[source_y * stride]; - auto* destination = &frame_store_buffer[destination_y * frame_store_width + MV_BORDER]; - AK::TypedTransfer>::copy(destination, source, width); - } - - for (auto destination_y = 0u; destination_y < frame_store_height; destination_y++) { - // Stretch the leftmost samples out into the border. - auto sample = frame_store_buffer[destination_y * frame_store_width + MV_BORDER]; - - for (auto destination_x = 0u; destination_x < MV_BORDER; destination_x++) { - frame_store_buffer[destination_y * frame_store_width + destination_x] = sample; - } - - // Stretch the rightmost samples out into the border. - sample = frame_store_buffer[destination_y * frame_store_width + MV_BORDER + width - 1]; - - for (auto destination_x = MV_BORDER + width; destination_x < frame_store_width; destination_x++) { - frame_store_buffer[destination_y * frame_store_width + destination_x] = sample; - } - } - } - } - } - - // 2. If show_existing_frame is equal to 0, the following applies: - 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, - // for col = 0..MiCols-1, for list = 0..1, for comp = 0..1. - // And from decode_frame(): - // - If all of the following conditions are true, PrevSegmentIds[ row ][ col ] is set equal to - // SegmentIds[ row ][ col ] for row = 0..MiRows-1, for col = 0..MiCols-1: - // − show_existing_frame is equal to 0, - // − segmentation_enabled is equal to 1, - // − segmentation_update_map is equal to 1. - bool keep_segment_ids = !frame_context.shows_existing_frame() && frame_context.segmentation_enabled && frame_context.use_full_segment_id_tree; - 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; - return persistent_context; - }); - } - - return {}; -} - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Decoder.h b/Userland/Libraries/LibMedia/Video/VP9/Decoder.h deleted file mode 100644 index f72b20a966a..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Decoder.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Parser.h" - -namespace Media::Video::VP9 { - -class Decoder final : public VideoDecoder { - friend class Parser; - -public: - Decoder(); - ~Decoder() override { } - /* (8.1) General */ - DecoderErrorOr receive_sample(Duration timestamp, ReadonlyBytes) override; - - DecoderErrorOr> get_decoded_frame() override; - - void flush() override; - -private: - typedef i32 Intermediate; - - // Based on the maximum size resulting from num_4x4_blocks_wide_lookup. - static constexpr size_t maximum_block_dimensions = 64ULL; - static constexpr size_t maximum_block_size = maximum_block_dimensions * maximum_block_dimensions; - // Based on the maximum for TXSize. - static constexpr size_t maximum_transform_size = 32ULL * 32ULL; - - DecoderErrorOr decode_frame(Duration timestamp, ReadonlyBytes); - template - DecoderErrorOr create_video_frame(Duration timestamp, FrameContext const&); - - DecoderErrorOr allocate_buffers(FrameContext const&); - Vector& get_output_buffer(u8 plane); - - /* (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 adapt_coef_probs(FrameContext const&); - DecoderErrorOr adapt_non_coef_probs(FrameContext const&); - void adapt_probs(int const* tree, u8* probs, u32* counts); - u8 adapt_prob(u8 prob, u32 counts[2]); - - /* (8.5) Prediction Processes */ - // (8.5.1) Intra prediction process - DecoderErrorOr predict_intra(u8 plane, BlockContext const& block_context, u32 x, u32 y, bool have_left, bool have_above, bool not_on_right, TransformSize transform_size, u32 block_index); - - DecoderErrorOr prepare_referenced_frame(Gfx::Size frame_size, u8 reference_frame_index); - - // (8.5.1) Inter prediction process - DecoderErrorOr 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, BlockContext const&, ReferenceIndex, u32 block_index); - // (8.5.2.2) Motion vector clamping process - MotionVector clamp_motion_vector(u8 plane, BlockContext const&, u32 block_row, u32 block_column, MotionVector vector); - // From (8.5.1) Inter prediction process, steps 2-5 - DecoderErrorOr predict_inter_block(u8 plane, BlockContext const&, ReferenceIndex, u32 block_row, u32 block_column, u32 x, u32 y, u32 width, u32 height, u32 block_index, Span block_buffer); - - /* (8.6) Reconstruction and Dequantization */ - - // Returns the quantizer index for the current block - static u8 get_base_quantizer_index(SegmentFeatureStatus alternative_quantizer_feature, bool should_use_absolute_segment_base_quantizer, u8 base_quantizer_index); - // Returns the quantizer value for the dc coefficient for a particular plane - static u16 get_dc_quantizer(u8 bit_depth, u8 base, i8 delta); - // Returns the quantizer value for the ac coefficient for a particular plane - static u16 get_ac_quantizer(u8 bit_depth, u8 base, i8 delta); - - // (8.6.2) Reconstruct process - DecoderErrorOr reconstruct(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TransformSize transform_block_size, TransformSet); - template - DecoderErrorOr reconstruct_templated(u8 plane, BlockContext const&, u32 transform_block_x, u32 transform_block_y, TransformSet); - - // (8.7) Inverse transform process - template - DecoderErrorOr inverse_transform_2d(BlockContext const&, Span dequantized, TransformSet); - - // (8.7.1) 1D Transforms - // (8.7.1.1) Butterfly functions - - inline i32 cos64(u8 angle); - inline i32 sin64(u8 angle); - // The function B( a, b, angle, 0 ) performs a butterfly rotation. - inline void butterfly_rotation_in_place(Span data, size_t index_a, size_t index_b, u8 angle, bool flip); - // The function H( a, b, 0 ) performs a Hadamard rotation. - inline void hadamard_rotation_in_place(Span data, size_t index_a, size_t index_b, bool flip); - // The function SB( a, b, angle, 0 ) performs a butterfly rotation. - // Spec defines the source as array T, and the destination array as S. - template - inline void butterfly_rotation(Span source, Span destination, size_t index_a, size_t index_b, u8 angle, bool flip); - // The function SH( a, b ) performs a Hadamard rotation and rounding. - // Spec defines the source array as S, and the destination array as T. - template - inline void hadamard_rotation(Span source, Span destination, size_t index_a, size_t index_b); - - // (8.7.1.10) This process does an in-place Walsh-Hadamard transform of the array T (of length 4). - inline DecoderErrorOr inverse_walsh_hadamard_transform(Span data, u8 log2_of_block_size, u8 shift); - - // (8.7.1.2) Inverse DCT array permutation process - template - inline DecoderErrorOr inverse_discrete_cosine_transform_array_permutation(Span data); - // (8.7.1.3) Inverse DCT process - template - inline DecoderErrorOr inverse_discrete_cosine_transform(Span data); - - // (8.7.1.4) This process performs the in-place permutation of the array T of length 2 n which is required as the first step of - // the inverse ADST. - template - inline void inverse_asymmetric_discrete_sine_transform_input_array_permutation(Span data); - // (8.7.1.5) This process performs the in-place permutation of the array T of length 2 n which is required before the final - // step of the inverse ADST. - template - inline void inverse_asymmetric_discrete_sine_transform_output_array_permutation(Span data); - - // (8.7.1.6) This process does an in-place transform of the array T to perform an inverse ADST. - inline void inverse_asymmetric_discrete_sine_transform_4(Span data); - // (8.7.1.7) This process does an in-place transform of the array T using a higher precision array S for intermediate - // results. - inline DecoderErrorOr inverse_asymmetric_discrete_sine_transform_8(Span data); - // (8.7.1.8) This process does an in-place transform of the array T using a higher precision array S for intermediate - // results. - inline DecoderErrorOr inverse_asymmetric_discrete_sine_transform_16(Span data); - // (8.7.1.9) This process performs an in-place inverse ADST process on the array T of size 2 n for 2 ≤ n ≤ 4. - template - inline DecoderErrorOr inverse_asymmetric_discrete_sine_transform(Span data); - - /* (8.10) Reference Frame Update Process */ - DecoderErrorOr update_reference_frames(FrameContext const&); - - NonnullOwnPtr m_parser; - - Vector m_output_buffers[3]; - - Queue, 1> m_video_frame_queue; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Enums.h b/Userland/Libraries/LibMedia/Video/VP9/Enums.h deleted file mode 100644 index 89848f29177..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Enums.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Symbols.h" -#include - -namespace Media::Video::VP9 { - -enum class FrameType { - KeyFrame, - IntraOnlyFrame, - InterFrame -}; - -enum ColorSpace : u8 { - Unknown = 0, - Bt601 = 1, - Bt709 = 2, - Smpte170 = 3, - Smpte240 = 4, - Bt2020 = 5, - Reserved = 6, - RGB = 7 -}; - -enum InterpolationFilter : u8 { - EightTap = 0, - EightTapSmooth = 1, - EightTapSharp = 2, - Bilinear = 3, - Switchable = 4 -}; - -enum ReferenceFrameType : u8 { - // None represents both INTRA_FRAME and NONE in the spec. When the primary reference - // frame type is None, that means that the frame/block is not inter-predicted. - None = 0, - LastFrame = 1, - GoldenFrame = 2, - AltRefFrame = 3, -}; - -enum class TransformMode : u8 { - Only_4x4 = 0, - Allow_8x8 = 1, - Allow_16x16 = 2, - Allow_32x32 = 3, - Select = 4, -}; - -enum TransformSize : u8 { - Transform_4x4 = 0, - Transform_8x8 = 1, - Transform_16x16 = 2, - Transform_32x32 = 3, -}; - -enum class TransformType : u8 { - DCT = 0, - ADST = 1, -}; - -struct TransformSet { - TransformType first_transform : 1; - TransformType second_transform : 1; - - bool operator==(TransformSet const& other) const - { - return first_transform == other.first_transform && second_transform == other.second_transform; - } -}; - -enum ReferenceMode : u8 { - SingleReference = 0, - CompoundReference = 1, - ReferenceModeSelect = 2, -}; - -enum class ReferenceIndex : u8 { - Primary = 0, - Secondary = 1, -}; - -enum BlockSubsize : u8 { - Block_4x4 = 0, - Block_4x8 = 1, - Block_8x4 = 2, - Block_8x8 = 3, - Block_8x16 = 4, - Block_16x8 = 5, - Block_16x16 = 6, - Block_16x32 = 7, - Block_32x16 = 8, - Block_32x32 = 9, - Block_32x64 = 10, - Block_64x32 = 11, - Block_64x64 = 12, - Block_Invalid = BLOCK_INVALID -}; - -enum Partition : u8 { - PartitionNone = 0, - PartitionHorizontal = 1, - PartitionVertical = 2, - PartitionSplit = 3, -}; - -enum class PredictionMode : u8 { - DcPred = 0, - VPred = 1, - HPred = 2, - D45Pred = 3, - D135Pred = 4, - D117Pred = 5, - D153Pred = 6, - D207Pred = 7, - D63Pred = 8, - TmPred = 9, - NearestMv = 10, - NearMv = 11, - ZeroMv = 12, - NewMv = 13, -}; - -enum MvJoint : u8 { - MotionVectorAllZero = 0, - MotionVectorNonZeroColumn = 1, - MotionVectorNonZeroRow = 2, -}; - -enum MvClass : u8 { - MvClass0 = 0, - MvClass1 = 1, - MvClass2 = 2, - MvClass3 = 3, - MvClass4 = 4, - MvClass5 = 5, - MvClass6 = 6, - MvClass7 = 7, - MvClass8 = 8, - MvClass9 = 9, - MvClass10 = 10, -}; - -enum Token : u8 { - ZeroToken = 0, - OneToken = 1, - TwoToken = 2, - ThreeToken = 3, - FourToken = 4, - DctValCat1 = 5, - DctValCat2 = 6, - DctValCat3 = 7, - DctValCat4 = 8, - DctValCat5 = 9, - DctValCat6 = 10, -}; - -enum class SegmentFeature : u8 { - // SEG_LVL_ALT_Q - AlternativeQuantizerBase, - // SEG_LVL_ALT_L - AlternativeLoopFilterBase, - // SEG_LVL_REF_FRAME - ReferenceFrameOverride, - // SEG_LVL_SKIP - SkipResidualsOverride, - // SEG_LVL_MAX - Sentinel, -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/LookupTables.h b/Userland/Libraries/LibMedia/Video/VP9/LookupTables.h deleted file mode 100644 index 5168eeba3bc..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/LookupTables.h +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Enums.h" -#include "MotionVector.h" -#include "Symbols.h" - -namespace Media::Video::VP9 { - -static constexpr InterpolationFilter literal_to_type[4] = { EightTapSmooth, EightTap, EightTapSharp, Bilinear }; -static constexpr TransformSize tx_mode_to_biggest_tx_size[TX_MODES] = { Transform_4x4, Transform_8x8, Transform_16x16, Transform_32x32, Transform_32x32 }; -static constexpr u8 segmentation_feature_bits[to_underlying(SegmentFeature::Sentinel)] = { 8, 6, 2, 0 }; -static constexpr bool segmentation_feature_signed[to_underlying(SegmentFeature::Sentinel)] = { true, true, false, false }; -static constexpr u8 inv_map_table[MAX_PROB] = { - 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189, 202, 215, 228, 241, 254, - 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 253 -}; -static constexpr BlockSubsize subsize_lookup[PARTITION_TYPES][BLOCK_SIZES] = { - { - // PARTITION_NONE - Block_4x4, - Block_4x8, - Block_8x4, - Block_8x8, - Block_8x16, - Block_16x8, - Block_16x16, - Block_16x32, - Block_32x16, - Block_32x32, - Block_32x64, - Block_64x32, - Block_64x64, - }, - { - // PARTITION_HORZ - Block_Invalid, - Block_Invalid, - Block_Invalid, - Block_8x4, - Block_Invalid, - Block_Invalid, - Block_16x8, - Block_Invalid, - Block_Invalid, - Block_32x16, - Block_Invalid, - Block_Invalid, - Block_64x32, - }, - { - // PARTITION_VERT - Block_Invalid, - Block_Invalid, - Block_Invalid, - Block_4x8, - Block_Invalid, - Block_Invalid, - Block_8x16, - Block_Invalid, - Block_Invalid, - Block_16x32, - Block_Invalid, - Block_Invalid, - Block_32x64, - }, - { - // PARTITION_SPLIT - Block_Invalid, - Block_Invalid, - Block_Invalid, - Block_4x4, - Block_Invalid, - Block_Invalid, - Block_8x8, - Block_Invalid, - Block_Invalid, - Block_16x16, - Block_Invalid, - Block_Invalid, - Block_32x32, - } -}; - -static constexpr int partition_tree[6] = { - -PartitionNone, 2, - -PartitionHorizontal, 4, - -PartitionVertical, -PartitionSplit -}; -static constexpr int cols_partition_tree[2] = { -PartitionHorizontal, -PartitionSplit }; -static constexpr int rows_partition_tree[2] = { -PartitionVertical, -PartitionSplit }; -static constexpr int intra_mode_tree[18] = { - -to_underlying(PredictionMode::DcPred), 2, - -to_underlying(PredictionMode::TmPred), 4, - -to_underlying(PredictionMode::VPred), 6, - 8, 12, - -to_underlying(PredictionMode::HPred), 10, - -to_underlying(PredictionMode::D135Pred), -to_underlying(PredictionMode::D117Pred), - -to_underlying(PredictionMode::D45Pred), 14, - -to_underlying(PredictionMode::D63Pred), 16, - -to_underlying(PredictionMode::D153Pred), -to_underlying(PredictionMode::D207Pred) -}; -static constexpr int segment_tree[14] = { - 2, 4, 6, 8, 10, 12, - 0, -1, -2, -3, -4, -5, -6, -7 -}; -static constexpr int binary_tree[2] = { 0, -1 }; -static constexpr int tx_size_32_tree[6] = { - -Transform_4x4, 2, - -Transform_8x8, 4, - -Transform_16x16, -Transform_32x32 -}; -static constexpr int tx_size_16_tree[4] = { - -Transform_4x4, 2, - -Transform_8x8, -Transform_16x16 -}; -static constexpr int tx_size_8_tree[2] = { -Transform_4x4, -Transform_8x8 }; -inline constexpr int inter_mode(PredictionMode mode) -{ - return to_underlying(mode) - to_underlying(PredictionMode::NearestMv); -} -static constexpr int inter_mode_tree[6] = { - -inter_mode(PredictionMode::ZeroMv), 2, - -inter_mode(PredictionMode::NearestMv), 4, - -inter_mode(PredictionMode::NearMv), -inter_mode(PredictionMode::NewMv) -}; -static constexpr int interp_filter_tree[4] = { - -EightTap, 2, - -EightTapSmooth, -EightTapSharp -}; -static constexpr int mv_joint_tree[6] = { - -MotionVectorAllZero, 2, - -MotionVectorNonZeroColumn, 4, - -MotionVectorNonZeroRow, -(MotionVectorNonZeroColumn | MotionVectorNonZeroRow) -}; -static constexpr int mv_class_tree[20] = { - -MvClass0, 2, - -MvClass1, 4, - 6, 8, - -MvClass2, -MvClass3, - 10, 12, - -MvClass4, -MvClass5, - -MvClass6, 14, - 16, 18, - -MvClass7, -MvClass8, - -MvClass9, -MvClass10 -}; -static constexpr int mv_fr_tree[6] = { - -0, 2, - -1, 4, - -2, -3 -}; -static constexpr int token_tree[20] = { - -ZeroToken, 2, - -OneToken, 4, - 6, 10, - -TwoToken, 8, - -ThreeToken, -FourToken, - 12, 14, - -DctValCat1, -DctValCat2, - 16, 18, - -DctValCat3, -DctValCat4, - -DctValCat5, -DctValCat6 -}; - -static constexpr u8 b_width_log2_lookup[BLOCK_SIZES] = { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }; -static constexpr u8 b_height_log2_lookup[BLOCK_SIZES] = { 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4 }; -static constexpr u8 num_4x4_blocks_wide_lookup[BLOCK_SIZES] = { 1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16 }; -static constexpr u8 num_4x4_blocks_high_lookup[BLOCK_SIZES] = { 1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16 }; -static constexpr u8 mi_width_log2_lookup[BLOCK_SIZES] = { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3 }; -static constexpr u8 num_8x8_blocks_wide_lookup[BLOCK_SIZES] = { 1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8 }; -static constexpr u8 mi_height_log2_lookup[BLOCK_SIZES] = { 0, 0, 0, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3 }; -static constexpr u8 num_8x8_blocks_high_lookup[BLOCK_SIZES] = { 1, 1, 1, 1, 2, 1, 2, 4, 2, 4, 8, 4, 8 }; -static constexpr u8 size_group_lookup[BLOCK_SIZES] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3 }; - -static constexpr TransformSize max_txsize_lookup[BLOCK_SIZES] = { - Transform_4x4, - Transform_4x4, - Transform_4x4, - Transform_8x8, - Transform_8x8, - Transform_8x8, - Transform_16x16, - Transform_16x16, - Transform_16x16, - Transform_32x32, - Transform_32x32, - Transform_32x32, - Transform_32x32, -}; - -static constexpr BlockSubsize ss_size_lookup[BLOCK_SIZES][2][2] = { - { { Block_4x4, Block_Invalid }, { Block_Invalid, Block_Invalid } }, - { { Block_4x8, Block_4x4 }, { Block_Invalid, Block_Invalid } }, - { { Block_8x4, Block_Invalid }, { Block_4x4, Block_Invalid } }, - { { Block_8x8, Block_8x4 }, { Block_4x8, Block_4x4 } }, - { { Block_8x16, Block_8x8 }, { Block_Invalid, Block_4x8 } }, - { { Block_16x8, Block_Invalid }, { Block_8x8, Block_8x4 } }, - { { Block_16x16, Block_16x8 }, { Block_8x16, Block_8x8 } }, - { { Block_16x32, Block_16x16 }, { Block_Invalid, Block_8x16 } }, - { { Block_32x16, Block_Invalid }, { Block_16x16, Block_16x8 } }, - { { Block_32x32, Block_32x16 }, { Block_16x32, Block_16x16 } }, - { { Block_32x64, Block_32x32 }, { Block_Invalid, Block_16x32 } }, - { { Block_64x32, Block_Invalid }, { Block_32x32, Block_32x16 } }, - { { Block_64x64, Block_64x32 }, { Block_32x64, Block_32x32 } }, -}; - -static constexpr int small_token_tree[6] = { - 0, 0, // Unused - -ZeroToken, 4, - -OneToken, -TwoToken -}; - -static constexpr u16 default_scan_4x4[16] = { 0, 4, 1, 5, 8, 2, 12, 9, 3, 6, 13, 10, 7, 14, 11, 15 }; - -static constexpr u16 col_scan_4x4[16] = { 0, 4, 8, 1, 12, 5, 9, 2, 13, 6, 10, 3, 7, 14, 11, 15 }; - -static constexpr u16 row_scan_4x4[16] = { 0, 1, 4, 2, 5, 3, 6, 8, 9, 7, 12, 10, 13, 11, 14, 15 }; - -static constexpr u16 default_scan_8x8[64] = { 0, 8, 1, 16, 9, 2, 17, 24, 10, 3, 18, 25, 32, 11, 4, 26, 33, 19, 40, 12, 34, 27, 5, 41, 20, 48, 13, 35, 42, 28, 21, 6, 49, 56, 36, 43, 29, 7, 14, 50, 57, 44, 22, 37, 15, 51, 58, 30, 45, 23, 52, 59, 38, 31, 60, 53, 46, 39, 61, 54, 47, 62, 55, 63 }; - -static constexpr u16 col_scan_8x8[64] = { 0, 8, 16, 1, 24, 9, 32, 17, 2, 40, 25, 10, 33, 18, 48, 3, 26, 41, 11, 56, 19, 34, 4, 49, 27, 42, 12, 35, 20, 57, 50, 28, 5, 43, 13, 36, 58, 51, 21, 44, 6, 29, 59, 37, 14, 52, 22, 7, 45, 60, 30, 15, 38, 53, 23, 46, 31, 61, 39, 54, 47, 62, 55, 63 }; - -static constexpr u16 row_scan_8x8[64] = { 0, 1, 2, 8, 9, 3, 16, 10, 4, 17, 11, 24, 5, 18, 25, 12, 19, 26, 32, 6, 13, 20, 33, 27, 7, 34, 40, 21, 28, 41, 14, 35, 48, 42, 29, 36, 49, 22, 43, 15, 56, 37, 50, 44, 30, 57, 23, 51, 58, 45, 38, 52, 31, 59, 53, 46, 60, 39, 61, 47, 54, 55, 62, 63 }; - -static constexpr u16 default_scan_16x16[256] = { 0, 16, 1, 32, 17, 2, 48, 33, 18, 3, 64, 34, 49, 19, 65, 80, 50, 4, 35, 66, 20, 81, 96, 51, 5, 36, 82, 97, 67, 112, 21, 52, 98, 37, 83, 113, 6, 68, 128, 53, 22, 99, 114, 84, 7, 129, 38, 69, 100, 115, 144, 130, 85, 54, 23, 8, 145, 39, 70, 116, 101, 131, 160, 146, 55, 86, 24, 71, 132, 117, 161, 40, 9, 102, 147, 176, 162, 87, 56, 25, 133, 118, 177, 148, 72, 103, 41, 163, 10, 192, 178, 88, 57, 134, 149, 119, 26, 164, 73, 104, 193, 42, 179, 208, 11, 135, 89, 165, 120, 150, 58, 194, 180, 27, 74, 209, 105, 151, 136, 43, 90, 224, 166, 195, 181, 121, 210, 59, 12, 152, 106, 167, 196, 75, 137, 225, 211, 240, 182, 122, 91, 28, 197, 13, 226, 168, 183, 153, 44, 212, 138, 107, 241, 60, 29, 123, 198, 184, 227, 169, 242, 76, 213, 154, 45, 92, 14, 199, 139, 61, 228, 214, 170, 185, 243, 108, 77, 155, 30, 15, 200, 229, 124, 215, 244, 93, 46, 186, 171, 201, 109, 140, 230, 62, 216, 245, 31, 125, 78, 156, 231, 47, 187, 202, 217, 94, 246, 141, 63, 232, 172, 110, 247, 157, 79, 218, 203, 126, 233, 188, 248, 95, 173, 142, 219, 111, 249, 234, 158, 127, 189, 204, 250, 235, 143, 174, 220, 205, 159, 251, 190, 221, 175, 236, 237, 191, 206, 252, 222, 253, 207, 238, 223, 254, 239, 255 }; - -static constexpr u16 col_scan_16x16[256] = { 0, 16, 32, 48, 1, 64, 17, 80, 33, 96, 49, 2, 65, 112, 18, 81, 34, 128, 50, 97, 3, 66, 144, 19, 113, 35, 82, 160, 98, 51, 129, 4, 67, 176, 20, 114, 145, 83, 36, 99, 130, 52, 192, 5, 161, 68, 115, 21, 146, 84, 208, 177, 37, 131, 100, 53, 162, 224, 69, 6, 116, 193, 147, 85, 22, 240, 132, 38, 178, 101, 163, 54, 209, 117, 70, 7, 148, 194, 86, 179, 225, 23, 133, 39, 164, 8, 102, 210, 241, 55, 195, 118, 149, 71, 180, 24, 87, 226, 134, 165, 211, 40, 103, 56, 72, 150, 196, 242, 119, 9, 181, 227, 88, 166, 25, 135, 41, 104, 212, 57, 151, 197, 120, 73, 243, 182, 136, 167, 213, 89, 10, 228, 105, 152, 198, 26, 42, 121, 183, 244, 168, 58, 137, 229, 74, 214, 90, 153, 199, 184, 11, 106, 245, 27, 122, 230, 169, 43, 215, 59, 200, 138, 185, 246, 75, 12, 91, 154, 216, 231, 107, 28, 44, 201, 123, 170, 60, 247, 232, 76, 139, 13, 92, 217, 186, 248, 155, 108, 29, 124, 45, 202, 233, 171, 61, 14, 77, 140, 15, 249, 93, 30, 187, 156, 218, 46, 109, 125, 62, 172, 78, 203, 31, 141, 234, 94, 47, 188, 63, 157, 110, 250, 219, 79, 126, 204, 173, 142, 95, 189, 111, 235, 158, 220, 251, 127, 174, 143, 205, 236, 159, 190, 221, 252, 175, 206, 237, 191, 253, 222, 238, 207, 254, 223, 239, 255 }; - -static constexpr u16 row_scan_16x16[256] = { 0, 1, 2, 16, 3, 17, 4, 18, 32, 5, 33, 19, 6, 34, 48, 20, 49, 7, 35, 21, 50, 64, 8, 36, 65, 22, 51, 37, 80, 9, 66, 52, 23, 38, 81, 67, 10, 53, 24, 82, 68, 96, 39, 11, 54, 83, 97, 69, 25, 98, 84, 40, 112, 55, 12, 70, 99, 113, 85, 26, 41, 56, 114, 100, 13, 71, 128, 86, 27, 115, 101, 129, 42, 57, 72, 116, 14, 87, 130, 102, 144, 73, 131, 117, 28, 58, 15, 88, 43, 145, 103, 132, 146, 118, 74, 160, 89, 133, 104, 29, 59, 147, 119, 44, 161, 148, 90, 105, 134, 162, 120, 176, 75, 135, 149, 30, 60, 163, 177, 45, 121, 91, 106, 164, 178, 150, 192, 136, 165, 179, 31, 151, 193, 76, 122, 61, 137, 194, 107, 152, 180, 208, 46, 166, 167, 195, 92, 181, 138, 209, 123, 153, 224, 196, 77, 168, 210, 182, 240, 108, 197, 62, 154, 225, 183, 169, 211, 47, 139, 93, 184, 226, 212, 241, 198, 170, 124, 155, 199, 78, 213, 185, 109, 227, 200, 63, 228, 242, 140, 214, 171, 186, 156, 229, 243, 125, 94, 201, 244, 215, 216, 230, 141, 187, 202, 79, 172, 110, 157, 245, 217, 231, 95, 246, 232, 126, 203, 247, 233, 173, 218, 142, 111, 158, 188, 248, 127, 234, 219, 249, 189, 204, 143, 174, 159, 250, 235, 205, 220, 175, 190, 251, 221, 191, 206, 236, 207, 237, 252, 222, 253, 223, 238, 239, 254, 255 }; - -static constexpr u16 default_scan_32x32[1024] = { 0, 32, 1, 64, 33, 2, 96, 65, 34, 128, 3, 97, 66, 160, 129, 35, 98, 4, 67, 130, 161, 192, 36, 99, 224, 5, 162, 193, 68, 131, 37, 100, 225, 194, 256, 163, 69, 132, 6, 226, 257, 288, 195, 101, 164, 38, 258, 7, 227, 289, 133, 320, 70, 196, 165, 290, 259, 228, 39, 321, 102, 352, 8, 197, 71, 134, 322, 291, 260, 353, 384, 229, 166, 103, 40, 354, 323, 292, 135, 385, 198, 261, 72, 9, 416, 167, 386, 355, 230, 324, 104, 293, 41, 417, 199, 136, 262, 387, 448, 325, 356, 10, 73, 418, 231, 168, 449, 294, 388, 105, 419, 263, 42, 200, 357, 450, 137, 480, 74, 326, 232, 11, 389, 169, 295, 420, 106, 451, 481, 358, 264, 327, 201, 43, 138, 512, 482, 390, 296, 233, 170, 421, 75, 452, 359, 12, 513, 265, 483, 328, 107, 202, 514, 544, 422, 391, 453, 139, 44, 234, 484, 297, 360, 171, 76, 515, 545, 266, 329, 454, 13, 423, 203, 108, 546, 485, 576, 298, 235, 140, 361, 330, 172, 547, 45, 455, 267, 577, 486, 77, 204, 362, 608, 14, 299, 578, 109, 236, 487, 609, 331, 141, 579, 46, 15, 173, 610, 363, 78, 205, 16, 110, 237, 611, 142, 47, 174, 79, 206, 17, 111, 238, 48, 143, 80, 175, 112, 207, 49, 18, 239, 81, 113, 19, 50, 82, 114, 51, 83, 115, 640, 516, 392, 268, 144, 20, 672, 641, 548, 517, 424, 393, 300, 269, 176, 145, 52, 21, 704, 673, 642, 580, 549, 518, 456, 425, 394, 332, 301, 270, 208, 177, 146, 84, 53, 22, 736, 705, 674, 643, 612, 581, 550, 519, 488, 457, 426, 395, 364, 333, 302, 271, 240, 209, 178, 147, 116, 85, 54, 23, 737, 706, 675, 613, 582, 551, 489, 458, 427, 365, 334, 303, 241, 210, 179, 117, 86, 55, 738, 707, 614, 583, 490, 459, 366, 335, 242, 211, 118, 87, 739, 615, 491, 367, 243, 119, 768, 644, 520, 396, 272, 148, 24, 800, 769, 676, 645, 552, 521, 428, 397, 304, 273, 180, 149, 56, 25, 832, 801, 770, 708, 677, 646, 584, 553, 522, 460, 429, 398, 336, 305, 274, 212, 181, 150, 88, 57, 26, 864, 833, 802, 771, 740, 709, 678, 647, 616, 585, 554, 523, 492, 461, 430, 399, 368, 337, 306, 275, 244, 213, 182, 151, 120, 89, 58, 27, 865, 834, 803, 741, 710, 679, 617, 586, 555, 493, 462, 431, 369, 338, 307, 245, 214, 183, 121, 90, 59, 866, 835, 742, 711, 618, 587, 494, 463, 370, 339, 246, 215, 122, 91, 867, 743, 619, 495, 371, 247, 123, 896, 772, 648, 524, 400, 276, 152, 28, 928, 897, 804, 773, 680, 649, 556, 525, 432, 401, 308, 277, 184, 153, 60, 29, 960, 929, 898, 836, 805, 774, 712, 681, 650, 588, 557, 526, 464, 433, 402, 340, 309, 278, 216, 185, 154, 92, 61, 30, 992, 961, 930, 899, 868, 837, 806, 775, 744, 713, 682, 651, 620, 589, 558, 527, 496, 465, 434, 403, 372, 341, 310, 279, 248, 217, 186, 155, 124, 93, 62, 31, 993, 962, 931, 869, 838, 807, 745, 714, 683, 621, 590, 559, 497, 466, 435, 373, 342, 311, 249, 218, 187, 125, 94, 63, 994, 963, 870, 839, 746, 715, 622, 591, 498, 467, 374, 343, 250, 219, 126, 95, 995, 871, 747, 623, 499, 375, 251, 127, 900, 776, 652, 528, 404, 280, 156, 932, 901, 808, 777, 684, 653, 560, 529, 436, 405, 312, 281, 188, 157, 964, 933, 902, 840, 809, 778, 716, 685, 654, 592, 561, 530, 468, 437, 406, 344, 313, 282, 220, 189, 158, 996, 965, 934, 903, 872, 841, 810, 779, 748, 717, 686, 655, 624, 593, 562, 531, 500, 469, 438, 407, 376, 345, 314, 283, 252, 221, 190, 159, 997, 966, 935, 873, 842, 811, 749, 718, 687, 625, 594, 563, 501, 470, 439, 377, 346, 315, 253, 222, 191, 998, 967, 874, 843, 750, 719, 626, 595, 502, 471, 378, 347, 254, 223, 999, 875, 751, 627, 503, 379, 255, 904, 780, 656, 532, 408, 284, 936, 905, 812, 781, 688, 657, 564, 533, 440, 409, 316, 285, 968, 937, 906, 844, 813, 782, 720, 689, 658, 596, 565, 534, 472, 441, 410, 348, 317, 286, 1000, 969, 938, 907, 876, 845, 814, 783, 752, 721, 690, 659, 628, 597, 566, 535, 504, 473, 442, 411, 380, 349, 318, 287, 1001, 970, 939, 877, 846, 815, 753, 722, 691, 629, 598, 567, 505, 474, 443, 381, 350, 319, 1002, 971, 878, 847, 754, 723, 630, 599, 506, 475, 382, 351, 1003, 879, 755, 631, 507, 383, 908, 784, 660, 536, 412, 940, 909, 816, 785, 692, 661, 568, 537, 444, 413, 972, 941, 910, 848, 817, 786, 724, 693, 662, 600, 569, 538, 476, 445, 414, 1004, 973, 942, 911, 880, 849, 818, 787, 756, 725, 694, 663, 632, 601, 570, 539, 508, 477, 446, 415, 1005, 974, 943, 881, 850, 819, 757, 726, 695, 633, 602, 571, 509, 478, 447, 1006, 975, 882, 851, 758, 727, 634, 603, 510, 479, 1007, 883, 759, 635, 511, 912, 788, 664, 540, 944, 913, 820, 789, 696, 665, 572, 541, 976, 945, 914, 852, 821, 790, 728, 697, 666, 604, 573, 542, 1008, 977, 946, 915, 884, 853, 822, 791, 760, 729, 698, 667, 636, 605, 574, 543, 1009, 978, 947, 885, 854, 823, 761, 730, 699, 637, 606, 575, 1010, 979, 886, 855, 762, 731, 638, 607, 1011, 887, 763, 639, 916, 792, 668, 948, 917, 824, 793, 700, 669, 980, 949, 918, 856, 825, 794, 732, 701, 670, 1012, 981, 950, 919, 888, 857, 826, 795, 764, 733, 702, 671, 1013, 982, 951, 889, 858, 827, 765, 734, 703, 1014, 983, 890, 859, 766, 735, 1015, 891, 767, 920, 796, 952, 921, 828, 797, 984, 953, 922, 860, 829, 798, 1016, 985, 954, 923, 892, 861, 830, 799, 1017, 986, 955, 893, 862, 831, 1018, 987, 894, 863, 1019, 895, 924, 956, 925, 988, 957, 926, 1020, 989, 958, 927, 1021, 990, 959, 1022, 991, 1023 }; - -static constexpr TransformSet mode_to_txfm_map[MB_MODE_COUNT] = { - { TransformType::DCT, TransformType::DCT }, // DC - { TransformType::ADST, TransformType::DCT }, // V - { TransformType::DCT, TransformType::ADST }, // H - { TransformType::DCT, TransformType::DCT }, // D45 - { TransformType::ADST, TransformType::ADST }, // D135 - { TransformType::ADST, TransformType::DCT }, // D117 - { TransformType::DCT, TransformType::ADST }, // D153 - { TransformType::DCT, TransformType::ADST }, // D207 - { TransformType::ADST, TransformType::DCT }, // D63 - { TransformType::ADST, TransformType::ADST }, // TM - { TransformType::DCT, TransformType::DCT }, // NEARESTMV - { TransformType::DCT, TransformType::DCT }, // NEARMV - { TransformType::DCT, TransformType::DCT }, // ZEROMV - { TransformType::DCT, TransformType::DCT } // NEWMV -}; - -static constexpr u8 coefband_4x4[16] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5 }; - -static constexpr u8 coefband_8x8plus[1024] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; - -static constexpr u8 energy_class[12] = { 0, 1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5 }; - -static constexpr u8 extra_bits[11][3] = { - { 0, 0, 0 }, - { 0, 0, 1 }, - { 0, 0, 2 }, - { 0, 0, 3 }, - { 0, 0, 4 }, - { 1, 1, 5 }, - { 2, 2, 7 }, - { 3, 3, 11 }, - { 4, 4, 19 }, - { 5, 5, 35 }, - { 6, 14, 67 } -}; - -static constexpr u8 cat_probs[7][14] = { - { 0 }, - { 159 }, - { 165, 145 }, - { 173, 148, 140 }, - { 176, 155, 140, 135 }, - { 180, 157, 141, 134, 130 }, - { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 } -}; - -static constexpr MotionVector mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBORS] = { - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { -2, 0 }, { 0, -2 }, { -2, -1 }, { -1, -2 }, { -2, -2 } }, - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { -2, 0 }, { 0, -2 }, { -2, -1 }, { -1, -2 }, { -2, -2 } }, - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { -2, 0 }, { 0, -2 }, { -2, -1 }, { -1, -2 }, { -2, -2 } }, - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { -2, 0 }, { 0, -2 }, { -2, -1 }, { -1, -2 }, { -2, -2 } }, - { { 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, -1 }, { 0, -2 }, { -2, 0 }, { -2, -1 }, { -1, -2 } }, - { { -1, 0 }, { 0, -1 }, { -1, 1 }, { -1, -1 }, { -2, 0 }, { 0, -2 }, { -1, -2 }, { -2, -1 } }, - { { -1, 0 }, { 0, -1 }, { -1, 1 }, { 1, -1 }, { -1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 } }, - { { 0, -1 }, { -1, 0 }, { 2, -1 }, { -1, -1 }, { -1, 1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } }, - { { -1, 0 }, { 0, -1 }, { -1, 2 }, { -1, -1 }, { 1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 } }, - { { -1, 1 }, { 1, -1 }, { -1, 2 }, { 2, -1 }, { -1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 } }, - { { 0, -1 }, { -1, 0 }, { 4, -1 }, { -1, 2 }, { -1, -1 }, { 0, -3 }, { -3, 0 }, { 2, -1 } }, - { { -1, 0 }, { 0, -1 }, { -1, 4 }, { 2, -1 }, { -1, -1 }, { -3, 0 }, { 0, -3 }, { -1, 2 } }, - { { -1, 3 }, { 3, -1 }, { -1, 4 }, { 4, -1 }, { -1, -1 }, { -1, 0 }, { 0, -1 }, { -1, 6 } } -}; - -static constexpr u8 mode_2_counter[MB_MODE_COUNT] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 3, 1 }; - -static constexpr u8 counter_to_context[19] = { - BOTH_PREDICTED, - NEW_PLUS_NON_INTRA, - BOTH_NEW, - ZERO_PLUS_PREDICTED, - NEW_PLUS_NON_INTRA, - INVALID_CASE, - BOTH_ZERO, - INVALID_CASE, - INVALID_CASE, - INTRA_PLUS_NON_INTRA, - INTRA_PLUS_NON_INTRA, - INVALID_CASE, - INTRA_PLUS_NON_INTRA, - INVALID_CASE, - INVALID_CASE, - INVALID_CASE, - INVALID_CASE, - INVALID_CASE, - BOTH_INTRA -}; - -// Coefficients used by predict_inter -static constexpr i16 subpel_filters[4][16][8] = { - { { 0, 0, 0, 128, 0, 0, 0, 0 }, - { 0, 1, -5, 126, 8, -3, 1, 0 }, - { -1, 3, -10, 122, 18, -6, 2, 0 }, - { -1, 4, -13, 118, 27, -9, 3, -1 }, - { -1, 4, -16, 112, 37, -11, 4, -1 }, - { -1, 5, -18, 105, 48, -14, 4, -1 }, - { -1, 5, -19, 97, 58, -16, 5, -1 }, - { -1, 6, -19, 88, 68, -18, 5, -1 }, - { -1, 6, -19, 78, 78, -19, 6, -1 }, - { -1, 5, -18, 68, 88, -19, 6, -1 }, - { -1, 5, -16, 58, 97, -19, 5, -1 }, - { -1, 4, -14, 48, 105, -18, 5, -1 }, - { -1, 4, -11, 37, 112, -16, 4, -1 }, - { -1, 3, -9, 27, 118, -13, 4, -1 }, - { 0, 2, -6, 18, 122, -10, 3, -1 }, - { 0, 1, -3, 8, 126, -5, 1, 0 } }, - { { 0, 0, 0, 128, 0, 0, 0, 0 }, - { -3, -1, 32, 64, 38, 1, -3, 0 }, - { -2, -2, 29, 63, 41, 2, -3, 0 }, - { -2, -2, 26, 63, 43, 4, -4, 0 }, - { -2, -3, 24, 62, 46, 5, -4, 0 }, - { -2, -3, 21, 60, 49, 7, -4, 0 }, - { -1, -4, 18, 59, 51, 9, -4, 0 }, - { -1, -4, 16, 57, 53, 12, -4, -1 }, - { -1, -4, 14, 55, 55, 14, -4, -1 }, - { -1, -4, 12, 53, 57, 16, -4, -1 }, - { 0, -4, 9, 51, 59, 18, -4, -1 }, - { 0, -4, 7, 49, 60, 21, -3, -2 }, - { 0, -4, 5, 46, 62, 24, -3, -2 }, - { 0, -4, 4, 43, 63, 26, -2, -2 }, - { 0, -3, 2, 41, 63, 29, -2, -2 }, - { 0, -3, 1, 38, 64, 32, -1, -3 } }, - { { 0, 0, 0, 128, 0, 0, 0, 0 }, - { -1, 3, -7, 127, 8, -3, 1, 0 }, - { -2, 5, -13, 125, 17, -6, 3, -1 }, - { -3, 7, -17, 121, 27, -10, 5, -2 }, - { -4, 9, -20, 115, 37, -13, 6, -2 }, - { -4, 10, -23, 108, 48, -16, 8, -3 }, - { -4, 10, -24, 100, 59, -19, 9, -3 }, - { -4, 11, -24, 90, 70, -21, 10, -4 }, - { -4, 11, -23, 80, 80, -23, 11, -4 }, - { -4, 10, -21, 70, 90, -24, 11, -4 }, - { -3, 9, -19, 59, 100, -24, 10, -4 }, - { -3, 8, -16, 48, 108, -23, 10, -4 }, - { -2, 6, -13, 37, 115, -20, 9, -4 }, - { -2, 5, -10, 27, 121, -17, 7, -3 }, - { -1, 3, -6, 17, 125, -13, 5, -2 }, - { 0, 1, -3, 8, 127, -7, 3, -1 } }, - { { 0, 0, 0, 128, 0, 0, 0, 0 }, - { 0, 0, 0, 120, 8, 0, 0, 0 }, - { 0, 0, 0, 112, 16, 0, 0, 0 }, - { 0, 0, 0, 104, 24, 0, 0, 0 }, - { 0, 0, 0, 96, 32, 0, 0, 0 }, - { 0, 0, 0, 88, 40, 0, 0, 0 }, - { 0, 0, 0, 80, 48, 0, 0, 0 }, - { 0, 0, 0, 72, 56, 0, 0, 0 }, - { 0, 0, 0, 64, 64, 0, 0, 0 }, - { 0, 0, 0, 56, 72, 0, 0, 0 }, - { 0, 0, 0, 48, 80, 0, 0, 0 }, - { 0, 0, 0, 40, 88, 0, 0, 0 }, - { 0, 0, 0, 32, 96, 0, 0, 0 }, - { 0, 0, 0, 24, 104, 0, 0, 0 }, - { 0, 0, 0, 16, 112, 0, 0, 0 }, - { 0, 0, 0, 8, 120, 0, 0, 0 } } -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/MotionVector.h b/Userland/Libraries/LibMedia/Video/VP9/MotionVector.h deleted file mode 100644 index 0d96fa40151..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/MotionVector.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Media::Video::VP9 { - -struct MotionVector { -public: - constexpr MotionVector() = default; - constexpr MotionVector(MotionVector const& other) = default; - constexpr MotionVector(i32 row, i32 col) - : m_row(row) - , m_column(col) - { - } - - constexpr MotionVector& operator=(MotionVector const& other) = default; - constexpr MotionVector& operator=(MotionVector&& other) = default; - - constexpr i32 row() const { return m_row; } - constexpr void set_row(i32 row) { m_row = row; } - constexpr i32 column() const { return m_column; } - constexpr void set_column(i32 col) { m_column = col; } - - constexpr MotionVector operator+(MotionVector const& other) const - { - return MotionVector(this->row() + other.row(), this->column() + other.column()); - } - constexpr MotionVector& operator+=(MotionVector const& other) - { - *this = *this + other; - return *this; - } - - constexpr MotionVector operator*(i32 scalar) const - { - return MotionVector(this->row() * scalar, this->column() * scalar); - } - constexpr MotionVector& operator*=(i32 scalar) - { - *this = *this * scalar; - return *this; - } - - constexpr bool operator==(MotionVector const& other) const - { - return this->row() == other.row() && this->column() == other.column(); - } - -private: - i32 m_row { 0 }; - i32 m_column { 0 }; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Parser.cpp b/Userland/Libraries/LibMedia/Video/VP9/Parser.cpp deleted file mode 100644 index 0fcc2332f0e..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Parser.cpp +++ /dev/null @@ -1,1782 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -#include "Context.h" -#include "Decoder.h" -#include "Parser.h" -#include "Utilities.h" - -#if defined(AK_COMPILER_GCC) -# pragma GCC optimize("O3") -#endif - -// Beware, threading is unstable in Serenity with smp=on, and performs worse than with it off. -#define VP9_TILE_THREADING - -namespace Media::Video::VP9 { - -#define TRY_READ(expression) DECODER_TRY(DecoderErrorCategory::Corrupted, expression) - -Parser::Parser(Decoder& decoder) - : m_decoder(decoder) -{ -} - -Parser::~Parser() -{ -} - -Vector Parser::parse_superframe_sizes(ReadonlyBytes frame_data) -{ - if (frame_data.size() < 1) - return {}; - - // The decoder determines the presence of a superframe by: - // 1. parsing the final byte of the chunk and checking that the superframe_marker equals 0b110, - - // If the checks in steps 1 and 3 both pass, then the chunk is determined to contain a superframe and each - // frame in the superframe is passed to the decoding process in turn. - // Otherwise, the chunk is determined to not contain a superframe, and the whole chunk is passed to the - // decoding process. - - // NOTE: Reading from span data will be quicker than spinning up a BitStream. - u8 superframe_byte = frame_data[frame_data.size() - 1]; - - // NOTE: We have to read out of the byte from the little end first, hence the padding bits in the masks below. - u8 superframe_marker = superframe_byte & 0b1110'0000; - if (superframe_marker == 0b1100'0000) { - u8 bytes_per_framesize = ((superframe_byte >> 3) & 0b11) + 1; - u8 frames_in_superframe = (superframe_byte & 0b111) + 1; - // 2. setting the total size of the superframe_index SzIndex equal to 2 + NumFrames * SzBytes, - size_t index_size = 2 + bytes_per_framesize * frames_in_superframe; - - if (index_size > frame_data.size()) - return {}; - - auto superframe_header_data = frame_data.data() + frame_data.size() - index_size; - - u8 start_superframe_byte = *(superframe_header_data++); - // 3. checking that the first byte of the superframe_index matches the final byte. - if (superframe_byte != start_superframe_byte) - return {}; - - Vector result; - for (u8 i = 0; i < frames_in_superframe; i++) { - size_t frame_size = 0; - for (u8 j = 0; j < bytes_per_framesize; j++) - frame_size |= (static_cast(*(superframe_header_data++)) << (j * 8)); - result.append(frame_size); - } - return result; - } - - return {}; -} - -/* (6.1) */ -DecoderErrorOr Parser::parse_frame(ReadonlyBytes frame_data) -{ - if (!m_probability_tables) - m_probability_tables = DECODER_TRY_ALLOC(try_make()); - - // 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. - 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); - - TRY(compressed_header(frame_context)); - - TRY(m_decoder.allocate_buffers(frame_context)); - - TRY(decode_tiles(frame_context)); - TRY(refresh_probs(frame_context)); - - m_previous_frame_type = frame_context.type; - m_previous_frame_size = frame_context.size(); - m_previous_show_frame = frame_context.shows_a_frame(); - m_previous_color_config = frame_context.color_config; - m_previous_loop_filter_ref_deltas = frame_context.loop_filter_reference_deltas; - m_previous_loop_filter_mode_deltas = frame_context.loop_filter_mode_deltas; - - if (frame_context.segmentation_enabled) { - m_previous_should_use_absolute_segment_base_quantizer = frame_context.should_use_absolute_segment_base_quantizer; - m_previous_segmentation_features = frame_context.segmentation_features; - } - - return frame_context; -} - -DecoderErrorOr 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)); - 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)); - } - } - if (frame_context.should_replace_probability_context) - m_probability_tables->save_probs(frame_context.probability_context_index); - return {}; -} - -DecoderErrorOr Parser::read_video_full_range_flag(BigEndianInputBitStream& bit_stream) -{ - if (TRY_READ(bit_stream.read_bit())) - return VideoFullRangeFlag::Full; - return VideoFullRangeFlag::Studio; -} - -template -static ErrorOr read_signed(BigEndianInputBitStream& bit_stream, u8 bits) -{ - auto value_unsigned = static_cast(TRY(bit_stream.read_bits(bits))); - if (TRY(bit_stream.read_bit())) - return -value_unsigned; - return value_unsigned; -} - -static DecoderErrorOr read_delta_q(BigEndianInputBitStream& bit_stream) -{ - if (TRY_READ(bit_stream.read_bit())) - return TRY_READ(read_signed(bit_stream, 4)); - return 0; -} - -struct QuantizationParameters { - u8 base_quantizer_index { 0 }; - i8 y_dc_quantizer_index_delta { 0 }; - i8 uv_dc_quantizer_index_delta { 0 }; - i8 uv_ac_quantizer_index_delta { 0 }; -}; - -static DecoderErrorOr quantization_params(BigEndianInputBitStream& bit_stream) -{ - QuantizationParameters result; - result.base_quantizer_index = TRY_READ(bit_stream.read_bits(8)); - result.y_dc_quantizer_index_delta = TRY(read_delta_q(bit_stream)); - result.uv_dc_quantizer_index_delta = TRY(read_delta_q(bit_stream)); - result.uv_ac_quantizer_index_delta = TRY(read_delta_q(bit_stream)); - return result; -} - -/* (6.2) */ -DecoderErrorOr Parser::uncompressed_header(FrameContext& frame_context) -{ - frame_context.color_config = m_previous_color_config; - - auto frame_marker = TRY_READ(frame_context.bit_stream.read_bits(2)); - if (frame_marker != 2) - return DecoderError::corrupted("uncompressed_header: Frame marker must be 2"sv); - - auto profile_low_bit = TRY_READ(frame_context.bit_stream.read_bit()); - auto profile_high_bit = TRY_READ(frame_context.bit_stream.read_bit()); - frame_context.profile = (profile_high_bit << 1u) + profile_low_bit; - if (frame_context.profile == 3 && TRY_READ(frame_context.bit_stream.read_bit())) - return DecoderError::corrupted("uncompressed_header: Profile 3 reserved bit was non-zero"sv); - - if (TRY_READ(frame_context.bit_stream.read_bit())) { - frame_context.set_existing_frame_to_show(TRY_READ(frame_context.bit_stream.read_bits(3))); - return {}; - } - - bool is_keyframe = !TRY_READ(frame_context.bit_stream.read_bit()); - - if (!TRY_READ(frame_context.bit_stream.read_bit())) - frame_context.set_frame_hidden(); - - frame_context.error_resilient_mode = TRY_READ(frame_context.bit_stream.read_bit()); - - FrameType type; - - Gfx::Size frame_size; - Gfx::Size render_size; - u8 reference_frames_to_update_flags = 0xFF; // Save frame to all reference indices by default. - - enum class ResetProbabilities : u8 { - No = 0, - // 1 also means No here, but we don't need to do anything with the No case. - OnlyCurrent = 2, - All = 3, - }; - ResetProbabilities reset_frame_context = ResetProbabilities::All; - - if (is_keyframe) { - type = FrameType::KeyFrame; - TRY(frame_sync_code(frame_context.bit_stream)); - frame_context.color_config = TRY(parse_color_config(frame_context.bit_stream, frame_context.profile)); - frame_size = TRY(parse_frame_size(frame_context.bit_stream)); - render_size = TRY(parse_render_size(frame_context.bit_stream, frame_size)); - } else { - if (!frame_context.shows_a_frame() && TRY_READ(frame_context.bit_stream.read_bit())) { - type = FrameType::IntraOnlyFrame; - } else { - type = FrameType::InterFrame; - reset_frame_context = ResetProbabilities::No; - } - - if (!frame_context.error_resilient_mode) - reset_frame_context = static_cast(TRY_READ(frame_context.bit_stream.read_bits(2))); - - if (type == FrameType::IntraOnlyFrame) { - TRY(frame_sync_code(frame_context.bit_stream)); - - if (frame_context.profile == 0) { - frame_context.color_config = ColorConfig(); - } else { - frame_context.color_config = TRY(parse_color_config(frame_context.bit_stream, frame_context.profile)); - } - - reference_frames_to_update_flags = TRY_READ(frame_context.bit_stream.read_bits(8)); - frame_size = TRY(parse_frame_size(frame_context.bit_stream)); - render_size = TRY(parse_render_size(frame_context.bit_stream, frame_size)); - } else { - reference_frames_to_update_flags = TRY_READ(frame_context.bit_stream.read_bits(NUM_REF_FRAMES)); - for (auto i = 0; i < REFS_PER_FRAME; i++) { - frame_context.reference_frame_indices[i] = TRY_READ(frame_context.bit_stream.read_bits(LOG2_OF_NUM_REF_FRAMES)); - frame_context.reference_frame_sign_biases[ReferenceFrameType::LastFrame + i] = TRY_READ(frame_context.bit_stream.read_bit()); - } - frame_size = TRY(parse_frame_size_with_refs(frame_context.bit_stream, frame_context.reference_frame_indices)); - render_size = TRY(parse_render_size(frame_context.bit_stream, frame_size)); - frame_context.high_precision_motion_vectors_allowed = TRY_READ(frame_context.bit_stream.read_bit()); - frame_context.interpolation_filter = TRY(read_interpolation_filter(frame_context.bit_stream)); - for (auto i = 0; i < REFS_PER_FRAME; i++) { - TRY(m_decoder.prepare_referenced_frame(frame_size, frame_context.reference_frame_indices[i])); - } - } - } - - bool should_replace_probability_context = false; - bool parallel_decoding_mode = true; - if (!frame_context.error_resilient_mode) { - should_replace_probability_context = TRY_READ(frame_context.bit_stream.read_bit()); - parallel_decoding_mode = TRY_READ(frame_context.bit_stream.read_bit()); - } - - u8 probability_context_index = TRY_READ(frame_context.bit_stream.read_bits(2)); - switch (reset_frame_context) { - case ResetProbabilities::All: - setup_past_independence(); - for (auto i = 0; i < 4; i++) { - m_probability_tables->save_probs(i); - } - probability_context_index = 0; - break; - case ResetProbabilities::OnlyCurrent: - setup_past_independence(); - m_probability_tables->save_probs(probability_context_index); - probability_context_index = 0; - break; - default: - break; - } - - frame_context.type = type; - DECODER_TRY_ALLOC(frame_context.set_size(frame_size)); - frame_context.render_size = render_size; - TRY(compute_image_size(frame_context)); - - frame_context.reference_frames_to_update_flags = reference_frames_to_update_flags; - frame_context.parallel_decoding_mode = parallel_decoding_mode; - - frame_context.should_replace_probability_context = should_replace_probability_context; - frame_context.probability_context_index = probability_context_index; - - TRY(loop_filter_params(frame_context)); - auto quantization_parameters = TRY(quantization_params(frame_context.bit_stream)); - TRY(segmentation_params(frame_context)); - precalculate_quantizers(frame_context, quantization_parameters); - - TRY(parse_tile_counts(frame_context)); - - frame_context.header_size_in_bytes = TRY_READ(frame_context.bit_stream.read_bits(16)); - - frame_context.bit_stream.align_to_byte_boundary(); - return {}; -} - -DecoderErrorOr Parser::frame_sync_code(BigEndianInputBitStream& bit_stream) -{ - if (TRY_READ(bit_stream.read_bits(24)) != 0x498342) { - return DecoderError::corrupted("frame sync code was not 0x498342."sv); - } - return {}; -} - -DecoderErrorOr Parser::parse_color_config(BigEndianInputBitStream& bit_stream, u8 profile) -{ - // (6.2.2) color_config( ) - u8 bit_depth; - if (profile >= 2) { - bit_depth = TRY_READ(bit_stream.read_bit()) ? 12 : 10; - } else { - bit_depth = 8; - } - - auto color_space = static_cast(TRY_READ(bit_stream.read_bits(3))); - if (color_space == ColorSpace::Reserved) - return DecoderError::corrupted("color_config: Color space reserved value was set"sv); - - VERIFY(color_space <= ColorSpace::RGB); - - VideoFullRangeFlag video_full_range_flag; - bool subsampling_x, subsampling_y; - - if (color_space != ColorSpace::RGB) { - video_full_range_flag = TRY(read_video_full_range_flag(bit_stream)); - if (profile == 1 || profile == 3) { - subsampling_x = TRY_READ(bit_stream.read_bit()); - subsampling_y = TRY_READ(bit_stream.read_bit()); - if (TRY_READ(bit_stream.read_bit())) - return DecoderError::corrupted("color_config: Subsampling reserved zero was set"sv); - } else { - subsampling_x = true; - subsampling_y = true; - } - } else { - video_full_range_flag = VideoFullRangeFlag::Full; - if (profile == 1 || profile == 3) { - subsampling_x = false; - subsampling_y = false; - if (TRY_READ(bit_stream.read_bit())) - return DecoderError::corrupted("color_config: RGB reserved zero was set"sv); - } else { - // FIXME: Spec does not specify the subsampling value here. Is this an error or should we set a default? - return DecoderError::corrupted("color_config: Invalid subsampling value for profile 0 or 2"sv); - } - } - - return ColorConfig { bit_depth, color_space, video_full_range_flag, subsampling_x, subsampling_y }; -} - -DecoderErrorOr> Parser::parse_frame_size(BigEndianInputBitStream& bit_stream) -{ - return Gfx::Size { TRY_READ(bit_stream.read_bits(16)) + 1, TRY_READ(bit_stream.read_bits(16)) + 1 }; -} - -DecoderErrorOr> Parser::parse_render_size(BigEndianInputBitStream& bit_stream, Gfx::Size frame_size) -{ - // FIXME: This function should save this bit as a value in the FrameContext. The bit can be - // used in files where the pixel aspect ratio changes between samples in the video. - // If the bit is set, the pixel aspect ratio should be recalculated, whereas if only - // the frame size has changed and the render size is unadjusted, then the pixel aspect - // ratio should be retained and the new render size determined based on that. - // See the Firefox source code here: - // https://searchfox.org/mozilla-central/source/dom/media/platforms/wrappers/MediaChangeMonitor.cpp#268-276 - if (!TRY_READ(bit_stream.read_bit())) - return frame_size; - return Gfx::Size { TRY_READ(bit_stream.read_bits(16)) + 1, TRY_READ(bit_stream.read_bits(16)) + 1 }; -} - -DecoderErrorOr> Parser::parse_frame_size_with_refs(BigEndianInputBitStream& bit_stream, Array const& reference_indices) -{ - Optional> size; - for (auto frame_index : reference_indices) { - if (TRY_READ(bit_stream.read_bit())) { - if (!m_reference_frames[frame_index].is_valid()) - return DecoderError::corrupted("Frame size referenced a frame that does not exist"sv); - size.emplace(m_reference_frames[frame_index].size); - break; - } - } - - if (size.has_value()) - return size.value(); - - return TRY(parse_frame_size(bit_stream)); -} - -DecoderErrorOr Parser::compute_image_size(FrameContext& frame_context) -{ - // 7.2.6 Compute image size semantics - // When compute_image_size is invoked, the following ordered steps occur: - // 1. If this is the first time compute_image_size is invoked, or if either FrameWidth or FrameHeight have - // changed in value compared to the previous time this function was invoked, then the segmentation map is - // cleared to all zeros by setting SegmentId[ row ][ col ] equal to 0 for row = 0..MiRows-1 and col = - // 0..MiCols-1. - // FIXME: What does this mean? SegmentIds is scoped to one frame, so it will not contain values here. It's - // also suspicious that spec refers to this as SegmentId rather than SegmentIds (plural). Is this - // supposed to refer to PrevSegmentIds? - bool first_invoke = m_is_first_compute_image_size_invoke; - m_is_first_compute_image_size_invoke = false; - bool same_size = m_previous_frame_size == frame_context.size(); - - // 2. The variable UsePrevFrameMvs is set equal to 1 if all of the following conditions are true: - // a. This is not the first time compute_image_size is invoked. - // b. Both FrameWidth and FrameHeight have the same value compared to the previous time this function - // was invoked. - // c. show_frame was equal to 1 the previous time this function was invoked. - // d. error_resilient_mode is equal to 0. - // e. FrameIsIntra is equal to 0. - // Otherwise, UsePrevFrameMvs is set equal to 0. - frame_context.use_previous_frame_motion_vectors = !first_invoke && same_size && m_previous_show_frame && !frame_context.error_resilient_mode && frame_context.is_inter_predicted(); - return {}; -} - -DecoderErrorOr Parser::read_interpolation_filter(BigEndianInputBitStream& bit_stream) -{ - if (TRY_READ(bit_stream.read_bit())) { - return InterpolationFilter::Switchable; - } - return literal_to_type[TRY_READ(bit_stream.read_bits(2))]; -} - -DecoderErrorOr Parser::loop_filter_params(FrameContext& frame_context) -{ - // FIXME: These should be moved to their own struct to return here. - frame_context.loop_filter_level = TRY_READ(frame_context.bit_stream.read_bits(6)); - frame_context.loop_filter_sharpness = TRY_READ(frame_context.bit_stream.read_bits(3)); - frame_context.loop_filter_delta_enabled = TRY_READ(frame_context.bit_stream.read_bit()); - - auto reference_deltas = m_previous_loop_filter_ref_deltas; - auto mode_deltas = m_previous_loop_filter_mode_deltas; - if (frame_context.loop_filter_delta_enabled && TRY_READ(frame_context.bit_stream.read_bit())) { - for (auto& loop_filter_ref_delta : reference_deltas) { - if (TRY_READ(frame_context.bit_stream.read_bit())) - loop_filter_ref_delta = TRY_READ(read_signed(frame_context.bit_stream, 6)); - } - for (auto& loop_filter_mode_delta : mode_deltas) { - if (TRY_READ(frame_context.bit_stream.read_bit())) - loop_filter_mode_delta = TRY_READ(read_signed(frame_context.bit_stream, 6)); - } - } - frame_context.loop_filter_reference_deltas = reference_deltas; - frame_context.loop_filter_mode_deltas = mode_deltas; - - return {}; -} - -DecoderErrorOr Parser::segmentation_params(FrameContext& frame_context) -{ - frame_context.segmentation_enabled = TRY_READ(frame_context.bit_stream.read_bit()); - if (!frame_context.segmentation_enabled) - return {}; - - frame_context.should_use_absolute_segment_base_quantizer = m_previous_should_use_absolute_segment_base_quantizer; - frame_context.segmentation_features = m_previous_segmentation_features; - - if (TRY_READ(frame_context.bit_stream.read_bit())) { - frame_context.use_full_segment_id_tree = true; - for (auto& segmentation_tree_prob : frame_context.full_segment_id_tree_probabilities) - segmentation_tree_prob = TRY(read_prob(frame_context.bit_stream)); - - if (TRY_READ(frame_context.bit_stream.read_bit())) { - frame_context.use_predicted_segment_id_tree = true; - for (auto& segmentation_pred_prob : frame_context.predicted_segment_id_tree_probabilities) - segmentation_pred_prob = TRY(read_prob(frame_context.bit_stream)); - } - } - - auto segmentation_update_data = (TRY_READ(frame_context.bit_stream.read_bit())); - - if (!segmentation_update_data) - return {}; - - frame_context.should_use_absolute_segment_base_quantizer = TRY_READ(frame_context.bit_stream.read_bit()); - for (auto segment_id = 0; segment_id < MAX_SEGMENTS; segment_id++) { - for (auto feature_id = 0; feature_id < to_underlying(SegmentFeature::Sentinel); feature_id++) { - auto& feature = frame_context.segmentation_features[segment_id][feature_id]; - feature.enabled = TRY_READ(frame_context.bit_stream.read_bit()); - if (feature.enabled) { - auto bits_to_read = segmentation_feature_bits[feature_id]; - feature.value = TRY_READ(frame_context.bit_stream.read_bits(bits_to_read)); - if (segmentation_feature_signed[feature_id]) { - if (TRY_READ(frame_context.bit_stream.read_bit())) - feature.value = -feature.value; - } - } - } - } - - return {}; -} - -DecoderErrorOr Parser::read_prob(BigEndianInputBitStream& bit_stream) -{ - if (TRY_READ(bit_stream.read_bit())) - return TRY_READ(bit_stream.read_bits(8)); - return 255; -} - -void Parser::precalculate_quantizers(FrameContext& frame_context, QuantizationParameters quantization_parameters) -{ - frame_context.lossless = quantization_parameters.base_quantizer_index == 0 - && quantization_parameters.y_dc_quantizer_index_delta == 0 - && quantization_parameters.uv_dc_quantizer_index_delta == 0 - && quantization_parameters.uv_ac_quantizer_index_delta == 0; - - // Pre-calculate the quantizers so that the decoder doesn't have to do it repeatedly. - for (u8 segment_id = 0; segment_id < MAX_SEGMENTS; segment_id++) { - auto alternative_quantizer_feature = frame_context.get_segment_feature(segment_id, SegmentFeature::AlternativeQuantizerBase); - auto base = Decoder::get_base_quantizer_index(alternative_quantizer_feature, frame_context.should_use_absolute_segment_base_quantizer, quantization_parameters.base_quantizer_index); - - // The function get_ac_quant( plane ) returns the quantizer value for the ac coefficient for a particular plane and - // is derived as follows: - // − If plane is equal to 0, return ac_q( get_qindex( ) ). - // − Otherwise, return ac_q( get_qindex( ) + delta_q_uv_ac ). - auto& current_quantizers = frame_context.segment_quantizers[segment_id]; - current_quantizers.y_ac_quantizer = Decoder::get_ac_quantizer(frame_context.color_config.bit_depth, base, 0); - current_quantizers.uv_ac_quantizer = Decoder::get_ac_quantizer(frame_context.color_config.bit_depth, base, quantization_parameters.uv_ac_quantizer_index_delta); - - // The function get_dc_quant( plane ) returns the quantizer value for the dc coefficient for a particular plane and - // is derived as follows: - // − If plane is equal to 0, return dc_q( get_qindex( ) + delta_q_y_dc ). - // − Otherwise, return dc_q( get_qindex( ) + delta_q_uv_dc ). - current_quantizers.y_dc_quantizer = Decoder::get_dc_quantizer(frame_context.color_config.bit_depth, base, quantization_parameters.y_dc_quantizer_index_delta); - current_quantizers.uv_dc_quantizer = Decoder::get_dc_quantizer(frame_context.color_config.bit_depth, base, quantization_parameters.uv_dc_quantizer_index_delta); - } -} - -static u16 calc_min_log2_of_tile_columns(u32 superblock_columns) -{ - auto min_log_2 = 0u; - while ((u32)(MAX_TILE_WIDTH_B64 << min_log_2) < superblock_columns) - min_log_2++; - return min_log_2; -} - -static u16 calc_max_log2_tile_cols(u32 superblock_columns) -{ - u16 max_log_2 = 1; - while ((superblock_columns >> max_log_2) >= MIN_TILE_WIDTH_B64) - max_log_2++; - return max_log_2 - 1; -} - -DecoderErrorOr Parser::parse_tile_counts(FrameContext& frame_context) -{ - auto superblock_columns = frame_context.superblock_columns(); - - auto log2_of_tile_columns = calc_min_log2_of_tile_columns(superblock_columns); - auto log2_of_tile_columns_maximum = calc_max_log2_tile_cols(superblock_columns); - while (log2_of_tile_columns < log2_of_tile_columns_maximum) { - if (TRY_READ(frame_context.bit_stream.read_bit())) - log2_of_tile_columns++; - else - break; - } - - u16 log2_of_tile_rows = TRY_READ(frame_context.bit_stream.read_bit()); - if (log2_of_tile_rows > 0) { - log2_of_tile_rows += TRY_READ(frame_context.bit_stream.read_bit()); - } - frame_context.log2_of_tile_counts = Gfx::Size(log2_of_tile_columns, log2_of_tile_rows); - return {}; -} - -void Parser::setup_past_independence() -{ - m_previous_block_contexts.reset(); - m_previous_loop_filter_ref_deltas[ReferenceFrameType::None] = 1; - m_previous_loop_filter_ref_deltas[ReferenceFrameType::LastFrame] = 0; - m_previous_loop_filter_ref_deltas[ReferenceFrameType::GoldenFrame] = -1; - m_previous_loop_filter_ref_deltas[ReferenceFrameType::AltRefFrame] = -1; - m_previous_loop_filter_mode_deltas.fill(0); - m_previous_should_use_absolute_segment_base_quantizer = false; - for (auto& segment_levels : m_previous_segmentation_features) - segment_levels.fill({ false, 0 }); - m_probability_tables->reset_probs(); -} - -DecoderErrorOr Parser::compressed_header(FrameContext& frame_context) -{ - auto decoder = TRY(frame_context.create_range_decoder(frame_context.header_size_in_bytes)); - - frame_context.transform_mode = read_tx_mode(decoder, frame_context); - if (frame_context.transform_mode == TransformMode::Select) - tx_mode_probs(decoder); - read_coef_probs(decoder, frame_context.transform_mode); - read_skip_prob(decoder); - if (frame_context.is_inter_predicted()) { - read_inter_mode_probs(decoder); - if (frame_context.interpolation_filter == Switchable) - read_interp_filter_probs(decoder); - read_is_inter_probs(decoder); - frame_reference_mode(frame_context, decoder); - frame_reference_mode_probs(decoder, frame_context); - read_y_mode_probs(decoder); - read_partition_probs(decoder); - mv_probs(decoder, frame_context); - } - TRY_READ(decoder.finish_decode()); - return {}; -} - -TransformMode Parser::read_tx_mode(BooleanDecoder& decoder, FrameContext const& frame_context) -{ - if (frame_context.lossless) { - return TransformMode::Only_4x4; - } - - auto tx_mode = decoder.read_literal(2); - if (tx_mode == to_underlying(TransformMode::Allow_32x32)) - tx_mode += decoder.read_literal(1); - return static_cast(tx_mode); -} - -void Parser::tx_mode_probs(BooleanDecoder& decoder) -{ - auto& tx_probs = m_probability_tables->tx_probs(); - for (auto i = 0; i < TX_SIZE_CONTEXTS; i++) { - for (auto j = 0; j < TX_SIZES - 3; j++) - tx_probs[Transform_8x8][i][j] = diff_update_prob(decoder, tx_probs[Transform_8x8][i][j]); - } - for (auto i = 0; i < TX_SIZE_CONTEXTS; i++) { - for (auto j = 0; j < TX_SIZES - 2; j++) - tx_probs[Transform_16x16][i][j] = diff_update_prob(decoder, tx_probs[Transform_16x16][i][j]); - } - for (auto i = 0; i < TX_SIZE_CONTEXTS; i++) { - for (auto j = 0; j < TX_SIZES - 1; j++) - tx_probs[Transform_32x32][i][j] = diff_update_prob(decoder, tx_probs[Transform_32x32][i][j]); - } -} - -u8 Parser::diff_update_prob(BooleanDecoder& decoder, u8 prob) -{ - auto update_prob = decoder.read_bool(252); - if (update_prob) { - auto delta_prob = decode_term_subexp(decoder); - prob = inv_remap_prob(delta_prob, prob); - } - return prob; -} - -u8 Parser::decode_term_subexp(BooleanDecoder& decoder) -{ - if (decoder.read_literal(1) == 0) - return decoder.read_literal(4); - if (decoder.read_literal(1) == 0) - return decoder.read_literal(4) + 16; - if (decoder.read_literal(1) == 0) - return decoder.read_literal(5) + 32; - - auto v = decoder.read_literal(7); - if (v < 65) - return v + 64; - return (v << 1u) - 1 + decoder.read_literal(1); -} - -u8 Parser::inv_remap_prob(u8 delta_prob, u8 prob) -{ - u8 m = prob - 1; - auto v = inv_map_table[delta_prob]; - if ((m << 1u) <= 255) - return 1 + inv_recenter_nonneg(v, m); - return 255 - inv_recenter_nonneg(v, 254 - m); -} - -u8 Parser::inv_recenter_nonneg(u8 v, u8 m) -{ - if (v > 2 * m) - return v; - if (v & 1u) - return m - ((v + 1u) >> 1u); - return m + (v >> 1u); -} - -void Parser::read_coef_probs(BooleanDecoder& decoder, TransformMode transform_mode) -{ - auto max_tx_size = tx_mode_to_biggest_tx_size[to_underlying(transform_mode)]; - for (u8 transform_size = 0; transform_size <= max_tx_size; transform_size++) { - auto update_probs = decoder.read_literal(1); - if (update_probs == 1) { - for (auto i = 0; i < 2; i++) { - for (auto j = 0; j < 2; j++) { - for (auto k = 0; k < 6; k++) { - auto max_l = (k == 0) ? 3 : 6; - for (auto l = 0; l < max_l; l++) { - for (auto m = 0; m < 3; m++) { - auto& prob = m_probability_tables->coef_probs()[transform_size][i][j][k][l][m]; - prob = diff_update_prob(decoder, prob); - } - } - } - } - } - } - } -} - -void Parser::read_skip_prob(BooleanDecoder& decoder) -{ - for (auto i = 0; i < SKIP_CONTEXTS; i++) - m_probability_tables->skip_prob()[i] = diff_update_prob(decoder, m_probability_tables->skip_prob()[i]); -} - -void Parser::read_inter_mode_probs(BooleanDecoder& decoder) -{ - for (auto i = 0; i < INTER_MODE_CONTEXTS; i++) { - for (auto j = 0; j < INTER_MODES - 1; j++) - m_probability_tables->inter_mode_probs()[i][j] = diff_update_prob(decoder, m_probability_tables->inter_mode_probs()[i][j]); - } -} - -void Parser::read_interp_filter_probs(BooleanDecoder& decoder) -{ - for (auto i = 0; i < INTERP_FILTER_CONTEXTS; i++) { - for (auto j = 0; j < SWITCHABLE_FILTERS - 1; j++) - m_probability_tables->interp_filter_probs()[i][j] = diff_update_prob(decoder, m_probability_tables->interp_filter_probs()[i][j]); - } -} - -void Parser::read_is_inter_probs(BooleanDecoder& decoder) -{ - for (auto i = 0; i < IS_INTER_CONTEXTS; i++) - m_probability_tables->is_inter_prob()[i] = diff_update_prob(decoder, m_probability_tables->is_inter_prob()[i]); -} - -static void setup_compound_reference_mode(FrameContext& frame_context) -{ - ReferenceFrameType fixed_reference; - ReferenceFramePair variable_references; - if (frame_context.reference_frame_sign_biases[ReferenceFrameType::LastFrame] == frame_context.reference_frame_sign_biases[ReferenceFrameType::GoldenFrame]) { - fixed_reference = ReferenceFrameType::AltRefFrame; - variable_references = { ReferenceFrameType::LastFrame, ReferenceFrameType::GoldenFrame }; - } else if (frame_context.reference_frame_sign_biases[ReferenceFrameType::LastFrame] == frame_context.reference_frame_sign_biases[ReferenceFrameType::AltRefFrame]) { - fixed_reference = ReferenceFrameType::GoldenFrame; - variable_references = { ReferenceFrameType::LastFrame, ReferenceFrameType::AltRefFrame }; - } else { - fixed_reference = ReferenceFrameType::LastFrame; - variable_references = { ReferenceFrameType::GoldenFrame, ReferenceFrameType::AltRefFrame }; - } - frame_context.fixed_reference_type = fixed_reference; - frame_context.variable_reference_types = variable_references; -} - -void Parser::frame_reference_mode(FrameContext& frame_context, BooleanDecoder& decoder) -{ - auto compound_reference_allowed = false; - for (size_t i = 2; i <= REFS_PER_FRAME; i++) { - if (frame_context.reference_frame_sign_biases[i] != frame_context.reference_frame_sign_biases[1]) - compound_reference_allowed = true; - } - ReferenceMode reference_mode; - if (compound_reference_allowed) { - auto non_single_reference = decoder.read_literal(1); - if (non_single_reference == 0) { - reference_mode = SingleReference; - } else { - auto reference_select = decoder.read_literal(1); - if (reference_select == 0) - reference_mode = CompoundReference; - else - reference_mode = ReferenceModeSelect; - } - } else { - reference_mode = SingleReference; - } - frame_context.reference_mode = reference_mode; - if (reference_mode != SingleReference) - setup_compound_reference_mode(frame_context); -} - -void Parser::frame_reference_mode_probs(BooleanDecoder& decoder, FrameContext const& frame_context) -{ - if (frame_context.reference_mode == ReferenceModeSelect) { - for (auto i = 0; i < COMP_MODE_CONTEXTS; i++) { - auto& comp_mode_prob = m_probability_tables->comp_mode_prob(); - comp_mode_prob[i] = diff_update_prob(decoder, comp_mode_prob[i]); - } - } - if (frame_context.reference_mode != CompoundReference) { - for (auto i = 0; i < REF_CONTEXTS; i++) { - auto& single_ref_prob = m_probability_tables->single_ref_prob(); - single_ref_prob[i][0] = diff_update_prob(decoder, single_ref_prob[i][0]); - single_ref_prob[i][1] = diff_update_prob(decoder, single_ref_prob[i][1]); - } - } - if (frame_context.reference_mode != SingleReference) { - for (auto i = 0; i < REF_CONTEXTS; i++) { - auto& comp_ref_prob = m_probability_tables->comp_ref_prob(); - comp_ref_prob[i] = diff_update_prob(decoder, comp_ref_prob[i]); - } - } -} - -void Parser::read_y_mode_probs(BooleanDecoder& decoder) -{ - for (auto i = 0; i < BLOCK_SIZE_GROUPS; i++) { - for (auto j = 0; j < INTRA_MODES - 1; j++) { - auto& y_mode_probs = m_probability_tables->y_mode_probs(); - y_mode_probs[i][j] = diff_update_prob(decoder, y_mode_probs[i][j]); - } - } -} - -void Parser::read_partition_probs(BooleanDecoder& decoder) -{ - for (auto i = 0; i < PARTITION_CONTEXTS; i++) { - for (auto j = 0; j < PARTITION_TYPES - 1; j++) { - auto& partition_probs = m_probability_tables->partition_probs(); - partition_probs[i][j] = diff_update_prob(decoder, partition_probs[i][j]); - } - } -} - -void Parser::mv_probs(BooleanDecoder& decoder, FrameContext const& frame_context) -{ - for (auto j = 0; j < MV_JOINTS - 1; j++) { - auto& mv_joint_probs = m_probability_tables->mv_joint_probs(); - mv_joint_probs[j] = update_mv_prob(decoder, mv_joint_probs[j]); - } - - for (auto i = 0; i < 2; i++) { - auto& mv_sign_prob = m_probability_tables->mv_sign_prob(); - mv_sign_prob[i] = update_mv_prob(decoder, mv_sign_prob[i]); - for (auto j = 0; j < MV_CLASSES - 1; j++) { - auto& mv_class_probs = m_probability_tables->mv_class_probs(); - mv_class_probs[i][j] = update_mv_prob(decoder, mv_class_probs[i][j]); - } - auto& mv_class0_bit_prob = m_probability_tables->mv_class0_bit_prob(); - mv_class0_bit_prob[i] = update_mv_prob(decoder, mv_class0_bit_prob[i]); - for (auto j = 0; j < MV_OFFSET_BITS; j++) { - auto& mv_bits_prob = m_probability_tables->mv_bits_prob(); - mv_bits_prob[i][j] = update_mv_prob(decoder, mv_bits_prob[i][j]); - } - } - - for (auto i = 0; i < 2; i++) { - for (auto j = 0; j < CLASS0_SIZE; j++) { - for (auto k = 0; k < MV_FR_SIZE - 1; k++) { - auto& mv_class0_fr_probs = m_probability_tables->mv_class0_fr_probs(); - mv_class0_fr_probs[i][j][k] = update_mv_prob(decoder, mv_class0_fr_probs[i][j][k]); - } - } - for (auto k = 0; k < MV_FR_SIZE - 1; k++) { - auto& mv_fr_probs = m_probability_tables->mv_fr_probs(); - mv_fr_probs[i][k] = update_mv_prob(decoder, mv_fr_probs[i][k]); - } - } - - if (frame_context.high_precision_motion_vectors_allowed) { - for (auto i = 0; i < 2; i++) { - auto& mv_class0_hp_prob = m_probability_tables->mv_class0_hp_prob(); - auto& mv_hp_prob = m_probability_tables->mv_hp_prob(); - mv_class0_hp_prob[i] = update_mv_prob(decoder, mv_class0_hp_prob[i]); - mv_hp_prob[i] = update_mv_prob(decoder, mv_hp_prob[i]); - } - } -} - -u8 Parser::update_mv_prob(BooleanDecoder& decoder, u8 prob) -{ - if (decoder.read_bool(252)) { - return (decoder.read_literal(7) << 1u) | 1u; - } - return prob; -} - -static u32 get_tile_offset(u32 tile_start, u32 frame_size_in_blocks, u32 tile_size_log2) -{ - u32 superblocks = blocks_ceiled_to_superblocks(frame_size_in_blocks); - u32 offset = superblocks_to_blocks((tile_start * superblocks) >> tile_size_log2); - return min(offset, frame_size_in_blocks); -} - -DecoderErrorOr Parser::decode_tiles(FrameContext& frame_context) -{ - auto log2_dimensions = frame_context.log2_of_tile_counts; - auto tile_cols = 1u << log2_dimensions.width(); - auto tile_rows = 1u << log2_dimensions.height(); - - PartitionContext above_partition_context = DECODER_TRY_ALLOC(PartitionContext::create(superblocks_to_blocks(frame_context.superblock_columns()))); - NonZeroTokens above_non_zero_tokens = DECODER_TRY_ALLOC(create_non_zero_tokens(blocks_to_sub_blocks(frame_context.columns()), frame_context.color_config.subsampling_x)); - SegmentationPredictionContext above_segmentation_ids = DECODER_TRY_ALLOC(SegmentationPredictionContext::create(frame_context.columns())); - - // FIXME: To implement tiled decoding, we'll need to pre-parse the tile positions and sizes into a 2D vector of ReadonlyBytes, - // then run through each column of tiles in top to bottom order afterward. Each column can be sent to a worker thread - // for execution. Each worker thread will want to create a set of above contexts sized to its tile width, then provide - // those to each tile as it decodes them. - Vector, 4> tile_workloads; - DECODER_TRY_ALLOC(tile_workloads.try_ensure_capacity(tile_cols)); - for (auto tile_col = 0u; tile_col < tile_cols; tile_col++) { - tile_workloads.append({}); - DECODER_TRY_ALLOC(tile_workloads[tile_col].try_ensure_capacity(tile_rows)); - } - - for (auto tile_row = 0u; tile_row < tile_rows; tile_row++) { - for (auto tile_col = 0u; tile_col < tile_cols; tile_col++) { - 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(); - else - tile_size = TRY_READ(frame_context.bit_stream.read_bits(32)); - - auto rows_start = get_tile_offset(tile_row, frame_context.rows(), log2_dimensions.height()); - auto rows_end = get_tile_offset(tile_row + 1, frame_context.rows(), log2_dimensions.height()); - auto columns_start = get_tile_offset(tile_col, frame_context.columns(), log2_dimensions.width()); - auto columns_end = get_tile_offset(tile_col + 1, frame_context.columns(), log2_dimensions.width()); - - auto width = columns_end - columns_start; - auto above_partition_context_for_tile = above_partition_context.span().slice(columns_start, superblocks_to_blocks(blocks_ceiled_to_superblocks(width))); - auto above_non_zero_tokens_view = create_non_zero_tokens_view(above_non_zero_tokens, blocks_to_sub_blocks(columns_start), blocks_to_sub_blocks(columns_end - columns_start), frame_context.color_config.subsampling_x); - auto above_segmentation_ids_for_tile = safe_slice(above_segmentation_ids.span(), columns_start, columns_end - columns_start); - - tile_workloads[tile_col].append(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))); - } - } - - auto decode_tile_column = [this, tile_rows](auto& column_workloads) -> DecoderErrorOr { - VERIFY(column_workloads.size() == tile_rows); - for (auto tile_row = 0u; tile_row < tile_rows; tile_row++) - TRY(decode_tile(column_workloads[tile_row])); - return {}; - }; - -#ifdef VP9_TILE_THREADING - auto const worker_count = tile_cols - 1; - - if (m_worker_threads.size() < worker_count) { - m_worker_threads.clear(); - m_worker_threads.ensure_capacity(worker_count); - for (auto i = 0u; i < worker_count; i++) - m_worker_threads.append(DECODER_TRY_ALLOC(Threading::WorkerThread::create("Decoder Worker"sv))); - } - VERIFY(m_worker_threads.size() >= worker_count); - - // Start tile column decoding tasks in thread workers starting from the second column. - for (auto tile_col = 1u; tile_col < tile_cols; tile_col++) { - auto& column_workload = tile_workloads[tile_col]; - m_worker_threads[tile_col - 1]->start_task([&decode_tile_column, &column_workload]() -> DecoderErrorOr { - return decode_tile_column(column_workload); - }); - } - - // Decode the first column in this thread. - auto result = decode_tile_column(tile_workloads[0]); - - for (auto& worker_thread : m_worker_threads) { - auto task_result = worker_thread->wait_until_task_is_finished(); - if (!result.is_error() && task_result.is_error()) - result = move(task_result); - } - - if (result.is_error()) - return result; -#else - for (auto& column_workloads : tile_workloads) - TRY(decode_tile_column(column_workloads)); -#endif - - // Sum up all tile contexts' syntax element counters after all decodes have finished. - for (auto& tile_contexts : tile_workloads) { - for (auto& tile_context : tile_contexts) { - *frame_context.counter += *tile_context.counter; - } - } - - return {}; -} - -DecoderErrorOr Parser::decode_tile(TileContext& tile_context) -{ - for (auto row = tile_context.rows_start; row < tile_context.rows_end; row += 8) { - clear_left_context(tile_context); - for (auto col = tile_context.columns_start; col < tile_context.columns_end; col += 8) { - TRY(decode_partition(tile_context, row, col, Block_64x64)); - } - } - TRY_READ(tile_context.decoder.finish_decode()); - return {}; -} - -void Parser::clear_left_context(TileContext& tile_context) -{ - for (auto& context_for_plane : tile_context.left_non_zero_tokens) - context_for_plane.fill_with(false); - tile_context.left_segmentation_ids.fill_with(0); - tile_context.left_partition_context.fill_with(0); -} - -DecoderErrorOr Parser::decode_partition(TileContext& tile_context, u32 row, u32 column, BlockSubsize subsize) -{ - if (row >= tile_context.frame_context.rows() || column >= tile_context.frame_context.columns()) - return {}; - u8 num_8x8 = num_8x8_blocks_wide_lookup[subsize]; - auto half_block_8x8 = num_8x8 >> 1; - bool has_rows = (row + half_block_8x8) < tile_context.frame_context.rows(); - 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 = 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) { - TRY(decode_block(tile_context, row, column, child_subsize)); - } else if (partition == PartitionHorizontal) { - TRY(decode_block(tile_context, row, column, child_subsize)); - if (has_rows) - TRY(decode_block(tile_context, row + half_block_8x8, column, child_subsize)); - } else if (partition == PartitionVertical) { - TRY(decode_block(tile_context, row, column, child_subsize)); - if (has_cols) - TRY(decode_block(tile_context, row, column + half_block_8x8, child_subsize)); - } else { - TRY(decode_partition(tile_context, row, column, child_subsize)); - TRY(decode_partition(tile_context, row, column + half_block_8x8, child_subsize)); - TRY(decode_partition(tile_context, row + half_block_8x8, column, child_subsize)); - TRY(decode_partition(tile_context, row + half_block_8x8, column + half_block_8x8, child_subsize)); - } - if (subsize == Block_8x8 || partition != PartitionSplit) { - auto above_context = 15 >> b_width_log2_lookup[child_subsize]; - auto left_context = 15 >> b_height_log2_lookup[child_subsize]; - for (size_t i = 0; i < num_8x8; i++) { - tile_context.above_partition_context[column_in_tile + i] = above_context; - tile_context.left_partition_context[row_in_tile + i] = left_context; - } - } - return {}; -} - -size_t Parser::get_image_index(FrameContext const& frame_context, u32 row, u32 column) const -{ - VERIFY(row < frame_context.rows() && column < frame_context.columns()); - return row * frame_context.columns() + column; -} - -DecoderErrorOr Parser::decode_block(TileContext& tile_context, u32 row, u32 column, BlockSubsize subsize) -{ - auto above_context = row > 0 ? tile_context.frame_block_contexts().at(row - 1, column) : FrameBlockContext(); - auto left_context = column > tile_context.columns_start ? tile_context.frame_block_contexts().at(row, column - 1) : FrameBlockContext(); - auto block_context = BlockContext::create(tile_context, row, column, subsize); - - mode_info(block_context, above_context, left_context); - auto had_residual_tokens = TRY(residual(block_context, above_context.is_available, left_context.is_available)); - if (block_context.is_inter_predicted() && subsize >= Block_8x8 && !had_residual_tokens) - block_context.should_skip_residuals = true; - - for (size_t y = 0; y < block_context.contexts_view.height(); y++) { - for (size_t x = 0; x < block_context.contexts_view.width(); x++) { - auto sub_block_context = FrameBlockContext { true, block_context.should_skip_residuals, block_context.transform_size, block_context.y_prediction_mode(), block_context.sub_block_prediction_modes, block_context.interpolation_filter, block_context.reference_frame_types, block_context.sub_block_motion_vectors, block_context.segment_id }; - block_context.contexts_view.at(y, x) = sub_block_context; - VERIFY(block_context.frame_block_contexts().at(row + y, column + x).transform_size == sub_block_context.transform_size); - } - } - return {}; -} - -void Parser::mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - if (block_context.frame_context.is_inter_predicted()) - inter_frame_mode_info(block_context, above_context, left_context); - else - intra_frame_mode_info(block_context, above_context, left_context); -} - -void Parser::intra_frame_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - block_context.reference_frame_types = { ReferenceFrameType::None, ReferenceFrameType::None }; - VERIFY(!block_context.is_inter_predicted()); - set_intra_segment_id(block_context); - block_context.should_skip_residuals = read_should_skip_residuals(block_context, above_context, left_context); - block_context.transform_size = read_tx_size(block_context, above_context, left_context, true); - // FIXME: This if statement is also present in parse_default_intra_mode. The selection of parameters for - // the probability table lookup should be inlined here. - if (block_context.size >= Block_8x8) { - auto mode = TreeParser::parse_default_intra_mode(block_context.decoder, *m_probability_tables, block_context.size, above_context, left_context, block_context.sub_block_prediction_modes, 0, 0); - for (auto& block_sub_mode : block_context.sub_block_prediction_modes) - block_sub_mode = mode; - } else { - 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_mode = TreeParser::parse_default_intra_mode(block_context.decoder, *m_probability_tables, block_context.size, above_context, left_context, block_context.sub_block_prediction_modes, idx, idy); - - for (auto y = 0; y < size_in_sub_blocks.height(); y++) { - for (auto x = 0; x < size_in_sub_blocks.width(); x++) { - auto index = (idy + y) * 2 + idx + x; - block_context.sub_block_prediction_modes[index] = sub_mode; - } - } - } - } - } - block_context.uv_prediction_mode = TreeParser::parse_default_uv_mode(block_context.decoder, *m_probability_tables, block_context.y_prediction_mode()); -} - -void Parser::set_intra_segment_id(BlockContext& block_context) -{ - if (block_context.frame_context.segmentation_enabled && block_context.frame_context.use_full_segment_id_tree) - block_context.segment_id = TreeParser::parse_segment_id(block_context.decoder, block_context.frame_context.full_segment_id_tree_probabilities); - else - block_context.segment_id = 0; -} - -bool Parser::read_should_skip_residuals(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - if (block_context.get_segment_feature(SegmentFeature::SkipResidualsOverride).enabled) - return true; - return TreeParser::parse_skip(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context); -} - -TransformSize Parser::read_tx_size(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select) -{ - 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 (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)]); -} - -void Parser::inter_frame_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - set_inter_segment_id(block_context); - block_context.should_skip_residuals = read_should_skip_residuals(block_context, above_context, left_context); - auto is_inter = read_is_inter(block_context, above_context, left_context); - block_context.transform_size = read_tx_size(block_context, above_context, left_context, !block_context.should_skip_residuals || !is_inter); - if (is_inter) { - inter_block_mode_info(block_context, above_context, left_context); - } else { - intra_block_mode_info(block_context); - } -} - -void Parser::set_inter_segment_id(BlockContext& block_context) -{ - if (!block_context.frame_context.segmentation_enabled) { - block_context.segment_id = 0; - return; - } - auto predicted_segment_id = get_segment_id(block_context); - if (!block_context.frame_context.use_full_segment_id_tree) { - block_context.segment_id = predicted_segment_id; - return; - } - if (!block_context.frame_context.use_predicted_segment_id_tree) { - block_context.segment_id = TreeParser::parse_segment_id(block_context.decoder, block_context.frame_context.full_segment_id_tree_probabilities); - return; - } - - auto above_segmentation_id = block_context.tile_context.above_segmentation_ids[block_context.row - block_context.tile_context.rows_start]; - auto left_segmentation_id = block_context.tile_context.left_segmentation_ids[block_context.column - block_context.tile_context.columns_start]; - auto seg_id_predicted = TreeParser::parse_segment_id_predicted(block_context.decoder, block_context.frame_context.predicted_segment_id_tree_probabilities, above_segmentation_id, left_segmentation_id); - if (seg_id_predicted) - block_context.segment_id = predicted_segment_id; - else - block_context.segment_id = TreeParser::parse_segment_id(block_context.decoder, block_context.frame_context.full_segment_id_tree_probabilities); - - // (7.4.1) AboveSegPredContext[ i ] only needs to be set to 0 for i = 0..MiCols-1. - // This is taken care of by the slicing in BlockContext. - block_context.above_segmentation_ids.fill(seg_id_predicted); - // (7.4.1) LeftSegPredContext[ i ] only needs to be set to 0 for i = 0..MiRows-1. - // This is taken care of by the slicing in BlockContext. - block_context.left_segmentation_ids.fill(seg_id_predicted); -} - -u8 Parser::get_segment_id(BlockContext const& block_context) -{ - auto bw = num_8x8_blocks_wide_lookup[block_context.size]; - auto bh = num_8x8_blocks_high_lookup[block_context.size]; - auto xmis = min(block_context.frame_context.columns() - block_context.column, (u32)bw); - auto ymis = min(block_context.frame_context.rows() - block_context.row, (u32)bh); - u8 segment = 7; - for (size_t y = 0; y < ymis; y++) { - for (size_t x = 0; x < xmis; x++) { - segment = min(segment, m_previous_block_contexts.index_at(block_context.row + y, block_context.column + x)); - } - } - return segment; -} - -bool Parser::read_is_inter(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - auto reference_frame_override_feature = block_context.get_segment_feature(SegmentFeature::ReferenceFrameOverride); - if (reference_frame_override_feature.enabled) - return reference_frame_override_feature.value != ReferenceFrameType::None; - return TreeParser::parse_block_is_inter_predicted(block_context.decoder, *m_probability_tables, block_context.counter, above_context, left_context); -} - -void Parser::intra_block_mode_info(BlockContext& block_context) -{ - block_context.reference_frame_types = { ReferenceFrameType::None, ReferenceFrameType::None }; - VERIFY(!block_context.is_inter_predicted()); - auto& sub_modes = block_context.sub_block_prediction_modes; - if (block_context.size >= Block_8x8) { - auto mode = 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 = 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; - } - } - } - } - block_context.uv_prediction_mode = TreeParser::parse_uv_mode(block_context.decoder, *m_probability_tables, block_context.counter, block_context.y_prediction_mode()); -} - -static void select_best_reference_motion_vectors(BlockContext& block_context, MotionVectorPair reference_motion_vectors, BlockMotionVectorCandidates& candidates, ReferenceIndex); - -void Parser::inter_block_mode_info(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - read_ref_frames(block_context, above_context, left_context); - VERIFY(block_context.is_inter_predicted()); - - BlockMotionVectorCandidates motion_vector_candidates; - auto reference_motion_vectors = find_reference_motion_vectors(block_context, block_context.reference_frame_types.primary, -1); - select_best_reference_motion_vectors(block_context, reference_motion_vectors, motion_vector_candidates, ReferenceIndex::Primary); - if (block_context.is_compound()) { - auto reference_motion_vectors = find_reference_motion_vectors(block_context, block_context.reference_frame_types.secondary, -1); - select_best_reference_motion_vectors(block_context, reference_motion_vectors, motion_vector_candidates, ReferenceIndex::Secondary); - } - - if (block_context.get_segment_feature(SegmentFeature::SkipResidualsOverride).enabled) { - block_context.y_prediction_mode() = PredictionMode::ZeroMv; - } else if (block_context.size >= Block_8x8) { - block_context.y_prediction_mode() = 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 = 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() = 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()) - select_best_sub_block_reference_motion_vectors(block_context, motion_vector_candidates, idy * 2 + idx, ReferenceIndex::Secondary); - } - auto new_motion_vector_pair = get_motion_vector(block_context, motion_vector_candidates); - for (auto y = 0; y < size_in_sub_blocks.height(); y++) { - for (auto x = 0; x < size_in_sub_blocks.width(); x++) { - auto sub_block_index = (idy + y) * 2 + idx + x; - block_context.sub_block_motion_vectors[sub_block_index] = new_motion_vector_pair; - } - } - } - } - return; - } - auto new_motion_vector_pair = get_motion_vector(block_context, motion_vector_candidates); - for (auto block = 0; block < 4; block++) - block_context.sub_block_motion_vectors[block] = new_motion_vector_pair; -} - -void Parser::read_ref_frames(BlockContext& block_context, FrameBlockContext above_context, FrameBlockContext left_context) -{ - auto reference_frame_override_feature = block_context.get_segment_feature(SegmentFeature::ReferenceFrameOverride); - if (reference_frame_override_feature.enabled) { - block_context.reference_frame_types = { static_cast(reference_frame_override_feature.value), ReferenceFrameType::None }; - return; - } - - 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 = 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; - - auto fixed_reference_index = ReferenceIndex::Primary; - auto variable_reference_index = ReferenceIndex::Secondary; - if (block_context.frame_context.reference_frame_sign_biases[fixed_reference]) - swap(fixed_reference_index, variable_reference_index); - - auto variable_reference_selection = 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]; - return; - } - - // 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 = 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 = 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 }; -} - -// assign_mv( isCompound ) in the spec. -MotionVectorPair Parser::get_motion_vector(BlockContext const& block_context, BlockMotionVectorCandidates const& candidates) -{ - MotionVectorPair result; - auto read_one = [&](ReferenceIndex index) -> void { - switch (block_context.y_prediction_mode()) { - case PredictionMode::NewMv: - result[index] = read_motion_vector(block_context, candidates, index); - break; - case PredictionMode::NearestMv: - result[index] = candidates[index].nearest_vector; - break; - case PredictionMode::NearMv: - result[index] = candidates[index].near_vector; - break; - default: - result[index] = {}; - break; - } - return; - }; - read_one(ReferenceIndex::Primary); - if (block_context.is_compound()) - read_one(ReferenceIndex::Secondary); - return result; -} - -// use_mv_hp( deltaMv ) in the spec. -static bool should_use_high_precision_motion_vector(MotionVector const& delta_vector) -{ - return (abs(delta_vector.row()) >> 3) < COMPANDED_MVREF_THRESH && (abs(delta_vector.column()) >> 3) < COMPANDED_MVREF_THRESH; -} - -// read_mv( ref ) in the spec. -MotionVector Parser::read_motion_vector(BlockContext const& block_context, BlockMotionVectorCandidates const& candidates, ReferenceIndex reference_index) -{ - 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 = TreeParser::parse_motion_vector_joint(block_context.decoder, *m_probability_tables, block_context.counter); - if ((joint & MotionVectorNonZeroRow) != 0) - delta_vector.set_row(read_single_motion_vector_component(block_context.decoder, block_context.counter, 0, use_high_precision)); - if ((joint & MotionVectorNonZeroColumn) != 0) - delta_vector.set_column(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. -i32 Parser::read_single_motion_vector_component(BooleanDecoder& decoder, SyntaxElementCounter& counter, u8 component, bool use_high_precision) -{ - auto mv_sign = TreeParser::parse_motion_vector_sign(decoder, *m_probability_tables, counter, component); - auto mv_class = TreeParser::parse_motion_vector_class(decoder, *m_probability_tables, counter, component); - u32 magnitude; - if (mv_class == MvClass0) { - auto mv_class0_bit = TreeParser::parse_motion_vector_class0_bit(decoder, *m_probability_tables, counter, component); - auto mv_class0_fr = TreeParser::parse_motion_vector_class0_fr(decoder, *m_probability_tables, counter, component, mv_class0_bit); - auto mv_class0_hp = 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 = 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 = TreeParser::parse_motion_vector_fr(decoder, *m_probability_tables, counter, component); - auto mv_hp = 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(magnitude); -} - -static TransformSize get_uv_transform_size(TransformSize transform_size, BlockSubsize size_for_plane) -{ - return min(transform_size, max_txsize_lookup[size_for_plane]); -} - -static TransformSet select_transform_type(BlockContext const& block_context, u8 plane, TransformSize transform_size, u32 block_index) -{ - if (plane > 0 || transform_size == Transform_32x32) - return TransformSet { TransformType::DCT, TransformType::DCT }; - if (transform_size == Transform_4x4) { - if (block_context.frame_context.lossless || block_context.is_inter_predicted()) - return TransformSet { TransformType::DCT, TransformType::DCT }; - - return mode_to_txfm_map[to_underlying(block_context.size < Block_8x8 ? block_context.sub_block_prediction_modes[block_index] : block_context.y_prediction_mode())]; - } - - return mode_to_txfm_map[to_underlying(block_context.y_prediction_mode())]; -} - -DecoderErrorOr Parser::residual(BlockContext& block_context, bool has_block_above, bool has_block_left) -{ - bool block_had_non_zero_tokens = false; - Array token_cache; - for (u8 plane = 0; plane < 3; plane++) { - auto plane_subsampling_x = (plane > 0) ? block_context.frame_context.color_config.subsampling_x : false; - auto plane_subsampling_y = (plane > 0) ? block_context.frame_context.color_config.subsampling_y : false; - auto plane_size = get_subsampled_block_size(block_context.size, plane_subsampling_x, plane_subsampling_y); - if (plane_size == Block_Invalid) { - return DecoderError::corrupted("Invalid block size"sv); - } - auto transform_size = get_uv_transform_size(block_context.transform_size, plane_size); - auto transform_size_in_sub_blocks = transform_size_to_sub_blocks(transform_size); - auto block_size_in_sub_blocks = block_size_to_sub_blocks(plane_size); - - auto base_x_in_pixels = (blocks_to_pixels(block_context.column)) >> plane_subsampling_x; - auto base_y_in_pixels = (blocks_to_pixels(block_context.row)) >> plane_subsampling_y; - if (block_context.is_inter_predicted()) { - if (block_context.size < Block_8x8) { - for (auto y = 0; y < block_size_in_sub_blocks.height(); y++) { - for (auto x = 0; x < block_size_in_sub_blocks.width(); x++) { - TRY(m_decoder.predict_inter(plane, block_context, base_x_in_pixels + sub_blocks_to_pixels(x), base_y_in_pixels + sub_blocks_to_pixels(y), sub_blocks_to_pixels(1), sub_blocks_to_pixels(1), (y * block_size_in_sub_blocks.width()) + x)); - } - } - } else { - TRY(m_decoder.predict_inter(plane, block_context, base_x_in_pixels, base_y_in_pixels, sub_blocks_to_pixels(block_size_in_sub_blocks.width()), sub_blocks_to_pixels(block_size_in_sub_blocks.height()), 0)); - } - } - - auto frame_right_in_pixels = (blocks_to_pixels(block_context.frame_context.columns())) >> plane_subsampling_x; - auto frame_bottom_in_pixels = (blocks_to_pixels(block_context.frame_context.rows())) >> plane_subsampling_y; - - auto sub_block_index = 0; - for (u32 y = 0; y < block_size_in_sub_blocks.height(); y += transform_size_in_sub_blocks) { - for (u32 x = 0; x < block_size_in_sub_blocks.width(); x += transform_size_in_sub_blocks) { - auto transform_x_in_px = base_x_in_pixels + sub_blocks_to_pixels(x); - auto transform_y_in_px = base_y_in_pixels + sub_blocks_to_pixels(y); - - auto sub_block_had_non_zero_tokens = false; - if (transform_x_in_px < frame_right_in_pixels && transform_y_in_px < frame_bottom_in_pixels) { - if (!block_context.is_inter_predicted()) - TRY(m_decoder.predict_intra(plane, block_context, transform_x_in_px, transform_y_in_px, has_block_left || x > 0, has_block_above || y > 0, (x + transform_size_in_sub_blocks) < block_size_in_sub_blocks.width(), transform_size, sub_block_index)); - if (!block_context.should_skip_residuals) { - auto transform_set = select_transform_type(block_context, plane, transform_size, sub_block_index); - sub_block_had_non_zero_tokens = tokens(block_context, plane, x, y, transform_size, transform_set, token_cache); - block_had_non_zero_tokens = block_had_non_zero_tokens || sub_block_had_non_zero_tokens; - TRY(m_decoder.reconstruct(plane, block_context, transform_x_in_px, transform_y_in_px, transform_size, transform_set)); - } - } - - auto& above_sub_block_tokens = block_context.above_non_zero_tokens[plane]; - auto transform_right_in_sub_blocks = min(x + transform_size_in_sub_blocks, above_sub_block_tokens.size()); - for (size_t inside_x = x; inside_x < transform_right_in_sub_blocks; inside_x++) - above_sub_block_tokens[inside_x] = sub_block_had_non_zero_tokens; - - auto& left_sub_block_context = block_context.left_non_zero_tokens[plane]; - auto transform_bottom_in_sub_blocks = min(y + transform_size_in_sub_blocks, left_sub_block_context.size()); - for (size_t inside_y = y; inside_y < transform_bottom_in_sub_blocks; inside_y++) - left_sub_block_context[inside_y] = sub_block_had_non_zero_tokens; - - sub_block_index++; - } - } - } - return block_had_non_zero_tokens; -} - -static u16 const* get_scan(TransformSize transform_size, TransformSet transform_set) -{ - constexpr TransformSet adst_dct { TransformType::ADST, TransformType::DCT }; - constexpr TransformSet dct_adst { TransformType::DCT, TransformType::ADST }; - - if (transform_size == Transform_4x4) { - if (transform_set == adst_dct) - return row_scan_4x4; - if (transform_set == dct_adst) - return col_scan_4x4; - return default_scan_4x4; - } - if (transform_size == Transform_8x8) { - if (transform_set == adst_dct) - return row_scan_8x8; - if (transform_set == dct_adst) - return col_scan_8x8; - return default_scan_8x8; - } - if (transform_size == Transform_16x16) { - if (transform_set == adst_dct) - return row_scan_16x16; - if (transform_set == dct_adst) - return col_scan_16x16; - return default_scan_16x16; - } - return default_scan_32x32; -} - -bool Parser::tokens(BlockContext& block_context, size_t plane, u32 sub_block_column, u32 sub_block_row, TransformSize transform_size, TransformSet transform_set, Array token_cache) -{ - block_context.residual_tokens.fill(0); - - auto const* scan = get_scan(transform_size, transform_set); - - auto check_for_more_coefficients = true; - u16 coef_index = 0; - u16 transform_pixel_count = 16 << (transform_size << 1); - for (; coef_index < transform_pixel_count; coef_index++) { - auto band = (transform_size == Transform_4x4) ? coefband_4x4[coef_index] : coefband_8x8plus[coef_index]; - auto token_position = scan[coef_index]; - TokensContext tokens_context; - if (coef_index == 0) - tokens_context = TreeParser::get_context_for_first_token(block_context.above_non_zero_tokens, block_context.left_non_zero_tokens, transform_size, plane, sub_block_column, sub_block_row, block_context.is_inter_predicted(), band); - 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 && !TreeParser::parse_more_coefficients(block_context.decoder, *m_probability_tables, block_context.counter, tokens_context)) - break; - - auto token = TreeParser::parse_token(block_context.decoder, *m_probability_tables, block_context.counter, tokens_context); - token_cache[token_position] = energy_class[token]; - - i32 coef; - if (token == ZeroToken) { - coef = 0; - check_for_more_coefficients = false; - } else { - coef = read_coef(block_context.decoder, block_context.frame_context.color_config.bit_depth, token); - check_for_more_coefficients = true; - } - block_context.residual_tokens[token_position] = coef; - } - - return coef_index > 0; -} - -i32 Parser::read_coef(BooleanDecoder& decoder, u8 bit_depth, Token token) -{ - auto cat = extra_bits[token][0]; - auto num_extra = extra_bits[token][1]; - i32 coef = extra_bits[token][2]; - if (token == DctValCat6) { - for (size_t e = 0; e < (u8)(bit_depth - 8); e++) { - auto high_bit = decoder.read_bool(255); - coef += high_bit << (5 + bit_depth - e); - } - } - for (size_t e = 0; e < num_extra; e++) { - auto coef_bit = decoder.read_bool(cat_probs[cat][e]); - coef += coef_bit << (num_extra - 1 - e); - } - bool sign_bit = decoder.read_literal(1); - coef = sign_bit ? -coef : coef; - return coef; -} - -// is_inside( candidateR, candidateC ) in the spec. -static bool motion_vector_is_inside_tile(TileContext const& tile_context, MotionVector vector) -{ - if (vector.row() < 0) - return false; - if (vector.column() < 0) - return false; - u32 row_positive = vector.row(); - u32 column_positive = vector.column(); - return row_positive < tile_context.frame_context.rows() && column_positive >= tile_context.columns_start && column_positive < tile_context.columns_end; -} - -// add_mv_ref_list( refList ) in the spec. -static void add_motion_vector_to_list_deduped(MotionVector const& vector, Vector& list) -{ - if (list.size() >= 2) - return; - if (list.size() == 1 && vector == list[0]) - return; - - list.append(vector); -} - -// get_block_mv( candidateR, candidateC, refList, usePrev ) in the spec. -MotionVectorCandidate Parser::get_motion_vector_from_current_or_previous_frame(BlockContext const& block_context, MotionVector candidate_vector, ReferenceIndex reference_index, bool use_prev) -{ - if (use_prev) { - auto const& prev_context = m_previous_block_contexts.at(candidate_vector.row(), candidate_vector.column()); - return { prev_context.ref_frames[reference_index], prev_context.primary_motion_vector_pair[reference_index] }; - } - - auto const& current_context = block_context.frame_block_contexts().at(candidate_vector.row(), candidate_vector.column()); - return { current_context.ref_frames[reference_index], current_context.primary_motion_vector_pair()[reference_index] }; -} - -// if_same_ref_frame_add_mv( candidateR, candidateC, refFrame, usePrev ) in the spec. -void Parser::add_motion_vector_if_reference_frame_type_is_same(BlockContext const& block_context, MotionVector candidate_vector, ReferenceFrameType ref_frame, Vector& list, bool use_prev) -{ - for (auto i = 0u; i < 2; i++) { - auto candidate = get_motion_vector_from_current_or_previous_frame(block_context, candidate_vector, static_cast(i), use_prev); - if (candidate.type == ref_frame) { - add_motion_vector_to_list_deduped(candidate.vector, list); - return; - } - } -} - -// scale_mv( refList, refFrame ) in the spec. -static void apply_sign_bias_to_motion_vector(FrameContext const& frame_context, MotionVectorCandidate& candidate, ReferenceFrameType ref_frame) -{ - if (frame_context.reference_frame_sign_biases[candidate.type] != frame_context.reference_frame_sign_biases[ref_frame]) - candidate.vector *= -1; -} - -// if_diff_ref_frame_add_mv( candidateR, candidateC, refFrame, usePrev ) in the spec. -void Parser::add_motion_vector_if_reference_frame_type_is_different(BlockContext const& block_context, MotionVector candidate_vector, ReferenceFrameType ref_frame, Vector& list, bool use_prev) -{ - auto first_candidate = get_motion_vector_from_current_or_previous_frame(block_context, candidate_vector, ReferenceIndex::Primary, use_prev); - if (first_candidate.type > ReferenceFrameType::None && first_candidate.type != ref_frame) { - apply_sign_bias_to_motion_vector(block_context.frame_context, first_candidate, ref_frame); - add_motion_vector_to_list_deduped(first_candidate.vector, list); - } - - auto second_candidate = get_motion_vector_from_current_or_previous_frame(block_context, candidate_vector, ReferenceIndex::Secondary, use_prev); - auto mvs_are_same = first_candidate.vector == second_candidate.vector; - if (second_candidate.type > ReferenceFrameType::None && second_candidate.type != ref_frame && !mvs_are_same) { - apply_sign_bias_to_motion_vector(block_context.frame_context, second_candidate, ref_frame); - add_motion_vector_to_list_deduped(second_candidate.vector, list); - } -} - -// This function handles both clamp_mv_row( mvec, border ) and clamp_mv_col( mvec, border ) in the spec. -static MotionVector clamp_motion_vector(BlockContext const& block_context, MotionVector vector, i32 border) -{ - 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 = -8 * (static_cast(block_context.row) * MI_SIZE); - i32 mb_to_bottom_edge = 8 * ((static_cast(block_context.frame_context.rows()) - blocks_high - static_cast(block_context.row)) * MI_SIZE); - - i32 blocks_wide = num_8x8_blocks_wide_lookup[block_context.size]; - i32 mb_to_left_edge = -8 * (static_cast(block_context.column) * MI_SIZE); - i32 mb_to_right_edge = 8 * ((static_cast(block_context.frame_context.columns()) - blocks_wide - static_cast(block_context.column)) * MI_SIZE); - - return { - clip_3(mb_to_top_edge - border, mb_to_bottom_edge + border, vector.row()), - clip_3(mb_to_left_edge - border, mb_to_right_edge + border, vector.column()) - }; -} - -// 6.5.1 Find MV refs syntax -// find_mv_refs( refFrame, block ) in the spec. -MotionVectorPair Parser::find_reference_motion_vectors(BlockContext& block_context, ReferenceFrameType reference_frame, i32 block) -{ - // FIXME: We should be able to change behavior based on the reference motion vector that will be selected. - // If block_context.y_prediction_mode() != NearMv, then we only need the first motion vector that is added to our result. - // This behavior should combine this function with select_best_reference_motion_vectors(). When that is done, check whether - // the motion vector clamping in that function is always a larger area than in this function. If so, we can drop that call. - bool different_ref_found = false; - u8 context_counter = 0; - - Vector list; - - MotionVector base_coordinates = MotionVector(block_context.row, block_context.column); - - for (auto i = 0u; i < 2; i++) { - auto offset_vector = mv_ref_blocks[block_context.size][i]; - auto candidate = base_coordinates + offset_vector; - - if (motion_vector_is_inside_tile(block_context.tile_context, candidate)) { - different_ref_found = true; - auto context = block_context.frame_block_contexts().at(candidate.row(), candidate.column()); - context_counter += mode_2_counter[to_underlying(context.y_mode)]; - - for (auto i = 0u; i < 2; i++) { - auto reference_index = static_cast(i); - if (context.ref_frames[reference_index] == 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 }, - { 1, 3 }, - { 3, 2 }, - { 3, 3 } - }; - auto index = block >= 0 ? idx_n_column_to_subblock[block][offset_vector.column() == 0] : 3; - - add_motion_vector_to_list_deduped(context.sub_block_motion_vectors[index][reference_index], list); - break; - } - } - } - } - block_context.mode_context[reference_frame] = counter_to_context[context_counter]; - - for (auto i = 2u; i < MVREF_NEIGHBORS; i++) { - MotionVector candidate = base_coordinates + mv_ref_blocks[block_context.size][i]; - if (motion_vector_is_inside_tile(block_context.tile_context, candidate)) { - different_ref_found = true; - add_motion_vector_if_reference_frame_type_is_same(block_context, candidate, reference_frame, list, false); - } - } - if (block_context.frame_context.use_previous_frame_motion_vectors) - add_motion_vector_if_reference_frame_type_is_same(block_context, base_coordinates, reference_frame, list, true); - - if (different_ref_found) { - for (auto i = 0u; i < MVREF_NEIGHBORS; i++) { - MotionVector candidate = base_coordinates + mv_ref_blocks[block_context.size][i]; - if (motion_vector_is_inside_tile(block_context.tile_context, candidate)) - add_motion_vector_if_reference_frame_type_is_different(block_context, candidate, reference_frame, list, false); - } - } - if (block_context.frame_context.use_previous_frame_motion_vectors) - add_motion_vector_if_reference_frame_type_is_different(block_context, base_coordinates, reference_frame, list, true); - - for (auto i = 0u; i < list.size(); i++) { - // clamp_mv_ref( i ) in the spec. - list[i] = clamp_motion_vector(block_context, list[i], MV_BORDER); - } - - MotionVectorPair result; - for (auto i = 0u; i < list.size(); i++) - result[static_cast(i)] = list[i]; - result.primary = clamp_motion_vector(block_context, result.primary, MV_BORDER); - result.secondary = clamp_motion_vector(block_context, result.secondary, MV_BORDER); - return result; -} - -// find_best_ref_mvs( refList ) in the spec. -static void select_best_reference_motion_vectors(BlockContext& block_context, MotionVectorPair reference_motion_vectors, BlockMotionVectorCandidates& candidates, ReferenceIndex reference_index) -{ - auto adjust_and_clamp_vector = [&](MotionVector& vector) { - auto delta_row = vector.row(); - auto delta_column = vector.column(); - if (!block_context.frame_context.high_precision_motion_vectors_allowed || !should_use_high_precision_motion_vector(vector)) { - if ((delta_row & 1) != 0) - delta_row += delta_row > 0 ? -1 : 1; - if ((delta_column & 1) != 0) - delta_column += delta_column > 0 ? -1 : 1; - } - vector = { delta_row, delta_column }; - vector = clamp_motion_vector(block_context, vector, (BORDERINPIXELS - INTERP_EXTEND) << 3); - }; - adjust_and_clamp_vector(reference_motion_vectors.primary); - adjust_and_clamp_vector(reference_motion_vectors.secondary); - - candidates[reference_index].nearest_vector = reference_motion_vectors.primary; - candidates[reference_index].near_vector = reference_motion_vectors.secondary; - candidates[reference_index].best_vector = reference_motion_vectors.primary; -} - -// append_sub8x8_mvs( block, refList ) in the spec. -void Parser::select_best_sub_block_reference_motion_vectors(BlockContext& block_context, BlockMotionVectorCandidates& candidates, i32 block, ReferenceIndex reference_index) -{ - Array sub_8x8_mvs; - MotionVectorPair reference_motion_vectors = find_reference_motion_vectors(block_context, block_context.reference_frame_types[reference_index], block); - auto destination_index = 0; - if (block == 0) { - sub_8x8_mvs[destination_index++] = reference_motion_vectors.primary; - sub_8x8_mvs[destination_index++] = reference_motion_vectors.secondary; - } else if (block <= 2) { - sub_8x8_mvs[destination_index++] = block_context.sub_block_motion_vectors[0][reference_index]; - } else { - sub_8x8_mvs[destination_index++] = block_context.sub_block_motion_vectors[2][reference_index]; - for (auto index = 1; index >= 0 && destination_index < 2; index--) { - auto block_vector = block_context.sub_block_motion_vectors[index][reference_index]; - if (block_vector != sub_8x8_mvs[0]) - sub_8x8_mvs[destination_index++] = block_vector; - } - } - - for (auto n = 0u; n < 2 && destination_index < 2; n++) { - auto ref_list_vector = reference_motion_vectors[static_cast(n)]; - if (ref_list_vector != sub_8x8_mvs[0]) - sub_8x8_mvs[destination_index++] = ref_list_vector; - } - - if (destination_index < 2) - sub_8x8_mvs[destination_index++] = {}; - candidates[reference_index].nearest_vector = sub_8x8_mvs[0]; - candidates[reference_index].near_vector = sub_8x8_mvs[1]; -} - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Parser.h b/Userland/Libraries/LibMedia/Video/VP9/Parser.h deleted file mode 100644 index 8e92531b9af..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Parser.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ContextStorage.h" -#include "LookupTables.h" -#include "MotionVector.h" -#include "ProbabilityTables.h" -#include "SyntaxElementCounter.h" -#include "TreeParser.h" - -namespace Media::Video::VP9 { - -class Decoder; - -struct FrameContext; -struct TileContext; -struct BlockContext; -struct MotionVectorCandidate; -struct QuantizationParameters; - -class Parser { - friend class TreeParser; - friend class Decoder; - -public: - explicit Parser(Decoder&); - ~Parser(); - DecoderErrorOr parse_frame(ReadonlyBytes); - -private: - /* Annex B: Superframes are a method of storing multiple coded frames into a single chunk - * See also section 5.26. */ - Vector parse_superframe_sizes(ReadonlyBytes); - - DecoderErrorOr read_video_full_range_flag(BigEndianInputBitStream&); - - /* (6.1) Frame Syntax */ - bool trailing_bits(); - DecoderErrorOr refresh_probs(FrameContext const&); - - /* (6.2) Uncompressed Header Syntax */ - DecoderErrorOr uncompressed_header(FrameContext& frame_context); - DecoderErrorOr frame_sync_code(BigEndianInputBitStream&); - DecoderErrorOr parse_color_config(BigEndianInputBitStream&, u8 profile); - DecoderErrorOr> parse_frame_size(BigEndianInputBitStream&); - DecoderErrorOr> parse_frame_size_with_refs(BigEndianInputBitStream&, Array const& reference_indices); - DecoderErrorOr> parse_render_size(BigEndianInputBitStream&, Gfx::Size frame_size); - DecoderErrorOr compute_image_size(FrameContext&); - DecoderErrorOr read_interpolation_filter(BigEndianInputBitStream&); - DecoderErrorOr loop_filter_params(FrameContext&); - DecoderErrorOr read_delta_q(BigEndianInputBitStream&); - DecoderErrorOr segmentation_params(FrameContext&); - DecoderErrorOr read_prob(BigEndianInputBitStream&); - static void precalculate_quantizers(FrameContext& frame_context, QuantizationParameters quantization_parameters); - DecoderErrorOr parse_tile_counts(FrameContext&); - void setup_past_independence(); - - /* (6.3) Compressed Header Syntax */ - DecoderErrorOr compressed_header(FrameContext&); - TransformMode read_tx_mode(BooleanDecoder&, FrameContext const&); - void tx_mode_probs(BooleanDecoder&); - u8 diff_update_prob(BooleanDecoder&, u8 prob); - u8 decode_term_subexp(BooleanDecoder&); - u8 inv_remap_prob(u8 delta_prob, u8 prob); - u8 inv_recenter_nonneg(u8 v, u8 m); - void read_coef_probs(BooleanDecoder&, TransformMode); - void read_skip_prob(BooleanDecoder&); - void read_inter_mode_probs(BooleanDecoder&); - void read_interp_filter_probs(BooleanDecoder&); - void read_is_inter_probs(BooleanDecoder&); - void frame_reference_mode(FrameContext&, BooleanDecoder&); - void frame_reference_mode_probs(BooleanDecoder&, FrameContext const&); - void read_y_mode_probs(BooleanDecoder&); - void read_partition_probs(BooleanDecoder&); - void mv_probs(BooleanDecoder&, FrameContext const&); - u8 update_mv_prob(BooleanDecoder&, u8 prob); - - /* (6.4) Decode Tiles Syntax */ - DecoderErrorOr decode_tiles(FrameContext&); - DecoderErrorOr decode_tile(TileContext&); - void clear_left_context(TileContext&); - DecoderErrorOr decode_partition(TileContext&, u32 row, u32 column, BlockSubsize subsize); - DecoderErrorOr decode_block(TileContext&, u32 row, u32 column, BlockSubsize subsize); - void mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - void intra_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - void set_intra_segment_id(BlockContext&); - bool read_should_skip_residuals(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - TransformSize read_tx_size(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context, bool allow_select); - void inter_frame_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - void set_inter_segment_id(BlockContext&); - u8 get_segment_id(BlockContext const&); - bool read_is_inter(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - void intra_block_mode_info(BlockContext&); - void inter_block_mode_info(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - void read_ref_frames(BlockContext&, FrameBlockContext above_context, FrameBlockContext left_context); - MotionVectorPair get_motion_vector(BlockContext const&, BlockMotionVectorCandidates const&); - MotionVector read_motion_vector(BlockContext const&, BlockMotionVectorCandidates const&, ReferenceIndex); - i32 read_single_motion_vector_component(BooleanDecoder&, SyntaxElementCounter&, u8 component, bool use_high_precision); - DecoderErrorOr residual(BlockContext&, bool has_block_above, bool has_block_left); - bool tokens(BlockContext&, size_t plane, u32 x, u32 y, TransformSize, TransformSet, Array token_cache); - i32 read_coef(BooleanDecoder&, u8 bit_depth, Token token); - - /* (6.5) Motion Vector Prediction */ - MotionVectorPair find_reference_motion_vectors(BlockContext&, ReferenceFrameType, i32 block); - void select_best_sub_block_reference_motion_vectors(BlockContext&, BlockMotionVectorCandidates&, i32 block, ReferenceIndex); - size_t get_image_index(FrameContext const&, u32 row, u32 column) const; - MotionVectorCandidate get_motion_vector_from_current_or_previous_frame(BlockContext const&, MotionVector candidate_vector, ReferenceIndex, bool use_prev); - void add_motion_vector_if_reference_frame_type_is_same(BlockContext const&, MotionVector candidate_vector, ReferenceFrameType ref_frame, Vector& list, bool use_prev); - void add_motion_vector_if_reference_frame_type_is_different(BlockContext const&, MotionVector candidate_vector, ReferenceFrameType ref_frame, Vector& list, bool use_prev); - - bool m_is_first_compute_image_size_invoke { true }; - Gfx::Size m_previous_frame_size { 0, 0 }; - bool m_previous_show_frame { false }; - ColorConfig m_previous_color_config; - FrameType m_previous_frame_type { FrameType::KeyFrame }; - Array m_previous_loop_filter_ref_deltas; - Array m_previous_loop_filter_mode_deltas; - bool m_previous_should_use_absolute_segment_base_quantizer; - SegmentationFeatures m_previous_segmentation_features; - - ReferenceFrame m_reference_frames[NUM_REF_FRAMES]; - - Vector2D m_reusable_frame_block_contexts; - Vector2D m_previous_block_contexts; - - OwnPtr m_probability_tables; - Decoder& m_decoder; - - Vector>> m_worker_threads; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.cpp b/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.cpp deleted file mode 100644 index 9d0e4bf9acf..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.cpp +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ProbabilityTables.h" - -namespace Media::Video::VP9 { - -static constexpr ParetoTable constant_pareto_table = { - { 3, 86, 128, 6, 86, 23, 88, 29 }, - { 9, 86, 129, 17, 88, 61, 94, 76 }, - { 15, 87, 129, 28, 89, 93, 100, 110 }, - { 20, 88, 130, 38, 91, 118, 106, 136 }, - { 26, 89, 131, 48, 92, 139, 111, 156 }, - { 31, 90, 131, 58, 94, 156, 117, 171 }, - { 37, 90, 132, 66, 95, 171, 122, 184 }, - { 42, 91, 132, 75, 97, 183, 127, 194 }, - { 47, 92, 133, 83, 98, 193, 132, 202 }, - { 52, 93, 133, 90, 100, 201, 137, 208 }, - { 57, 94, 134, 98, 101, 208, 142, 214 }, - { 62, 94, 135, 105, 103, 214, 146, 218 }, - { 66, 95, 135, 111, 104, 219, 151, 222 }, - { 71, 96, 136, 117, 106, 224, 155, 225 }, - { 76, 97, 136, 123, 107, 227, 159, 228 }, - { 80, 98, 137, 129, 109, 231, 162, 231 }, - { 84, 98, 138, 134, 110, 234, 166, 233 }, - { 89, 99, 138, 140, 112, 236, 170, 235 }, - { 93, 100, 139, 145, 113, 238, 173, 236 }, - { 97, 101, 140, 149, 115, 240, 176, 238 }, - { 101, 102, 140, 154, 116, 242, 179, 239 }, - { 105, 103, 141, 158, 118, 243, 182, 240 }, - { 109, 104, 141, 162, 119, 244, 185, 241 }, - { 113, 104, 142, 166, 120, 245, 187, 242 }, - { 116, 105, 143, 170, 122, 246, 190, 243 }, - { 120, 106, 143, 173, 123, 247, 192, 244 }, - { 123, 107, 144, 177, 125, 248, 195, 244 }, - { 127, 108, 145, 180, 126, 249, 197, 245 }, - { 130, 109, 145, 183, 128, 249, 199, 245 }, - { 134, 110, 146, 186, 129, 250, 201, 246 }, - { 137, 111, 147, 189, 131, 251, 203, 246 }, - { 140, 112, 147, 192, 132, 251, 205, 247 }, - { 143, 113, 148, 194, 133, 251, 207, 247 }, - { 146, 114, 149, 197, 135, 252, 208, 248 }, - { 149, 115, 149, 199, 136, 252, 210, 248 }, - { 152, 115, 150, 201, 138, 252, 211, 248 }, - { 155, 116, 151, 204, 139, 253, 213, 249 }, - { 158, 117, 151, 206, 140, 253, 214, 249 }, - { 161, 118, 152, 208, 142, 253, 216, 249 }, - { 163, 119, 153, 210, 143, 253, 217, 249 }, - { 166, 120, 153, 212, 144, 254, 218, 250 }, - { 168, 121, 154, 213, 146, 254, 220, 250 }, - { 171, 122, 155, 215, 147, 254, 221, 250 }, - { 173, 123, 155, 217, 148, 254, 222, 250 }, - { 176, 124, 156, 218, 150, 254, 223, 250 }, - { 178, 125, 157, 220, 151, 254, 224, 251 }, - { 180, 126, 157, 221, 152, 254, 225, 251 }, - { 183, 127, 158, 222, 153, 254, 226, 251 }, - { 185, 128, 159, 224, 155, 255, 227, 251 }, - { 187, 129, 160, 225, 156, 255, 228, 251 }, - { 189, 131, 160, 226, 157, 255, 228, 251 }, - { 191, 132, 161, 227, 159, 255, 229, 251 }, - { 193, 133, 162, 228, 160, 255, 230, 252 }, - { 195, 134, 163, 230, 161, 255, 231, 252 }, - { 197, 135, 163, 231, 162, 255, 231, 252 }, - { 199, 136, 164, 232, 163, 255, 232, 252 }, - { 201, 137, 165, 233, 165, 255, 233, 252 }, - { 202, 138, 166, 233, 166, 255, 233, 252 }, - { 204, 139, 166, 234, 167, 255, 234, 252 }, - { 206, 140, 167, 235, 168, 255, 235, 252 }, - { 207, 141, 168, 236, 169, 255, 235, 252 }, - { 209, 142, 169, 237, 171, 255, 236, 252 }, - { 210, 144, 169, 237, 172, 255, 236, 252 }, - { 212, 145, 170, 238, 173, 255, 237, 252 }, - { 214, 146, 171, 239, 174, 255, 237, 253 }, - { 215, 147, 172, 240, 175, 255, 238, 253 }, - { 216, 148, 173, 240, 176, 255, 238, 253 }, - { 218, 149, 173, 241, 177, 255, 239, 253 }, - { 219, 150, 174, 241, 179, 255, 239, 253 }, - { 220, 152, 175, 242, 180, 255, 240, 253 }, - { 222, 153, 176, 242, 181, 255, 240, 253 }, - { 223, 154, 177, 243, 182, 255, 240, 253 }, - { 224, 155, 178, 244, 183, 255, 241, 253 }, - { 225, 156, 178, 244, 184, 255, 241, 253 }, - { 226, 158, 179, 244, 185, 255, 242, 253 }, - { 228, 159, 180, 245, 186, 255, 242, 253 }, - { 229, 160, 181, 245, 187, 255, 242, 253 }, - { 230, 161, 182, 246, 188, 255, 243, 253 }, - { 231, 163, 183, 246, 189, 255, 243, 253 }, - { 232, 164, 184, 247, 190, 255, 243, 253 }, - { 233, 165, 185, 247, 191, 255, 244, 253 }, - { 234, 166, 185, 247, 192, 255, 244, 253 }, - { 235, 168, 186, 248, 193, 255, 244, 253 }, - { 236, 169, 187, 248, 194, 255, 244, 253 }, - { 236, 170, 188, 248, 195, 255, 245, 253 }, - { 237, 171, 189, 249, 196, 255, 245, 254 }, - { 238, 173, 190, 249, 197, 255, 245, 254 }, - { 239, 174, 191, 249, 198, 255, 245, 254 }, - { 240, 175, 192, 249, 199, 255, 246, 254 }, - { 240, 177, 193, 250, 200, 255, 246, 254 }, - { 241, 178, 194, 250, 201, 255, 246, 254 }, - { 242, 179, 195, 250, 202, 255, 246, 254 }, - { 242, 181, 196, 250, 203, 255, 247, 254 }, - { 243, 182, 197, 251, 204, 255, 247, 254 }, - { 244, 184, 198, 251, 205, 255, 247, 254 }, - { 244, 185, 199, 251, 206, 255, 247, 254 }, - { 245, 186, 200, 251, 207, 255, 247, 254 }, - { 246, 188, 201, 252, 207, 255, 248, 254 }, - { 246, 189, 202, 252, 208, 255, 248, 254 }, - { 247, 191, 203, 252, 209, 255, 248, 254 }, - { 247, 192, 204, 252, 210, 255, 248, 254 }, - { 248, 194, 205, 252, 211, 255, 248, 254 }, - { 248, 195, 206, 252, 212, 255, 249, 254 }, - { 249, 197, 207, 253, 213, 255, 249, 254 }, - { 249, 198, 208, 253, 214, 255, 249, 254 }, - { 250, 200, 210, 253, 215, 255, 249, 254 }, - { 250, 201, 211, 253, 215, 255, 249, 254 }, - { 250, 203, 212, 253, 216, 255, 249, 254 }, - { 251, 204, 213, 253, 217, 255, 250, 254 }, - { 251, 206, 214, 254, 218, 255, 250, 254 }, - { 252, 207, 216, 254, 219, 255, 250, 254 }, - { 252, 209, 217, 254, 220, 255, 250, 254 }, - { 252, 211, 218, 254, 221, 255, 250, 254 }, - { 253, 213, 219, 254, 222, 255, 250, 254 }, - { 253, 214, 221, 254, 223, 255, 250, 254 }, - { 253, 216, 222, 254, 224, 255, 251, 254 }, - { 253, 218, 224, 254, 225, 255, 251, 254 }, - { 254, 220, 225, 254, 225, 255, 251, 254 }, - { 254, 222, 227, 255, 226, 255, 251, 254 }, - { 254, 224, 228, 255, 227, 255, 251, 254 }, - { 254, 226, 230, 255, 228, 255, 251, 254 }, - { 255, 228, 231, 255, 230, 255, 251, 254 }, - { 255, 230, 233, 255, 231, 255, 252, 254 }, - { 255, 232, 235, 255, 232, 255, 252, 254 }, - { 255, 235, 237, 255, 233, 255, 252, 254 }, - { 255, 238, 240, 255, 235, 255, 252, 255 }, - { 255, 241, 243, 255, 236, 255, 252, 254 }, - { 255, 246, 247, 255, 239, 255, 253, 255 } -}; - -static constexpr KfPartitionProbs constant_kf_partition_probs = { - // 8x8 -> 4x4 - { 158, 97, 94 }, // a/l both not split - { 93, 24, 99 }, // a split, l not split - { 85, 119, 44 }, // l split, a not split - { 62, 59, 67 }, // a/l both split - // 16x16 -> 8x8 - { 149, 53, 53 }, // a/l both not split - { 94, 20, 48 }, // a split, l not split - { 83, 53, 24 }, // l split, a not split - { 52, 18, 18 }, // a/l both split - // 32x32 -> 16x16 - { 150, 40, 39 }, // a/l both not split - { 78, 12, 26 }, // a split, l not split - { 67, 33, 11 }, // l split, a not split - { 24, 7, 5 }, // a/l both split - // 64x64 -> 32x32 - { 174, 35, 49 }, // a/l both not split - { 68, 11, 27 }, // a split, l not split - { 57, 15, 9 }, // l split, a not split - { 12, 3, 3 }, // a/l both split -}; - -static constexpr KfYModeProbs constant_kf_y_mode_probs = { - { - // above = dc - { 137, 30, 42, 148, 151, 207, 70, 52, 91 }, // left = dc - { 92, 45, 102, 136, 116, 180, 74, 90, 100 }, // left = v - { 73, 32, 19, 187, 222, 215, 46, 34, 100 }, // left = h - { 91, 30, 32, 116, 121, 186, 93, 86, 94 }, // left = d45 - { 72, 35, 36, 149, 68, 206, 68, 63, 105 }, // left = d135 - { 73, 31, 28, 138, 57, 124, 55, 122, 151 }, // left = d117 - { 67, 23, 21, 140, 126, 197, 40, 37, 171 }, // left = d153 - { 86, 27, 28, 128, 154, 212, 45, 43, 53 }, // left = d207 - { 74, 32, 27, 107, 86, 160, 63, 134, 102 }, // left = d63 - { 59, 67, 44, 140, 161, 202, 78, 67, 119 } // left = tm - }, - { - // above = v - { 63, 36, 126, 146, 123, 158, 60, 90, 96 }, // left = dc - { 43, 46, 168, 134, 107, 128, 69, 142, 92 }, // left = v - { 44, 29, 68, 159, 201, 177, 50, 57, 77 }, // left = h - { 58, 38, 76, 114, 97, 172, 78, 133, 92 }, // left = d45 - { 46, 41, 76, 140, 63, 184, 69, 112, 57 }, // left = d135 - { 38, 32, 85, 140, 46, 112, 54, 151, 133 }, // left = d117 - { 39, 27, 61, 131, 110, 175, 44, 75, 136 }, // left = d153 - { 52, 30, 74, 113, 130, 175, 51, 64, 58 }, // left = d207 - { 47, 35, 80, 100, 74, 143, 64, 163, 74 }, // left = d63 - { 36, 61, 116, 114, 128, 162, 80, 125, 82 } // left = tm - }, - { - // above = h - { 82, 26, 26, 171, 208, 204, 44, 32, 105 }, // left = dc - { 55, 44, 68, 166, 179, 192, 57, 57, 108 }, // left = v - { 42, 26, 11, 199, 241, 228, 23, 15, 85 }, // left = h - { 68, 42, 19, 131, 160, 199, 55, 52, 83 }, // left = d45 - { 58, 50, 25, 139, 115, 232, 39, 52, 118 }, // left = d135 - { 50, 35, 33, 153, 104, 162, 64, 59, 131 }, // left = d117 - { 44, 24, 16, 150, 177, 202, 33, 19, 156 }, // left = d153 - { 55, 27, 12, 153, 203, 218, 26, 27, 49 }, // left = d207 - { 53, 49, 21, 110, 116, 168, 59, 80, 76 }, // left = d63 - { 38, 72, 19, 168, 203, 212, 50, 50, 107 } // left = tm - }, - { - // above = d45 - { 103, 26, 36, 129, 132, 201, 83, 80, 93 }, // left = dc - { 59, 38, 83, 112, 103, 162, 98, 136, 90 }, // left = v - { 62, 30, 23, 158, 200, 207, 59, 57, 50 }, // left = h - { 67, 30, 29, 84, 86, 191, 102, 91, 59 }, // left = d45 - { 60, 32, 33, 112, 71, 220, 64, 89, 104 }, // left = d135 - { 53, 26, 34, 130, 56, 149, 84, 120, 103 }, // left = d117 - { 53, 21, 23, 133, 109, 210, 56, 77, 172 }, // left = d153 - { 77, 19, 29, 112, 142, 228, 55, 66, 36 }, // left = d207 - { 61, 29, 29, 93, 97, 165, 83, 175, 162 }, // left = d63 - { 47, 47, 43, 114, 137, 181, 100, 99, 95 } // left = tm - }, - { - // above = d135 - { 69, 23, 29, 128, 83, 199, 46, 44, 101 }, // left = dc - { 53, 40, 55, 139, 69, 183, 61, 80, 110 }, // left = v - { 40, 29, 19, 161, 180, 207, 43, 24, 91 }, // left = h - { 60, 34, 19, 105, 61, 198, 53, 64, 89 }, // left = d45 - { 52, 31, 22, 158, 40, 209, 58, 62, 89 }, // left = d135 - { 44, 31, 29, 147, 46, 158, 56, 102, 198 }, // left = d117 - { 35, 19, 12, 135, 87, 209, 41, 45, 167 }, // left = d153 - { 55, 25, 21, 118, 95, 215, 38, 39, 66 }, // left = d207 - { 51, 38, 25, 113, 58, 164, 70, 93, 97 }, // left = d63 - { 47, 54, 34, 146, 108, 203, 72, 103, 151 } // left = tm - }, - { - // above = d117 - { 64, 19, 37, 156, 66, 138, 49, 95, 133 }, // left = dc - { 46, 27, 80, 150, 55, 124, 55, 121, 135 }, // left = v - { 36, 23, 27, 165, 149, 166, 54, 64, 118 }, // left = h - { 53, 21, 36, 131, 63, 163, 60, 109, 81 }, // left = d45 - { 40, 26, 35, 154, 40, 185, 51, 97, 123 }, // left = d135 - { 35, 19, 34, 179, 19, 97, 48, 129, 124 }, // left = d117 - { 36, 20, 26, 136, 62, 164, 33, 77, 154 }, // left = d153 - { 45, 18, 32, 130, 90, 157, 40, 79, 91 }, // left = d207 - { 45, 26, 28, 129, 45, 129, 49, 147, 123 }, // left = d63 - { 38, 44, 51, 136, 74, 162, 57, 97, 121 } // left = tm - }, - { - // above = d153 - { 75, 17, 22, 136, 138, 185, 32, 34, 166 }, // left = dc - { 56, 39, 58, 133, 117, 173, 48, 53, 187 }, // left = v - { 35, 21, 12, 161, 212, 207, 20, 23, 145 }, // left = h - { 56, 29, 19, 117, 109, 181, 55, 68, 112 }, // left = d45 - { 47, 29, 17, 153, 64, 220, 59, 51, 114 }, // left = d135 - { 46, 16, 24, 136, 76, 147, 41, 64, 172 }, // left = d117 - { 34, 17, 11, 108, 152, 187, 13, 15, 209 }, // left = d153 - { 51, 24, 14, 115, 133, 209, 32, 26, 104 }, // left = d207 - { 55, 30, 18, 122, 79, 179, 44, 88, 116 }, // left = d63 - { 37, 49, 25, 129, 168, 164, 41, 54, 148 } // left = tm - }, - { - // above = d207 - { 82, 22, 32, 127, 143, 213, 39, 41, 70 }, // left = dc - { 62, 44, 61, 123, 105, 189, 48, 57, 64 }, // left = v - { 47, 25, 17, 175, 222, 220, 24, 30, 86 }, // left = h - { 68, 36, 17, 106, 102, 206, 59, 74, 74 }, // left = d45 - { 57, 39, 23, 151, 68, 216, 55, 63, 58 }, // left = d135 - { 49, 30, 35, 141, 70, 168, 82, 40, 115 }, // left = d117 - { 51, 25, 15, 136, 129, 202, 38, 35, 139 }, // left = d153 - { 68, 26, 16, 111, 141, 215, 29, 28, 28 }, // left = d207 - { 59, 39, 19, 114, 75, 180, 77, 104, 42 }, // left = d63 - { 40, 61, 26, 126, 152, 206, 61, 59, 93 } // left = tm - }, - { - // above = d63 - { 78, 23, 39, 111, 117, 170, 74, 124, 94 }, // left = dc - { 48, 34, 86, 101, 92, 146, 78, 179, 134 }, // left = v - { 47, 22, 24, 138, 187, 178, 68, 69, 59 }, // left = h - { 56, 25, 33, 105, 112, 187, 95, 177, 129 }, // left = d45 - { 48, 31, 27, 114, 63, 183, 82, 116, 56 }, // left = d135 - { 43, 28, 37, 121, 63, 123, 61, 192, 169 }, // left = d117 - { 42, 17, 24, 109, 97, 177, 56, 76, 122 }, // left = d153 - { 58, 18, 28, 105, 139, 182, 70, 92, 63 }, // left = d207 - { 46, 23, 32, 74, 86, 150, 67, 183, 88 }, // left = d63 - { 36, 38, 48, 92, 122, 165, 88, 137, 91 } // left = tm - }, - { - // above = tm - { 65, 70, 60, 155, 159, 199, 61, 60, 81 }, // left = dc - { 44, 78, 115, 132, 119, 173, 71, 112, 93 }, // left = v - { 39, 38, 21, 184, 227, 206, 42, 32, 64 }, // left = h - { 58, 47, 36, 124, 137, 193, 80, 82, 78 }, // left = d45 - { 49, 50, 35, 144, 95, 205, 63, 78, 59 }, // left = d135 - { 41, 53, 52, 148, 71, 142, 65, 128, 51 }, // left = d117 - { 40, 36, 28, 143, 143, 202, 40, 55, 137 }, // left = d153 - { 52, 34, 29, 129, 183, 227, 42, 35, 43 }, // left = d207 - { 42, 44, 44, 104, 105, 164, 64, 130, 80 }, // left = d63 - { 43, 81, 53, 140, 169, 204, 68, 84, 72 } // left = tm - } -}; - -static constexpr KfUVModeProbs constant_kf_uv_mode_prob = { - { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, // y = dc - { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, // y = v - { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, // y = h - { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, // y = d45 - { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, // y = d135 - { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, // y = d117 - { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, // y = d153 - { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, // y = d207 - { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, // y = d63 - { 102, 19, 66, 162, 182, 122, 35, 59, 128 } // y = tm -}; - -static constexpr PartitionProbs default_partition_probs = { - // 8x8 -> 4x4 - { 199, 122, 141 }, // a/l both not split - { 147, 63, 159 }, // a split, l not split - { 148, 133, 118 }, // l split, a not split - { 121, 104, 114 }, // a/l both split - // 16x16 -> 8x8 - { 174, 73, 87 }, // a/l both not split - { 92, 41, 83 }, // a split, l not split - { 82, 99, 50 }, // l split, a not split - { 53, 39, 39 }, // a/l both split - // 32x32 -> 16x16 - { 177, 58, 59 }, // a/l both not split - { 68, 26, 63 }, // a split, l not split - { 52, 79, 25 }, // l split, a not split - { 17, 14, 12 }, // a/l both split - // 64x64 -> 32x32 - { 222, 34, 30 }, // a/l both not split - { 72, 16, 44 }, // a split, l not split - { 58, 32, 12 }, // l split, a not split - { 10, 7, 6 }, // a/l both split -}; - -static constexpr YModeProbs default_y_mode_probs = { - { 65, 32, 18, 144, 162, 194, 41, 51, 98 }, // block_size < 8x8 - { 132, 68, 18, 165, 217, 196, 45, 40, 78 }, // block_size < 16x16 - { 173, 80, 19, 176, 240, 193, 64, 35, 46 }, // block_size < 32x32 - { 221, 135, 38, 194, 248, 121, 96, 85, 29 } // block_size >= 32x32 -}; - -static constexpr UVModeProbs default_uv_mode_probs = { - { 120, 7, 76, 176, 208, 126, 28, 54, 103 }, // y = dc - { 48, 12, 154, 155, 139, 90, 34, 117, 119 }, // y = v - { 67, 6, 25, 204, 243, 158, 13, 21, 96 }, // y = h - { 97, 5, 44, 131, 176, 139, 48, 68, 97 }, // y = d45 - { 83, 5, 42, 156, 111, 152, 26, 49, 152 }, // y = d135 - { 80, 5, 58, 178, 74, 83, 33, 62, 145 }, // y = d117 - { 86, 5, 32, 154, 192, 168, 14, 22, 163 }, // y = d153 - { 85, 5, 32, 156, 216, 148, 19, 29, 73 }, // y = d207 - { 77, 7, 64, 116, 132, 122, 37, 126, 120 }, // y = d63 - { 101, 21, 107, 181, 192, 103, 19, 67, 125 } // y = tm -}; - -static constexpr SkipProb default_skip_prob = { - 192, 128, 64 -}; - -static constexpr IsInterProb default_is_inter_prob = { - 9, 102, 187, 225 -}; - -static constexpr CompModeProb default_comp_mode_prob = { - 239, 183, 119, 96, 41 -}; - -static constexpr CompRefProb default_comp_ref_prob = { - 50, 126, 123, 221, 226 -}; - -static constexpr SingleRefProb default_single_ref_prob = { - { 33, 16 }, - { 77, 74 }, - { 142, 142 }, - { 172, 170 }, - { 238, 247 } -}; - -static constexpr MvSignProb default_mv_sign_prob = { - 128, 128 -}; - -static constexpr MvBitsProb default_mv_bits_prob = { - { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, - { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 } -}; - -static constexpr MvClass0BitProb default_mv_class0_bit_prob = { - 216, 208 -}; - -static constexpr TxProbs default_tx_probs = { - { { 0, 0, 0 }, { 0, 0, 0 } }, - { { 100, 0, 0 }, { 66, 0, 0 } }, - { { 20, 152, 0 }, { 15, 101, 0 } }, - { { 3, 136, 37 }, { 5, 52, 13 } } -}; - -static constexpr InterModeProbs default_inter_mode_probs = { - { 2, 173, 34 }, // 0 = both zero mv - { 7, 145, 85 }, // 1 = one zero mv + one a predicted mv - { 7, 166, 63 }, // 2 = two predicted mvs - { 7, 94, 66 }, // 3 = one predicted/zero and one new mv - { 8, 64, 46 }, // 4 = two new mvs - { 17, 81, 31 }, // 5 = one intra neighbor + x - { 25, 29, 30 }, // 6 = two intra neighbors -}; - -static constexpr InterpFilterProbs default_interp_filter_probs = { - { 235, 162 }, { 36, 255 }, { 34, 3 }, { 149, 144 } -}; - -static constexpr MvJointProbs default_mv_joint_probs = { - 32, 64, 96 -}; - -static constexpr MvClassProbs default_mv_class_probs = { - { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 }, { 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 } -}; - -static constexpr MvClass0FrProbs default_mv_class0_fr_probs = { - { { 128, 128, 64 }, { 96, 112, 64 } }, { { 128, 128, 64 }, { 96, 112, 64 } } -}; - -static constexpr MvClass0HpProbs default_mv_class0_hp_prob = { - 160, 160 -}; - -static constexpr MvFrProbs default_mv_fr_probs = { - { 64, 96, 64 }, { 64, 96, 64 } -}; - -static constexpr MvHpProb default_mv_hp_prob = { - 128, 128 -}; - -static constexpr CoefProbs default_coef_probs = { - { { /* block Type 0 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 195, 29, 183 }, - { 84, 49, 136 }, - { 8, 42, 71 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 31, 107, 169 }, - { 35, 99, 159 }, - { 17, 82, 140 }, - { 8, 66, 114 }, - { 2, 44, 76 }, - { 1, 19, 32 } }, - { /* Coeff Band 2 */ - { 40, 132, 201 }, - { 29, 114, 187 }, - { 13, 91, 157 }, - { 7, 75, 127 }, - { 3, 58, 95 }, - { 1, 28, 47 } }, - { /* Coeff Band 3 */ - { 69, 142, 221 }, - { 42, 122, 201 }, - { 15, 91, 159 }, - { 6, 67, 121 }, - { 1, 42, 77 }, - { 1, 17, 31 } }, - { /* Coeff Band 4 */ - { 102, 148, 228 }, - { 67, 117, 204 }, - { 17, 82, 154 }, - { 6, 59, 114 }, - { 2, 39, 75 }, - { 1, 15, 29 } }, - { /* Coeff Band 5 */ - { 156, 57, 233 }, - { 119, 57, 212 }, - { 58, 48, 163 }, - { 29, 40, 124 }, - { 12, 30, 81 }, - { 3, 12, 31 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 191, 107, 226 }, - { 124, 117, 204 }, - { 25, 99, 155 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 29, 148, 210 }, - { 37, 126, 194 }, - { 8, 93, 157 }, - { 2, 68, 118 }, - { 1, 39, 69 }, - { 1, 17, 33 } }, - { /* Coeff Band 2 */ - { 41, 151, 213 }, - { 27, 123, 193 }, - { 3, 82, 144 }, - { 1, 58, 105 }, - { 1, 32, 60 }, - { 1, 13, 26 } }, - { /* Coeff Band 3 */ - { 59, 159, 220 }, - { 23, 126, 198 }, - { 4, 88, 151 }, - { 1, 66, 114 }, - { 1, 38, 71 }, - { 1, 18, 34 } }, - { /* Coeff Band 4 */ { 114, 136, 232 }, - { 51, 114, 207 }, - { 11, 83, 155 }, - { 3, 56, 105 }, - { 1, 33, 65 }, - { 1, 17, 34 } }, - { /* Coeff Band 5 */ - { 149, 65, 234 }, - { 121, 57, 215 }, - { 61, 49, 166 }, - { 28, 36, 114 }, - { 12, 25, 76 }, - { 3, 16, 42 } } } }, - { /* block Type 1 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 214, 49, 220 }, - { 132, 63, 188 }, - { 42, 65, 137 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 85, 137, 221 }, - { 104, 131, 216 }, - { 49, 111, 192 }, - { 21, 87, 155 }, - { 2, 49, 87 }, - { 1, 16, 28 } }, - { /* Coeff Band 2 */ - { 89, 163, 230 }, - { 90, 137, 220 }, - { 29, 100, 183 }, - { 10, 70, 135 }, - { 2, 42, 81 }, - { 1, 17, 33 } }, - { /* Coeff Band 3 */ - { 108, 167, 237 }, - { 55, 133, 222 }, - { 15, 97, 179 }, - { 4, 72, 135 }, - { 1, 45, 85 }, - { 1, 19, 38 } }, - { /* Coeff Band 4 */ - { 124, 146, 240 }, - { 66, 124, 224 }, - { 17, 88, 175 }, - { 4, 58, 122 }, - { 1, 36, 75 }, - { 1, 18, 37 } }, - { /* Coeff Band 5 */ - { 141, 79, 241 }, - { 126, 70, 227 }, - { 66, 58, 182 }, - { 30, 44, 136 }, - { 12, 34, 96 }, - { 2, 20, 47 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 229, 99, 249 }, - { 143, 111, 235 }, - { 46, 109, 192 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 82, 158, 236 }, - { 94, 146, 224 }, - { 25, 117, 191 }, - { 9, 87, 149 }, - { 3, 56, 99 }, - { 1, 33, 57 } }, - { /* Coeff Band 2 */ - { 83, 167, 237 }, - { 68, 145, 222 }, - { 10, 103, 177 }, - { 2, 72, 131 }, - { 1, 41, 79 }, - { 1, 20, 39 } }, - { /* Coeff Band 3 */ - { 99, 167, 239 }, - { 47, 141, 224 }, - { 10, 104, 178 }, - { 2, 73, 133 }, - { 1, 44, 85 }, - { 1, 22, 47 } }, - { /* Coeff Band 4 */ { 127, 145, 243 }, - { 71, 129, 228 }, - { 17, 93, 177 }, - { 3, 61, 124 }, - { 1, 41, 84 }, - { 1, 21, 52 } }, - { /* Coeff Band 5 */ - { 157, 78, 244 }, - { 140, 72, 231 }, - { 69, 58, 184 }, - { 31, 44, 137 }, - { 14, 38, 105 }, - { 8, 23, 61 } } } } }, - { { /* block Type 0 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 125, 34, 187 }, - { 52, 41, 133 }, - { 6, 31, 56 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 37, 109, 153 }, - { 51, 102, 147 }, - { 23, 87, 128 }, - { 8, 67, 101 }, - { 1, 41, 63 }, - { 1, 19, 29 } }, - { /* Coeff Band 2 */ - { 31, 154, 185 }, - { 17, 127, 175 }, - { 6, 96, 145 }, - { 2, 73, 114 }, - { 1, 51, 82 }, - { 1, 28, 45 } }, - { /* Coeff Band 3 */ - { 23, 163, 200 }, - { 10, 131, 185 }, - { 2, 93, 148 }, { 1, 67, 111 }, - { 1, 41, 69 }, - { 1, 14, 24 } }, - { /* Coeff Band 4 */ - { 29, 176, 217 }, - { 12, 145, 201 }, - { 3, 101, 156 }, - { 1, 69, 111 }, - { 1, 39, 63 }, - { 1, 14, 23 } }, - { /* Coeff Band 5 */ - { 57, 192, 233 }, - { 25, 154, 215 }, - { 6, 109, 167 }, - { 3, 78, 118 }, - { 1, 48, 69 }, - { 1, 21, 29 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 202, 105, 245 }, - { 108, 106, 216 }, - { 18, 90, 144 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 33, 172, 219 }, - { 64, 149, 206 }, - { 14, 117, 177 }, - { 5, 90, 141 }, - { 2, 61, 95 }, - { 1, 37, 57 } }, - { /* Coeff Band 2 */ - { 33, 179, 220 }, - { 11, 140, 198 }, - { 1, 89, 148 }, - { 1, 60, 104 }, - { 1, 33, 57 }, - { 1, 12, 21 } }, - { /* Coeff Band 3 */ - { 30, 181, 221 }, - { 8, 141, 198 }, - { 1, 87, 145 }, - { 1, 58, 100 }, { 1, 31, 55 }, - { 1, 12, 20 } }, - { /* Coeff Band 4 */ - { 32, 186, 224 }, - { 7, 142, 198 }, - { 1, 86, 143 }, - { 1, 58, 100 }, - { 1, 31, 55 }, - { 1, 12, 22 } }, - { /* Coeff Band 5 */ - { 57, 192, 227 }, - { 20, 143, 204 }, - { 3, 96, 154 }, - { 1, 68, 112 }, - { 1, 42, 69 }, - { 1, 19, 32 } } } }, - { /* block Type 1 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 212, 35, 215 }, - { 113, 47, 169 }, - { 29, 48, 105 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 74, 129, 203 }, - { 106, 120, 203 }, - { 49, 107, 178 }, - { 19, 84, 144 }, - { 4, 50, 84 }, - { 1, 15, 25 } }, - { /* Coeff Band 2 */ - { 71, 172, 217 }, - { 44, 141, 209 }, - { 15, 102, 173 }, - { 6, 76, 133 }, - { 2, 51, 89 }, - { 1, 24, 42 } }, - { /* Coeff Band 3 */ - { 64, 185, 231 }, - { 31, 148, 216 }, - { 8, 103, 175 }, { 3, 74, 131 }, - { 1, 46, 81 }, - { 1, 18, 30 } }, - { /* Coeff Band 4 */ - { 65, 196, 235 }, - { 25, 157, 221 }, - { 5, 105, 174 }, - { 1, 67, 120 }, - { 1, 38, 69 }, - { 1, 15, 30 } }, - { /* Coeff Band 5 */ - { 65, 204, 238 }, - { 30, 156, 224 }, - { 7, 107, 177 }, - { 2, 70, 124 }, - { 1, 42, 73 }, - { 1, 18, 34 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 225, 86, 251 }, - { 144, 104, 235 }, - { 42, 99, 181 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 85, 175, 239 }, - { 112, 165, 229 }, - { 29, 136, 200 }, - { 12, 103, 162 }, - { 6, 77, 123 }, - { 2, 53, 84 } }, - { /* Coeff Band 2 */ - { 75, 183, 239 }, - { 30, 155, 221 }, - { 3, 106, 171 }, - { 1, 74, 128 }, - { 1, 44, 76 }, - { 1, 17, 28 } }, - { /* Coeff Band 3 */ - { 73, 185, 240 }, - { 27, 159, 222 }, - { 2, 107, 172 }, - { 1, 75, 127 }, { 1, 42, 73 }, - { 1, 17, 29 } }, - { /* Coeff Band 4 */ - { 62, 190, 238 }, - { 21, 159, 222 }, - { 2, 107, 172 }, - { 1, 72, 122 }, - { 1, 40, 71 }, - { 1, 18, 32 } }, - { /* Coeff Band 5 */ - { 61, 199, 240 }, - { 27, 161, 226 }, - { 4, 113, 180 }, - { 1, 76, 129 }, - { 1, 46, 80 }, - { 1, 23, 41 } } } } }, - { { /* block Type 0 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 7, 27, 153 }, - { 5, 30, 95 }, - { 1, 16, 30 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 50, 75, 127 }, - { 57, 75, 124 }, - { 27, 67, 108 }, - { 10, 54, 86 }, - { 1, 33, 52 }, - { 1, 12, 18 } }, - { /* Coeff Band 2 */ - { 43, 125, 151 }, - { 26, 108, 148 }, - { 7, 83, 122 }, - { 2, 59, 89 }, - { 1, 38, 60 }, - { 1, 17, 27 } }, - { /* Coeff Band 3 */ { 23, 144, 163 }, - { 13, 112, 154 }, - { 2, 75, 117 }, - { 1, 50, 81 }, - { 1, 31, 51 }, - { 1, 14, 23 } }, - { /* Coeff Band 4 */ - { 18, 162, 185 }, - { 6, 123, 171 }, - { 1, 78, 125 }, - { 1, 51, 86 }, - { 1, 31, 54 }, - { 1, 14, 23 } }, - { /* Coeff Band 5 */ - { 15, 199, 227 }, - { 3, 150, 204 }, - { 1, 91, 146 }, - { 1, 55, 95 }, - { 1, 30, 53 }, - { 1, 11, 20 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 19, 55, 240 }, - { 19, 59, 196 }, - { 3, 52, 105 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 41, 166, 207 }, - { 104, 153, 199 }, - { 31, 123, 181 }, - { 14, 101, 152 }, - { 5, 72, 106 }, - { 1, 36, 52 } }, - { /* Coeff Band 2 */ - { 35, 176, 211 }, - { 12, 131, 190 }, - { 2, 88, 144 }, - { 1, 60, 101 }, - { 1, 36, 60 }, - { 1, 16, 28 } }, - { /* Coeff Band 3 */ - { 28, 183, 213 }, { 8, 134, 191 }, - { 1, 86, 142 }, - { 1, 56, 96 }, - { 1, 30, 53 }, - { 1, 12, 20 } }, - { /* Coeff Band 4 */ - { 20, 190, 215 }, - { 4, 135, 192 }, - { 1, 84, 139 }, - { 1, 53, 91 }, - { 1, 28, 49 }, - { 1, 11, 20 } }, - { /* Coeff Band 5 */ - { 13, 196, 216 }, - { 2, 137, 192 }, - { 1, 86, 143 }, - { 1, 57, 99 }, - { 1, 32, 56 }, - { 1, 13, 24 } } } }, - { /* block Type 1 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 211, 29, 217 }, - { 96, 47, 156 }, - { 22, 43, 87 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 78, 120, 193 }, - { 111, 116, 186 }, - { 46, 102, 164 }, - { 15, 80, 128 }, - { 2, 49, 76 }, - { 1, 18, 28 } }, - { /* Coeff Band 2 */ - { 71, 161, 203 }, - { 42, 132, 192 }, - { 10, 98, 150 }, - { 3, 69, 109 }, - { 1, 44, 70 }, - { 1, 18, 29 } }, - { /* Coeff Band 3 */ { 57, 186, 211 }, - { 30, 140, 196 }, - { 4, 93, 146 }, - { 1, 62, 102 }, - { 1, 38, 65 }, - { 1, 16, 27 } }, - { /* Coeff Band 4 */ - { 47, 199, 217 }, - { 14, 145, 196 }, - { 1, 88, 142 }, - { 1, 57, 98 }, - { 1, 36, 62 }, - { 1, 15, 26 } }, - { /* Coeff Band 5 */ - { 26, 219, 229 }, - { 5, 155, 207 }, - { 1, 94, 151 }, - { 1, 60, 104 }, - { 1, 36, 62 }, - { 1, 16, 28 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 233, 29, 248 }, - { 146, 47, 220 }, - { 43, 52, 140 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 100, 163, 232 }, - { 179, 161, 222 }, - { 63, 142, 204 }, - { 37, 113, 174 }, - { 26, 89, 137 }, - { 18, 68, 97 } }, - { /* Coeff Band 2 */ - { 85, 181, 230 }, - { 32, 146, 209 }, - { 7, 100, 164 }, - { 3, 71, 121 }, - { 1, 45, 77 }, - { 1, 18, 30 } }, - { /* Coeff Band 3 */ - { 65, 187, 230 }, { 20, 148, 207 }, - { 2, 97, 159 }, - { 1, 68, 116 }, - { 1, 40, 70 }, - { 1, 14, 29 } }, - { /* Coeff Band 4 */ - { 40, 194, 227 }, - { 8, 147, 204 }, - { 1, 94, 155 }, - { 1, 65, 112 }, - { 1, 39, 66 }, - { 1, 14, 26 } }, - { /* Coeff Band 5 */ - { 16, 208, 228 }, - { 3, 151, 207 }, - { 1, 98, 160 }, - { 1, 67, 117 }, - { 1, 41, 74 }, - { 1, 17, 31 } } } } }, - { { /* block Type 0 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 17, 38, 140 }, - { 7, 34, 80 }, - { 1, 17, 29 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 37, 75, 128 }, - { 41, 76, 128 }, - { 26, 66, 116 }, - { 12, 52, 94 }, - { 2, 32, 55 }, - { 1, 10, 16 } }, - { /* Coeff Band 2 */ - { 50, 127, 154 }, - { 37, 109, 152 }, - { 16, 82, 121 }, - { 5, 59, 85 }, { 1, 35, 54 }, - { 1, 13, 20 } }, - { /* Coeff Band 3 */ - { 40, 142, 167 }, - { 17, 110, 157 }, - { 2, 71, 112 }, - { 1, 44, 72 }, - { 1, 27, 45 }, - { 1, 11, 17 } }, - { /* Coeff Band 4 */ - { 30, 175, 188 }, - { 9, 124, 169 }, - { 1, 74, 116 }, - { 1, 48, 78 }, - { 1, 30, 49 }, - { 1, 11, 18 } }, - { /* Coeff Band 5 */ - { 10, 222, 223 }, - { 2, 150, 194 }, - { 1, 83, 128 }, - { 1, 48, 79 }, - { 1, 27, 45 }, - { 1, 11, 17 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 36, 41, 235 }, - { 29, 36, 193 }, - { 10, 27, 111 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 85, 165, 222 }, - { 177, 162, 215 }, - { 110, 135, 195 }, - { 57, 113, 168 }, - { 23, 83, 120 }, - { 10, 49, 61 } }, - { /* Coeff Band 2 */ - { 85, 190, 223 }, - { 36, 139, 200 }, - { 5, 90, 146 }, - { 1, 60, 103 }, - { 1, 38, 65 }, { 1, 18, 30 } }, - { /* Coeff Band 3 */ - { 72, 202, 223 }, - { 23, 141, 199 }, - { 2, 86, 140 }, - { 1, 56, 97 }, - { 1, 36, 61 }, - { 1, 16, 27 } }, - { /* Coeff Band 4 */ - { 55, 218, 225 }, - { 13, 145, 200 }, - { 1, 86, 141 }, - { 1, 57, 99 }, - { 1, 35, 61 }, - { 1, 13, 22 } }, - { /* Coeff Band 5 */ - { 15, 235, 212 }, - { 1, 132, 184 }, - { 1, 84, 139 }, - { 1, 57, 97 }, - { 1, 34, 56 }, - { 1, 14, 23 } } } }, - { /* block Type 1 */ - { /* Intra */ - { - /* Coeff Band 0 */ - { 181, 21, 201 }, - { 61, 37, 123 }, - { 10, 38, 71 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 47, 106, 172 }, - { 95, 104, 173 }, - { 42, 93, 159 }, - { 18, 77, 131 }, - { 4, 50, 81 }, - { 1, 17, 23 } }, - { /* Coeff Band 2 */ - { 62, 147, 199 }, - { 44, 130, 189 }, - { 28, 102, 154 }, - { 18, 75, 115 }, { 2, 44, 65 }, - { 1, 12, 19 } }, - { /* Coeff Band 3 */ - { 55, 153, 210 }, - { 24, 130, 194 }, - { 3, 93, 146 }, - { 1, 61, 97 }, - { 1, 31, 50 }, - { 1, 10, 16 } }, - { /* Coeff Band 4 */ - { 49, 186, 223 }, - { 17, 148, 204 }, - { 1, 96, 142 }, - { 1, 53, 83 }, - { 1, 26, 44 }, - { 1, 11, 17 } }, - { /* Coeff Band 5 */ - { 13, 217, 212 }, - { 2, 136, 180 }, - { 1, 78, 124 }, - { 1, 50, 83 }, - { 1, 29, 49 }, - { 1, 14, 23 } } }, - { /* Inter */ - { - /* Coeff Band 0 */ - { 197, 13, 247 }, - { 82, 17, 222 }, - { 25, 17, 162 }, - { 0, 0, 0 }, // unused - { 0, 0, 0 }, // unused - { 0, 0, 0 } // unused - }, - { /* Coeff Band 1 */ - { 126, 186, 247 }, - { 234, 191, 243 }, - { 176, 177, 234 }, - { 104, 158, 220 }, - { 66, 128, 186 }, - { 55, 90, 137 } }, - { /* Coeff Band 2 */ - { 111, 197, 242 }, - { 46, 158, 219 }, - { 9, 104, 171 }, - { 2, 65, 125 }, - { 1, 44, 80 }, { 1, 17, 91 } }, - { /* Coeff Band 3 */ - { 104, 208, 245 }, - { 39, 168, 224 }, - { 3, 109, 162 }, - { 1, 79, 124 }, - { 1, 50, 102 }, - { 1, 43, 102 } }, - { /* Coeff Band 4 */ - { 84, 220, 246 }, - { 31, 177, 231 }, - { 2, 115, 180 }, - { 1, 79, 134 }, - { 1, 55, 77 }, - { 1, 60, 79 } }, - { /* Coeff Band 5 */ - { 43, 243, 240 }, - { 8, 180, 217 }, - { 1, 115, 166 }, - { 1, 84, 121 }, - { 1, 51, 67 }, - { 1, 16, 6 } } } } } -}; - -ParetoTable const& ProbabilityTables::pareto_table() const -{ - return constant_pareto_table; -} - -KfPartitionProbs const& ProbabilityTables::kf_partition_probs() const -{ - return constant_kf_partition_probs; -} - -KfYModeProbs const& ProbabilityTables::kf_y_mode_probs() const -{ - return constant_kf_y_mode_probs; -} - -KfUVModeProbs const& ProbabilityTables::kf_uv_mode_prob() const -{ - return constant_kf_uv_mode_prob; -} - -void ProbabilityTables::save_probs(u8 index) -{ - m_saved_probability_tables[index] = m_current_probability_table; -} - -void ProbabilityTables::reset_probs() -{ - __builtin_memcpy(m_current_probability_table.partition_probs, default_partition_probs, sizeof(PartitionProbs)); - __builtin_memcpy(m_current_probability_table.y_mode_probs, default_y_mode_probs, sizeof(YModeProbs)); - __builtin_memcpy(m_current_probability_table.uv_mode_probs, default_uv_mode_probs, sizeof(UVModeProbs)); - __builtin_memcpy(m_current_probability_table.skip_prob, default_skip_prob, sizeof(SkipProb)); - __builtin_memcpy(m_current_probability_table.is_inter_prob, default_is_inter_prob, sizeof(IsInterProb)); - __builtin_memcpy(m_current_probability_table.comp_mode_prob, default_comp_mode_prob, sizeof(CompModeProb)); - __builtin_memcpy(m_current_probability_table.comp_ref_prob, default_comp_ref_prob, sizeof(CompRefProb)); - __builtin_memcpy(m_current_probability_table.single_ref_prob, default_single_ref_prob, sizeof(SingleRefProb)); - __builtin_memcpy(m_current_probability_table.mv_sign_prob, default_mv_sign_prob, sizeof(MvSignProb)); - __builtin_memcpy(m_current_probability_table.mv_bits_prob, default_mv_bits_prob, sizeof(MvBitsProb)); - __builtin_memcpy(m_current_probability_table.mv_class0_bit_prob, default_mv_class0_bit_prob, sizeof(MvClass0BitProb)); - __builtin_memcpy(m_current_probability_table.tx_probs, default_tx_probs, sizeof(TxProbs)); - __builtin_memcpy(m_current_probability_table.inter_mode_probs, default_inter_mode_probs, sizeof(InterModeProbs)); - __builtin_memcpy(m_current_probability_table.interp_filter_probs, default_interp_filter_probs, sizeof(InterpFilterProbs)); - __builtin_memcpy(m_current_probability_table.mv_joint_probs, default_mv_joint_probs, sizeof(MvJointProbs)); - __builtin_memcpy(m_current_probability_table.mv_class_probs, default_mv_class_probs, sizeof(MvClassProbs)); - __builtin_memcpy(m_current_probability_table.mv_class0_fr_probs, default_mv_class0_fr_probs, sizeof(MvClass0FrProbs)); - __builtin_memcpy(m_current_probability_table.mv_class0_hp_prob, default_mv_class0_hp_prob, sizeof(MvClass0HpProbs)); - __builtin_memcpy(m_current_probability_table.mv_fr_probs, default_mv_fr_probs, sizeof(MvFrProbs)); - __builtin_memcpy(m_current_probability_table.mv_hp_prob, default_mv_hp_prob, sizeof(MvHpProb)); - __builtin_memcpy(m_current_probability_table.coef_probs, default_coef_probs, sizeof(CoefProbs)); -} - -void ProbabilityTables::load_probs(u8 index) -{ - auto old_table = m_current_probability_table; - m_current_probability_table = m_saved_probability_tables.at(index); - __builtin_memcpy(m_current_probability_table.skip_prob, old_table.skip_prob, sizeof(SkipProb)); - __builtin_memcpy(m_current_probability_table.tx_probs, old_table.tx_probs, sizeof(TxProbs)); -} - -void ProbabilityTables::load_probs2(u8 index) -{ - auto new_table = m_saved_probability_tables.at(index); - __builtin_memcpy(m_current_probability_table.skip_prob, new_table.skip_prob, sizeof(SkipProb)); - __builtin_memcpy(m_current_probability_table.tx_probs, new_table.tx_probs, sizeof(TxProbs)); -} - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.h b/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.h deleted file mode 100644 index 1fc3c537eb3..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/ProbabilityTables.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "Symbols.h" - -namespace Media::Video::VP9 { - -typedef u8 ParetoTable[128][8]; -typedef u8 KfPartitionProbs[PARTITION_CONTEXTS][PARTITION_TYPES - 1]; -typedef u8 KfYModeProbs[INTRA_MODES][INTRA_MODES][INTRA_MODES - 1]; -typedef u8 KfUVModeProbs[INTRA_MODES][INTRA_MODES - 1]; -typedef u8 PartitionProbs[PARTITION_CONTEXTS][PARTITION_TYPES - 1]; -typedef u8 YModeProbs[BLOCK_SIZE_GROUPS][INTRA_MODES - 1]; -typedef u8 UVModeProbs[INTRA_MODES][INTRA_MODES - 1]; -typedef u8 SkipProb[SKIP_CONTEXTS]; -typedef u8 IsInterProb[IS_INTER_CONTEXTS]; -typedef u8 CompModeProb[COMP_MODE_CONTEXTS]; -typedef u8 CompRefProb[REF_CONTEXTS]; -typedef u8 SingleRefProb[REF_CONTEXTS][2]; -typedef u8 MvSignProb[2]; -typedef u8 MvBitsProb[2][MV_OFFSET_BITS]; -typedef u8 MvClass0BitProb[2]; -typedef u8 TxProbs[TX_SIZES][TX_SIZE_CONTEXTS][TX_SIZES - 1]; -typedef u8 InterModeProbs[INTER_MODE_CONTEXTS][INTER_MODES - 1]; -typedef u8 InterpFilterProbs[INTERP_FILTER_CONTEXTS][SWITCHABLE_FILTERS - 1]; -typedef u8 MvJointProbs[3]; -typedef u8 MvClassProbs[2][MV_CLASSES - 1]; -typedef u8 MvClass0FrProbs[2][CLASS0_SIZE][3]; -typedef u8 MvClass0HpProbs[2]; -typedef u8 MvFrProbs[2][3]; -typedef u8 MvHpProb[2]; -typedef u8 CoefProbs[TX_SIZES][BLOCK_TYPES][REF_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS][UNCONSTRAINED_NODES]; - -class ProbabilityTables final { -public: - void save_probs(u8 index); - void reset_probs(); - void load_probs(u8 index); - void load_probs2(u8 index); - - ParetoTable const& pareto_table() const; - KfPartitionProbs const& kf_partition_probs() const; - KfYModeProbs const& kf_y_mode_probs() const; - KfUVModeProbs const& kf_uv_mode_prob() const; - - PartitionProbs& partition_probs() { return m_current_probability_table.partition_probs; } - PartitionProbs const& partition_probs() const { return m_current_probability_table.partition_probs; } - YModeProbs& y_mode_probs() { return m_current_probability_table.y_mode_probs; } - YModeProbs const& y_mode_probs() const { return m_current_probability_table.y_mode_probs; } - UVModeProbs& uv_mode_probs() { return m_current_probability_table.uv_mode_probs; } - UVModeProbs const& uv_mode_probs() const { return m_current_probability_table.uv_mode_probs; } - SkipProb& skip_prob() { return m_current_probability_table.skip_prob; } - SkipProb const& skip_prob() const { return m_current_probability_table.skip_prob; } - IsInterProb& is_inter_prob() { return m_current_probability_table.is_inter_prob; } - IsInterProb const& is_inter_prob() const { return m_current_probability_table.is_inter_prob; } - CompModeProb& comp_mode_prob() { return m_current_probability_table.comp_mode_prob; } - CompModeProb const& comp_mode_prob() const { return m_current_probability_table.comp_mode_prob; } - CompRefProb& comp_ref_prob() { return m_current_probability_table.comp_ref_prob; } - CompRefProb const& comp_ref_prob() const { return m_current_probability_table.comp_ref_prob; } - SingleRefProb& single_ref_prob() { return m_current_probability_table.single_ref_prob; } - SingleRefProb const& single_ref_prob() const { return m_current_probability_table.single_ref_prob; } - MvSignProb& mv_sign_prob() { return m_current_probability_table.mv_sign_prob; } - MvSignProb const& mv_sign_prob() const { return m_current_probability_table.mv_sign_prob; } - MvBitsProb& mv_bits_prob() { return m_current_probability_table.mv_bits_prob; } - MvBitsProb const& mv_bits_prob() const { return m_current_probability_table.mv_bits_prob; } - MvClass0BitProb& mv_class0_bit_prob() { return m_current_probability_table.mv_class0_bit_prob; } - MvClass0BitProb const& mv_class0_bit_prob() const { return m_current_probability_table.mv_class0_bit_prob; } - TxProbs& tx_probs() { return m_current_probability_table.tx_probs; } - TxProbs const& tx_probs() const { return m_current_probability_table.tx_probs; } - InterModeProbs& inter_mode_probs() { return m_current_probability_table.inter_mode_probs; } - InterModeProbs const& inter_mode_probs() const { return m_current_probability_table.inter_mode_probs; } - InterpFilterProbs& interp_filter_probs() { return m_current_probability_table.interp_filter_probs; } - InterpFilterProbs const& interp_filter_probs() const { return m_current_probability_table.interp_filter_probs; } - MvJointProbs& mv_joint_probs() { return m_current_probability_table.mv_joint_probs; } - MvJointProbs const& mv_joint_probs() const { return m_current_probability_table.mv_joint_probs; } - MvClassProbs& mv_class_probs() { return m_current_probability_table.mv_class_probs; } - MvClassProbs const& mv_class_probs() const { return m_current_probability_table.mv_class_probs; } - MvClass0FrProbs& mv_class0_fr_probs() { return m_current_probability_table.mv_class0_fr_probs; } - MvClass0FrProbs const& mv_class0_fr_probs() const { return m_current_probability_table.mv_class0_fr_probs; } - MvClass0HpProbs& mv_class0_hp_prob() { return m_current_probability_table.mv_class0_hp_prob; } - MvClass0HpProbs const& mv_class0_hp_prob() const { return m_current_probability_table.mv_class0_hp_prob; } - MvFrProbs& mv_fr_probs() { return m_current_probability_table.mv_fr_probs; } - MvFrProbs const& mv_fr_probs() const { return m_current_probability_table.mv_fr_probs; } - MvHpProb& mv_hp_prob() { return m_current_probability_table.mv_hp_prob; } - MvHpProb const& mv_hp_prob() const { return m_current_probability_table.mv_hp_prob; } - CoefProbs& coef_probs() { return m_current_probability_table.coef_probs; } - CoefProbs const& coef_probs() const { return m_current_probability_table.coef_probs; } - -private: - struct ProbabilityTable { - PartitionProbs partition_probs; - YModeProbs y_mode_probs; - UVModeProbs uv_mode_probs; - SkipProb skip_prob; - IsInterProb is_inter_prob; - CompModeProb comp_mode_prob; - CompRefProb comp_ref_prob; - SingleRefProb single_ref_prob; - MvSignProb mv_sign_prob; - MvBitsProb mv_bits_prob; - MvClass0BitProb mv_class0_bit_prob; - TxProbs tx_probs; - InterModeProbs inter_mode_probs; - InterpFilterProbs interp_filter_probs; - MvJointProbs mv_joint_probs; - MvClassProbs mv_class_probs; - MvClass0FrProbs mv_class0_fr_probs; - MvClass0HpProbs mv_class0_hp_prob; - MvFrProbs mv_fr_probs; - MvHpProb mv_hp_prob; - CoefProbs coef_probs; - }; - - Array m_saved_probability_tables; - ProbabilityTable m_current_probability_table; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Symbols.h b/Userland/Libraries/LibMedia/Video/VP9/Symbols.h deleted file mode 100644 index 171eb97c500..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Symbols.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -namespace Media::Video::VP9 { - -// FIXME: These should be placed in logical groupings based on the -// context they are used in, and perhaps split into multiple -// files. While doing so, as many of these as possible should be -// renamed to be more human-readable, and most if not all should -// be constexpr variables rather than preprocessor definitions. - -#define REFS_PER_FRAME 3 -#define MV_FR_SIZE 4 -#define MVREF_NEIGHBORS 8 -#define BLOCK_SIZE_GROUPS 4 -#define BLOCK_SIZES 13 -#define BLOCK_INVALID 14 -#define PARTITION_CONTEXTS 16 -#define MI_SIZE 8 -#define MIN_TILE_WIDTH_B64 4 -#define MAX_TILE_WIDTH_B64 64 -#define MAX_MV_REF_CANDIDATES 2 -#define LOG2_OF_NUM_REF_FRAMES 3 -#define NUM_REF_FRAMES 1 << LOG2_OF_NUM_REF_FRAMES -#define MAX_REF_FRAMES 4 -#define IS_INTER_CONTEXTS 4 -#define COMP_MODE_CONTEXTS 5 -#define REF_CONTEXTS 5 -#define MAX_SEGMENTS 8 -#define BLOCK_TYPES 2 -#define REF_TYPES 2 -#define COEF_BANDS 6 -#define PREV_COEF_CONTEXTS 6 -#define UNCONSTRAINED_NODES 3 -#define TX_SIZE_CONTEXTS 2 -#define SWITCHABLE_FILTERS 3 -#define INTERP_FILTER_CONTEXTS 4 -#define SKIP_CONTEXTS 3 -#define PARTITION_TYPES 4 -#define TX_SIZES 4 -#define TX_MODES 5 -#define MB_MODE_COUNT 14 -#define INTRA_MODES 10 -#define INTER_MODES 4 -#define INTER_MODE_CONTEXTS 7 -#define MV_JOINTS 4 -#define MV_CLASSES 11 -#define CLASS0_SIZE 2 -#define MV_OFFSET_BITS 10 -#define MAX_PROB 255 -#define MAX_MODE_LF_DELTAS 2 -#define COMPANDED_MVREF_THRESH 8 -#define MAX_LOOP_FILTER 63 -#define REF_SCALE_SHIFT 14 -// Number of bits of precision when performing inter prediction. -#define SUBPEL_BITS 4 -#define SUBPEL_SHIFTS 16 -#define SUBPEL_MASK 15 -#define MV_BORDER 128 -// Value used when clipping motion vectors. -#define INTERP_EXTEND 4 -// Value used when clipping motion vectors. -#define BORDERINPIXELS 160 -#define MAX_UPDATE_FACTOR 128 -#define COUNT_SAT 20 -#define BOTH_ZERO 0 -#define ZERO_PLUS_PREDICTED 1 -#define BOTH_PREDICTED 2 -#define NEW_PLUS_NON_INTRA 3 -#define BOTH_NEW 4 -#define INTRA_PLUS_NON_INTRA 5 -#define BOTH_INTRA 6 -#define INVALID_CASE 9 - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.cpp b/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.cpp deleted file mode 100644 index 373dc3fa175..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "SyntaxElementCounter.h" -#include - -namespace Media::Video::VP9 { - -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)); - __builtin_memset(m_counts_partition, 0, sizeof(m_counts_partition)); - __builtin_memset(m_counts_interp_filter, 0, sizeof(m_counts_interp_filter)); - __builtin_memset(m_counts_inter_mode, 0, sizeof(m_counts_inter_mode)); - __builtin_memset(m_counts_tx_size, 0, sizeof(m_counts_tx_size)); - __builtin_memset(m_counts_is_inter, 0, sizeof(m_counts_is_inter)); - __builtin_memset(m_counts_comp_mode, 0, sizeof(m_counts_comp_mode)); - __builtin_memset(m_counts_single_ref, 0, sizeof(m_counts_single_ref)); - __builtin_memset(m_counts_comp_ref, 0, sizeof(m_counts_comp_ref)); - __builtin_memset(m_counts_skip, 0, sizeof(m_counts_skip)); - __builtin_memset(m_counts_mv_joint, 0, sizeof(m_counts_mv_joint)); - __builtin_memset(m_counts_mv_sign, 0, sizeof(m_counts_mv_sign)); - __builtin_memset(m_counts_mv_class, 0, sizeof(m_counts_mv_class)); - __builtin_memset(m_counts_mv_class0_bit, 0, sizeof(m_counts_mv_class0_bit)); - __builtin_memset(m_counts_mv_class0_fr, 0, sizeof(m_counts_mv_class0_fr)); - __builtin_memset(m_counts_mv_class0_hp, 0, sizeof(m_counts_mv_class0_hp)); - __builtin_memset(m_counts_mv_bits, 0, sizeof(m_counts_mv_bits)); - __builtin_memset(m_counts_mv_fr, 0, sizeof(m_counts_mv_fr)); - __builtin_memset(m_counts_mv_hp, 0, sizeof(m_counts_mv_hp)); - __builtin_memset(m_counts_token, 0, sizeof(m_counts_token)); - __builtin_memset(m_counts_more_coefs, 0, sizeof(m_counts_more_coefs)); -} - -template -static void sum_arrays(T (&destination)[size], T const (&left)[size], T const (&right)[size]) -{ - for (size_t i = 0; i < size; i++) { - destination[i] = left[i] + right[i]; - } -} - -template -static void sum_arrays(T (&destination)[size][size_2], T const (&left)[size][size_2], T const (&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; -} - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.h b/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.h deleted file mode 100644 index aa2427a79c3..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/SyntaxElementCounter.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Symbols.h" -#include - -namespace Media::Video::VP9 { - -class SyntaxElementCounter final { -public: - SyntaxElementCounter(); - - /* (8.3) Clear Counts Process */ - void clear_counts(); - - u32 m_counts_intra_mode[BLOCK_SIZE_GROUPS][INTRA_MODES]; - u32 m_counts_uv_mode[INTRA_MODES][INTRA_MODES]; - u32 m_counts_partition[PARTITION_CONTEXTS][PARTITION_TYPES]; - u32 m_counts_interp_filter[INTERP_FILTER_CONTEXTS][SWITCHABLE_FILTERS]; - u32 m_counts_inter_mode[INTER_MODE_CONTEXTS][INTER_MODES]; - u32 m_counts_tx_size[TX_SIZES][TX_SIZE_CONTEXTS][TX_SIZES]; - u32 m_counts_is_inter[IS_INTER_CONTEXTS][2]; - u32 m_counts_comp_mode[COMP_MODE_CONTEXTS][2]; - u32 m_counts_single_ref[REF_CONTEXTS][2][2]; - u32 m_counts_comp_ref[REF_CONTEXTS][2]; - u32 m_counts_skip[SKIP_CONTEXTS][2]; - u32 m_counts_mv_joint[MV_JOINTS]; - u32 m_counts_mv_sign[2][2]; - u32 m_counts_mv_class[2][MV_CLASSES]; - u32 m_counts_mv_class0_bit[2][CLASS0_SIZE]; - u32 m_counts_mv_class0_fr[2][CLASS0_SIZE][MV_FR_SIZE]; - u32 m_counts_mv_class0_hp[2][2]; - u32 m_counts_mv_bits[2][MV_OFFSET_BITS][2]; - u32 m_counts_mv_fr[2][MV_FR_SIZE]; - 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&); -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/TreeParser.cpp b/Userland/Libraries/LibMedia/Video/VP9/TreeParser.cpp deleted file mode 100644 index 05f066549e0..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/TreeParser.cpp +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -#include "Context.h" -#include "Enums.h" -#include "LookupTables.h" -#include "Parser.h" -#include "TreeParser.h" -#include "Utilities.h" - -namespace Media::Video::VP9 { - -// Parsing of binary trees is handled here, as defined in sections 9.3. -// Each syntax element is defined in its own section for each overarching section listed here: -// - 9.3.1: Selection of the binary tree to be used. -// - 9.3.2: Probability selection based on context and often the node of the tree. -// - 9.3.4: Counting each syntax element when it is read. - -class TreeSelection { -public: - union TreeSelectionValue { - int const* m_tree; - int m_value; - }; - - constexpr TreeSelection(int const* values) - : m_is_single_value(false) - , m_value { .m_tree = values } - { - } - - constexpr TreeSelection(int value) - : m_is_single_value(true) - , m_value { .m_value = value } - { - } - - bool is_single_value() const { return m_is_single_value; } - int single_value() const { return m_value.m_value; } - int const* tree() const { return m_value.m_tree; } - -private: - bool m_is_single_value; - TreeSelectionValue m_value; -}; - -template -inline OutputType parse_tree(BooleanDecoder& decoder, TreeSelection tree_selection, Function const& probability_getter) -{ - // 9.3.3: The tree decoding function. - if (tree_selection.is_single_value()) - return static_cast(tree_selection.single_value()); - - int const* tree = tree_selection.tree(); - int n = 0; - do { - u8 node = n >> 1; - n = tree[n + decoder.read_bool(probability_getter(node))]; - } while (n > 0); - - return static_cast(-n); -} - -Partition TreeParser::parse_partition(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, bool has_rows, bool has_columns, BlockSubsize block_subsize, u8 num_8x8, PartitionContextView above_partition_context, PartitionContextView left_partition_context, u32 row, u32 column, bool frame_is_intra) -{ - // Tree array - TreeSelection tree = { PartitionSplit }; - if (has_rows && has_columns) - tree = { partition_tree }; - else if (has_rows) - tree = { rows_partition_tree }; - else if (has_columns) - tree = { cols_partition_tree }; - - // Probability array - u32 above = 0; - u32 left = 0; - auto bsl = mi_width_log2_lookup[block_subsize]; - auto block_offset = mi_width_log2_lookup[Block_64x64] - bsl; - for (auto i = 0; i < num_8x8; i++) { - above |= above_partition_context[column + i]; - left |= left_partition_context[row + i]; - } - above = (above & (1 << block_offset)) > 0; - left = (left & (1 << block_offset)) > 0; - auto context = bsl * 4 + left * 2 + above; - u8 const* probabilities = frame_is_intra ? probability_table.kf_partition_probs()[context] : probability_table.partition_probs()[context]; - - Function probability_getter = [&](u8 node) { - if (has_rows && has_columns) - return probabilities[node]; - if (has_columns) - return probabilities[1]; - return probabilities[2]; - }; - - auto value = parse_tree(decoder, tree, probability_getter); - counter.m_counts_partition[context][value]++; - return value; -} - -PredictionMode TreeParser::parse_default_intra_mode(BooleanDecoder& decoder, 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. - - // Tree - TreeSelection tree = { intra_mode_tree }; - - // Probabilities - PredictionMode above_mode, left_mode; - if (mi_size >= Block_8x8) { - 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.sub_modes[2 + index_x]; - - if (index_x > 0) - left_mode = block_sub_modes[index_y << 1]; - else - 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)]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - // Default intra mode is not counted. - return value; -} - -PredictionMode TreeParser::parse_default_uv_mode(BooleanDecoder& decoder, ProbabilityTables const& probability_table, PredictionMode y_mode) -{ - // Tree - TreeSelection tree = { intra_mode_tree }; - - // Probabilities - u8 const* probabilities = probability_table.kf_uv_mode_prob()[to_underlying(y_mode)]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - // Default UV mode is not counted. - return value; -} - -PredictionMode TreeParser::parse_intra_mode(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, BlockSubsize mi_size) -{ - // Tree - TreeSelection tree = { intra_mode_tree }; - - // Probabilities - auto context = size_group_lookup[mi_size]; - u8 const* probabilities = probability_table.y_mode_probs()[context]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_intra_mode[context][to_underlying(value)]++; - return value; -} - -PredictionMode TreeParser::parse_sub_intra_mode(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter) -{ - // Tree - TreeSelection tree = { intra_mode_tree }; - - // Probabilities - u8 const* probabilities = probability_table.y_mode_probs()[0]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_intra_mode[0][to_underlying(value)]++; - return value; -} - -PredictionMode TreeParser::parse_uv_mode(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, PredictionMode y_mode) -{ - // Tree - TreeSelection tree = { intra_mode_tree }; - - // Probabilities - u8 const* probabilities = probability_table.uv_mode_probs()[to_underlying(y_mode)]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_uv_mode[to_underlying(y_mode)][to_underlying(value)]++; - return value; -} - -u8 TreeParser::parse_segment_id(BooleanDecoder& decoder, Array const& probabilities) -{ - auto value = parse_tree(decoder, { segment_tree }, [&](u8 node) { return probabilities[node]; }); - // Segment ID is not counted. - return value; -} - -bool TreeParser::parse_segment_id_predicted(BooleanDecoder& decoder, Array const& probabilities, u8 above_seg_pred_context, u8 left_seg_pred_context) -{ - auto context = left_seg_pred_context + above_seg_pred_context; - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probabilities[context]; }); - // Segment ID prediction is not counted. - return value; -} - -PredictionMode TreeParser::parse_inter_mode(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 mode_context_for_ref_frame_0) -{ - // Tree - TreeSelection tree = { inter_mode_tree }; - - // Probabilities - u8 const* probabilities = probability_table.inter_mode_probs()[mode_context_for_ref_frame_0]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_inter_mode[mode_context_for_ref_frame_0][value]++; - return static_cast(value + to_underlying(PredictionMode::NearestMv)); -} - -InterpolationFilter TreeParser::parse_interpolation_filter(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left) -{ - // FIXME: Above and left context should be provided by a struct. - - // Tree - TreeSelection tree = { interp_filter_tree }; - - // Probabilities - // 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.is_intra_predicted() ? left.interpolation_filter : SWITCHABLE_FILTERS; - u8 above_interp = !above.is_intra_predicted() ? above.interpolation_filter : SWITCHABLE_FILTERS; - u8 context = SWITCHABLE_FILTERS; - if (above_interp == left_interp || above_interp == SWITCHABLE_FILTERS) - context = left_interp; - else if (left_interp == SWITCHABLE_FILTERS) - context = above_interp; - u8 const* probabilities = probability_table.interp_filter_probs()[context]; - - auto value = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_interp_filter[context][to_underlying(value)]++; - return value; -} - -bool TreeParser::parse_skip(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left) -{ - // Probabilities - u8 context = 0; - context += static_cast(above.skip_coefficients); - context += static_cast(left.skip_coefficients); - u8 probability = probability_table.skip_prob()[context]; - - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_skip[context][value]++; - return value; -} - -TransformSize TreeParser::parse_tx_size(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TransformSize max_tx_size, FrameBlockContext above, FrameBlockContext left) -{ - // FIXME: Above and left contexts should be in structs. - - // Tree - TreeSelection tree { tx_size_8_tree }; - if (max_tx_size == Transform_16x16) - tree = { tx_size_16_tree }; - if (max_tx_size == Transform_32x32) - tree = { tx_size_32_tree }; - - // Probabilities - auto above_context = max_tx_size; - auto left_context = max_tx_size; - if (above.is_available && !above.skip_coefficients) - above_context = above.transform_size; - if (left.is_available && !left.skip_coefficients) - left_context = left.transform_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 = parse_tree(decoder, tree, [&](u8 node) { return probabilities[node]; }); - counter.m_counts_tx_size[max_tx_size][context][value]++; - return value; -} - -bool TreeParser::parse_block_is_inter_predicted(BooleanDecoder& decoder, 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.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 = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_is_inter[context][value]++; - return value; -} - -ReferenceMode TreeParser::parse_comp_mode(BooleanDecoder& decoder, 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.is_available && left.is_available) { - if (above.is_single_reference() && left.is_single_reference()) { - auto is_above_fixed = above.ref_frames.primary == comp_fixed_ref; - auto is_left_fixed = left.ref_frames.primary == comp_fixed_ref; - context = is_above_fixed ^ is_left_fixed; - } else if (above.is_single_reference()) { - auto is_above_fixed = above.ref_frames.primary == 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.primary == comp_fixed_ref; - context = 2 + static_cast(is_left_fixed || left.is_intra_predicted()); - } else { - context = 4; - } - } else if (above.is_available) { - if (above.is_single_reference()) - context = above.ref_frames.primary == comp_fixed_ref; - else - context = 3; - } else if (left.is_available) { - if (left.is_single_reference()) - context = static_cast(left.ref_frames.primary == comp_fixed_ref); - else - context = 3; - } else { - context = 1; - } - u8 probability = probability_table.comp_mode_prob()[context]; - - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_comp_mode[context][value]++; - return value; -} - -ReferenceIndex TreeParser::parse_comp_ref(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, ReferenceIndex variable_reference_index, FrameBlockContext above, FrameBlockContext left) -{ - // FIXME: Above and left contexts should be in structs. - - // Probabilities - u8 context; - - if (above.is_available && left.is_available) { - if (above.is_intra_predicted() && left.is_intra_predicted()) { - context = 2; - } else if (left.is_intra_predicted()) { - if (above.is_single_reference()) { - context = 1 + 2 * (above.ref_frames.primary != comp_var_ref.secondary); - } else { - context = 1 + 2 * (above.ref_frames[variable_reference_index] != comp_var_ref.secondary); - } - } else if (above.is_intra_predicted()) { - if (left.is_single_reference()) { - context = 1 + 2 * (left.ref_frames.primary != comp_var_ref.secondary); - } else { - context = 1 + 2 * (left.ref_frames[variable_reference_index] != comp_var_ref.secondary); - } - } else { - auto var_ref_above = above.is_single_reference() ? above.ref_frames.primary : above.ref_frames[variable_reference_index]; - auto var_ref_left = left.is_single_reference() ? left.ref_frames.primary : left.ref_frames[variable_reference_index]; - if (var_ref_above == var_ref_left && comp_var_ref.secondary == var_ref_above) { - context = 0; - } else if (left.is_single_reference() && above.is_single_reference()) { - if ((var_ref_above == comp_fixed_ref && var_ref_left == comp_var_ref.primary) - || (var_ref_left == comp_fixed_ref && var_ref_above == comp_var_ref.primary)) { - context = 4; - } else if (var_ref_above == var_ref_left) { - context = 3; - } else { - context = 1; - } - } 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.secondary && rfs != comp_var_ref.secondary) { - context = 1; - } else if (rfs == comp_var_ref.secondary && vrfc != comp_var_ref.secondary) { - context = 2; - } else { - context = 4; - } - } else if (var_ref_above == var_ref_left) { - context = 4; - } else { - context = 2; - } - } - } else if (above.is_available) { - if (above.is_intra_predicted()) { - context = 2; - } else { - if (above.is_single_reference()) { - context = 3 * static_cast(above.ref_frames.primary != comp_var_ref.secondary); - } else { - context = 4 * static_cast(above.ref_frames[variable_reference_index] != comp_var_ref.secondary); - } - } - } else if (left.is_available) { - if (left.is_intra_predicted()) { - context = 2; - } else { - if (left.is_single_reference()) { - context = 3 * static_cast(left.ref_frames.primary != comp_var_ref.secondary); - } else { - context = 4 * static_cast(left.ref_frames[variable_reference_index] != comp_var_ref.secondary); - } - } - } else { - context = 2; - } - - u8 probability = probability_table.comp_ref_prob()[context]; - - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_comp_ref[context][to_underlying(value)]++; - return value; -} - -bool TreeParser::parse_single_ref_part_1(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left) -{ - // FIXME: Above and left contexts should be in structs. - - // Probabilities - u8 context; - if (above.is_available && left.is_available) { - if (above.is_intra_predicted() && left.is_intra_predicted()) { - context = 2; - } else if (left.is_intra_predicted()) { - if (above.is_single_reference()) { - context = 4 * (above.ref_frames.primary == ReferenceFrameType::LastFrame); - } else { - context = 1 + (above.ref_frames.primary == ReferenceFrameType::LastFrame || above.ref_frames.secondary == ReferenceFrameType::LastFrame); - } - } else if (above.is_intra_predicted()) { - if (left.is_single_reference()) { - context = 4 * (left.ref_frames.primary == ReferenceFrameType::LastFrame); - } else { - context = 1 + (left.ref_frames.primary == ReferenceFrameType::LastFrame || left.ref_frames.secondary == ReferenceFrameType::LastFrame); - } - } else { - if (left.is_single_reference() && above.is_single_reference()) { - context = 2 * (above.ref_frames.primary == ReferenceFrameType::LastFrame) + 2 * (left.ref_frames.primary == ReferenceFrameType::LastFrame); - } else if (!left.is_single_reference() && !above.is_single_reference()) { - auto above_used_last_frame = above.ref_frames.primary == ReferenceFrameType::LastFrame || above.ref_frames.secondary == ReferenceFrameType::LastFrame; - auto left_used_last_frame = left.ref_frames.primary == ReferenceFrameType::LastFrame || left.ref_frames.secondary == ReferenceFrameType::LastFrame; - context = 1 + (above_used_last_frame || left_used_last_frame); - } else { - auto single_reference_type = above.is_single_reference() ? above.ref_frames.primary : left.ref_frames.primary; - auto compound_reference_a_type = above.is_single_reference() ? left.ref_frames.primary : above.ref_frames.primary; - auto compound_reference_b_type = above.is_single_reference() ? left.ref_frames.secondary : above.ref_frames.secondary; - context = compound_reference_a_type == ReferenceFrameType::LastFrame || compound_reference_b_type == ReferenceFrameType::LastFrame; - if (single_reference_type == ReferenceFrameType::LastFrame) - context += 3; - } - } - } else if (above.is_available) { - if (above.is_intra_predicted()) { - context = 2; - } else { - if (above.is_single_reference()) { - context = 4 * (above.ref_frames.primary == ReferenceFrameType::LastFrame); - } else { - context = 1 + (above.ref_frames.primary == ReferenceFrameType::LastFrame || above.ref_frames.secondary == ReferenceFrameType::LastFrame); - } - } - } else if (left.is_available) { - if (left.is_intra_predicted()) { - context = 2; - } else { - if (left.is_single_reference()) { - context = 4 * (left.ref_frames.primary == ReferenceFrameType::LastFrame); - } else { - context = 1 + (left.ref_frames.primary == ReferenceFrameType::LastFrame || left.ref_frames.secondary == ReferenceFrameType::LastFrame); - } - } - } else { - context = 2; - } - u8 probability = probability_table.single_ref_prob()[context][0]; - - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_single_ref[context][0][value]++; - return value; -} - -bool TreeParser::parse_single_ref_part_2(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, FrameBlockContext above, FrameBlockContext left) -{ - // FIXME: Above and left contexts should be in structs. - - // Probabilities - u8 context; - if (above.is_available && left.is_available) { - if (above.is_intra_predicted() && left.is_intra_predicted()) { - context = 2; - } else if (left.is_intra_predicted()) { - if (above.is_single_reference()) { - if (above.ref_frames.primary == ReferenceFrameType::LastFrame) { - context = 3; - } else { - context = 4 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } - } else { - context = 1 + 2 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame || above.ref_frames.secondary == ReferenceFrameType::GoldenFrame); - } - } else if (above.is_intra_predicted()) { - if (left.is_single_reference()) { - if (left.ref_frames.primary == ReferenceFrameType::LastFrame) { - context = 3; - } else { - context = 4 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } - } else { - context = 1 + 2 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame || left.ref_frames.secondary == ReferenceFrameType::GoldenFrame); - } - } else { - if (left.is_single_reference() && above.is_single_reference()) { - auto above_last = above.ref_frames.primary == ReferenceFrameType::LastFrame; - auto left_last = left.ref_frames.primary == ReferenceFrameType::LastFrame; - if (above_last && left_last) { - context = 3; - } else if (above_last) { - context = 4 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } else if (left_last) { - context = 4 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } else { - context = 2 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame) + 2 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } - } else if (!left.is_single_reference() && !above.is_single_reference()) { - if (above.ref_frames.primary == left.ref_frames.primary && above.ref_frames.secondary == left.ref_frames.secondary) { - context = 3 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame || above.ref_frames.secondary == ReferenceFrameType::GoldenFrame); - } else { - context = 2; - } - } else { - auto single_reference_type = above.is_single_reference() ? above.ref_frames.primary : left.ref_frames.primary; - auto compound_reference_a_type = above.is_single_reference() ? left.ref_frames.primary : above.ref_frames.primary; - auto compound_reference_b_type = above.is_single_reference() ? left.ref_frames.secondary : above.ref_frames.secondary; - context = compound_reference_a_type == ReferenceFrameType::GoldenFrame || compound_reference_b_type == ReferenceFrameType::GoldenFrame; - if (single_reference_type == ReferenceFrameType::GoldenFrame) { - context += 3; - } else if (single_reference_type != ReferenceFrameType::AltRefFrame) { - context = 1 + (2 * context); - } - } - } - } else if (above.is_available) { - if (above.is_intra_predicted() || (above.ref_frames.primary == ReferenceFrameType::LastFrame && above.is_single_reference())) { - context = 2; - } else if (above.is_single_reference()) { - context = 4 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } else { - context = 3 * (above.ref_frames.primary == ReferenceFrameType::GoldenFrame || above.ref_frames.secondary == ReferenceFrameType::GoldenFrame); - } - } else if (left.is_available) { - if (left.is_intra_predicted() || (left.ref_frames.primary == ReferenceFrameType::LastFrame && left.is_single_reference())) { - context = 2; - } else if (left.is_single_reference()) { - context = 4 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame); - } else { - context = 3 * (left.ref_frames.primary == ReferenceFrameType::GoldenFrame || left.ref_frames.secondary == ReferenceFrameType::GoldenFrame); - } - } else { - context = 2; - } - u8 probability = probability_table.single_ref_prob()[context][1]; - - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_single_ref[context][1][value]++; - return value; -} - -MvJoint TreeParser::parse_motion_vector_joint(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter) -{ - auto value = parse_tree(decoder, { mv_joint_tree }, [&](u8 node) { return probability_table.mv_joint_probs()[node]; }); - counter.m_counts_mv_joint[value]++; - return value; -} - -bool TreeParser::parse_motion_vector_sign(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component) -{ - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability_table.mv_sign_prob()[component]; }); - counter.m_counts_mv_sign[component][value]++; - return value; -} - -MvClass TreeParser::parse_motion_vector_class(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component) -{ - // Spec doesn't mention node, but the probabilities table has an extra dimension - // so we will use node for that. - auto value = parse_tree(decoder, { mv_class_tree }, [&](u8 node) { return probability_table.mv_class_probs()[component][node]; }); - counter.m_counts_mv_class[component][value]++; - return value; -} - -bool TreeParser::parse_motion_vector_class0_bit(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component) -{ - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability_table.mv_class0_bit_prob()[component]; }); - counter.m_counts_mv_class0_bit[component][value]++; - return value; -} - -u8 TreeParser::parse_motion_vector_class0_fr(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component, bool class_0_bit) -{ - auto value = parse_tree(decoder, { mv_fr_tree }, [&](u8 node) { return probability_table.mv_class0_fr_probs()[component][class_0_bit][node]; }); - counter.m_counts_mv_class0_fr[component][class_0_bit][value]++; - return value; -} - -bool TreeParser::parse_motion_vector_class0_hp(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component, bool use_hp) -{ - TreeSelection tree { 1 }; - if (use_hp) - tree = { binary_tree }; - auto value = parse_tree(decoder, tree, [&](u8) { return probability_table.mv_class0_hp_prob()[component]; }); - counter.m_counts_mv_class0_hp[component][value]++; - return value; -} - -bool TreeParser::parse_motion_vector_bit(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component, u8 bit_index) -{ - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability_table.mv_bits_prob()[component][bit_index]; }); - counter.m_counts_mv_bits[component][bit_index][value]++; - return value; -} - -u8 TreeParser::parse_motion_vector_fr(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component) -{ - auto value = parse_tree(decoder, { mv_fr_tree }, [&](u8 node) { return probability_table.mv_fr_probs()[component][node]; }); - counter.m_counts_mv_fr[component][value]++; - return value; -} - -bool TreeParser::parse_motion_vector_hp(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, u8 component, bool use_hp) -{ - TreeSelection tree { 1 }; - if (use_hp) - tree = { binary_tree }; - auto value = parse_tree(decoder, tree, [&](u8) { return probability_table.mv_hp_prob()[component]; }); - counter.m_counts_mv_hp[component][value]++; - return value; -} - -TokensContext TreeParser::get_context_for_first_token(NonZeroTokensView above_non_zero_tokens, NonZeroTokensView left_non_zero_tokens_in_block, TransformSize transform_size, u8 plane, u32 sub_block_column, u32 sub_block_row, bool is_inter, u8 band) -{ - u8 transform_size_in_sub_blocks = transform_size_to_sub_blocks(transform_size); - bool above_has_non_zero_tokens = false; - for (u8 x = 0; x < transform_size_in_sub_blocks && x < above_non_zero_tokens[plane].size() - sub_block_column; x++) { - if (above_non_zero_tokens[plane][sub_block_column + x]) { - above_has_non_zero_tokens = true; - break; - } - } - bool left_has_non_zero_tokens = false; - for (u8 y = 0; y < transform_size_in_sub_blocks && y < left_non_zero_tokens_in_block[plane].size() - sub_block_row; y++) { - if (left_non_zero_tokens_in_block[plane][sub_block_row + y]) { - left_has_non_zero_tokens = true; - break; - } - } - - u8 context = above_has_non_zero_tokens + left_has_non_zero_tokens; - return TokensContext { transform_size, plane > 0, is_inter, band, context }; -} - -TokensContext TreeParser::get_context_for_other_tokens(Array token_cache, TransformSize transform_size, TransformSet transform_set, u8 plane, u16 token_position, bool is_inter, u8 band) -{ - auto transform_size_in_pixels = sub_blocks_to_pixels(transform_size_to_sub_blocks(transform_size)); - auto log2_of_transform_size = transform_size + 2; - auto pixel_y = token_position >> log2_of_transform_size; - auto pixel_x = token_position - (pixel_y << log2_of_transform_size); - auto above_token_energy = pixel_y > 0 ? (pixel_y - 1) * transform_size_in_pixels + pixel_x : 0; - auto left_token_energy = pixel_y * transform_size_in_pixels + pixel_x - 1; - - u32 neighbor_a, neighbor_b; - if (pixel_y > 0 && pixel_x > 0) { - if (transform_set == TransformSet { TransformType::DCT, TransformType::ADST }) { - neighbor_a = above_token_energy; - neighbor_b = above_token_energy; - } else if (transform_set == TransformSet { TransformType::ADST, TransformType::DCT }) { - neighbor_a = left_token_energy; - neighbor_b = left_token_energy; - } else { - neighbor_a = above_token_energy; - neighbor_b = left_token_energy; - } - } else if (pixel_y > 0) { - neighbor_a = above_token_energy; - neighbor_b = above_token_energy; - } else { - neighbor_a = left_token_energy; - neighbor_b = left_token_energy; - } - - u8 context = (1 + token_cache[neighbor_a] + token_cache[neighbor_b]) >> 1; - return TokensContext { transform_size, plane > 0, is_inter, band, context }; -} - -bool TreeParser::parse_more_coefficients(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TokensContext const& context) -{ - auto probability = probability_table.coef_probs()[context.m_tx_size][context.m_is_uv_plane][context.m_is_inter][context.m_band][context.m_context_index][0]; - auto value = parse_tree(decoder, { binary_tree }, [&](u8) { return probability; }); - counter.m_counts_more_coefs[context.m_tx_size][context.m_is_uv_plane][context.m_is_inter][context.m_band][context.m_context_index][value]++; - return value; -} - -Token TreeParser::parse_token(BooleanDecoder& decoder, ProbabilityTables const& probability_table, SyntaxElementCounter& counter, TokensContext const& context) -{ - Function probability_getter = [&](u8 node) -> u8 { - auto prob = probability_table.coef_probs()[context.m_tx_size][context.m_is_uv_plane][context.m_is_inter][context.m_band][context.m_context_index][min(2, 1 + node)]; - if (node < 2) - return prob; - auto x = (prob - 1) / 2; - auto const& pareto_table = probability_table.pareto_table(); - if ((prob & 1) != 0) - return pareto_table[x][node - 2]; - return (pareto_table[x][node - 2] + pareto_table[x + 1][node - 2]) >> 1; - }; - - auto value = parse_tree(decoder, { token_tree }, probability_getter); - counter.m_counts_token[context.m_tx_size][context.m_is_uv_plane][context.m_is_inter][context.m_band][context.m_context_index][min(2, value)]++; - return value; -} - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/TreeParser.h b/Userland/Libraries/LibMedia/Video/VP9/TreeParser.h deleted file mode 100644 index bc3f3143209..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/TreeParser.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "BooleanDecoder.h" -#include "ContextStorage.h" -#include "Enums.h" -#include "ProbabilityTables.h" -#include "SyntaxElementCounter.h" - -namespace Media::Video::VP9 { - -class Parser; - -struct BlockContext; -struct FrameBlockContext; - -struct TokensContext { - TransformSize m_tx_size; - bool m_is_uv_plane; - bool m_is_inter; - u8 m_band; - u8 m_context_index; -}; - -class TreeParser { -public: - static Partition parse_partition(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, bool has_rows, bool has_columns, BlockSubsize block_subsize, u8 num_8x8, PartitionContextView above_partition_context, PartitionContextView left_partition_context, u32 row, u32 column, bool frame_is_intra); - static PredictionMode parse_default_intra_mode(BooleanDecoder&, ProbabilityTables const&, BlockSubsize mi_size, FrameBlockContext above, FrameBlockContext left, Array const& block_sub_modes, u8 index_x, u8 index_y); - static PredictionMode parse_default_uv_mode(BooleanDecoder&, ProbabilityTables const&, PredictionMode y_mode); - static PredictionMode parse_intra_mode(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, BlockSubsize mi_size); - static PredictionMode parse_sub_intra_mode(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&); - static PredictionMode parse_uv_mode(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, PredictionMode y_mode); - static u8 parse_segment_id(BooleanDecoder&, Array const& probabilities); - static bool parse_segment_id_predicted(BooleanDecoder&, Array const& probabilities, u8 above_seg_pred_context, u8 left_seg_pred_context); - static PredictionMode parse_inter_mode(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 mode_context_for_ref_frame_0); - static InterpolationFilter parse_interpolation_filter(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); - static bool parse_skip(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); - static TransformSize parse_tx_size(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, TransformSize max_tx_size, FrameBlockContext above, FrameBlockContext left); - static bool parse_block_is_inter_predicted(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); - static ReferenceMode parse_comp_mode(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, FrameBlockContext above, FrameBlockContext left); - static ReferenceIndex parse_comp_ref(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, ReferenceFrameType comp_fixed_ref, ReferenceFramePair comp_var_ref, ReferenceIndex variable_reference_index, FrameBlockContext above, FrameBlockContext left); - static bool parse_single_ref_part_1(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); - static bool parse_single_ref_part_2(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, FrameBlockContext above, FrameBlockContext left); - - static MvJoint parse_motion_vector_joint(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&); - static bool parse_motion_vector_sign(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component); - static MvClass parse_motion_vector_class(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component); - static bool parse_motion_vector_class0_bit(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component); - static u8 parse_motion_vector_class0_fr(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component, bool class_0_bit); - static bool parse_motion_vector_class0_hp(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component, bool use_hp); - static bool parse_motion_vector_bit(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component, u8 bit_index); - static u8 parse_motion_vector_fr(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component); - static bool parse_motion_vector_hp(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, u8 component, bool use_hp); - - static TokensContext get_context_for_first_token(NonZeroTokensView above_non_zero_tokens, NonZeroTokensView left_non_zero_tokens, TransformSize transform_size, u8 plane, u32 sub_block_column, u32 sub_block_row, bool is_inter, u8 band); - static TokensContext get_context_for_other_tokens(Array token_cache, TransformSize transform_size, TransformSet transform_set, u8 plane, u16 token_position, bool is_inter, u8 band); - static bool parse_more_coefficients(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, TokensContext const& context); - static Token parse_token(BooleanDecoder&, ProbabilityTables const&, SyntaxElementCounter&, TokensContext const& context); -}; - -struct PartitionTreeContext { - 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; -}; - -} diff --git a/Userland/Libraries/LibMedia/Video/VP9/Utilities.h b/Userland/Libraries/LibMedia/Video/VP9/Utilities.h deleted file mode 100644 index 9b4176aff21..00000000000 --- a/Userland/Libraries/LibMedia/Video/VP9/Utilities.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2021, Hunter Salyer - * Copyright (c) 2022, Gregory Bertilson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -#include "LookupTables.h" - -namespace Media::Video::VP9 { - -// FIXME: Once everything is working, replace this with plain clamp -// since parameter order is different -template -T clip_3(T x, T y, T z) -{ - return clamp(z, x, y); -} - -template -u16 clip_1(u8 bit_depth, T x) -{ - if (x < 0) { - return 0u; - } - T const max = (1u << bit_depth) - 1u; - if (x > max) - return max; - return x; -} - -template -inline u8 brev(u8 value) -{ - static_assert(bits <= 8, "brev() expects an 8-bit value."); - - static constexpr auto lookup_table = [] { - constexpr size_t value_count = 1 << bits; - Array the_table; - for (u8 lookup_value = 0; lookup_value < value_count; lookup_value++) { - u8 reversed = 0; - for (u8 bit_index = 0; bit_index < bits; bit_index++) { - auto bit = (lookup_value >> bit_index) & 1; - reversed |= bit << (bits - 1 - bit_index); - } - the_table[lookup_value] = reversed; - } - return the_table; - }(); - - return lookup_table[value]; -} - -inline BlockSubsize get_subsampled_block_size(BlockSubsize size, bool subsampling_x, bool subsampling_y) -{ - return ss_size_lookup[size < Block_8x8 ? Block_8x8 : size][subsampling_x][subsampling_y]; -} - -inline Gfx::Size block_size_to_blocks(BlockSubsize size) -{ - return Gfx::Size(num_8x8_blocks_wide_lookup[size], num_8x8_blocks_high_lookup[size]); -} - -inline Gfx::Size block_size_to_sub_blocks(BlockSubsize size) -{ - return Gfx::Size(num_4x4_blocks_wide_lookup[size], num_4x4_blocks_high_lookup[size]); -} - -template -inline T blocks_to_superblocks(T blocks) -{ - return blocks >> 3; -} - -template -inline T superblocks_to_blocks(T superblocks) -{ - return superblocks << 3; -} - -template -inline T blocks_ceiled_to_superblocks(T blocks) -{ - return blocks_to_superblocks(blocks + 7); -} - -template -inline T blocks_to_sub_blocks(T blocks) -{ - return blocks << 1; -} - -template -inline T sub_blocks_to_blocks(T sub_blocks) -{ - return sub_blocks >> 1; -} - -template -inline T sub_blocks_to_pixels(T sub_blocks) -{ - return sub_blocks << 2; -} - -template -inline T pixels_to_sub_blocks(T pixels) -{ - return pixels >> 2; -} - -template -inline T blocks_to_pixels(T blocks) -{ - return sub_blocks_to_pixels(blocks_to_sub_blocks(blocks)); -} - -template -inline T pixels_to_blocks(T pixels) -{ - return sub_blocks_to_blocks(pixels_to_sub_blocks(pixels)); -} - -inline u8 transform_size_to_sub_blocks(TransformSize transform_size) -{ - return 1 << transform_size; -} - -}