diff --git a/Userland/Libraries/LibVideo/CMakeLists.txt b/Userland/Libraries/LibVideo/CMakeLists.txt index ecc1b0483b..5e07b893f3 100644 --- a/Userland/Libraries/LibVideo/CMakeLists.txt +++ b/Userland/Libraries/LibVideo/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES VP9/Decoder.cpp VP9/Enums.h VP9/LookupTables.h + VP9/MV.cpp VP9/Parser.cpp VP9/ProbabilityTables.cpp VP9/Symbols.h diff --git a/Userland/Libraries/LibVideo/VP9/MV.cpp b/Userland/Libraries/LibVideo/VP9/MV.cpp new file mode 100644 index 0000000000..ac01e03e9c --- /dev/null +++ b/Userland/Libraries/LibVideo/VP9/MV.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Hunter Salyer + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "MV.h" + +namespace Video::VP9 { + +MV::MV(u32 row, u32 col) + : m_row(row) + , m_col(col) +{ +} + +MV& MV::operator=(MV const& other) +{ + if (this == &other) + return *this; + m_row = other.row(); + m_col = other.col(); + return *this; +} + +MV& MV::operator=(i32 value) +{ + m_row = value; + m_col = value; + return *this; +} + +MV MV::operator+(MV const& other) const +{ + return MV(this->row() + other.row(), this->col() + other.col()); +} + +} diff --git a/Userland/Libraries/LibVideo/VP9/MV.h b/Userland/Libraries/LibVideo/VP9/MV.h new file mode 100644 index 0000000000..7baa061247 --- /dev/null +++ b/Userland/Libraries/LibVideo/VP9/MV.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021, Hunter Salyer + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Video::VP9 { + +class MV { +public: + MV() = default; + MV(u32 row, u32 col); + + u32 row() const { return m_row; } + void set_row(u32 row) { m_row = row; } + u32 col() const { return m_col; } + void set_col(u32 col) { m_col = col; } + + MV& operator=(MV const& other); + MV& operator=(i32 value); + MV operator+(MV const& other) const; + +private: + u32 m_row { 0 }; + u32 m_col { 0 }; +}; + +} diff --git a/Userland/Libraries/LibVideo/VP9/Parser.cpp b/Userland/Libraries/LibVideo/VP9/Parser.cpp index edae871a7c..c8a459df2c 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.cpp +++ b/Userland/Libraries/LibVideo/VP9/Parser.cpp @@ -752,8 +752,8 @@ void Parser::allocate_tile_data() m_segment_ids = static_cast(malloc(sizeof(u8) * dimensions)); m_ref_frames = static_cast(malloc(sizeof(ReferenceFrame) * dimensions * 2)); m_interp_filters = static_cast(malloc(sizeof(InterpolationFilter) * dimensions)); - m_mvs = static_cast(malloc(sizeof(InterMode) * dimensions * 2)); - m_sub_mvs = static_cast(malloc(sizeof(InterMode) * dimensions * 2 * 4)); + m_mvs = static_cast(malloc(sizeof(MV) * dimensions * 2)); + m_sub_mvs = static_cast(malloc(sizeof(MV) * dimensions * 2 * 4)); m_sub_modes = static_cast(malloc(sizeof(IntraMode) * dimensions * 4)); m_allocated_dimensions = dimensions; } @@ -892,10 +892,10 @@ bool Parser::decode_block(u32 row, u32 col, u8 subsize) if (m_is_inter) { m_interp_filters[pos] = m_interp_filter; for (size_t ref_list = 0; ref_list < 2; ref_list++) { - auto pos_with_ref_list = pos * 2 + ref_list; + auto pos_with_ref_list = (pos * 2 + ref_list) * sizeof(MV); m_mvs[pos_with_ref_list] = m_block_mvs[ref_list][3]; for (size_t b = 0; b < 4; b++) - m_sub_mvs[pos_with_ref_list * 4 + b] = m_block_mvs[ref_list][b]; + m_sub_mvs[pos_with_ref_list * 4 + b * sizeof(MV)] = m_block_mvs[ref_list][b]; } } else { for (size_t b = 0; b < 4; b++) @@ -1168,7 +1168,7 @@ bool Parser::read_ref_frames() bool Parser::assign_mv(bool is_compound) { - m_mv[1] = ZeroMv; + m_mv[1] = 0; for (auto i = 0; i < 1 + is_compound; i++) { if (m_y_mode == NewMv) { SAFE_CALL(read_mv(i)); @@ -1177,18 +1177,49 @@ bool Parser::assign_mv(bool is_compound) } else if (m_y_mode == NearMv) { m_mv[i] = m_near_mv[i]; } else { - m_mv[i] = ZeroMv; + m_mv[i] = 0; } } return true; } -bool Parser::read_mv(u8) +bool Parser::read_mv(u8 ref) { - // TODO: Implement + m_use_hp = m_allow_high_precision_mv && use_mv_hp(m_best_mv[ref]); + MV diff_mv; + auto mv_joint = m_tree_parser->parse_tree(SyntaxElementType::MVJoint); + if (mv_joint == MvJointHzvnz || mv_joint == MvJointHnzvnz) + diff_mv.set_row(read_mv_component(0)); + if (mv_joint == MvJointHnzvz || mv_joint == MvJointHnzvnz) + diff_mv.set_col(read_mv_component(1)); + m_mv[ref] = m_best_mv[ref] + diff_mv; return true; } +i32 Parser::read_mv_component(u8) +{ + auto mv_sign = m_tree_parser->parse_tree(SyntaxElementType::MVSign); + auto mv_class = m_tree_parser->parse_tree(SyntaxElementType::MVClass); + u32 mag; + if (mv_class == MvClass0) { + auto mv_class0_bit = m_tree_parser->parse_tree(SyntaxElementType::MVClass0Bit); + auto mv_class0_fr = m_tree_parser->parse_tree(SyntaxElementType::MVClass0FR); + auto mv_class0_hp = m_tree_parser->parse_tree(SyntaxElementType::MVClass0HP); + mag = ((mv_class0_bit << 3) | (mv_class0_fr << 1) | mv_class0_hp) + 1; + } else { + auto d = 0; + for (size_t i = 0; i < mv_class; i++) { + auto mv_bit = m_tree_parser->parse_tree(SyntaxElementType::MVBit); + d |= mv_bit << i; + } + mag = CLASS0_SIZE << (mv_class + 2); + auto mv_fr = m_tree_parser->parse_tree(SyntaxElementType::MVFR); + auto mv_hp = m_tree_parser->parse_tree(SyntaxElementType::MVHP); + mag += ((d << 3) | (mv_fr << 1) | mv_hp) + 1; + } + return mv_sign ? -static_cast(mag) : static_cast(mag); +} + bool Parser::residual() { auto block_size = m_mi_size < Block_8x8 ? Block_8x8 : static_cast(m_mi_size); @@ -1365,6 +1396,12 @@ bool Parser::append_sub8x8_mvs(u8, u8) return true; } +bool Parser::use_mv_hp(const MV&) +{ + // TODO: Implement + return true; +} + void Parser::dump_info() { outln("Frame dimensions: {}x{}", m_frame_width, m_frame_height); diff --git a/Userland/Libraries/LibVideo/VP9/Parser.h b/Userland/Libraries/LibVideo/VP9/Parser.h index 8b1061652e..aeee6615d2 100644 --- a/Userland/Libraries/LibVideo/VP9/Parser.h +++ b/Userland/Libraries/LibVideo/VP9/Parser.h @@ -8,6 +8,7 @@ #include "BitStream.h" #include "LookupTables.h" +#include "MV.h" #include "ProbabilityTables.h" #include "SyntaxElementCounter.h" #include "TreeParser.h" @@ -116,6 +117,7 @@ private: bool read_ref_frames(); bool assign_mv(bool is_compound); bool read_mv(u8 ref); + i32 read_mv_component(u8 component); bool residual(); TXSize get_uv_tx_size(); BlockSubsize get_plane_block_size(u32 subsize, u8 plane); @@ -127,6 +129,7 @@ private: bool find_mv_refs(ReferenceFrame, int block); bool find_best_ref_mvs(int ref_list); bool append_sub8x8_mvs(u8 block, u8 ref_list); + bool use_mv_hp(MV const& delta_mv); u8 m_profile { 0 }; u8 m_frame_to_show_map_index { 0 }; @@ -216,9 +219,10 @@ private: bool m_left_single { false }; bool m_above_single { false }; InterpolationFilter m_interp_filter { EightTap }; - InterMode m_mv[2]; - InterMode m_near_mv[2]; - InterMode m_nearest_mv[2]; + MV m_mv[2]; + MV m_near_mv[2]; + MV m_nearest_mv[2]; + MV m_best_mv[2]; u32 m_ref_frame_width[NUM_REF_FRAMES]; u32 m_ref_frame_height[NUM_REF_FRAMES]; u32 m_eob_total { 0 }; @@ -230,7 +234,7 @@ private: ReferenceMode m_reference_mode; ReferenceFrame m_comp_fixed_ref; ReferenceFrame m_comp_var_ref[2]; - InterMode m_block_mvs[2][4]; + MV m_block_mvs[2][4]; u8* m_prev_segment_ids { nullptr }; u32 m_allocated_dimensions { 0 }; @@ -241,8 +245,8 @@ private: u8* m_segment_ids { nullptr }; ReferenceFrame* m_ref_frames { nullptr }; InterpolationFilter* m_interp_filters { nullptr }; - InterMode* m_mvs { nullptr }; - InterMode* m_sub_mvs { nullptr }; + MV* m_mvs { nullptr }; + MV* m_sub_mvs { nullptr }; IntraMode* m_sub_modes { nullptr }; OwnPtr m_bit_stream; diff --git a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp index aeb71a7930..bd702c251c 100644 --- a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp +++ b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp @@ -32,11 +32,14 @@ T TreeParser::parse_tree(SyntaxElementType type) template int TreeParser::parse_tree(SyntaxElementType); template bool TreeParser::parse_tree(SyntaxElementType); template u8 TreeParser::parse_tree(SyntaxElementType); +template u32 TreeParser::parse_tree(SyntaxElementType); template IntraMode TreeParser::parse_tree(SyntaxElementType); template TXSize TreeParser::parse_tree(SyntaxElementType); template InterpolationFilter TreeParser::parse_tree(SyntaxElementType); template ReferenceMode TreeParser::parse_tree(SyntaxElementType); template Token TreeParser::parse_tree(SyntaxElementType); +template MvClass TreeParser::parse_tree(SyntaxElementType); +template MvJoint TreeParser::parse_tree(SyntaxElementType); /* * Select a tree value based on the type of syntax element being parsed, as well as some parser state, as specified in section 9.3.1