1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:18:11 +00:00
serenity/Userland/Libraries/LibVideo/VP9/Decoder.cpp
FalseHonesty e4f015ce3d LibVideo/VP9: Implement more TreeParser probability calculations
Now TreeParser has mostly complete probability calculation
implementations for all currently used syntax elements. Some of these
calculation methods aren't actually finished because they use data
we have yet to parse in the Decoder, but they're close to finished.
2021-07-10 21:28:56 +02:00

1143 lines
36 KiB
C++

/*
* Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Decoder.h"
namespace Video::VP9 {
#define RESERVED_ZERO \
if (m_bit_stream->read_bit() != 0) \
return false
#define SAFE_CALL(call) \
if (!(call)) [[unlikely]] \
return false
Decoder::Decoder()
: m_probability_tables(make<ProbabilityTables>())
, m_tree_parser(make<TreeParser>(*this))
{
}
bool Decoder::parse_frame(ByteBuffer const& frame_data)
{
m_bit_stream = make<BitStream>(frame_data.data(), frame_data.size());
m_syntax_element_counter = make<SyntaxElementCounter>();
SAFE_CALL(uncompressed_header());
dbgln("Finished reading uncompressed header");
SAFE_CALL(trailing_bits());
if (m_header_size_in_bytes == 0) {
// FIXME: Do we really need to read all of these bits?
// while (m_bit_stream->get_position() < m_start_bit_pos + (8 * frame_data.size()))
// RESERVED_ZERO;
dbgln("No header");
return true;
}
m_probability_tables->load_probs(m_frame_context_idx);
m_probability_tables->load_probs2(m_frame_context_idx);
m_syntax_element_counter->clear_counts();
SAFE_CALL(m_bit_stream->init_bool(m_header_size_in_bytes));
dbgln("Reading compressed header");
SAFE_CALL(compressed_header());
dbgln("Finished reading compressed header");
SAFE_CALL(m_bit_stream->exit_bool());
dbgln("Finished reading frame!");
SAFE_CALL(decode_tiles());
return true;
}
bool Decoder::uncompressed_header()
{
auto frame_marker = m_bit_stream->read_f(2);
if (frame_marker != 2)
return false;
auto profile_low_bit = m_bit_stream->read_bit();
auto profile_high_bit = m_bit_stream->read_bit();
m_profile = (profile_high_bit << 1u) + profile_low_bit;
if (m_profile == 3)
RESERVED_ZERO;
auto show_existing_frame = m_bit_stream->read_bit();
if (show_existing_frame) {
m_frame_to_show_map_index = m_bit_stream->read_f(3);
m_header_size_in_bytes = 0;
m_refresh_frame_flags = 0;
m_loop_filter_level = 0;
return true;
}
m_last_frame_type = m_frame_type;
m_frame_type = read_frame_type();
m_show_frame = m_bit_stream->read_bit();
m_error_resilient_mode = m_bit_stream->read_bit();
if (m_frame_type == KeyFrame) {
SAFE_CALL(frame_sync_code());
SAFE_CALL(color_config());
SAFE_CALL(frame_size());
SAFE_CALL(render_size());
m_refresh_frame_flags = 0xFF;
m_frame_is_intra = true;
} else {
m_frame_is_intra = !m_show_frame && m_bit_stream->read_bit();
if (!m_error_resilient_mode) {
m_reset_frame_context = m_bit_stream->read_f(2);
} else {
m_reset_frame_context = 0;
}
if (m_frame_is_intra) {
SAFE_CALL(frame_sync_code());
if (m_profile > 0) {
SAFE_CALL(color_config());
} else {
m_color_space = Bt601;
m_subsampling_x = true;
m_subsampling_y = true;
m_bit_depth = 8;
}
m_refresh_frame_flags = m_bit_stream->read_f8();
SAFE_CALL(frame_size());
SAFE_CALL(render_size());
} else {
m_refresh_frame_flags = m_bit_stream->read_f8();
for (auto i = 0; i < 3; i++) {
m_ref_frame_idx[i] = m_bit_stream->read_f(3);
m_ref_frame_sign_bias[LastFrame + i] = m_bit_stream->read_bit();
}
SAFE_CALL(frame_size_with_refs());
m_allow_high_precision_mv = m_bit_stream->read_bit();
SAFE_CALL(read_interpolation_filter());
}
}
if (!m_error_resilient_mode) {
m_refresh_frame_context = m_bit_stream->read_bit();
m_frame_parallel_decoding_mode = m_bit_stream->read_bit();
} else {
m_refresh_frame_context = false;
m_frame_parallel_decoding_mode = true;
}
m_frame_context_idx = m_bit_stream->read_f(2);
if (m_frame_is_intra || m_error_resilient_mode) {
SAFE_CALL(setup_past_independence());
if (m_frame_type == KeyFrame || m_error_resilient_mode || m_reset_frame_context == 3) {
for (auto i = 0; i < 4; i++) {
m_probability_tables->save_probs(i);
}
} else if (m_reset_frame_context == 2) {
m_probability_tables->save_probs(m_frame_context_idx);
}
m_frame_context_idx = 0;
}
SAFE_CALL(loop_filter_params());
SAFE_CALL(quantization_params());
SAFE_CALL(segmentation_params());
SAFE_CALL(tile_info());
m_header_size_in_bytes = m_bit_stream->read_f16();
return true;
}
bool Decoder::frame_sync_code()
{
if (m_bit_stream->read_byte() != 0x49)
return false;
if (m_bit_stream->read_byte() != 0x83)
return false;
return m_bit_stream->read_byte() == 0x42;
}
bool Decoder::color_config()
{
if (m_profile >= 2) {
m_bit_depth = m_bit_stream->read_bit() ? 12 : 10;
} else {
m_bit_depth = 8;
}
auto color_space = m_bit_stream->read_f(3);
if (color_space > RGB)
return false;
m_color_space = static_cast<ColorSpace>(color_space);
if (color_space != RGB) {
m_color_range = read_color_range();
if (m_profile == 1 || m_profile == 3) {
m_subsampling_x = m_bit_stream->read_bit();
m_subsampling_y = m_bit_stream->read_bit();
RESERVED_ZERO;
} else {
m_subsampling_x = true;
m_subsampling_y = true;
}
} else {
m_color_range = FullSwing;
if (m_profile == 1 || m_profile == 3) {
m_subsampling_x = false;
m_subsampling_y = false;
RESERVED_ZERO;
}
}
return true;
}
bool Decoder::frame_size()
{
m_frame_width = m_bit_stream->read_f16() + 1;
m_frame_height = m_bit_stream->read_f16() + 1;
SAFE_CALL(compute_image_size());
return true;
}
bool Decoder::render_size()
{
if (m_bit_stream->read_bit()) {
m_render_width = m_bit_stream->read_f16() + 1;
m_render_height = m_bit_stream->read_f16() + 1;
} else {
m_render_width = m_frame_width;
m_render_height = m_frame_height;
}
return true;
}
bool Decoder::frame_size_with_refs()
{
bool found_ref;
for (auto i = 0; i < 3; i++) {
found_ref = m_bit_stream->read_bit();
if (found_ref) {
// TODO:
// - FrameWidth = RefFrameWidth[ref_frame_idx[ i] ];
// - FrameHeight = RefFrameHeight[ref_frame_idx[ i] ];
break;
}
}
if (!found_ref) {
SAFE_CALL(frame_size());
} else {
SAFE_CALL(compute_image_size());
}
SAFE_CALL(render_size());
return true;
}
bool Decoder::compute_image_size()
{
m_mi_cols = (m_frame_width + 7u) >> 3u;
m_mi_rows = (m_frame_height + 7u) >> 3u;
m_sb64_cols = (m_mi_cols + 7u) >> 3u;
m_sb64_rows = (m_mi_rows + 7u) >> 3u;
return true;
}
bool Decoder::read_interpolation_filter()
{
if (m_bit_stream->read_bit()) {
m_interpolation_filter = Switchable;
} else {
m_interpolation_filter = literal_to_type[m_bit_stream->read_f(2)];
}
return true;
}
bool Decoder::loop_filter_params()
{
m_loop_filter_level = m_bit_stream->read_f(6);
m_loop_filter_sharpness = m_bit_stream->read_f(3);
m_loop_filter_delta_enabled = m_bit_stream->read_bit();
if (m_loop_filter_delta_enabled) {
if (m_bit_stream->read_bit()) {
for (auto i = 0; i < 4; i++) {
if (m_bit_stream->read_bit()) {
// TODO: loop_filter_ref_deltas[i] = s(6);
}
}
for (auto i = 0; i < 2; i++) {
if (m_bit_stream->read_bit()) {
// TODO: loop_filter_mode_deltas[i] = s(6);
}
}
}
}
return true;
}
bool Decoder::quantization_params()
{
auto base_q_idx = m_bit_stream->read_byte();
auto delta_q_y_dc = read_delta_q();
auto delta_q_uv_dc = read_delta_q();
auto delta_q_uv_ac = read_delta_q();
m_lossless = base_q_idx == 0 && delta_q_y_dc == 0 && delta_q_uv_dc == 0 && delta_q_uv_ac == 0;
return true;
}
i8 Decoder::read_delta_q()
{
if (m_bit_stream->read_bit())
return m_bit_stream->read_s(4);
return 0;
}
bool Decoder::segmentation_params()
{
m_segmentation_enabled = m_bit_stream->read_bit();
if (!m_segmentation_enabled)
return true;
m_segmentation_update_map = m_bit_stream->read_bit();
if (m_segmentation_update_map) {
for (auto i = 0; i < 7; i++)
m_segmentation_tree_probs[i] = read_prob();
m_segmentation_temporal_update = m_bit_stream->read_bit();
for (auto i = 0; i < 3; i++)
m_segmentation_pred_prob[i] = m_segmentation_temporal_update ? read_prob() : 255;
}
SAFE_CALL(m_bit_stream->read_bit());
m_segmentation_abs_or_delta_update = m_bit_stream->read_bit();
for (auto i = 0; i < MAX_SEGMENTS; i++) {
for (auto j = 0; j < SEG_LVL_MAX; j++) {
auto feature_value = 0;
auto feature_enabled = m_bit_stream->read_bit();
m_feature_enabled[i][j] = feature_enabled;
if (feature_enabled) {
auto bits_to_read = segmentation_feature_bits[j];
feature_value = m_bit_stream->read_f(bits_to_read);
if (segmentation_feature_signed[j]) {
if (m_bit_stream->read_bit())
feature_value = -feature_value;
}
}
m_feature_data[i][j] = feature_value;
}
}
return true;
}
u8 Decoder::read_prob()
{
if (m_bit_stream->read_bit())
return m_bit_stream->read_byte();
return 255;
}
bool Decoder::tile_info()
{
auto min_log2_tile_cols = calc_min_log2_tile_cols();
auto max_log2_tile_cols = calc_max_log2_tile_cols();
m_tile_cols_log2 = min_log2_tile_cols;
while (m_tile_cols_log2 < max_log2_tile_cols) {
if (m_bit_stream->read_bit())
m_tile_cols_log2++;
else
break;
}
m_tile_rows_log2 = m_bit_stream->read_bit();
if (m_tile_rows_log2) {
m_tile_rows_log2 += m_bit_stream->read_bit();
}
return true;
}
u16 Decoder::calc_min_log2_tile_cols()
{
auto min_log_2 = 0u;
while ((u8)(MAX_TILE_WIDTH_B64 << min_log_2) < m_sb64_cols)
min_log_2++;
return min_log_2;
}
u16 Decoder::calc_max_log2_tile_cols()
{
u16 max_log_2 = 1;
while ((m_sb64_cols >> max_log_2) >= MIN_TILE_WIDTH_B64)
max_log_2++;
return max_log_2 - 1;
}
bool Decoder::setup_past_independence()
{
for (auto i = 0; i < 8; i++) {
for (auto j = 0; j < 4; j++) {
m_feature_data[i][j] = 0;
m_feature_enabled[i][j] = false;
}
}
m_segmentation_abs_or_delta_update = false;
for (auto row = 0u; row < m_mi_rows; row++) {
for (auto col = 0u; col < m_mi_cols; col++) {
// TODO: m_prev_segment_ids[row][col] = 0;
}
}
m_loop_filter_delta_enabled = true;
m_loop_filter_ref_deltas[IntraFrame] = 1;
m_loop_filter_ref_deltas[LastFrame] = 0;
m_loop_filter_ref_deltas[GoldenFrame] = -1;
m_loop_filter_ref_deltas[AltRefFrame] = -1;
for (auto i = 0; i < 2; i++) {
m_loop_filter_mode_deltas[i] = 0;
}
m_probability_tables->reset_probs();
return true;
}
bool Decoder::trailing_bits()
{
while (m_bit_stream->get_position() & 7u)
RESERVED_ZERO;
return true;
}
bool Decoder::compressed_header()
{
SAFE_CALL(read_tx_mode());
if (m_tx_mode == TXModeSelect) {
SAFE_CALL(tx_mode_probs());
}
SAFE_CALL(read_coef_probs());
SAFE_CALL(read_skip_prob());
if (!m_frame_is_intra) {
SAFE_CALL(read_inter_mode_probs());
if (m_interpolation_filter == Switchable) {
SAFE_CALL(read_interp_filter_probs());
}
SAFE_CALL(read_is_inter_probs());
SAFE_CALL(frame_reference_mode());
SAFE_CALL(frame_reference_mode_probs());
SAFE_CALL(read_y_mode_probs());
SAFE_CALL(read_partition_probs());
SAFE_CALL(mv_probs());
}
return true;
}
bool Decoder::read_tx_mode()
{
if (m_lossless) {
m_tx_mode = Only_4x4;
} else {
auto tx_mode = m_bit_stream->read_literal(2);
if (tx_mode == Allow_32x32) {
tx_mode += m_bit_stream->read_literal(1);
}
m_tx_mode = static_cast<TXMode>(tx_mode);
}
return true;
}
bool Decoder::tx_mode_probs()
{
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[TX_8x8][i][j] = diff_update_prob(tx_probs[TX_8x8][i][j]);
}
}
for (auto i = 0; i < TX_SIZE_CONTEXTS; i++) {
for (auto j = 0; j < TX_SIZES - 2; j++) {
tx_probs[TX_16x16][i][j] = diff_update_prob(tx_probs[TX_16x16][i][j]);
}
}
for (auto i = 0; i < TX_SIZE_CONTEXTS; i++) {
for (auto j = 0; j < TX_SIZES - 1; j++) {
tx_probs[TX_32x32][i][j] = diff_update_prob(tx_probs[TX_32x32][i][j]);
}
}
return true;
}
u8 Decoder::diff_update_prob(u8 prob)
{
if (m_bit_stream->read_bool(252)) {
auto delta_prob = decode_term_subexp();
prob = inv_remap_prob(delta_prob, prob);
}
return prob;
}
u8 Decoder::decode_term_subexp()
{
if (m_bit_stream->read_literal(1) == 0)
return m_bit_stream->read_literal(4);
if (m_bit_stream->read_literal(1) == 0)
return m_bit_stream->read_literal(4) + 16;
if (m_bit_stream->read_literal(1) == 0)
return m_bit_stream->read_literal(4) + 32;
auto v = m_bit_stream->read_literal(7);
if (v < 65)
return v + 64;
return (v << 1u) - 1 + m_bit_stream->read_literal(1);
}
u8 Decoder::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 Decoder::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);
}
bool Decoder::read_coef_probs()
{
m_max_tx_size = tx_mode_to_biggest_tx_size[m_tx_mode];
for (auto tx_size = TX_4x4; tx_size <= m_max_tx_size; tx_size = static_cast<TXSize>(static_cast<int>(tx_size) + 1)) {
auto update_probs = m_bit_stream->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& coef_probs = m_probability_tables->coef_probs()[tx_size];
coef_probs[i][j][k][l][m] = diff_update_prob(coef_probs[i][j][k][l][m]);
}
}
}
}
}
}
}
return true;
}
bool Decoder::read_skip_prob()
{
for (auto i = 0; i < SKIP_CONTEXTS; i++)
m_probability_tables->skip_prob()[i] = diff_update_prob(m_probability_tables->skip_prob()[i]);
return true;
}
bool Decoder::read_inter_mode_probs()
{
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(m_probability_tables->inter_mode_probs()[i][j]);
}
return true;
}
bool Decoder::read_interp_filter_probs()
{
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(m_probability_tables->interp_filter_probs()[i][j]);
}
return true;
}
bool Decoder::read_is_inter_probs()
{
for (auto i = 0; i < IS_INTER_CONTEXTS; i++)
m_probability_tables->is_inter_prob()[i] = diff_update_prob(m_probability_tables->is_inter_prob()[i]);
return true;
}
bool Decoder::frame_reference_mode()
{
auto compound_reference_allowed = false;
for (size_t i = 2; i <= REFS_PER_FRAME; i++) {
if (m_ref_frame_sign_bias[i] != m_ref_frame_sign_bias[1])
compound_reference_allowed = true;
}
if (compound_reference_allowed) {
auto non_single_reference = m_bit_stream->read_literal(1);
if (non_single_reference == 0) {
m_reference_mode = SingleReference;
} else {
auto reference_select = m_bit_stream->read_literal(1);
if (reference_select == 0)
m_reference_mode = CompoundReference;
else
m_reference_mode = ReferenceModeSelect;
SAFE_CALL(setup_compound_reference_mode());
}
} else {
m_reference_mode = SingleReference;
}
return true;
}
bool Decoder::frame_reference_mode_probs()
{
if (m_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(comp_mode_prob[i]);
}
}
if (m_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(single_ref_prob[i][0]);
single_ref_prob[i][1] = diff_update_prob(single_ref_prob[i][1]);
}
}
if (m_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(comp_ref_prob[i]);
}
}
return true;
}
bool Decoder::read_y_mode_probs()
{
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(y_mode_probs[i][j]);
}
}
return true;
}
bool Decoder::read_partition_probs()
{
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(partition_probs[i][j]);
}
}
return true;
}
bool Decoder::mv_probs()
{
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(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(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(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(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(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(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(mv_fr_probs[i][k]);
}
}
if (m_allow_high_precision_mv) {
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(mv_class0_hp_prob[i]);
mv_hp_prob[i] = update_mv_prob(mv_hp_prob[i]);
}
}
return true;
}
u8 Decoder::update_mv_prob(u8 prob)
{
if (m_bit_stream->read_bool(252)) {
return (m_bit_stream->read_literal(7) << 1u) | 1u;
}
return prob;
}
bool Decoder::setup_compound_reference_mode()
{
if (m_ref_frame_sign_bias[LastFrame] == m_ref_frame_sign_bias[GoldenFrame]) {
m_comp_fixed_ref = AltRefFrame;
m_comp_var_ref[0] = LastFrame;
m_comp_var_ref[1] = GoldenFrame;
} else if (m_ref_frame_sign_bias[LastFrame] == m_ref_frame_sign_bias[AltRefFrame]) {
m_comp_fixed_ref = GoldenFrame;
m_comp_var_ref[0] = LastFrame;
m_comp_var_ref[1] = AltRefFrame;
} else {
m_comp_fixed_ref = LastFrame;
m_comp_var_ref[0] = GoldenFrame;
m_comp_var_ref[1] = AltRefFrame;
}
return true;
}
bool Decoder::decode_tiles()
{
auto tile_cols = 1 << m_tile_cols_log2;
auto tile_rows = 1 << m_tile_rows_log2;
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++) {
auto last_tile = (tile_row == tile_rows - 1) && (tile_col == tile_cols - 1);
// FIXME: Spec has `sz -= tile_size + 4`, but I think we don't need this because our bit stream manages how much data we have left?
auto tile_size = last_tile ? m_bit_stream->bytes_remaining() : m_bit_stream->read_f(32);
m_mi_row_start = get_tile_offset(tile_row, m_mi_rows, m_tile_rows_log2);
m_mi_row_end = get_tile_offset(tile_row + 1, m_mi_rows, m_tile_rows_log2);
m_mi_col_start = get_tile_offset(tile_col, m_mi_cols, m_tile_cols_log2);
m_mi_col_end = get_tile_offset(tile_col + 1, m_mi_cols, m_tile_cols_log2);
SAFE_CALL(m_bit_stream->init_bool(tile_size));
SAFE_CALL(decode_tile());
SAFE_CALL(m_bit_stream->exit_bool());
}
}
return true;
}
template<typename T>
void clear_context(T* context, size_t size)
{
if (!(*context))
*context = static_cast<T>(malloc(size));
else
__builtin_memset(*context, 0, size);
}
bool Decoder::clear_above_context()
{
clear_context(&m_above_nonzero_context, sizeof(u8) * 3 * m_mi_cols * 2);
clear_context(&m_above_seg_pred_context, sizeof(u8) * m_mi_cols);
clear_context(&m_above_partition_context, sizeof(u8) * m_sb64_cols * 8);
return true;
}
u32 Decoder::get_tile_offset(u32 tile_num, u32 mis, u32 tile_size_log2)
{
u32 super_blocks = (mis + 7) >> 3u;
u32 offset = ((tile_num * super_blocks) >> tile_size_log2) << 3u;
return min(offset, mis);
}
bool Decoder::decode_tile()
{
for (auto row = m_mi_row_start; row < m_mi_row_end; row += 8) {
SAFE_CALL(clear_left_context());
m_row = row;
for (auto col = m_mi_col_start; col < m_mi_col_end; col += 8) {
m_col = col;
SAFE_CALL(decode_partition(row, col, Block_64x64));
}
}
return true;
}
bool Decoder::clear_left_context()
{
clear_context(&m_left_nonzero_context, sizeof(u8) * 3 * m_mi_rows * 2);
clear_context(&m_left_seg_pred_context, sizeof(u8) * m_mi_rows);
clear_context(&m_left_partition_context, sizeof(u8) * m_sb64_rows * 8);
return true;
}
bool Decoder::decode_partition(u32 row, u32 col, u8 block_subsize)
{
if (row >= m_mi_rows || col >= m_mi_cols)
return false;
m_block_subsize = block_subsize;
m_num_8x8 = num_8x8_blocks_wide_lookup[block_subsize];
auto half_block_8x8 = m_num_8x8 >> 1;
m_has_rows = (row + half_block_8x8) < m_mi_rows;
m_has_cols = (col + half_block_8x8) < m_mi_cols;
auto partition = m_tree_parser->parse_tree(SyntaxElementType::Partition);
dbgln("Parsed partition value {}", partition);
auto subsize = subsize_lookup[partition][block_subsize];
if (subsize < Block_8x8 || partition == PartitionNone) {
SAFE_CALL(decode_block(row, col, subsize));
} else if (partition == PartitionHorizontal) {
SAFE_CALL(decode_block(row, col, subsize));
// FIXME: if (hasRows)
// decode_block(r + halfBlock8x8, c, subsize)
}
// FIXME: Finish implementing partition decoding
return true;
}
bool Decoder::decode_block(u32 row, u32 col, u8 subsize)
{
m_mi_row = row;
m_mi_col = col;
m_mi_size = subsize;
m_available_u = row > 0;
m_available_l = col > m_mi_col_start;
SAFE_CALL(mode_info());
// FIXME: Finish implementing
return true;
}
bool Decoder::mode_info()
{
if (m_frame_is_intra)
return intra_frame_mode_info();
return inter_frame_mode_info();
}
bool Decoder::intra_frame_mode_info()
{
SAFE_CALL(intra_segment_id());
SAFE_CALL(read_skip());
SAFE_CALL(read_tx_size(true));
m_ref_frame[0] = IntraFrame;
m_ref_frame[1] = None;
m_is_inter = false;
if (m_mi_size >= Block_8x8) {
m_default_intra_mode = m_tree_parser->parse_tree<IntraMode>(SyntaxElementType::DefaultIntraMode);
m_y_mode = m_default_intra_mode;
for (auto b = 0; b < 4; b++)
m_block_sub_modes[b] = m_y_mode;
} else {
m_num_4x4_w = num_4x4_blocks_wide_lookup[m_mi_size];
m_num_4x4_h = num_4x4_blocks_high_lookup[m_mi_size];
for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
m_tree_parser->set_default_intra_mode_variables(idx, idy);
m_default_intra_mode = m_tree_parser->parse_tree<IntraMode>(SyntaxElementType::DefaultIntraMode);
for (auto y = 0; y < m_num_4x4_h; y++) {
for (auto x = 0; x < m_num_4x4_w; x++) {
auto index = (idy + y) * 2 + idx + x;
if (index > 3)
dbgln("Trying to access index {} on m_sub_modes", index);
m_block_sub_modes[index] = m_default_intra_mode;
}
}
}
}
m_y_mode = m_default_intra_mode;
}
m_uv_mode = m_tree_parser->parse_tree<u8>(SyntaxElementType::DefaultUVMode);
return true;
}
bool Decoder::intra_segment_id()
{
if (m_segmentation_enabled && m_segmentation_update_map) {
m_segment_id = m_tree_parser->parse_tree<u8>(SyntaxElementType::SegmentID);
} else {
m_segment_id = 0;
}
return true;
}
bool Decoder::read_skip()
{
if (seg_feature_active(SEG_LVL_SKIP)) {
m_skip = true;
} else {
m_skip = m_tree_parser->parse_tree<bool>(SyntaxElementType::Skip);
}
return true;
}
bool Decoder::seg_feature_active(u8 feature)
{
return m_segmentation_enabled && m_feature_enabled[m_segment_id][feature];
}
bool Decoder::read_tx_size(bool allow_select)
{
m_max_tx_size = max_txsize_lookup[m_mi_size];
if (allow_select && m_tx_mode == TXModeSelect && m_mi_size >= Block_8x8) {
m_tx_size = m_tree_parser->parse_tree<TXSize>(SyntaxElementType::TXSize);
} else {
m_tx_size = min(m_max_tx_size, tx_mode_to_biggest_tx_size[m_tx_mode]);
}
return true;
}
bool Decoder::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_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;
m_above_single = m_above_ref_frame[1] <= None;
SAFE_CALL(inter_segment_id());
SAFE_CALL(read_skip());
SAFE_CALL(read_is_inter());
SAFE_CALL(read_tx_size(!m_skip || !m_is_inter));
if (m_is_inter) {
SAFE_CALL(inter_block_mode_info());
} else {
SAFE_CALL(intra_block_mode_info());
}
return true;
}
bool Decoder::inter_segment_id()
{
if (!m_segmentation_enabled) {
m_segment_id = 0;
return true;
}
auto predicted_segment_id = get_segment_id();
if (!m_segmentation_update_map) {
m_segment_id = predicted_segment_id;
return true;
}
if (!m_segmentation_temporal_update) {
m_segment_id = m_tree_parser->parse_tree<u8>(SyntaxElementType::SegmentID);
return true;
}
auto seg_id_predicted = m_tree_parser->parse_tree<bool>(SyntaxElementType::SegIDPredicted);
if (seg_id_predicted)
m_segment_id = predicted_segment_id;
else
m_segment_id = m_tree_parser->parse_tree<u8>(SyntaxElementType::SegmentID);
for (auto i = 0u; i < num_8x8_blocks_wide_lookup[m_mi_size]; i++)
m_above_seg_pred_context[m_mi_col + i] = seg_id_predicted;
for (auto i = 0u; i < num_8x8_blocks_high_lookup[m_mi_size]; i++)
m_left_seg_pred_context[m_mi_row + i] = seg_id_predicted;
return true;
}
u8 Decoder::get_segment_id()
{
auto bw = num_8x8_blocks_wide_lookup[m_mi_size];
auto bh = num_8x8_blocks_high_lookup[m_mi_size];
auto xmis = min(m_mi_cols - m_mi_col, (u32)bw);
auto ymis = min(m_mi_rows - m_mi_row, (u32)bh);
u8 segment = 7;
for (auto y = 0u; y < ymis; y++) {
for (auto x = 0u; x < xmis; x++) {
segment = min(segment, m_prev_segment_ids[m_mi_row + y][m_mi_col + x]);
}
}
return segment;
}
bool Decoder::read_is_inter()
{
if (seg_feature_active(SEG_LVL_REF_FRAME))
m_is_inter = m_feature_data[m_segment_id][SEG_LVL_REF_FRAME] != IntraFrame;
else
m_is_inter = m_tree_parser->parse_tree<bool>(SyntaxElementType::IsInter);
return true;
}
bool Decoder::intra_block_mode_info()
{
m_ref_frame[0] = IntraFrame;
m_ref_frame[1] = None;
if (m_mi_size >= Block_8x8) {
m_y_mode = m_tree_parser->parse_tree<u8>(SyntaxElementType::IntraMode);
for (auto b = 0; b < 4; b++)
m_block_sub_modes[b] = m_y_mode;
} else {
m_num_4x4_w = num_4x4_blocks_wide_lookup[m_mi_size];
m_num_4x4_h = num_4x4_blocks_high_lookup[m_mi_size];
u8 sub_intra_mode;
for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
sub_intra_mode = m_tree_parser->parse_tree<u8>(SyntaxElementType::SubIntraMode);
for (auto y = 0; y < m_num_4x4_h; y++) {
for (auto x = 0; x < m_num_4x4_w; x++) {
m_block_sub_modes[(idy + y) * 2 + idx + x] = sub_intra_mode;
}
}
}
}
m_y_mode = sub_intra_mode;
}
m_uv_mode = m_tree_parser->parse_tree<u8>(SyntaxElementType::UVMode);
return true;
}
bool Decoder::inter_block_mode_info()
{
SAFE_CALL(read_ref_frames());
for (auto j = 0; j < 2; j++) {
if (m_ref_frame[j] > IntraFrame) {
SAFE_CALL(find_mv_refs(m_ref_frame[j], -1));
SAFE_CALL(find_best_ref_mvs(j));
}
}
auto is_compound = m_ref_frame[1] > IntraFrame;
if (seg_feature_active(SEG_LVL_SKIP)) {
m_y_mode = ZeroMv;
} else if (m_mi_size >= Block_8x8) {
auto inter_mode = m_tree_parser->parse_tree(SyntaxElementType::InterMode);
m_y_mode = NearestMv + inter_mode;
}
if (m_interpolation_filter == Switchable)
m_interp_filter = m_tree_parser->parse_tree<InterpolationFilter>(SyntaxElementType::InterpFilter);
else
m_interp_filter = m_interpolation_filter;
if (m_mi_size < Block_8x8) {
m_num_4x4_w = num_4x4_blocks_wide_lookup[m_mi_size];
m_num_4x4_h = num_4x4_blocks_high_lookup[m_mi_size];
for (auto idy = 0; idy < 2; idy += m_num_4x4_h) {
for (auto idx = 0; idx < 2; idx += m_num_4x4_w) {
auto inter_mode = m_tree_parser->parse_tree(SyntaxElementType::InterMode);
m_y_mode = NearestMv + inter_mode;
if (m_y_mode == NearestMv || m_y_mode == NearMv) {
for (auto j = 0; j < 1 + is_compound; j++)
SAFE_CALL(append_sub8x8_mvs(idy * 2 + idx, j));
}
SAFE_CALL(assign_mv(is_compound));
for (auto y = 0; y < m_num_4x4_h; y++) {
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];
}
}
}
}
}
return true;
}
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];
}
}
return true;
}
bool Decoder::read_ref_frames()
{
if (seg_feature_active(SEG_LVL_REF_FRAME)) {
m_ref_frame[0] = static_cast<ReferenceFrame>(m_feature_data[m_segment_id][SEG_LVL_REF_FRAME]);
m_ref_frame[1] = None;
return true;
}
ReferenceMode comp_mode;
if (m_reference_mode == ReferenceModeSelect)
comp_mode = m_tree_parser->parse_tree<ReferenceMode>(SyntaxElementType::CompMode);
else
comp_mode = m_reference_mode;
if (comp_mode == CompoundReference) {
auto idx = m_ref_frame_sign_bias[m_comp_fixed_ref];
auto comp_ref = m_tree_parser->parse_tree(SyntaxElementType::CompRef);
m_ref_frame[idx] = m_comp_fixed_ref;
m_ref_frame[!idx] = m_comp_var_ref[comp_ref];
return true;
}
auto single_ref_p1 = m_tree_parser->parse_tree<bool>(SyntaxElementType::SingleRefP1);
if (single_ref_p1) {
auto single_ref_p2 = m_tree_parser->parse_tree<bool>(SyntaxElementType::SingleRefP2);
m_ref_frame[0] = single_ref_p2 ? AltRefFrame : GoldenFrame;
} else {
m_ref_frame[0] = LastFrame;
}
m_ref_frame[1] = None;
return true;
}
bool Decoder::assign_mv(bool is_compound)
{
m_mv[1] = ZeroMv;
for (auto i = 0; i < 1 + is_compound; i++) {
if (m_y_mode == NewMv) {
SAFE_CALL(read_mv(i));
} else if (m_y_mode == NearestMv) {
m_mv[i] = m_nearest_mv[i];
} else if (m_y_mode == NearMv) {
m_mv[i] = m_near_mv[i];
} else {
m_mv[i] = ZeroMv;
}
}
return true;
}
bool Decoder::read_mv(u8)
{
// TODO: Implement
return true;
}
bool Decoder::find_mv_refs(ReferenceFrame, int)
{
// TODO: Implement
return true;
}
bool Decoder::find_best_ref_mvs(int)
{
// TODO: Implement
return true;
}
bool Decoder::append_sub8x8_mvs(u8, u8)
{
// TODO: Implement
return true;
}
void Decoder::dump_info()
{
dbgln("Frame dimensions: {}x{}", m_frame_width, m_frame_height);
dbgln("Render dimensions: {}x{}", m_render_width, m_render_height);
dbgln("Bit depth: {}", m_bit_depth);
dbgln("Interpolation filter: {}", (u8)m_interpolation_filter);
}
Decoder::~Decoder()
{
if (m_above_nonzero_context)
free(m_above_nonzero_context);
if (m_left_nonzero_context)
free(m_left_nonzero_context);
if (m_above_seg_pred_context)
free(m_above_seg_pred_context);
if (m_left_seg_pred_context)
free(m_left_seg_pred_context);
if (m_above_partition_context)
free(m_above_partition_context);
if (m_left_partition_context)
free(m_left_partition_context);
}
}