summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibVideo
diff options
context:
space:
mode:
authorFalseHonesty <thefalsehonesty@gmail.com>2021-06-27 17:03:53 -0400
committerAndreas Kling <kling@serenityos.org>2021-07-10 21:28:56 +0200
commitd60bd42972b8146ec02cd884fdeac0304b234542 (patch)
treebaeb4f95a639aff7ba55ec43863af2b73a7c675c /Userland/Libraries/LibVideo
parent27fdf8361c454ed9de487201e4cc082dd177ac4b (diff)
downloadserenity-d60bd42972b8146ec02cd884fdeac0304b234542.zip
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.
Diffstat (limited to 'Userland/Libraries/LibVideo')
-rw-r--r--Userland/Libraries/LibVideo/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibVideo/VP9/MV.cpp38
-rw-r--r--Userland/Libraries/LibVideo/VP9/MV.h32
-rw-r--r--Userland/Libraries/LibVideo/VP9/Parser.cpp53
-rw-r--r--Userland/Libraries/LibVideo/VP9/Parser.h16
-rw-r--r--Userland/Libraries/LibVideo/VP9/TreeParser.cpp3
6 files changed, 129 insertions, 14 deletions
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 <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());
+}
+
+}
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 <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 };
+};
+
+}
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<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);
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<BitStream> 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