diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.cpp b/Userland/Libraries/LibVideo/VP9/Decoder.cpp index acb7b2ca27..f627aa27f0 100644 --- a/Userland/Libraries/LibVideo/VP9/Decoder.cpp +++ b/Userland/Libraries/LibVideo/VP9/Decoder.cpp @@ -16,6 +16,7 @@ Decoder::Decoder() : m_probability_tables(make()) , m_tree_parser(make(*m_probability_tables)) { + m_tree_parser->set_segmentation_tree_probs(m_segmentation_tree_probs); } bool Decoder::parse_frame(const ByteBuffer& frame_data) @@ -307,18 +308,18 @@ i8 Decoder::read_delta_q() bool Decoder::segmentation_params() { - auto segmentation_enabled = m_bit_stream->read_bit(); - if (!segmentation_enabled) + m_segmentation_enabled = m_bit_stream->read_bit(); + if (!m_segmentation_enabled) return true; - auto segmentation_update_map = m_bit_stream->read_bit(); - if (segmentation_update_map) { + 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(); } - auto segmentation_temporal_update = m_bit_stream->read_bit(); + m_segmentation_temporal_update = m_bit_stream->read_bit(); for (auto i = 0; i < 3; i++) { - m_segmentation_pred_prob[i] = segmentation_temporal_update ? read_prob() : 255; + m_segmentation_pred_prob[i] = m_segmentation_temporal_update ? read_prob() : 255; } } @@ -808,11 +809,94 @@ bool Decoder::decode_partition(u32 row, u32 col, u8 block_subsize) 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) { + if (!decode_block(row, col, subsize)) + return false; + } else if (partition == PartitionHorizontal) { + if (!decode_block(row, col, subsize)) + return false; + // 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_tree_parser->set_mi_row(m_mi_row); + m_mi_col = col; + m_tree_parser->set_mi_col(m_mi_col); + m_mi_size = subsize; + m_available_u = row > 0; + m_tree_parser->set_available_u(m_available_u); + m_available_l = col > m_mi_col_start; + m_tree_parser->set_available_l(m_available_l); + if (!mode_info()) + return false; + // 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() +{ + if (!intra_segment_id()) + return false; + if (!read_skip()) + return false; + if (!read_tx_size(true)) + return false; + // FIXME: Finish implementing + return true; +} + +bool Decoder::intra_segment_id() +{ + if (m_segmentation_enabled && m_segmentation_update_map) { + m_segment_id = m_tree_parser->parse_tree(SyntaxElementType::SegmentID); + } else { + m_segment_id = 0; + } + return true; +} + +bool Decoder::read_skip() +{ + if (seg_feature_active(SEG_LVL_SKIP)) { + m_skip = 1; + } else { + m_skip = m_tree_parser->parse_tree(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) +{ + // FIXME: Implement + (void)allow_select; + return true; +} + +bool Decoder::inter_frame_mode_info() +{ + return true; +} + void Decoder::dump_info() { dbgln("Frame dimensions: {}x{}", m_frame_width, m_frame_height); diff --git a/Userland/Libraries/LibVideo/VP9/Decoder.h b/Userland/Libraries/LibVideo/VP9/Decoder.h index f7740eacf8..159d993d0d 100644 --- a/Userland/Libraries/LibVideo/VP9/Decoder.h +++ b/Userland/Libraries/LibVideo/VP9/Decoder.h @@ -83,6 +83,15 @@ private: bool decode_tile(); bool clear_left_context(); bool decode_partition(u32 row, u32 col, u8 block_subsize); + bool decode_block(u32 row, u32 col, u8 subsize); + bool mode_info(); + bool intra_frame_mode_info(); + bool intra_segment_id(); + bool read_skip(); + bool seg_feature_active(u8 feature); + bool read_tx_size(bool allow_select); + + bool inter_frame_mode_info(); u8 m_profile { 0 }; u8 m_frame_to_show_map_index { 0 }; @@ -123,6 +132,9 @@ private: u8 m_segmentation_pred_prob[3]; bool m_feature_enabled[8][4]; u8 m_feature_data[8][4]; + bool m_segmentation_enabled { false }; + bool m_segmentation_update_map { false }; + bool m_segmentation_temporal_update { false }; bool m_segmentation_abs_or_delta_update { false }; u16 m_tile_cols_log2 { 0 }; u16 m_tile_rows_log2 { 0 }; @@ -139,6 +151,13 @@ private: u32 m_mi_row_end { 0 }; u32 m_mi_col_start { 0 }; u32 m_mi_col_end { 0 }; + u32 m_mi_row { 0 }; + u32 m_mi_col { 0 }; + u32 m_mi_size { 0 }; + bool m_available_u { false }; + bool m_available_l { false }; + int m_segment_id { 0 }; + int m_skip { false }; bool m_use_hp { false }; diff --git a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp index 28e9def16c..bbb3069212 100644 --- a/Userland/Libraries/LibVideo/VP9/TreeParser.cpp +++ b/Userland/Libraries/LibVideo/VP9/TreeParser.cpp @@ -108,9 +108,9 @@ u8 TreeParser::select_tree_probability(SyntaxElementType type, u8 node) case SyntaxElementType::UVMode: break; case SyntaxElementType::SegmentID: - break; + return m_segmentation_tree_probs[node]; case SyntaxElementType::Skip: - break; + return calculate_skip_probability(); case SyntaxElementType::SegIDPredicted: break; case SyntaxElementType::IsInter: @@ -182,6 +182,18 @@ u8 TreeParser::calculate_partition_probability(u8 node) return m_probability_tables.partition_probs()[m_ctx][node2]; } +u8 TreeParser::calculate_skip_probability() +{ + m_ctx = 0; + if (m_available_u) { + // FIXME: m_ctx += m_skips[m_mi_row - 1][m_mi_col]; + } + if (m_available_l) { + // FIXME: m_ctx += m_skips[m_mi_row][m_mi_col - 1]; + } + return m_probability_tables.skip_prob()[m_ctx]; +} + void TreeParser::count_syntax_element(SyntaxElementType type, int value) { switch (type) { @@ -195,6 +207,7 @@ void TreeParser::count_syntax_element(SyntaxElementType type, int value) case SyntaxElementType::UVMode: break; case SyntaxElementType::Skip: + m_syntax_element_counter->m_counts_skip[m_ctx][value]++; break; case SyntaxElementType::IsInter: break; diff --git a/Userland/Libraries/LibVideo/VP9/TreeParser.h b/Userland/Libraries/LibVideo/VP9/TreeParser.h index d444b136a3..272ee729da 100644 --- a/Userland/Libraries/LibVideo/VP9/TreeParser.h +++ b/Userland/Libraries/LibVideo/VP9/TreeParser.h @@ -57,9 +57,15 @@ public: void set_row(u32 row) { m_row = row; } void set_frame_is_intra(bool frame_is_intra) { m_frame_is_intra = frame_is_intra; } void set_syntax_element_counter(SyntaxElementCounter* syntax_element_counter) { m_syntax_element_counter = syntax_element_counter; } + void set_segmentation_tree_probs(u8* segmentation_tree_probs) { m_segmentation_tree_probs = segmentation_tree_probs; } + void set_available_u(bool available_u) { m_available_u = available_u; } + void set_available_l(bool available_l) { m_available_l = available_l; } + void set_mi_row(u32 mi_row) { m_mi_row = mi_row; } + void set_mi_col(u32 mi_col) { m_mi_col = mi_col; } private: u8 calculate_partition_probability(u8 node); + u8 calculate_skip_probability(); ProbabilityTables& m_probability_tables; BitStream* m_bit_stream { nullptr }; @@ -79,6 +85,11 @@ private: u32 m_col { 0 }; u32 m_row { 0 }; bool m_frame_is_intra { false }; + u8* m_segmentation_tree_probs { nullptr }; + bool m_available_u { false }; + bool m_available_l { false }; + u32 m_mi_col { 0 }; + u32 m_mi_row { 0 }; }; }