summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibVideo/VP9/Parser.cpp
diff options
context:
space:
mode:
authorFalseHonesty <thefalsehonesty@gmail.com>2021-06-26 17:10:14 -0400
committerAndreas Kling <kling@serenityos.org>2021-07-10 21:28:56 +0200
commit514559f07404bd740a9f4410303747438b163452 (patch)
treee622e3d709f03aacdf7aec6aa6fb2a9d115caba9 /Userland/Libraries/LibVideo/VP9/Parser.cpp
parent66628053d49880090e64d515e13500b466658bea (diff)
downloadserenity-514559f07404bd740a9f4410303747438b163452.zip
LibVideo/VP9: Rename Decoder -> Parser & create an actual Decoder class
The class that was previously named Decoder handled section 6.X.X of the spec, which actually deals with parsing out the syntax of the data, not the actual decoding logic which is specified in section 8.X.X. The new Decoder class will be in charge of owning and running the Parser, as well as implementing all of the decoding behavior.
Diffstat (limited to 'Userland/Libraries/LibVideo/VP9/Parser.cpp')
-rw-r--r--Userland/Libraries/LibVideo/VP9/Parser.cpp1212
1 files changed, 1212 insertions, 0 deletions
diff --git a/Userland/Libraries/LibVideo/VP9/Parser.cpp b/Userland/Libraries/LibVideo/VP9/Parser.cpp
new file mode 100644
index 0000000000..43d226f3be
--- /dev/null
+++ b/Userland/Libraries/LibVideo/VP9/Parser.cpp
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "Parser.h"
+#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
+
+Parser::Parser(Decoder& decoder)
+ : m_probability_tables(make<ProbabilityTables>())
+ , m_tree_parser(make<TreeParser>(*this))
+ , m_decoder(decoder)
+{
+}
+
+/* (6.1) */
+bool Parser::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) {
+ 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());
+
+ SAFE_CALL(decode_tiles());
+
+ dbgln("Finished reading frame!");
+ return true;
+}
+
+/* (6.2) */
+bool Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::frame_size_with_refs()
+{
+ bool found_ref;
+ for (auto frame_index : m_ref_frame_idx) {
+ found_ref = m_bit_stream->read_bit();
+ if (found_ref) {
+ m_frame_width = m_ref_frame_width[frame_index];
+ m_frame_height = m_ref_frame_height[frame_index];
+ break;
+ }
+ }
+
+ if (!found_ref) {
+ SAFE_CALL(frame_size());
+ } else {
+ SAFE_CALL(compute_image_size());
+ }
+
+ SAFE_CALL(render_size());
+ return true;
+}
+
+bool Parser::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 Parser::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 Parser::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& loop_filter_ref_delta : m_loop_filter_ref_deltas) {
+ if (m_bit_stream->read_bit())
+ loop_filter_ref_delta = m_bit_stream->read_s(6);
+ }
+ for (auto& loop_filter_mode_delta : m_loop_filter_mode_deltas) {
+ if (m_bit_stream->read_bit())
+ loop_filter_mode_delta = m_bit_stream->read_s(6);
+ }
+ }
+ }
+ return true;
+}
+
+bool Parser::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 Parser::read_delta_q()
+{
+ if (m_bit_stream->read_bit())
+ return m_bit_stream->read_s(4);
+ return 0;
+}
+
+bool Parser::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& segmentation_tree_prob : m_segmentation_tree_probs)
+ segmentation_tree_prob = read_prob();
+ m_segmentation_temporal_update = m_bit_stream->read_bit();
+ for (auto& segmentation_pred_prob : m_segmentation_pred_prob)
+ segmentation_pred_prob = 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 Parser::read_prob()
+{
+ if (m_bit_stream->read_bit())
+ return m_bit_stream->read_byte();
+ return 255;
+}
+
+bool Parser::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 Parser::calc_min_log2_tile_cols()
+{
+ auto min_log_2 = 0u;
+ while ((u32)(MAX_TILE_WIDTH_B64 << min_log_2) < m_sb64_cols)
+ min_log_2++;
+ return min_log_2;
+}
+
+u16 Parser::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 Parser::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;
+ 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);
+ }
+ 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& loop_filter_mode_delta : m_loop_filter_mode_deltas)
+ loop_filter_mode_delta = 0;
+ m_probability_tables->reset_probs();
+ return true;
+}
+
+bool Parser::trailing_bits()
+{
+ while (m_bit_stream->get_position() & 7u)
+ RESERVED_ZERO;
+ return true;
+}
+
+bool Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::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 Parser::update_mv_prob(u8 prob)
+{
+ if (m_bit_stream->read_bool(252)) {
+ return (m_bit_stream->read_literal(7) << 1u) | 1u;
+ }
+ return prob;
+}
+
+bool Parser::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 Parser::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);
+ 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;
+}
+
+void Parser::clear_context(Vector<u8>& context, size_t size)
+{
+ context.resize_and_keep_capacity(size);
+ __builtin_memset(context.data(), 0, sizeof(u8) * size);
+}
+
+void Parser::clear_context(Vector<Vector<u8>>& context, size_t outer_size, size_t inner_size)
+{
+ if (context.size() < outer_size)
+ context.resize(outer_size);
+ for (auto& sub_vector : context)
+ clear_context(sub_vector, inner_size);
+}
+
+bool Parser::clear_above_context()
+{
+ clear_context(m_above_nonzero_context, 2 * m_mi_cols, 3);
+ clear_context(m_above_seg_pred_context, m_mi_cols);
+ clear_context(m_above_partition_context, m_sb64_cols * 8);
+ return true;
+}
+
+u32 Parser::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 Parser::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 Parser::clear_left_context()
+{
+ clear_context(m_left_nonzero_context, 2 * m_mi_rows, 3);
+ clear_context(m_left_seg_pred_context, m_mi_rows);
+ clear_context(m_left_partition_context, m_sb64_rows * 8);
+ return true;
+}
+
+bool Parser::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);
+ 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));
+ if (m_has_rows)
+ SAFE_CALL(decode_block(row + half_block_8x8, col, subsize));
+ } else if (partition == PartitionVertical) {
+ SAFE_CALL(decode_block(row, col, subsize));
+ if (m_has_cols)
+ SAFE_CALL(decode_block(row, col + half_block_8x8, subsize));
+ } else {
+ SAFE_CALL(decode_partition(row, col, subsize));
+ SAFE_CALL(decode_partition(row, col + half_block_8x8, subsize));
+ SAFE_CALL(decode_partition(row + half_block_8x8, col, subsize));
+ SAFE_CALL(decode_partition(row + half_block_8x8, col + half_block_8x8, subsize));
+ }
+ if (block_subsize == Block_8x8 || partition != PartitionSplit) {
+ for (size_t i = 0; i < m_num_8x8; i++) {
+ m_above_partition_context[col + i] = 15 >> b_width_log2_lookup[subsize];
+ m_left_partition_context[row + i] = 15 >> b_width_log2_lookup[subsize];
+ }
+ }
+ return true;
+}
+
+bool Parser::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());
+ 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
+ return true;
+}
+
+bool Parser::mode_info()
+{
+ if (m_frame_is_intra)
+ return intra_frame_mode_info();
+ return inter_frame_mode_info();
+}
+
+bool Parser::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& block_sub_mode : m_block_sub_modes)
+ block_sub_mode = 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 Parser::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 Parser::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 Parser::seg_feature_active(u8 feature)
+{
+ return m_segmentation_enabled && m_feature_enabled[m_segment_id][feature];
+}
+
+bool Parser::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 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_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 Parser::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 (size_t i = 0; i < num_8x8_blocks_wide_lookup[m_mi_size]; i++)
+ m_above_seg_pred_context[m_mi_col + i] = seg_id_predicted;
+ for (size_t i = 0; 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 Parser::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 (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]);
+ }
+ }
+ return segment;
+}
+
+bool Parser::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 Parser::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& block_sub_mode : m_block_sub_modes)
+ block_sub_mode = 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 Parser::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 Parser::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 Parser::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 Parser::read_mv(u8)
+{
+ // TODO: Implement
+ return true;
+}
+
+bool Parser::residual()
+{
+ auto block_size = m_mi_size < Block_8x8 ? Block_8x8 : static_cast<BlockSubsize>(m_mi_size);
+ for (size_t plane = 0; plane < 3; plane++) {
+ auto tx_size = (plane > 0) ? get_uv_tx_size() : m_tx_size;
+ auto step = 1 << tx_size;
+ auto plane_size = get_plane_block_size(block_size, plane);
+ auto num_4x4_w = num_4x4_blocks_wide_lookup[plane_size];
+ auto num_4x4_h = num_4x4_blocks_high_lookup[plane_size];
+ auto sub_x = (plane > 0) ? m_subsampling_x : 0;
+ auto sub_y = (plane > 0) ? m_subsampling_y : 0;
+ auto base_x = (m_mi_col * 8) >> sub_x;
+ auto base_y = (m_mi_row * 8) >> sub_y;
+ if (m_is_inter) {
+ if (m_mi_size < Block_8x8) {
+ for (auto y = 0; y < num_4x4_h; y++) {
+ for (auto x = 0; x < num_4x4_w; x++) {
+ SAFE_CALL(m_decoder.predict_inter(plane, base_x + (4 * x), base_y + (4 * y), 4, 4, (y * num_4x4_w) + x));
+ }
+ }
+ } else {
+ SAFE_CALL(m_decoder.predict_inter(plane, base_x, base_y, num_4x4_w * 4, num_4x4_h * 4, 0));
+ }
+ }
+ auto max_x = (m_mi_cols * 8) >> sub_x;
+ auto max_y = (m_mi_rows * 8) >> sub_y;
+ auto block_index = 0;
+ for (auto y = 0; y < num_4x4_h; y += step) {
+ for (auto x = 0; x < num_4x4_w; x += step) {
+ auto start_x = base_x + (4 * x);
+ auto start_y = base_y + (4 * y);
+ auto non_zero = false;
+ if (start_x < max_x && start_y < max_y) {
+ if (!m_is_inter)
+ SAFE_CALL(m_decoder.predict_intra(plane, start_x, start_y, m_available_l || x > 0, m_available_u || y > 0, (x + step) < num_4x4_w, tx_size, block_index));
+ if (!m_skip) {
+ non_zero = tokens(plane, start_x, start_y, tx_size, block_index);
+ SAFE_CALL(m_decoder.reconstruct(plane, start_x, start_y, tx_size));
+ }
+ }
+ auto above_sub_context = m_above_nonzero_context[plane];
+ auto left_sub_context = m_left_nonzero_context[plane];
+ above_sub_context.resize_and_keep_capacity((start_x >> 2) + step);
+ left_sub_context.resize_and_keep_capacity((start_y >> 2) + step);
+ for (auto i = 0; i < step; i++) {
+ above_sub_context[(start_x >> 2) + i] = non_zero;
+ left_sub_context[(start_y >> 2) + i] = non_zero;
+ }
+ block_index++;
+ }
+ }
+ }
+ return true;
+}
+
+TXSize Parser::get_uv_tx_size()
+{
+ if (m_mi_size < Block_8x8)
+ return TX_4x4;
+ return min(m_tx_size, max_txsize_lookup[get_plane_block_size(m_mi_size, 1)]);
+}
+
+BlockSubsize Parser::get_plane_block_size(u32 subsize, u8 plane)
+{
+ auto sub_x = (plane > 0) ? m_subsampling_x : 0;
+ auto sub_y = (plane > 0) ? m_subsampling_y : 0;
+ return ss_size_lookup[subsize][sub_x][sub_y];
+}
+
+bool Parser::tokens(size_t, u32, u32, TXSize, u32)
+{
+ // TODO: Implement
+ return true;
+}
+
+bool Parser::find_mv_refs(ReferenceFrame, int)
+{
+ // TODO: Implement
+ return true;
+}
+
+bool Parser::find_best_ref_mvs(int)
+{
+ // TODO: Implement
+ return true;
+}
+
+bool Parser::append_sub8x8_mvs(u8, u8)
+{
+ // TODO: Implement
+ return true;
+}
+
+void Parser::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);
+}
+
+}