LibVideo/VP9: Finish implementing block decoding (6.4.4)

Though technically block decoding calls into some other incomplete
methods, so it isn't functionally complete yet. However, we are
very close to being done with the 6.4.X sections :)
This commit is contained in:
FalseHonesty 2021-06-27 15:55:41 -04:00 committed by Andreas Kling
parent 074fbd1b06
commit 27fdf8361c
4 changed files with 143 additions and 46 deletions

View file

@ -32,7 +32,7 @@ enum ColorRange {
FullSwing
};
enum InterpolationFilter {
enum InterpolationFilter : u8 {
EightTap = 0,
EightTapSmooth = 1,
EightTapSharp = 2,
@ -40,7 +40,7 @@ enum InterpolationFilter {
Switchable = 4
};
enum ReferenceFrame {
enum ReferenceFrame : u8 {
// 0 is both INTRA_FRAME and NONE because the value's meaning changes depending on which index they're in on the ref_frame array
None = 0,
IntraFrame = 0,
@ -49,7 +49,7 @@ enum ReferenceFrame {
AltRefFrame = 3,
};
enum TXMode {
enum TXMode : u8 {
Only_4x4 = 0,
Allow_8x8 = 1,
Allow_16x16 = 2,
@ -57,14 +57,14 @@ enum TXMode {
TXModeSelect = 4,
};
enum TXSize {
enum TXSize : u8 {
TX_4x4 = 0,
TX_8x8 = 1,
TX_16x16 = 2,
TX_32x32 = 3,
};
enum ReferenceMode {
enum ReferenceMode : u8 {
SingleReference = 0,
CompoundReference = 1,
ReferenceModeSelect = 2,

View file

@ -21,6 +21,37 @@ Parser::Parser(Decoder& decoder)
{
}
Parser::~Parser()
{
cleanup_tile_allocations();
if (m_prev_segment_ids)
free(m_prev_segment_ids);
}
void Parser::cleanup_tile_allocations()
{
if (m_skips)
free(m_skips);
if (m_tx_sizes)
free(m_tx_sizes);
if (m_mi_sizes)
free(m_mi_sizes);
if (m_y_modes)
free(m_y_modes);
if (m_segment_ids)
free(m_segment_ids);
if (m_ref_frames)
free(m_ref_frames);
if (m_interp_filters)
free(m_interp_filters);
if (m_mvs)
free(m_mvs);
if (m_sub_mvs)
free(m_sub_mvs);
if (m_sub_modes)
free(m_sub_modes);
}
/* (6.1) */
bool Parser::parse_frame(ByteBuffer const& frame_data)
{
@ -400,15 +431,9 @@ bool Parser::setup_past_independence()
}
}
m_segmentation_abs_or_delta_update = false;
m_prev_segment_ids.clear();
m_prev_segment_ids.ensure_capacity(m_mi_rows);
for (auto row = 0u; row < m_mi_rows; row++) {
Vector<u8> sub_vector = {};
sub_vector.ensure_capacity(m_mi_cols);
for (auto col = 0u; col < m_mi_cols; col++)
sub_vector.append(0);
m_prev_segment_ids.append(sub_vector);
}
if (m_prev_segment_ids)
free(m_prev_segment_ids);
m_prev_segment_ids = static_cast<u8*>(malloc(m_mi_rows * m_mi_cols));
m_loop_filter_delta_enabled = true;
m_loop_filter_ref_deltas[IntraFrame] = 1;
m_loop_filter_ref_deltas[LastFrame] = 0;
@ -714,10 +739,30 @@ bool Parser::setup_compound_reference_mode()
return true;
}
void Parser::allocate_tile_data()
{
auto dimensions = m_mi_rows * m_mi_cols;
if (dimensions == m_allocated_dimensions)
return;
cleanup_tile_allocations();
m_skips = static_cast<bool*>(malloc(sizeof(bool) * dimensions));
m_tx_sizes = static_cast<TXSize*>(malloc(sizeof(TXSize) * dimensions));
m_mi_sizes = static_cast<u32*>(malloc(sizeof(u32) * dimensions));
m_y_modes = static_cast<u8*>(malloc(sizeof(u8) * dimensions));
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_sub_modes = static_cast<IntraMode*>(malloc(sizeof(IntraMode) * dimensions * 4));
m_allocated_dimensions = dimensions;
}
bool Parser::decode_tiles()
{
auto tile_cols = 1 << m_tile_cols_log2;
auto tile_rows = 1 << m_tile_rows_log2;
allocate_tile_data();
SAFE_CALL(clear_above_context());
for (auto tile_row = 0; tile_row < tile_rows; tile_row++) {
for (auto tile_col = 0; tile_col < tile_cols; tile_col++) {
@ -732,7 +777,6 @@ bool Parser::decode_tiles()
SAFE_CALL(m_bit_stream->exit_bool());
}
}
return true;
}
@ -833,8 +877,32 @@ bool Parser::decode_block(u32 row, u32 col, u8 subsize)
SAFE_CALL(mode_info());
m_eob_total = 0;
SAFE_CALL(residual());
// FIXME: Finish implementing
// note: when finished, re-enable calculate_default_intra_mode_probability's usage of m_sub_modes
if (m_is_inter && subsize >= Block_8x8 && m_eob_total == 0)
m_skip = true;
for (size_t y = 0; y < num_8x8_blocks_high_lookup[subsize]; y++) {
for (size_t x = 0; x < num_8x8_blocks_wide_lookup[subsize]; x++) {
auto pos = (row + y) * m_mi_cols + (col + x);
m_skips[pos] = m_skip;
m_tx_sizes[pos] = m_tx_size;
m_mi_sizes[pos] = m_mi_size;
m_y_modes[pos] = m_y_mode;
m_segment_ids[pos] = m_segment_id;
for (size_t ref_list = 0; ref_list < 2; ref_list++)
m_ref_frames[(pos * 2) + ref_list] = m_ref_frame[ref_list];
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;
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];
}
} else {
for (size_t b = 0; b < 4; b++)
m_sub_modes[pos * 4 + b] = static_cast<IntraMode>(m_block_sub_modes[b]);
}
}
}
return true;
}
@ -916,10 +984,10 @@ bool Parser::read_tx_size(bool allow_select)
bool Parser::inter_frame_mode_info()
{
m_left_ref_frame[0] = m_available_l ? m_ref_frames[m_mi_row][m_mi_col - 1][0] : IntraFrame;
m_above_ref_frame[0] = m_available_u ? m_ref_frames[m_mi_row - 1][m_mi_col][0] : IntraFrame;
m_left_ref_frame[1] = m_available_l ? m_ref_frames[m_mi_row][m_mi_col - 1][1] : None;
m_above_ref_frame[1] = m_available_u ? m_ref_frames[m_mi_row - 1][m_mi_col][1] : None;
m_left_ref_frame[0] = m_available_l ? m_ref_frames[m_mi_row * m_mi_cols + (m_mi_col - 1)] : IntraFrame;
m_above_ref_frame[0] = m_available_u ? m_ref_frames[(m_mi_row - 1) * m_mi_cols + m_mi_col] : IntraFrame;
m_left_ref_frame[1] = m_available_l ? m_ref_frames[m_mi_row * m_mi_cols + (m_mi_col - 1) + 1] : None;
m_above_ref_frame[1] = m_available_u ? m_ref_frames[(m_mi_row - 1) * m_mi_cols + m_mi_col + 1] : None;
m_left_intra = m_left_ref_frame[0] <= IntraFrame;
m_above_intra = m_above_ref_frame[0] <= IntraFrame;
m_left_single = m_left_ref_frame[1] <= None;
@ -973,7 +1041,7 @@ u8 Parser::get_segment_id()
u8 segment = 7;
for (size_t y = 0; y < ymis; y++) {
for (size_t x = 0; x < xmis; x++) {
segment = min(segment, m_prev_segment_ids[m_mi_row + y][m_mi_col + x]);
segment = min(segment, m_prev_segment_ids[(m_mi_row + y) + (m_mi_col + x)]);
}
}
return segment;
@ -1051,8 +1119,7 @@ bool Parser::inter_block_mode_info()
for (auto x = 0; x < m_num_4x4_w; x++) {
auto block = (idy + y) * 2 + idx + x;
for (auto ref_list = 0; ref_list < 1 + is_compound; ref_list++) {
(void)block;
// TODO: m_block_mvs[ref_list][block] = m_mv[ref_list];
m_block_mvs[ref_list][block] = m_mv[ref_list];
}
}
}
@ -1063,7 +1130,7 @@ bool Parser::inter_block_mode_info()
SAFE_CALL(assign_mv(is_compound));
for (auto ref_list = 0; ref_list < 1 + is_compound; ref_list++) {
for (auto block = 0; block < 4; block++) {
// TODO: m_block_mvs[ref_list][block] = m_mv[ref_list];
m_block_mvs[ref_list][block] = m_mv[ref_list];
}
}
return true;

View file

@ -24,6 +24,7 @@ class Parser {
public:
explicit Parser(Decoder&);
~Parser();
bool parse_frame(ByteBuffer const&);
void dump_info();
@ -45,6 +46,8 @@ private:
/* Utilities */
void clear_context(Vector<u8>& context, size_t size);
void clear_context(Vector<Vector<u8>>& context, size_t outer_size, size_t inner_size);
void allocate_tile_data();
void cleanup_tile_allocations();
/* (6.1) Frame Syntax */
bool trailing_bits();
@ -208,30 +211,39 @@ private:
u8 m_uv_mode { 0 }; // FIXME: Is u8 the right size?
ReferenceFrame m_left_ref_frame[2];
ReferenceFrame m_above_ref_frame[2];
Vector<Vector<Vector<ReferenceFrame>>> m_ref_frames; // TODO: Can we make these fixed sized allocations?
bool m_left_intra { false };
bool m_above_intra { false };
bool m_left_single { false };
bool m_above_single { false };
Vector<Vector<u8>> m_prev_segment_ids;
InterpolationFilter m_interp_filter { EightTap };
InterMode m_mv[2];
InterMode m_near_mv[2];
InterMode m_nearest_mv[2];
Vector<Vector<Vector<IntraMode>>> m_sub_modes; // FIXME: Can we make these fixed sized allocations?
u32 m_ref_frame_width[NUM_REF_FRAMES];
u32 m_ref_frame_height[NUM_REF_FRAMES];
u32 m_eob_total { 0 };
u8 m_tx_type { 0 };
u8 m_token_cache[1024];
i32 m_tokens[1024];
bool m_use_hp { false };
TXMode m_tx_mode;
ReferenceMode m_reference_mode;
ReferenceFrame m_comp_fixed_ref;
ReferenceFrame m_comp_var_ref[2];
InterMode m_block_mvs[2][4];
u8* m_prev_segment_ids { nullptr };
u32 m_allocated_dimensions { 0 };
bool* m_skips { nullptr };
TXSize* m_tx_sizes { nullptr };
u32* m_mi_sizes { nullptr };
u8* m_y_modes { nullptr };
u8* m_segment_ids { nullptr };
ReferenceFrame* m_ref_frames { nullptr };
InterpolationFilter* m_interp_filters { nullptr };
InterMode* m_mvs { nullptr };
InterMode* m_sub_mvs { nullptr };
IntraMode* m_sub_modes { nullptr };
OwnPtr<BitStream> m_bit_stream;
OwnPtr<ProbabilityTables> m_probability_tables;

View file

@ -208,26 +208,26 @@ u8 TreeParser::calculate_default_intra_mode_probability(u8 node)
{
u32 above_mode, left_mode;
if (m_decoder.m_mi_size >= Block_8x8) {
above_mode = false // FIXME: AVAIL_U
? m_decoder.m_sub_modes[m_decoder.m_mi_row - 1][m_decoder.m_mi_col][2]
above_mode = AVAIL_U
? m_decoder.m_sub_modes[(m_decoder.m_mi_row - 1) * m_decoder.m_mi_cols * 4 + m_decoder.m_mi_col * 4 + 2]
: DcPred;
left_mode = false // FIXME: AVAIL_L
? m_decoder.m_sub_modes[m_decoder.m_mi_row][m_decoder.m_mi_col - 1][1]
left_mode = AVAIL_L
? m_decoder.m_sub_modes[m_decoder.m_mi_row * m_decoder.m_mi_cols * 4 + (m_decoder.m_mi_col - 1) * 4 + 1]
: DcPred;
} else {
if (m_idy) {
above_mode = m_decoder.m_block_sub_modes[m_idx];
} else {
above_mode = false // FIXME: AVAIL_U
? m_decoder.m_sub_modes[m_decoder.m_mi_row - 1][m_decoder.m_mi_col][2 + m_idx]
above_mode = AVAIL_U
? m_decoder.m_sub_modes[(m_decoder.m_mi_row - 1) * m_decoder.m_mi_cols * 4 + m_decoder.m_mi_col * 4 + 2 + m_idx]
: DcPred;
}
if (m_idx) {
left_mode = m_decoder.m_block_sub_modes[m_idy * 2];
} else {
left_mode = false // FIXME: AVAIL_L
? m_decoder.m_sub_modes[m_decoder.m_mi_row][m_decoder.m_mi_col - 1][1 + m_idy * 2]
left_mode = AVAIL_L
? m_decoder.m_sub_modes[m_decoder.m_mi_row * m_decoder.m_mi_cols * 4 + (m_decoder.m_mi_col - 1) * 4 + 1 + m_idy * 2]
: DcPred;
}
}
@ -265,12 +265,10 @@ u8 TreeParser::calculate_segment_id_probability(u8 node)
u8 TreeParser::calculate_skip_probability()
{
m_ctx = 0;
if (AVAIL_U) {
// FIXME: m_ctx += m_skips[m_mi_row - 1][m_mi_col];
}
if (AVAIL_L) {
// FIXME: m_ctx += m_skips[m_mi_row][m_mi_col - 1];
}
if (AVAIL_U)
m_ctx += m_decoder.m_skips[(m_decoder.m_mi_row - 1) * m_decoder.m_mi_cols + m_decoder.m_mi_col];
if (AVAIL_L)
m_ctx += m_decoder.m_skips[m_decoder.m_mi_row * m_decoder.m_mi_cols + m_decoder.m_mi_col - 1];
return m_decoder.m_probability_tables->skip_prob()[m_ctx];
}
@ -543,7 +541,16 @@ u8 TreeParser::calculate_tx_size_probability(u8 node)
{
auto above = m_decoder.m_max_tx_size;
auto left = m_decoder.m_max_tx_size;
// FIXME: Fix varying above/left when Skips is implemented
auto u_pos = (m_decoder.m_mi_row - 1) * m_decoder.m_mi_cols + m_decoder.m_mi_col;
if (AVAIL_U && !m_decoder.m_skips[u_pos])
above = m_decoder.m_tx_sizes[u_pos];
auto l_pos = m_decoder.m_mi_row * m_decoder.m_mi_cols + m_decoder.m_mi_col - 1;
if (AVAIL_L && !m_decoder.m_skips[l_pos])
left = m_decoder.m_tx_sizes[l_pos];
if (!AVAIL_L)
left = above;
if (!AVAIL_U)
above = left;
m_ctx = (above + left) > m_decoder.m_max_tx_size;
return m_decoder.m_probability_tables->tx_probs()[m_decoder.m_max_tx_size][m_ctx][node];
}
@ -557,7 +564,18 @@ u8 TreeParser::calculate_inter_mode_probability(u8 node)
u8 TreeParser::calculate_interp_filter_probability(u8 node)
{
// FIXME: Implement ctx calculation when InterpFilters is implemented
auto left_interp = (AVAIL_L && m_decoder.m_left_ref_frame[0] > IntraFrame)
? m_decoder.m_interp_filters[m_decoder.m_mi_row * m_decoder.m_mi_cols + m_decoder.m_mi_col - 1]
: 3;
auto above_interp = (AVAIL_U && m_decoder.m_above_ref_frame[0] > IntraFrame)
? m_decoder.m_interp_filters[m_decoder.m_mi_row * m_decoder.m_mi_cols + m_decoder.m_mi_col - 1]
: 3;
if (left_interp == above_interp || (left_interp != 3 && above_interp == 3))
m_ctx = left_interp;
else if (left_interp == 3 && above_interp != 3)
m_ctx = above_interp;
else
m_ctx = 3;
return m_decoder.m_probability_tables->interp_filter_probs()[m_ctx][node];
}