LibVideo/VP9: Implement MV reading & rectify MV storage issues

With this patch we are finally done with section 6.4.X of the spec :^)
The only parsing left to be done is 6.5.X, motion vector prediction.

Additionally, this patch fixes how MVs were being stored in the parser.
Originally, due to the spec naming two very different values very
similarly, these properties had totally wrong data types, but this has
now been rectified.
This commit is contained in:
FalseHonesty 2021-06-27 17:03:53 -04:00 committed by Andreas Kling
parent 27fdf8361c
commit d60bd42972
6 changed files with 129 additions and 14 deletions

View file

@ -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

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* 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());
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
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 };
};
}

View file

@ -752,8 +752,8 @@ void Parser::allocate_tile_data()
m_segment_ids = static_cast<u8*>(malloc(sizeof(u8) * dimensions));
m_ref_frames = static_cast<ReferenceFrame*>(malloc(sizeof(ReferenceFrame) * dimensions * 2));
m_interp_filters = static_cast<InterpolationFilter*>(malloc(sizeof(InterpolationFilter) * dimensions));
m_mvs = static_cast<InterMode*>(malloc(sizeof(InterMode) * dimensions * 2));
m_sub_mvs = static_cast<InterMode*>(malloc(sizeof(InterMode) * dimensions * 2 * 4));
m_mvs = static_cast<MV*>(malloc(sizeof(MV) * dimensions * 2));
m_sub_mvs = static_cast<MV*>(malloc(sizeof(MV) * dimensions * 2 * 4));
m_sub_modes = static_cast<IntraMode*>(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<MvJoint>(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<bool>(SyntaxElementType::MVSign);
auto mv_class = m_tree_parser->parse_tree<MvClass>(SyntaxElementType::MVClass);
u32 mag;
if (mv_class == MvClass0) {
auto mv_class0_bit = m_tree_parser->parse_tree<u32>(SyntaxElementType::MVClass0Bit);
auto mv_class0_fr = m_tree_parser->parse_tree<u32>(SyntaxElementType::MVClass0FR);
auto mv_class0_hp = m_tree_parser->parse_tree<u32>(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<bool>(SyntaxElementType::MVBit);
d |= mv_bit << i;
}
mag = CLASS0_SIZE << (mv_class + 2);
auto mv_fr = m_tree_parser->parse_tree<u32>(SyntaxElementType::MVFR);
auto mv_hp = m_tree_parser->parse_tree<u32>(SyntaxElementType::MVHP);
mag += ((d << 3) | (mv_fr << 1) | mv_hp) + 1;
}
return mv_sign ? -static_cast<i32>(mag) : static_cast<i32>(mag);
}
bool Parser::residual()
{
auto block_size = m_mi_size < Block_8x8 ? Block_8x8 : static_cast<BlockSubsize>(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);

View file

@ -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<BitStream> m_bit_stream;

View file

@ -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