From 6b0395018112ee0e1431e360a0ee9bdcf3fd4c62 Mon Sep 17 00:00:00 2001 From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:01:54 -0400 Subject: [PATCH] AV1: Added frame header and tile group OBU parsing. (#312) * * rocDecode/AV1: Added frame header OBU parsing. * * rocDecode/AV1: Added a missing function description. * * rocDecode/AV1: Added tile group OBU parsing. --- src/parser/av1_defines.h | 13 +- src/parser/av1_parser.cpp | 1332 +++++++++++++++++++++++++++++++++++++ src/parser/av1_parser.h | 317 ++++++++- 3 files changed, 1654 insertions(+), 8 deletions(-) diff --git a/src/parser/av1_defines.h b/src/parser/av1_defines.h index bbdbbcdfc3..1aadf65421 100644 --- a/src/parser/av1_defines.h +++ b/src/parser/av1_defines.h @@ -120,7 +120,7 @@ typedef enum { kOnly4x4 = 0, kTxModeLargest = 1, kTxModeSelect = 2, -} TX_Mode; +} Tx_Mode; typedef enum { kIdentity = 0, // Warp model is just an identity transform @@ -236,7 +236,10 @@ typedef struct { typedef struct { uint32_t frame_width_minus_1; + uint32_t frame_width; // FrameWidth uint32_t frame_height_minus_1; + uint32_t frame_height; // FrameHeight + uint32_t upscaled_width; // UpscaledWidth Av1SuperResParams superres_params; uint32_t mi_cols; uint32_t mi_rows; @@ -245,7 +248,9 @@ typedef struct { typedef struct { uint32_t render_and_frame_size_different; uint32_t render_width_minus_1; + uint32_t render_width; // RenderWidth uint32_t render_height_minus_1; + uint32_t render_height; // RenderHeight } Av1RenderSize; typedef struct { @@ -396,7 +401,7 @@ typedef struct { Av1TemporalPointInfo temporal_point_info; uint32_t display_frame_id; uint32_t frame_type; - uint32_t frame_isIntra; + uint32_t frame_is_intra; uint32_t show_frame; uint32_t showable_frame; uint32_t error_resilient_mode; @@ -423,7 +428,7 @@ typedef struct { uint32_t gold_frame_idx; int32_t ref_frame_idx[REFS_PER_FRAME]; uint32_t delta_frame_id_minus_1; - uint32_t expectedFrameId[REFS_PER_FRAME]; + uint32_t expected_frame_id[REFS_PER_FRAME]; uint32_t allow_high_precision_mv; uint32_t is_filter_switchable; uint32_t interpolation_filter; @@ -437,7 +442,7 @@ typedef struct { Av1DeltaLFParams delta_lf_params; uint32_t coded_lossless; uint32_t lossless_array[MAX_SEGMENTS]; - uint32_t seg_qm__level[3][MAX_SEGMENTS]; + uint32_t seg_qm_level[3][MAX_SEGMENTS]; uint32_t all_lossless; Av1LoopFilterParams loop_filter_params; Av1CdefParams cdef_params; diff --git a/src/parser/av1_parser.cpp b/src/parser/av1_parser.cpp index 538b831d83..e106111880 100644 --- a/src/parser/av1_parser.cpp +++ b/src/parser/av1_parser.cpp @@ -194,6 +194,404 @@ void Av1VideoParser::ParseSequenceHeader(uint8_t *p_stream, size_t size) { p_seq_header->film_grain_params_present = Parser::GetBit(p_stream, offset); } +ParserResult Av1VideoParser::ParseUncompressedHeader(uint8_t *p_stream, size_t size) { + size_t offset = 0; // current bit offset + Av1SequenceHeader *p_seq_header = &seq_header_; + Av1FrameHeader *p_frame_header = &frame_header_; + uint32_t frame_id_len = 0; + uint32_t all_frames = (1 << NUM_REF_FRAMES) - 1; + int i; + + memset(p_frame_header, 0, sizeof(Av1FrameHeader)); + + if (p_seq_header->frame_id_numbers_present_flag) { + frame_id_len = p_seq_header->additional_frame_id_length_minus_1 + p_seq_header-> delta_frame_id_length_minus_2 + 3; + } + + if (p_seq_header->reduced_still_picture_header) { + p_frame_header->show_existing_frame = 0; + p_frame_header->frame_type = kKeyFrame; + p_frame_header->frame_is_intra = 1; + p_frame_header->show_frame = 1; + p_frame_header->showable_frame = 0; + } else { + p_frame_header->show_existing_frame = Parser::GetBit(p_stream, offset); + if (p_frame_header->show_existing_frame == 1) { + p_frame_header->frame_to_show_map_idx = Parser::ReadBits(p_stream, offset, 3); + if (p_seq_header->decoder_model_info_present_flag && !p_seq_header->timing_info.equal_picture_interval) { + // temporal_point_info() + p_frame_header->temporal_point_info.frame_presentation_time = Parser::ReadBits(p_stream, offset, p_seq_header->decoder_model_info.frame_presentation_time_length_minus_1 + 1); + } + p_frame_header->refresh_frame_flags = 0; + if (p_seq_header->frame_id_numbers_present_flag) { + p_frame_header->display_frame_id = Parser::ReadBits(p_stream, offset, frame_id_len); + } + p_frame_header->frame_type = ref_frame_type_[p_frame_header->frame_to_show_map_idx]; + if (p_frame_header->frame_type == kKeyFrame) { + p_frame_header->refresh_frame_flags = all_frames; + } + if (p_seq_header->film_grain_params_present) { + // Todo + ERR("Film grain param loading not implemented.\n"); + // load_grain_params(p_frame_header->frame_to_show_map_idx); + return PARSER_NOT_IMPLEMENTED; + } + + return PARSER_OK; + } + + p_frame_header->frame_type = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->frame_is_intra = (p_frame_header->frame_type == kIntraOnlyFrame) || (p_frame_header->frame_type == kKeyFrame); + p_frame_header->show_frame = Parser::GetBit(p_stream, offset); + if (p_frame_header->show_frame && p_seq_header->decoder_model_info_present_flag && !p_seq_header->timing_info.equal_picture_interval) { + // temporal_point_info() + p_frame_header->temporal_point_info.frame_presentation_time = Parser::ReadBits(p_stream, offset, p_seq_header->decoder_model_info.frame_presentation_time_length_minus_1 + 1); + } + if (p_frame_header->show_frame) { + p_frame_header->showable_frame = p_frame_header->frame_type != kKeyFrame; + } else { + p_frame_header->showable_frame = Parser::GetBit(p_stream, offset); + } + if (p_frame_header->frame_type == kSwitchFrame || (p_frame_header->frame_type == kKeyFrame && p_frame_header->show_frame)) { + p_frame_header->error_resilient_mode = 1; + } else { + p_frame_header->error_resilient_mode = Parser::GetBit(p_stream, offset); + } + } + + if (p_frame_header->frame_type == kKeyFrame && p_frame_header->show_frame) { + for (i = 0; i < NUM_REF_FRAMES; i++) { + ref_valid_[i] = 0; + ref_order_hint_[i] = 0; + } + for (i = 0; i < REFS_PER_FRAME; i++) { + p_frame_header->order_hints[kLastFrame + i] = 0; + } + } + + p_frame_header->disable_cdf_update = Parser::GetBit(p_stream, offset); + if (p_seq_header->seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS) { + p_frame_header->allow_screen_content_tools = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->allow_screen_content_tools = p_seq_header->seq_force_screen_content_tools; + } + + if (p_frame_header->allow_screen_content_tools) { + if (p_seq_header->seq_force_integer_mv == SELECT_INTEGER_MV) { + p_frame_header->force_integer_mv = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->force_integer_mv = p_seq_header->seq_force_integer_mv; + } + } else { + p_frame_header->force_integer_mv = 0; + } + if (p_frame_header->frame_is_intra) { + p_frame_header->force_integer_mv = 1; + } + + if (p_seq_header->frame_id_numbers_present_flag) { + p_frame_header->prev_frame_id = p_frame_header->current_frame_id; + p_frame_header->current_frame_id = Parser::ReadBits(p_stream, offset, frame_id_len); + MarkRefFrames(p_seq_header, p_frame_header, frame_id_len); + } else { + p_frame_header->current_frame_id = 0; + } + + if (p_frame_header->frame_type == kSwitchFrame) { + p_frame_header->frame_size_override_flag = 1; + } else if (p_seq_header->reduced_still_picture_header) { + p_frame_header->frame_size_override_flag = 0; + } else { + p_frame_header->frame_size_override_flag = Parser::GetBit(p_stream, offset); + } + + p_frame_header->order_hint = Parser::ReadBits(p_stream, offset, p_seq_header->order_hint_bits); + if (p_frame_header->frame_is_intra || p_frame_header->error_resilient_mode) { + p_frame_header->primary_ref_frame = PRIMARY_REF_NONE; + } else { + p_frame_header->primary_ref_frame = Parser::ReadBits(p_stream, offset, 3); + } + + if (p_seq_header->decoder_model_info_present_flag) { + p_frame_header->buffer_removal_time_present_flag = Parser::GetBit(p_stream, offset); + if (p_frame_header->buffer_removal_time_present_flag) { + for (int op_num = 0; op_num <= p_seq_header->operating_points_cnt_minus_1; op_num++) { + if (p_seq_header->decoder_model_present_for_this_op[op_num]) { + uint32_t op_pt_idc = p_seq_header->operating_point_idc[op_num]; + uint32_t in_temporal_layer = (op_pt_idc >> temporal_id_) & 1; + uint32_t in_spatial_layer = (op_pt_idc >> (spatial_id_ + 8)) & 1; + if (op_pt_idc == 0 || (in_temporal_layer && in_spatial_layer)) { + p_frame_header->buffer_removal_time[op_num] = Parser::ReadBits(p_stream, offset, p_seq_header->decoder_model_info.buffer_removal_time_length_minus_1 + 1); + } + } + } + } + } + + p_frame_header->allow_high_precision_mv = 0; + p_frame_header->use_ref_frame_mvs = 0; + p_frame_header->allow_intrabc = 0; + + if (p_frame_header->frame_type == kSwitchFrame || (p_frame_header->frame_type == kKeyFrame && p_frame_header->show_frame)) { + p_frame_header->refresh_frame_flags = all_frames; + } else { + p_frame_header->refresh_frame_flags = Parser::ReadBits(p_stream, offset, 8); + } + // Clear reference list for kKeyFrame + if (p_frame_header->frame_type == kKeyFrame) { + for (i = 0; i < REFS_PER_FRAME; i++) { + ref_pictures_[i].index = INVALID_INDEX; + } + } + if (!p_frame_header->frame_is_intra || p_frame_header->refresh_frame_flags != all_frames) { + if (p_frame_header->error_resilient_mode && p_seq_header->enable_order_hint) { + for (i = 0; i < NUM_REF_FRAMES; i++) { + p_frame_header->ref_order_hint[i] = Parser::ReadBits(p_stream, offset, p_seq_header->order_hint_bits); + if (p_frame_header->ref_order_hint[i] != ref_order_hint_[i]) { + ref_valid_[i] = 0; + } + } + } + } + + if (p_frame_header->frame_is_intra) { + FrameSize(p_stream, offset, p_seq_header, p_frame_header); + RenderSize(p_stream, offset, p_frame_header); + if (p_frame_header->allow_screen_content_tools && p_frame_header->frame_size.upscaled_width == p_frame_header->frame_size.frame_width) { + p_frame_header->allow_intrabc = Parser::GetBit(p_stream, offset); + } + } else { + if (!p_seq_header->enable_order_hint) { + p_frame_header->frame_refs_short_signaling = 0; + } else { + p_frame_header->frame_refs_short_signaling = Parser::GetBit(p_stream, offset); + if (p_frame_header->frame_refs_short_signaling) { + p_frame_header->last_frame_idx = Parser::ReadBits(p_stream, offset, 3); + p_frame_header->gold_frame_idx = Parser::ReadBits(p_stream, offset, 3); + // 7.8. Set frame refs process + SetFrameRefs(p_seq_header, p_frame_header); + } + } + + for (int i = 0; i < REFS_PER_FRAME; i++) { + if (!p_frame_header->frame_refs_short_signaling) { + p_frame_header->ref_frame_idx[i] = Parser::ReadBits(p_stream, offset, 3); + } + if (p_seq_header->frame_id_numbers_present_flag) { + p_frame_header->delta_frame_id_minus_1 = Parser::ReadBits(p_stream, offset, p_seq_header->delta_frame_id_length_minus_2 + 2); + uint32_t delta_frame_id = p_frame_header->delta_frame_id_minus_1 + 1; + p_frame_header->expected_frame_id[i] = ((p_frame_header->current_frame_id + (1 << frame_id_len) - delta_frame_id ) % (1 << frame_id_len)); + if (p_frame_header->expected_frame_id[i] != ref_frame_id_[p_frame_header->ref_frame_idx[i]] || ref_valid_[p_frame_header->ref_frame_idx[i]] == 0) { + ERR("Syntax Error: Reference buffer frame ID mismatch.\n"); + return PARSER_INVALID_ARG; + } + } + } + + if (p_frame_header->frame_size_override_flag && !p_frame_header->error_resilient_mode) { + FrameSizeWithRefs(p_stream, offset, p_seq_header, p_frame_header); + } else { + FrameSize(p_stream, offset, p_seq_header, p_frame_header); + RenderSize(p_stream, offset, p_frame_header); + } + + if (p_frame_header->force_integer_mv) { + p_frame_header->allow_high_precision_mv = 0; + } else { + p_frame_header->allow_high_precision_mv = Parser::GetBit(p_stream, offset); + } + + // read_interpolation_filter() + p_frame_header->is_filter_switchable = Parser::GetBit(p_stream, offset); + if (p_frame_header->is_filter_switchable == 1) { + p_frame_header->interpolation_filter = kSwitchable; + } else { + p_frame_header->interpolation_filter = Parser::ReadBits(p_stream, offset, 2); + } + p_frame_header->is_motion_mode_switchable = Parser::GetBit(p_stream, offset); + if (p_frame_header->error_resilient_mode || !p_seq_header->enable_ref_frame_mvs) { + p_frame_header->use_ref_frame_mvs = 0; + } else { + p_frame_header->use_ref_frame_mvs = Parser::GetBit(p_stream, offset); + } + + for (i = 0; i < REFS_PER_FRAME; i++) { + uint32_t ref_frame = kLastFrame + i; + uint32_t hint = ref_order_hint_[p_frame_header->ref_frame_idx[i]]; + p_frame_header->order_hints[ref_frame] = hint; + if (!p_seq_header->enable_order_hint) { + p_frame_header->ref_frame_sign_bias[ref_frame] = 0; + } else { + p_frame_header->ref_frame_sign_bias[ref_frame] = GetRelativeDist(p_seq_header, hint, p_frame_header->order_hint) > 0; + } + } + } + + // Generate reference map for the next picture + int ref_index = 0; + for (int mask = p_frame_header->refresh_frame_flags; mask; mask >>= 1) { + if (mask & 1) { + ref_pic_map_next_[ref_index] = new_fb_index_; + } else { + ref_pic_map_next_[ref_index] = ref_pic_map_[ref_index]; + } + ++ref_index; + } + for (; ref_index < NUM_REF_FRAMES; ++ref_index) { + ref_pic_map_next_[ref_index] = ref_pic_map_[ref_index]; + } + + if (p_seq_header->reduced_still_picture_header || p_frame_header->disable_cdf_update) { + p_frame_header->disable_frame_end_update_cdf = 1; + } else { + p_frame_header->disable_frame_end_update_cdf = Parser::GetBit(p_stream, offset); + } + + if (p_frame_header->primary_ref_frame == PRIMARY_REF_NONE) { + // Todo + ERR("Warning: need to implement init_non_coeff_cdfs()\n"); + + SetupPastIndependence(p_frame_header); + } else { + // Todo + ERR("Warning: need to implement load_cdfs()\n"); + ERR("Warning: need to implement load_previous()\n"); + return PARSER_NOT_IMPLEMENTED; + } + + if (p_frame_header->use_ref_frame_mvs == 1) { + // Todo + ERR("Warning: need to implement motion_field_estimation()\n"); + return PARSER_NOT_IMPLEMENTED; + } + + TileInfo(p_stream, offset, p_seq_header, p_frame_header); + + QuantizationParams(p_stream, offset, p_seq_header, p_frame_header); + + SegmentationParams(p_stream, offset, p_frame_header); + + DeltaQParams(p_stream, offset, p_frame_header); + + DeltaLFParams(p_stream, offset, p_frame_header); + + if (p_frame_header->primary_ref_frame == PRIMARY_REF_NONE) { + // Todo + ERR("Warning: Need to implement init_coeff_cdfs()\n"); + } else { + // Todo + ERR("Warning: Need to implement load_previous_segment_ids()\n"); + } + + p_frame_header->coded_lossless = 1; + for (int segment_id = 0; segment_id < MAX_SEGMENTS; segment_id++) { + // Todo int qindex = get_qindex( 1, segment_id ); + ERR("Warning: Need to implement get_qindex()\n"); + int qindex = 1; + p_frame_header->lossless_array[segment_id] = qindex == 0 && p_frame_header->quantization_params.delta_q_y_dc == 0 && p_frame_header->quantization_params.delta_q_u_ac == 0 && p_frame_header->quantization_params.delta_q_u_dc == 0 && p_frame_header->quantization_params.delta_q_v_ac == 0 && p_frame_header->quantization_params.delta_q_v_dc == 0; + if (!p_frame_header->lossless_array[segment_id]) { + p_frame_header->coded_lossless = 0; + } + if (p_frame_header->quantization_params.using_qmatrix) { + if (p_frame_header->lossless_array[segment_id]) { + p_frame_header->seg_qm_level[0][segment_id] = 15; + p_frame_header->seg_qm_level[1][segment_id] = 15; + p_frame_header->seg_qm_level[2][segment_id] = 15; + } else { + p_frame_header->seg_qm_level[0][segment_id] = p_frame_header->quantization_params.qm_y; + p_frame_header->seg_qm_level[1][segment_id] = p_frame_header->quantization_params.qm_u; + p_frame_header->seg_qm_level[2][segment_id] = p_frame_header->quantization_params.qm_v; + } + } + } + + p_frame_header->all_lossless = p_frame_header->coded_lossless && (p_frame_header->frame_size.frame_width == p_frame_header->frame_size.upscaled_width); + + LoopFilterParams(p_stream, offset, p_seq_header, p_frame_header); + + CdefParams(p_stream, offset, p_seq_header, p_frame_header); + + LrParams(p_stream, offset, p_seq_header, p_frame_header); + + ReadTxMode(p_stream, offset, p_frame_header); + + // frame_reference_mode() + if (p_frame_header->frame_is_intra) { + p_frame_header->frame_reference_mode.reference_select = 0; + } else { + p_frame_header->frame_reference_mode.reference_select = Parser::GetBit(p_stream, offset); + } + + SkipModeParams(p_stream, offset, p_seq_header, p_frame_header); + + if (p_frame_header->frame_is_intra || p_frame_header->error_resilient_mode || !p_seq_header->enable_warped_motion) { + p_frame_header->allow_warped_motion = 0; + } else { + p_frame_header->allow_warped_motion = Parser::GetBit(p_stream, offset); + } + + p_frame_header->reduced_tx_set = Parser::GetBit(p_stream, offset); + + GlobalMotionParams(p_stream, offset, p_frame_header); + + FilmGrainParams(p_stream, offset, p_seq_header, p_frame_header); + + return PARSER_OK; +} + +void Av1VideoParser::ParseTileGroupInfo(uint8_t *p_stream, size_t size) { + size_t offset = 0; // current bit offset + Av1SequenceHeader *p_seq_header = &seq_header_; + Av1FrameHeader *p_frame_header = &frame_header_; + Av1TileGroupDataInfo *p_tile_group = &tile_group_data_; + uint32_t num_tiles; + uint32_t tile_start_and_end_present_flag = 0; + uint32_t tg_start, tg_end; + uint32_t header_types = 0; + uint32_t tile_cols = p_frame_header->tile_info.tile_cols; + uint32_t tile_rows = p_frame_header->tile_info.tile_rows; + uint8_t *p_tg_buf = p_stream; + uint32_t tg_size = size; + + memset(p_tile_group, 0, sizeof(Av1TileGroupDataInfo)); + p_tile_group->buffer_ptr = p_tg_buf; + p_tile_group->buffer_size = tg_size; + + // First parse the header + num_tiles = tile_cols * tile_rows; + if (num_tiles > 1) { + tile_start_and_end_present_flag = Parser::GetBit(p_stream, offset); + } + if (num_tiles == 1 || !tile_start_and_end_present_flag) { + tg_start = 0; + tg_end = num_tiles - 1; + } else { + uint32_t tile_bits = p_frame_header->tile_info.tile_cols_log2 + p_frame_header->tile_info.tile_rows_log2; + tg_start = Parser::ReadBits(p_stream, offset, tile_bits); + tg_end = Parser::ReadBits(p_stream, offset, tile_bits); + } + + header_types = ((offset + 7) >> 3); + p_tg_buf += header_types; + tg_size -= header_types; + for (int tile_num = tg_start; tile_num <= tg_end; tile_num++) { + int tile_row = tile_num / tile_cols; + int tile_col = tile_num % tile_cols; + int last_tile = tile_num == tg_end; + if (last_tile) { + p_tile_group->tile_data_info[tile_row][tile_col].size = tg_size; + p_tile_group->tile_data_info[tile_row][tile_col].offset = p_tg_buf - p_tile_group->buffer_ptr; + } else { + uint32_t tile_size_bytes = p_frame_header->tile_info.tile_size_bytes_minus_1 + 1; + uint32_t tile_size = ReadLeBytes(p_tg_buf, tile_size_bytes) + 1; + p_tile_group->tile_data_info[tile_row][tile_col].size = tile_size; + p_tile_group->tile_data_info[tile_row][tile_col].offset = p_tg_buf + tile_size_bytes - p_tile_group->buffer_ptr; + tg_size -= tile_size + tile_size_bytes; + p_tg_buf += tile_size + tile_size_bytes; + } + } +} + void Av1VideoParser::ParseColorConfig(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header) { p_seq_header->color_config.bit_depth = 8; @@ -263,3 +661,937 @@ void Av1VideoParser::ParseColorConfig(const uint8_t *p_stream, size_t &offset, A p_seq_header->color_config.separate_uv_delta_q = Parser::GetBit(p_stream, offset); } + +void Av1VideoParser::MarkRefFrames(Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header, uint32_t id_len) { + int diff_len = p_seq_header->delta_frame_id_length_minus_2 + 2; + for (int i = 0; i < NUM_REF_FRAMES; i++) { + if (p_frame_header->frame_type == kKeyFrame && p_frame_header->show_frame) { + ref_valid_[i] = 0; + } else if (p_frame_header->current_frame_id > (1 << diff_len)) { + if (ref_frame_id_[i] > p_frame_header->current_frame_id || ref_frame_id_[i] < (p_frame_header->current_frame_id - (1 << diff_len))) { + ref_valid_[i] = 0; + } + } else { + if (ref_frame_id_[i] > p_frame_header->current_frame_id && ref_frame_id_[i] < ((1 << id_len) + p_frame_header->current_frame_id - (1 << diff_len))) { + ref_valid_[ i ] = 0; + } + } + } +} + +void Av1VideoParser::FrameSize(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + if (p_frame_header->frame_size_override_flag) { + p_frame_header->frame_size.frame_width_minus_1 = Parser::ReadBits(p_stream, offset, p_seq_header->frame_width_bits_minus_1 + 1); + p_frame_header->frame_size.frame_width = p_frame_header->frame_size.frame_width_minus_1 + 1; + p_frame_header->frame_size.frame_height_minus_1 = Parser::ReadBits(p_stream, offset, p_seq_header->frame_height_bits_minus_1 + 1); + p_frame_header->frame_size.frame_height = p_frame_header->frame_size.frame_height_minus_1 + 1; + } else { + p_frame_header->frame_size.frame_width = p_seq_header->max_frame_width_minus_1 + 1; + p_frame_header->frame_size.frame_height = p_seq_header->max_frame_height_minus_1 + 1; + } + + SuperResParams(p_stream, offset, p_seq_header, p_frame_header); + ComputeImageSize(p_frame_header); +} + +void Av1VideoParser::SuperResParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + uint32_t super_res_denom; + + if (p_seq_header->enable_superres) { + p_frame_header->frame_size.superres_params.use_superres = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->frame_size.superres_params.use_superres = 0; + } + + if (p_frame_header->frame_size.superres_params.use_superres) { + p_frame_header->frame_size.superres_params.coded_denom = Parser::ReadBits(p_stream, offset, SUPERRES_DENOM_BITS); + super_res_denom = p_frame_header->frame_size.superres_params.coded_denom + SUPERRES_DENOM_MIN; + } else { + super_res_denom = SUPERRES_NUM; + } + + p_frame_header->frame_size.upscaled_width = p_frame_header->frame_size.frame_width; + p_frame_header->frame_size.frame_width = (p_frame_header->frame_size.upscaled_width * SUPERRES_NUM + (super_res_denom / 2)) / super_res_denom; +} + +void Av1VideoParser::ComputeImageSize(Av1FrameHeader *p_frame_header) { + p_frame_header->frame_size.mi_cols = 2 * ((p_frame_header->frame_size.frame_width + 7) >> 3); + p_frame_header->frame_size.mi_rows = 2 * ((p_frame_header->frame_size.frame_height + 7) >> 3); +} + +void Av1VideoParser::RenderSize(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + p_frame_header->render_size.render_and_frame_size_different = Parser::GetBit(p_stream, offset); + if (p_frame_header->render_size.render_and_frame_size_different) { + p_frame_header->render_size.render_width_minus_1 = Parser::ReadBits(p_stream, offset, 16); + p_frame_header->render_size.render_height_minus_1 = Parser::ReadBits(p_stream, offset, 16); + p_frame_header->render_size.render_width = p_frame_header->render_size.render_width_minus_1 + 1; + p_frame_header->render_size.render_height = p_frame_header->render_size.render_height_minus_1 + 1; + } else { + p_frame_header->render_size.render_width = p_frame_header->frame_size.upscaled_width; + p_frame_header->render_size.render_height = p_frame_header->frame_size.frame_height; + } +} + +void Av1VideoParser::SetFrameRefs(Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + int i; + int used_frame[NUM_REF_FRAMES]; + int curr_frame_hint; + int shifted_order_hints[NUM_REF_FRAMES]; + int ref; + + for (i = 0; i < REFS_PER_FRAME; i++) { + p_frame_header->ref_frame_idx[i] = -1; + } + p_frame_header->ref_frame_idx[kLastFrame - kLastFrame] = p_frame_header->last_frame_idx; + p_frame_header->ref_frame_idx[kGoldenFrame - kLastFrame] = p_frame_header->gold_frame_idx; + for (i = 0; i < NUM_REF_FRAMES; i++) { + used_frame[ i ] = 0; + } + used_frame[p_frame_header->last_frame_idx] = 1; + used_frame[p_frame_header->gold_frame_idx ] = 1; + + curr_frame_hint = 1 << (p_seq_header->order_hint_bits - 1); + for (i = 0; i < NUM_REF_FRAMES; i++) { + shifted_order_hints[i] = curr_frame_hint + GetRelativeDist(p_seq_header, ref_order_hint_[i], p_frame_header->order_hint); + } + + // The kAltRefFrame reference is set to be a backward reference to the frame with highest output order. + ref = FindLatestBackward(shifted_order_hints, used_frame, curr_frame_hint); + if (ref >= 0) { + p_frame_header->ref_frame_idx[kAltRefFrame - kLastFrame] = ref; + used_frame[ref] = 1; + } + // The kBwdRefFrame reference is set to be a backward reference to the closest frame. + ref = FindEarliestBackward(shifted_order_hints, used_frame, curr_frame_hint); + if ( ref >= 0 ) + { + p_frame_header->ref_frame_idx[kBwdRefFrame - kLastFrame] = ref; + used_frame[ref] = 1; + } + // The kAltRef2Frame reference is set to the next closest backward reference. + ref = FindEarliestBackward(shifted_order_hints, used_frame, curr_frame_hint); + if ( ref >= 0 ) + { + p_frame_header->ref_frame_idx[kAltRef2Frame - kLastFrame] = ref; + used_frame[ref] = 1; + } + + // The remaining references are set to be forward references in anti-chronological order. + int ref_frame_list[REFS_PER_FRAME - 2] = {kLast2Frame, kLast3Frame, kBwdRefFrame, kAltRef2Frame, kAltRefFrame}; + for (i = 0; i < REFS_PER_FRAME - 2; i++) { + int refFrame = ref_frame_list[i]; + if (p_frame_header->ref_frame_idx[refFrame - kLastFrame] < 0) { + ref = FindLatestForward(shifted_order_hints, used_frame, curr_frame_hint); + if (ref >= 0) { + p_frame_header->ref_frame_idx[refFrame - kLastFrame] = ref; + used_frame[ref] = 1; + } + } + } + + // Finally, any remaining references are set to the reference frame with smallest output order. + ref = -1; + for (i = 0; i < NUM_REF_FRAMES; i++) { + int earliest_order_hint = 9999; + int hint = shifted_order_hints[i]; + if (ref < 0 || hint < earliest_order_hint) { + ref = i; + earliest_order_hint = hint; + } + } + for (i = 0; i < REFS_PER_FRAME; i++) { + if (p_frame_header->ref_frame_idx[i] < 0) { + p_frame_header->ref_frame_idx[i] = ref; + } + } +} + +int Av1VideoParser::GetRelativeDist(Av1SequenceHeader *p_seq_header, int a, int b) { + if (!p_seq_header->enable_order_hint) { + return 0; + } + int diff = a - b; + int m = 1 << (p_seq_header->order_hint_bits - 1); + diff = (diff & (m - 1)) - (diff & m); + return diff; +} + +int Av1VideoParser::FindLatestBackward(int *shifted_order_hints, int *used_frame, int curr_frame_hint) { + int ref = -1; + int hint; + int latest_order_hint = -9999; + + for (int i = 0; i < NUM_REF_FRAMES; i++) { + hint = shifted_order_hints[i]; + if (!used_frame[i] && hint >= curr_frame_hint && (ref < 0 || hint >= latest_order_hint)) { + ref = i; + latest_order_hint = hint; + } + } + return ref; +} + +int Av1VideoParser::FindEarliestBackward(int *shifted_order_hints, int *used_frame, int curr_frame_hint) { + int ref = -1; + int hint; + int earliest_order_hint = 9999; + + for (int i = 0; i < NUM_REF_FRAMES; i++) { + hint = shifted_order_hints[i]; + if (!used_frame[i] && hint >= curr_frame_hint && (ref < 0 || hint < earliest_order_hint)) { + ref = i; + earliest_order_hint = hint; + } + } + return ref; +} + +int Av1VideoParser::FindLatestForward(int *shifted_order_hints, int *used_frame, int curr_frame_hint) { + int ref = -1; + int hint; + int latest_order_hint = -9999; + + for (int i = 0; i < NUM_REF_FRAMES; i++) { + hint = shifted_order_hints[i]; + if (!used_frame[i] && hint < curr_frame_hint && (ref < 0 || hint >= latest_order_hint)) { + ref = i; + latest_order_hint = hint; + } + } + return ref; +} + +void Av1VideoParser::FrameSizeWithRefs(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + for (int i = 0; i < REFS_PER_FRAME; i++) { + p_frame_header->found_ref = Parser::GetBit(p_stream, offset); + if (p_frame_header->found_ref) { + // Todo + ERR("Warning: Need to implement! found_ref == 1 case.\n"); +#if 0 + UpscaledWidth = RefUpscaledWidth[ ref_frame_idx[ i ] ] + FrameWidth = UpscaledWidth + FrameHeight = RefFrameHeight[ ref_frame_idx[ i ] ] + RenderWidth = RefRenderWidth[ ref_frame_idx[ i ] ] + RenderHeight = RefRenderHeight[ ref_frame_idx[ i ] ] +#endif + break; + } + } + + if (p_frame_header->found_ref == 0) { + FrameSize(p_stream, offset, p_seq_header, p_frame_header); + RenderSize(p_stream, offset, p_frame_header); + } else { + SuperResParams(p_stream, offset, p_seq_header, p_frame_header); + ComputeImageSize(p_frame_header); + } +} + +void Av1VideoParser::SetupPastIndependence(Av1FrameHeader *p_frame_header) { + p_frame_header->loop_filter_params.loop_filter_delta_enabled = 1; + p_frame_header->loop_filter_params.loop_filter_delta_update = 1; + + // Todo + ERR("Need to implement the rest of SetupPastIndependence"); +} + +void Av1VideoParser::TileInfo(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + int32_t sb_cols; + int32_t sb_rows; + int32_t sb_shift; + int32_t sb_size; + int32_t max_tile_width_sb; + int32_t max_tile_height_sb; + int32_t max_tile_area_sb; + int32_t min_log2_tile_cols; + int32_t min_log2_tile_rows; + int32_t max_log2_tile_cols; + int32_t max_log2_tile_rows; + int32_t min_log2_tiles; + int32_t tile_width_sb; + int32_t tile_height_sb; + int32_t max_width; + int32_t max_height; + int32_t size_sb; + int start_sb; + int i; + + sb_cols = p_seq_header->use_128x128_superblock ? ((p_frame_header->frame_size.mi_cols + 31) >> 5) : ((p_frame_header->frame_size.mi_cols + 15) >> 4); + sb_rows = p_seq_header->use_128x128_superblock ? ((p_frame_header->frame_size.mi_rows + 31) >> 5) : ((p_frame_header->frame_size.mi_rows + 15 ) >> 4); + sb_shift = p_seq_header->use_128x128_superblock ? 5 : 4; + sb_size = sb_shift + 2; + max_tile_width_sb = MAX_TILE_WIDTH >> sb_size; + max_tile_area_sb = MAX_TILE_AREA >> (2 * sb_size); + min_log2_tile_cols = TileLog2(max_tile_width_sb, sb_cols); + max_log2_tile_cols = TileLog2(1, std::min(sb_cols, MAX_TILE_COLS)); + max_log2_tile_rows = TileLog2(1, std::min(sb_rows, MAX_TILE_ROWS)); + min_log2_tiles = std::max(min_log2_tile_cols, static_cast(TileLog2(max_tile_area_sb, sb_rows * sb_cols))); + + p_frame_header->tile_info.uniform_tile_spacing_flag = Parser::GetBit(p_stream, offset); + if (p_frame_header->tile_info.uniform_tile_spacing_flag) { + p_frame_header->tile_info.tile_cols_log2 = min_log2_tile_cols; + while (p_frame_header->tile_info.tile_cols_log2 < max_log2_tile_cols) { + p_frame_header->tile_info.increment_tile_cols_log2 = Parser::GetBit(p_stream, offset); + if (p_frame_header->tile_info.increment_tile_cols_log2 == 1) { + p_frame_header->tile_info.tile_cols_log2++; + } else { + break; + } + } + + tile_width_sb = (sb_cols + (1 << p_frame_header->tile_info.tile_cols_log2) - 1) >> p_frame_header->tile_info.tile_cols_log2; + i = 0; + for (start_sb = 0; start_sb < sb_cols; start_sb += tile_width_sb) { + p_frame_header->tile_info.mi_col_starts[i] = start_sb << sb_shift; + i += 1; + } + p_frame_header->tile_info.mi_col_starts[i] = p_frame_header->frame_size.mi_cols; + p_frame_header->tile_info.tile_cols = i; + + min_log2_tile_rows = std::max(min_log2_tiles - p_frame_header->tile_info.tile_cols_log2, 0); + p_frame_header->tile_info.tile_rows_log2 = min_log2_tile_rows; + while (p_frame_header->tile_info.tile_rows_log2 < max_log2_tile_rows) { + p_frame_header->tile_info.increment_tile_rows_log2 = Parser::GetBit(p_stream, offset); + if (p_frame_header->tile_info.increment_tile_rows_log2 == 1) { + p_frame_header->tile_info.tile_rows_log2++; + } else { + break; + } + } + + tile_height_sb = (sb_rows + (1 << p_frame_header->tile_info.tile_rows_log2) - 1) >> p_frame_header->tile_info.tile_rows_log2; + i = 0; + for (start_sb = 0; start_sb < sb_rows; start_sb += tile_height_sb ) { + p_frame_header->tile_info.mi_row_starts[i] = start_sb << sb_shift; + i += 1; + } + p_frame_header->tile_info.mi_row_starts[i] = p_frame_header->frame_size.mi_rows; + p_frame_header->tile_info.tile_rows = i; + } else { + int widest_tile_sb = 0; + start_sb = 0; + for (i = 0; start_sb < sb_cols; i++) { + p_frame_header->tile_info.mi_col_starts[i] = start_sb << sb_shift; + max_width = std::min(sb_cols - start_sb, max_tile_width_sb); + p_frame_header->tile_info.width_in_sbs_minus_1 = ReadUnsignedNonSymmetic(p_stream, offset, max_width); + size_sb = p_frame_header->tile_info.width_in_sbs_minus_1 + 1; + widest_tile_sb = std::max(size_sb, widest_tile_sb); + start_sb += size_sb; + } + p_frame_header->tile_info.mi_col_starts[i] = p_frame_header->frame_size.mi_cols; + p_frame_header->tile_info.tile_cols = i; + p_frame_header->tile_info.tile_cols_log2 = TileLog2(1, p_frame_header->tile_info.tile_cols); + + if (min_log2_tiles > 0) { + max_tile_area_sb = (sb_rows * sb_cols) >> (min_log2_tiles + 1); + } else { + max_tile_area_sb = sb_rows * sb_cols; + } + max_tile_height_sb = std::max(max_tile_area_sb / widest_tile_sb, static_cast(1)); + + start_sb = 0; + for (i = 0; start_sb < sb_rows; i++) { + p_frame_header->tile_info.mi_row_starts[i] = start_sb << sb_shift; + max_height = std::min(sb_rows - start_sb, max_tile_height_sb); + p_frame_header->tile_info.height_in_sbs_minus_1 = ReadUnsignedNonSymmetic(p_stream, offset, max_height); + size_sb = p_frame_header->tile_info.height_in_sbs_minus_1 + 1; + start_sb += size_sb; + } + p_frame_header->tile_info.mi_row_starts[ i ] = p_frame_header->frame_size.mi_rows; + p_frame_header->tile_info.tile_rows = i; + p_frame_header->tile_info.tile_rows_log2 = TileLog2(1, p_frame_header->tile_info.tile_rows); + } + + if (p_frame_header->tile_info.tile_cols_log2 > 0 || p_frame_header->tile_info.tile_rows_log2 > 0) { + p_frame_header->tile_info.context_update_tile_id = Parser::ReadBits(p_stream, offset, p_frame_header->tile_info.tile_rows_log2 + p_frame_header->tile_info.tile_cols_log2); + p_frame_header->tile_info.tile_size_bytes_minus_1 = Parser::ReadBits(p_stream, offset, 2); + } else { + p_frame_header->tile_info.context_update_tile_id = 0; + } +} + +uint32_t Av1VideoParser::TileLog2(uint32_t blk_size, uint32_t target) { + uint32_t k; + for (k = 0; (blk_size << k) < target; k++ ) { + } + return k; +} + +void Av1VideoParser::QuantizationParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + p_frame_header->quantization_params.base_q_idx = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->quantization_params.delta_q_y_dc = ReadDeltaQ(p_stream, offset, p_frame_header); + + if (p_seq_header->color_config.num_planes > 1) { + if (p_seq_header->color_config.separate_uv_delta_q) { + p_frame_header->quantization_params.diff_uv_delta = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->quantization_params.diff_uv_delta = 0; + } + p_frame_header->quantization_params.delta_q_u_dc = ReadDeltaQ(p_stream, offset, p_frame_header); + p_frame_header->quantization_params.delta_q_u_ac = ReadDeltaQ(p_stream, offset, p_frame_header); + + if (p_frame_header->quantization_params.diff_uv_delta) { + p_frame_header->quantization_params.delta_q_v_dc = ReadDeltaQ(p_stream, offset, p_frame_header); + p_frame_header->quantization_params.delta_q_v_ac = ReadDeltaQ(p_stream, offset, p_frame_header); + } else { + p_frame_header->quantization_params.delta_q_v_dc = p_frame_header->quantization_params.delta_q_u_dc; + p_frame_header->quantization_params.delta_q_v_ac = p_frame_header->quantization_params.delta_q_u_ac; + } + } else { + p_frame_header->quantization_params.delta_q_u_dc = 0; + p_frame_header->quantization_params.delta_q_u_ac = 0; + p_frame_header->quantization_params.delta_q_v_dc = 0; + p_frame_header->quantization_params.delta_q_v_ac = 0; + } + + p_frame_header->quantization_params.using_qmatrix = Parser::GetBit(p_stream, offset); + if (p_frame_header->quantization_params.using_qmatrix) { + p_frame_header->quantization_params.qm_y = Parser::ReadBits(p_stream, offset, 4); + p_frame_header->quantization_params.qm_u = Parser::ReadBits(p_stream, offset, 4); + if (!p_seq_header->color_config.separate_uv_delta_q) { + p_frame_header->quantization_params.qm_v = p_frame_header->quantization_params.qm_u; + } else { + p_frame_header->quantization_params.qm_v = Parser::ReadBits(p_stream, offset, 4); + } + } +} + +uint32_t Av1VideoParser::ReadDeltaQ(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + p_frame_header->quantization_params.delta_coded = Parser::GetBit(p_stream, offset); + if (p_frame_header->quantization_params.delta_coded) { + p_frame_header->quantization_params.delta_q = ReadSigned(p_stream, offset, 1 + 6); + } else { + p_frame_header->quantization_params.delta_q = 0; + } + return p_frame_header->quantization_params.delta_q; +} + +void Av1VideoParser::SegmentationParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + int i, j; + int clipped_value; + uint32_t bits_to_read; + uint32_t segmentation_feature_bits[SEG_LVL_MAX] = {8,6,6,6,6,3,0,0}; + uint32_t segmentation_feature_signed[SEG_LVL_MAX] = { 1, 1, 1, 1, 1, 0, 0, 0 }; + uint32_t segmentation_feature_max[SEG_LVL_MAX] = {255, MAX_LOOP_FILTER, MAX_LOOP_FILTER, MAX_LOOP_FILTER, MAX_LOOP_FILTER, 7, 0, 0 }; + + p_frame_header->segmentation_params.segmentation_enabled = Parser::GetBit(p_stream, offset); + if (p_frame_header->segmentation_params.segmentation_enabled == 1) { + if (p_frame_header->primary_ref_frame == PRIMARY_REF_NONE) { + p_frame_header->segmentation_params.segmentation_update_map = 1; + p_frame_header->segmentation_params.segmentation_temporal_update = 0; + p_frame_header->segmentation_params.segmentation_update_data = 1; + } else { + p_frame_header->segmentation_params.segmentation_update_map = Parser::GetBit(p_stream, offset); + if (p_frame_header->segmentation_params.segmentation_update_map == 1) { + p_frame_header->segmentation_params.segmentation_temporal_update = Parser::GetBit(p_stream, offset); + } + p_frame_header->segmentation_params.segmentation_update_data = Parser::GetBit(p_stream, offset); + } + + if (p_frame_header->segmentation_params.segmentation_update_data == 1) { + for (i = 0; i < MAX_SEGMENTS; i++) { + for (j = 0; j < SEG_LVL_MAX; j++) { + p_frame_header->segmentation_params.feature_value = 0; + p_frame_header->segmentation_params.feature_enabled = Parser::GetBit(p_stream, offset); + p_frame_header->segmentation_params.feature_enabled_flags[i][j] = p_frame_header->segmentation_params.feature_enabled; + clipped_value = 0; + if (p_frame_header->segmentation_params.feature_enabled == 1) { + bits_to_read = segmentation_feature_bits[j]; + int limit = segmentation_feature_max[j]; + if (segmentation_feature_signed[j] == 1) { + p_frame_header->segmentation_params.feature_value = ReadSigned(p_stream, offset, 1 + bits_to_read); + clipped_value = std::clamp(static_cast(p_frame_header->segmentation_params.feature_value), -limit, limit); + } else { + p_frame_header->segmentation_params.feature_value = Parser::ReadBits(p_stream, offset, bits_to_read); + clipped_value = std::clamp(static_cast(p_frame_header->segmentation_params.feature_value), 0, limit); + } + } + p_frame_header->segmentation_params.feature_data[i][j] = clipped_value; + } + } + } + } else { + for (i = 0; i < MAX_SEGMENTS; i++) { + for (j = 0; j < SEG_LVL_MAX; j++) { + p_frame_header->segmentation_params.feature_enabled_flags[i][j] = 0; + p_frame_header->segmentation_params.feature_data[i][j] = 0; + } + } + } + + p_frame_header->segmentation_params.seg_id_pre_skip = 0; + p_frame_header->segmentation_params.last_active_seg_id = 0; + + for (i = 0; i < MAX_SEGMENTS; i++) { + for (j = 0; j < SEG_LVL_MAX; j++) { + if (p_frame_header->segmentation_params.feature_enabled_flags[i][j]) { + p_frame_header->segmentation_params.last_active_seg_id = i; + if (j >= SEG_LVL_REF_FRAME) { + p_frame_header->segmentation_params.seg_id_pre_skip = 1; + } + } + } + } +} + +void Av1VideoParser::DeltaQParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + p_frame_header->delta_q_params.delta_q_res = 0; + p_frame_header->delta_q_params.delta_q_present = 0; + if ( p_frame_header->quantization_params.base_q_idx > 0 ) + { + p_frame_header->delta_q_params.delta_q_present = Parser::GetBit(p_stream, offset); + } + if ( p_frame_header->delta_q_params.delta_q_present ) + { + p_frame_header->delta_q_params.delta_q_res = Parser::ReadBits(p_stream, offset, 2); + } +} + +void Av1VideoParser::DeltaLFParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + p_frame_header->delta_lf_params.delta_lf_present = 0; + p_frame_header->delta_lf_params.delta_lf_res = 0; + p_frame_header->delta_lf_params.delta_lf_multi = 0; + if (p_frame_header->delta_q_params.delta_q_present) { + if (!p_frame_header->allow_intrabc) { + p_frame_header->delta_lf_params.delta_lf_present = Parser::GetBit(p_stream, offset); + } + if (p_frame_header->delta_lf_params.delta_lf_present) { + p_frame_header->delta_lf_params.delta_lf_res = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->delta_lf_params.delta_lf_multi = Parser::GetBit(p_stream, offset); + } + } +} + +void Av1VideoParser::LoopFilterParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + int i; + + if (p_frame_header->coded_lossless || p_frame_header->allow_intrabc) { + p_frame_header->loop_filter_params.loop_filter_level[0] = 0; + p_frame_header->loop_filter_params.loop_filter_level[1] = 0; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kIntraFrame] = 1; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kLastFrame] = 0; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kLast2Frame] = 0; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kLast3Frame] = 0; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kBwdRefFrame] = 0; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kGoldenFrame] = -1; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kAltRefFrame] = -1; + p_frame_header->loop_filter_params.loop_filter_ref_deltas[kAltRef2Frame] = -1; + for (i = 0; i < 2; i++) { + p_frame_header->loop_filter_params.loop_filter_mode_deltas[i] = 0; + } + return; + } + + p_frame_header->loop_filter_params.loop_filter_level[0] = Parser::ReadBits(p_stream, offset, 6); + p_frame_header->loop_filter_params.loop_filter_level[1] = Parser::ReadBits(p_stream, offset, 6); + if (p_seq_header->color_config.num_planes > 1) { + if (p_frame_header->loop_filter_params.loop_filter_level[0] || p_frame_header->loop_filter_params.loop_filter_level[1]) { + p_frame_header->loop_filter_params.loop_filter_level[2] = Parser::ReadBits(p_stream, offset, 6); + p_frame_header->loop_filter_params.loop_filter_level[3] = Parser::ReadBits(p_stream, offset, 6); + } + } + + p_frame_header->loop_filter_params.loop_filter_sharpness = Parser::ReadBits(p_stream, offset, 3); + p_frame_header->loop_filter_params.loop_filter_delta_enabled = Parser::GetBit(p_stream, offset); + if (p_frame_header->loop_filter_params.loop_filter_delta_enabled == 1) { + p_frame_header->loop_filter_params.loop_filter_delta_update = Parser::GetBit(p_stream, offset); + if (p_frame_header->loop_filter_params.loop_filter_delta_update == 1) { + for (i = 0; i < TOTAL_REFS_PER_FRAME; i++) { + p_frame_header->loop_filter_params.update_ref_delta = Parser::GetBit(p_stream, offset); + if (p_frame_header->loop_filter_params.update_ref_delta == 1) { + p_frame_header->loop_filter_params.loop_filter_ref_deltas[i] = ReadSigned(p_stream, offset, 1 + 6); + } + } + for (i = 0; i < 2; i++) { + p_frame_header->loop_filter_params.update_mode_delta = Parser::GetBit(p_stream, offset); + if ( p_frame_header->loop_filter_params.update_mode_delta == 1 ) + { + p_frame_header->loop_filter_params.loop_filter_mode_deltas[i] = ReadSigned(p_stream, offset, 1 + 6); + } + } + } + } +} + +void Av1VideoParser::CdefParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + if (p_frame_header->coded_lossless || p_frame_header->allow_intrabc ||!p_seq_header->enable_cdef) { + p_frame_header->cdef_params.cdef_bits = 0; + p_frame_header->cdef_params.cdef_y_pri_strength[0] = 0; + p_frame_header->cdef_params.cdef_y_sec_strength[0] = 0; + p_frame_header->cdef_params.cdef_uv_pri_strength[0] = 0; + p_frame_header->cdef_params.cdef_uv_sec_strength[0] = 0; + p_frame_header->cdef_params.cdef_damping = 3; + return; + } + + p_frame_header->cdef_params.cdef_damping_minus_3 = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->cdef_params.cdef_damping = p_frame_header->cdef_params.cdef_damping_minus_3 + 3; + p_frame_header->cdef_params.cdef_bits = Parser::ReadBits(p_stream, offset, 2); + for (int i = 0; i < (1 << p_frame_header->cdef_params.cdef_bits); i++) { + p_frame_header->cdef_params.cdef_y_pri_strength[i] = Parser::ReadBits(p_stream, offset, 4); + p_frame_header->cdef_params.cdef_y_sec_strength[i] = Parser::ReadBits(p_stream, offset, 2); + if (p_frame_header->cdef_params.cdef_y_sec_strength[i] == 3) { + p_frame_header->cdef_params.cdef_y_sec_strength[i] += 1; + } + + if (p_seq_header->color_config.num_planes > 1) { + p_frame_header->cdef_params.cdef_uv_pri_strength[i] = Parser::ReadBits(p_stream, offset, 4); + p_frame_header->cdef_params.cdef_uv_sec_strength[i] = Parser::ReadBits(p_stream, offset, 2); + if (p_frame_header->cdef_params.cdef_uv_sec_strength[i] == 3) { + p_frame_header->cdef_params.cdef_uv_sec_strength[i] += 1; + } + } + } +} + +void Av1VideoParser::LrParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + uint32_t remap_lr_type[4] = {kRestoreNone, kRestoreSwitchable, kRestoreWiener, kRestoreSgrproj}; + + if (p_frame_header->all_lossless || p_frame_header->allow_intrabc || !p_seq_header->enable_restoration) { + p_frame_header->lr_params.frame_restoration_type[0] = kRestoreNone; + p_frame_header->lr_params.frame_restoration_type[1] = kRestoreNone; + p_frame_header->lr_params.frame_restoration_type[2] = kRestoreNone; + p_frame_header->lr_params.uses_lr = 0; + return; + } + + p_frame_header->lr_params.uses_lr = 0; + uint32_t uses_chroma_lr = 0; + for (int i = 0; i < p_seq_header->color_config.num_planes; i++) { + p_frame_header->lr_params.lr_type = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->lr_params.frame_restoration_type[i] = remap_lr_type[p_frame_header->lr_params.lr_type]; + if (p_frame_header->lr_params.frame_restoration_type[i] != kRestoreNone) { + p_frame_header->lr_params.uses_lr = 1; + if (i > 0) { + uses_chroma_lr = 1; + } + } + } + + if (p_frame_header->lr_params.uses_lr) { + if (p_seq_header->use_128x128_superblock) { + p_frame_header->lr_params.lr_unit_shift = Parser::GetBit(p_stream, offset); + p_frame_header->lr_params.lr_unit_shift++; + } else { + p_frame_header->lr_params.lr_unit_shift = Parser::GetBit(p_stream, offset); + if (p_frame_header->lr_params.lr_unit_shift) { + p_frame_header->lr_params.lr_unit_extra_shift = Parser::GetBit(p_stream, offset); + p_frame_header->lr_params.lr_unit_shift += p_frame_header->lr_params.lr_unit_extra_shift; + } + } + + p_frame_header->lr_params.loop_restoration_size[0] = RESTORATION_TILESIZE_MAX >> (2 - p_frame_header->lr_params.lr_unit_shift); + if (p_seq_header->color_config.subsampling_x && p_seq_header->color_config.subsampling_y && uses_chroma_lr) { + p_frame_header->lr_params.lr_uv_shift = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->lr_params.lr_uv_shift = 0; + } + p_frame_header->lr_params.loop_restoration_size[1] = p_frame_header->lr_params.loop_restoration_size[0] >> p_frame_header->lr_params.lr_uv_shift; + p_frame_header->lr_params.loop_restoration_size[2] = p_frame_header->lr_params.loop_restoration_size[0] >> p_frame_header->lr_params.lr_uv_shift; + } +} + +void Av1VideoParser::ReadTxMode(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + if (p_frame_header->coded_lossless == 1) { + p_frame_header->tx_mode.tx_mode = kOnly4x4; + } else { + p_frame_header->tx_mode.tx_mode_select = Parser::GetBit(p_stream, offset); + if (p_frame_header->tx_mode.tx_mode_select) { + p_frame_header->tx_mode.tx_mode = kTxModeSelect; + } else { + p_frame_header->tx_mode.tx_mode = kTxModeSelect; + } + } +} + +void Av1VideoParser::SkipModeParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + uint32_t skip_mode_allowed; + int forward_idx, backward_idx; + int forward_hint, backward_hint; + int second_forward_idx, second_forward_hint; + uint32_t ref_hint; + int i; + + if (p_frame_header->frame_is_intra || !p_frame_header->frame_reference_mode.reference_select || !p_seq_header->enable_order_hint) { + skip_mode_allowed = 0; + } else { + forward_idx = -1; + backward_idx = -1; + forward_hint = ref_order_hint_[0]; // init value. No effect. + backward_hint = ref_order_hint_[1]; // init value. No effect. + + for (i = 0; i < REFS_PER_FRAME; i++) { + ref_hint = ref_order_hint_[p_frame_header->ref_frame_idx[i]]; + if (GetRelativeDist(p_seq_header, ref_hint, p_frame_header->order_hint ) < 0) { + if (forward_idx < 0 || GetRelativeDist(p_seq_header, ref_hint, forward_hint) > 0) { + forward_idx = i; + forward_hint = ref_hint; + } + } else if (GetRelativeDist(p_seq_header, ref_hint, p_frame_header->order_hint) > 0) { + if (backward_idx < 0 || GetRelativeDist(p_seq_header, ref_hint, backward_hint) < 0 ) { + backward_idx = i; + backward_hint = ref_hint; + } + } + } + + if (forward_idx < 0) { + skip_mode_allowed = 0; + } else if (backward_idx >= 0) { + skip_mode_allowed = 1; + p_frame_header->skip_mode_params.skip_mode_frame[0] = kLastFrame + std::min(forward_idx, backward_idx); + p_frame_header->skip_mode_params.skip_mode_frame[1] = kLastFrame + std::max(forward_idx, backward_idx); + } else { + second_forward_idx = -1; + second_forward_hint = ref_order_hint_[0]; // init value. No effect. + for (i = 0; i < REFS_PER_FRAME; i++) { + ref_hint = ref_order_hint_[p_frame_header->ref_frame_idx[i]]; + if (GetRelativeDist(p_seq_header, ref_hint, forward_hint ) < 0) { + if (second_forward_idx < 0 || GetRelativeDist(p_seq_header, ref_hint, second_forward_hint ) > 0) { + second_forward_idx = i; + second_forward_hint = ref_hint; + } + } + } + if (second_forward_idx < 0) { + skip_mode_allowed = 0; + } else { + skip_mode_allowed = 1; + p_frame_header->skip_mode_params.skip_mode_frame[0] = kLastFrame + std::min(forward_idx, second_forward_idx); + p_frame_header->skip_mode_params.skip_mode_frame[1] = kLastFrame + std::max(forward_idx, second_forward_idx); + } + } + } + + if (skip_mode_allowed ) { + p_frame_header->skip_mode_params.skip_mode_present = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->skip_mode_params.skip_mode_present = 0; + } +} + +void Av1VideoParser::GlobalMotionParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header) { + int ref; + int type; + + for (ref = kLastFrame; ref <= kAltRefFrame; ref++) { + p_frame_header->global_motion_params.gm_type[ref] = kIdentity; + for (int i = 0; i < 6; i++) { + p_frame_header->global_motion_params.gm_params[ref][i] = ( ( i % 3 == 2 ) ? 1 << WARPEDMODEL_PREC_BITS : 0 ); + } + } + + if (p_frame_header->frame_is_intra) { + return; + } + + for (ref = kLastFrame; ref <= kAltRefFrame; ref++) { + p_frame_header->global_motion_params.is_global = Parser::GetBit(p_stream, offset); + if (p_frame_header->global_motion_params.is_global) { + p_frame_header->global_motion_params.is_rot_zoom = Parser::GetBit(p_stream, offset); + if (p_frame_header->global_motion_params.is_rot_zoom) { + type = kRotZoom; + } else { + p_frame_header->global_motion_params.is_translation = Parser::GetBit(p_stream, offset); + type = p_frame_header->global_motion_params.is_translation ? kTranslation : kAffine; + } + } else { + type = kIdentity; + } + p_frame_header->global_motion_params.gm_type[ref] = type; + + if (type >= kRotZoom) { + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 2); + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 3); + if (type == kAffine) { + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 4); + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 5); + } else { + p_frame_header->global_motion_params.gm_params[ref][4] = -p_frame_header->global_motion_params.gm_params[ref][3]; + p_frame_header->global_motion_params.gm_params[ref][5] = p_frame_header->global_motion_params.gm_params[ref][2]; + } + } + + if ( type >= kTranslation ) { + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 0); + ReadGlobalParam(p_stream, offset, p_frame_header, type, ref, 1); + } + } +} + +void Av1VideoParser::ReadGlobalParam(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header, int type, int ref, int idx) { + int abs_bits = GM_ABS_ALPHA_BITS; + int prec_bits = GM_ALPHA_PREC_BITS; + + if (idx < 2) { + if (type == kTranslation) { + abs_bits = GM_ABS_TRANS_ONLY_BITS - !p_frame_header->allow_high_precision_mv; + prec_bits = GM_TRANS_ONLY_PREC_BITS - !p_frame_header->allow_high_precision_mv; + } else { + abs_bits = GM_ABS_TRANS_BITS; + prec_bits = GM_TRANS_PREC_BITS; + } + } + + int prec_diff = WARPEDMODEL_PREC_BITS - prec_bits; + int round = (idx % 3) == 2 ? (1 << WARPEDMODEL_PREC_BITS) : 0; + int sub = (idx % 3) == 2 ? (1 << prec_bits) : 0; + int mx = (1 << abs_bits); + // Todo: + ERR("Error: PrevGmParams is calculated in SetupPastIndependence() (setup_past_independence()) function, which is not implemented yet.\n"); + int r = (p_frame_header->global_motion_params.prev_gm_params[ref][idx] >> prec_diff) - sub; + p_frame_header->global_motion_params.gm_params[ref][idx] = (DecodeSignedSubexpWithRef(p_stream, offset, -mx, mx + 1, r) << prec_diff) + round; +} + +int Av1VideoParser::DecodeSignedSubexpWithRef(const uint8_t *p_stream, size_t &offset, int low, int high, int r) { + int x = DecodeUnsignedSubexpWithRef(p_stream, offset, high - low, r - low); + return x + low; +} + +int Av1VideoParser::DecodeUnsignedSubexpWithRef(const uint8_t *p_stream, size_t &offset, int mx, int r) { + int v = DecodeSubexp(p_stream, offset, mx); + if ((r << 1) <= mx) { + return InverseRecenter(r, v); + } else { + return mx - 1 - InverseRecenter(mx - 1 - r, v); + } +} + +int Av1VideoParser::DecodeSubexp(const uint8_t *p_stream, size_t &offset, int num_syms) { + int i = 0; + int mk = 0; + int k = 3; + while (1) { + int b2 = i ? k + i - 1 : k; + int a = 1 << b2; + if (num_syms <= mk + 3 * a) { + int subexp_final_bits = ReadUnsignedNonSymmetic(p_stream, offset, num_syms - mk); + return subexp_final_bits + mk; + } else { + int subexp_more_bits = Parser::GetBit(p_stream, offset); + if (subexp_more_bits) { + i++; + mk += a; + } else { + int subexp_bits = Parser::ReadBits(p_stream, offset, b2); + return subexp_bits + mk; + } + } + } +} + +int Av1VideoParser::InverseRecenter(int r, int v) { + if (v > 2 * r) { + return v; + } else if (v & 1) { + return r - ((v + 1) >> 1); + } else { + return r + (v >> 1); + } +} + +void Av1VideoParser::FilmGrainParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header) { + int i; + + if (!p_seq_header->film_grain_params_present || (!p_frame_header->show_frame && !p_frame_header->showable_frame)) { + // reset_grain_params() + memset(&p_frame_header->film_grain_params, 0, sizeof(Av1FilmGrainParams)); + return; + } + p_frame_header->film_grain_params.apply_grain = Parser::GetBit(p_stream, offset); + if ( !p_frame_header->film_grain_params.apply_grain ) + { + // reset_grain_params() + memset(&p_frame_header->film_grain_params, 0, sizeof(Av1FilmGrainParams)); + return; + } + + p_frame_header->film_grain_params.grain_seed = Parser::ReadBits(p_stream, offset, 16); + if (p_frame_header->frame_type == kInterFrame) { + p_frame_header->film_grain_params.update_grain = Parser::GetBit(p_stream, offset); + } else { + p_frame_header->film_grain_params.update_grain = 1; + } + + if (!p_frame_header->film_grain_params.update_grain) { + p_frame_header->film_grain_params.film_grain_params_ref_idx = Parser::ReadBits(p_stream, offset, 3); + int temp_grain_seed = p_frame_header->film_grain_params.grain_seed; + //load_grain_params( film_grain_params_ref_idx ); + // Todo + ERR("Warning: need to implement film grain param loading load_grain_params( film_grain_params_ref_idx ).\n"); + p_frame_header->film_grain_params.grain_seed = temp_grain_seed; + return; + } + + p_frame_header->film_grain_params.num_y_points = Parser::ReadBits(p_stream, offset, 4); + for (i = 0; i < p_frame_header->film_grain_params.num_y_points; i++) { + p_frame_header->film_grain_params.point_y_value[i] = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.point_y_scaling[i] = Parser::ReadBits(p_stream, offset, 8); + } + + if (p_seq_header->color_config.mono_chrome) { + p_frame_header->film_grain_params.chroma_scaling_from_luma = 0; + } else { + p_frame_header->film_grain_params.chroma_scaling_from_luma = Parser::GetBit(p_stream, offset); + } + + if (p_seq_header->color_config.mono_chrome || p_frame_header->film_grain_params.chroma_scaling_from_luma || (p_seq_header->color_config.subsampling_x == 1 && p_seq_header->color_config.subsampling_y == 1 && p_frame_header->film_grain_params.num_y_points == 0)) { + p_frame_header->film_grain_params.num_cb_points = 0; + p_frame_header->film_grain_params.num_cr_points = 0; + } else { + p_frame_header->film_grain_params.num_cb_points = Parser::ReadBits(p_stream, offset, 4); + for (i = 0; i < p_frame_header->film_grain_params.num_cb_points; i++) { + p_frame_header->film_grain_params.point_cb_value[i] = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.point_cb_scaling[i] = Parser::ReadBits(p_stream, offset, 8); + } + p_frame_header->film_grain_params.num_cr_points = Parser::ReadBits(p_stream, offset, 4); + for ( i = 0; i < p_frame_header->film_grain_params.num_cr_points; i++ ) + { + p_frame_header->film_grain_params.point_cr_value[i] = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.point_cr_scaling[i] = Parser::ReadBits(p_stream, offset, 8); + } + } + + p_frame_header->film_grain_params.grain_scaling_minus_8 = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->film_grain_params.ar_coeff_lag = Parser::ReadBits(p_stream, offset, 2); + uint32_t num_pos_luma = 2 * p_frame_header->film_grain_params.ar_coeff_lag * (p_frame_header->film_grain_params.ar_coeff_lag + 1); + uint32_t num_pos_chroma; + if (p_frame_header->film_grain_params.num_y_points) { + num_pos_chroma = num_pos_luma + 1; + for (i = 0; i < num_pos_luma; i++) { + p_frame_header->film_grain_params.ar_coeffs_y_plus_128[i] = Parser::ReadBits(p_stream, offset, 8); + } + } else { + num_pos_chroma = num_pos_luma; + } + + if (p_frame_header->film_grain_params.chroma_scaling_from_luma || p_frame_header->film_grain_params.num_cb_points) { + for (i = 0; i < num_pos_chroma; i++) { + p_frame_header->film_grain_params.ar_coeffs_cb_plus_128[i] = Parser::ReadBits(p_stream, offset, 8); + } + } + + if (p_frame_header->film_grain_params.chroma_scaling_from_luma || p_frame_header->film_grain_params.num_cr_points) { + for (i = 0; i < num_pos_chroma; i++) { + p_frame_header->film_grain_params.ar_coeffs_cr_plus_128[i] = Parser::ReadBits(p_stream, offset, 8); + } + } + + p_frame_header->film_grain_params.ar_coeff_shift_minus_6 = Parser::ReadBits(p_stream, offset, 2); + p_frame_header->film_grain_params.grain_scale_shift = Parser::ReadBits(p_stream, offset, 2); + + if (p_frame_header->film_grain_params.num_cb_points) { + p_frame_header->film_grain_params.cb_mult = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.cb_luma_mult = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.cb_offset = Parser::ReadBits(p_stream, offset, 9); + } + + if (p_frame_header->film_grain_params.num_cr_points) { + p_frame_header->film_grain_params.cr_mult = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.cr_luma_mult = Parser::ReadBits(p_stream, offset, 8); + p_frame_header->film_grain_params.cr_offset = Parser::ReadBits(p_stream, offset, 9); + } + + p_frame_header->film_grain_params.overlap_flag = Parser::GetBit(p_stream, offset); + p_frame_header->film_grain_params.clip_to_restricted_range = Parser::GetBit(p_stream, offset); +} diff --git a/src/parser/av1_parser.h b/src/parser/av1_parser.h index 160b521a31..1dd85e5424 100644 --- a/src/parser/av1_parser.h +++ b/src/parser/av1_parser.h @@ -26,6 +26,7 @@ THE SOFTWARE. #define OBU_HEADER_SIZE 1 #define OBU_EXTENSION_SIZE 1 +#define INVALID_INDEX -1 // Invalid buffer index. class Av1VideoParser : public RocVideoParser { public: @@ -54,18 +55,70 @@ public: */ virtual rocDecStatus UnInitialize(); // derived method + typedef struct { + int index; + } Av1Picture; + + typedef struct { + uint32_t offset; + uint32_t size; + } Av1TileDataInfo; + + typedef struct { + uint32_t buffer_id; // buffer ID in the bitstream buffer pool. + uint8_t *buffer_ptr; // pointer of the tile group data buffer. + uint32_t buffer_size; // total size of the data buffer, may include the header bytes. + Av1TileDataInfo tile_data_info[MAX_TILE_ROWS][MAX_TILE_COLS]; + } Av1TileGroupDataInfo; + protected: Av1SequenceHeader seq_header_; + Av1FrameHeader frame_header_; + Av1TileGroupDataInfo tile_group_data_; + + int temporal_id_; // temporal level of the data contained in the OBU + int spatial_id_; // spatial level of the data contained in the OBU + + // Frame header syntax elements + int ref_frame_type_[NUM_REF_FRAMES]; + int ref_frame_id_[NUM_REF_FRAMES]; + int ref_order_hint_[NUM_REF_FRAMES]; + int ref_valid_[NUM_REF_FRAMES]; + + // A list of all frame buffers that may be used for reference of the current picture or any + // subsequent pictures. The value is the index of a frame in DPB buffer pool. If an entry is + // not used as reference, the value should be -1. + int ref_pic_map_[NUM_REF_FRAMES]; + int ref_pic_map_next_[NUM_REF_FRAMES]; // for next picture + + // The reference list for the current picture + Av1Picture ref_pictures_[REFS_PER_FRAME]; + // The free frame buffer in DPB pool that the current picutre is decoded into + int new_fb_index_; /*! \brief Function to parse a sequence header OBU - * \param p_stream Pointer to the bit stream - * \param size Byte size of the stream + * \param [in] p_stream Pointer to the bit stream + * \param [in] size Byte size of the stream * \return None */ void ParseSequenceHeader(uint8_t *p_stream, size_t size); + /*! \brief Function to parse a frame header OBU + * \param [in] p_stream Pointer to the bit stream + * \param [in] size Byte size of the stream + * \return ParserResult + */ + ParserResult ParseUncompressedHeader(uint8_t *p_stream, size_t size); + + /*! \brief Function to parse a tile group OBU + * \param [in] p_stream Pointer to the bit stream + * \param [in] size Byte size of the stream + * \return None + */ + void ParseTileGroupInfo(uint8_t *p_stream, size_t size); + /*! \brief Function to parse color config in sequence header - * \param p_stream Pointer to the bit stream + * \param [in] p_stream Pointer to the bit stream * \param [in] offset Starting bit offset * \param [out] offset Updated bit offset * \param [out] p_seq_header Pointer to sequence header struct @@ -73,7 +126,263 @@ protected: */ void ParseColorConfig(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header); - /*! \brief Function to calculate the floor of the base 2 logarithm of the input x + /*! \brief Function to mark reference frames + * \param [in] p_seq_header Pointer to sequence header + * \param [in] p_frame_header Ponter to frame header + * \param [in] id_len Current frame id length + */ + void MarkRefFrames(Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header, uint32_t id_len); + + /*! \brief Function to parse frame size + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void FrameSize(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse super res parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void SuperResParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to calculate 4x4 block columns and rows of the frame + * \param [in] p_frame_header Pointer to frame header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void ComputeImageSize(Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse render size info + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void RenderSize(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to compute the distance between two order hints by sign extending the result of subtracting the values. + * \param [in] p_seq_header Pointer to sequence header struct + * \param [in] a One order hint + * \param [in] b The other order hint + * \return The order hint distance + */ + int GetRelativeDist(Av1SequenceHeader *p_seq_header, int a, int b); + + /*! \brief Function to compute the elements in the ref_frame_idx array. 7.8. Set frame refs process. + * \param [in] p_seq_header Pinter to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void SetFrameRefs(Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to find the latest backward reference + * \param [in] shifted_order_hints An array containing the expected output order shifted such that the current + * frame has hint equal to curr_frame_hint + * \param [in] used_frame An array marking which reference frames have been used + * \param [in] curr_frame_hint A variable set equal to 1 << (OrderHintBits - 1) + */ + int FindLatestBackward(int *shifted_order_hints, int *used_frame, int curr_frame_hint); + + /*! \brief Function to find the earliest backward reference + * \param [in] shifted_order_hints An array containing the expected output order shifted such that the current + * frame has hint equal to curr_frame_hint + * \param [in] used_frame An array marking which reference frames have been used + * \param [in] curr_frame_hint A variable set equal to 1 << (OrderHintBits - 1) + */ + int FindEarliestBackward(int *shifted_order_hints, int *used_frame, int curr_frame_hint); + + /*! \brief Function to find the latest forward reference + * \param [in] shifted_order_hints An array containing the expected output order shifted such that the current + * frame has hint equal to curr_frame_hint + * \param [in] used_frame An array marking which reference frames have been used + * \param [in] curr_frame_hint A variable set equal to 1 << (OrderHintBits - 1) + */ + int FindLatestForward(int *shifted_order_hints, int *used_frame, int curr_frame_hint); + + /*! \brief Function to parse frame size with refs info + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void FrameSizeWithRefs(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to indicates that this frame can be decoded without dependence on previous coded frames. setup_past_independence(). + * \param [out] p_frame_header Pointer to frame header struct + */ + void SetupPastIndependence(Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse tile info + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void TileInfo(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to calculate the smallest value for k such that blk_size << k is greater than or equal to target. + * \param [in] blk_size Block size + * \param [in] target target value + * \return 32-bit unsigned + */ + uint32_t TileLog2(uint32_t blk_size, uint32_t target); + + /*! \brief Function to parse quantization parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void QuantizationParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to read delta quantizer + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + uint32_t ReadDeltaQ(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to segmentation parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void SegmentationParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse quantizer index delta parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void DeltaQParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse loop filter delta parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void DeltaLFParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse loop filter parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void LoopFilterParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse CDEF parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void CdefParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to loop restoration parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void LrParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse TX mode + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void ReadTxMode(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to skip mode parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void SkipModeParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to parse global motion parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void GlobalMotionParams(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header); + + /*! \brief Function to calculate global motion parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [out] p_frame_header Pointer to frame header struct + * \param [in] type Motion type + * \param [in] ref Reference frame + * \param [in] idx Parameter index + * \return None + */ + void ReadGlobalParam(const uint8_t *p_stream, size_t &offset, Av1FrameHeader *p_frame_header, int type, int ref, int idx); + + /*! \brief Function to decode signed subexp with ref. 5.9.26. decode_signed_subexp_with_ref() + */ + int DecodeSignedSubexpWithRef(const uint8_t *p_stream, size_t &offset, int low, int high, int r); + + /*! \brief Function to decode unsigned subexp with ref. 5.9.27. decode_unsigned_subexp_with_ref() + */ + int DecodeUnsignedSubexpWithRef(const uint8_t *p_stream, size_t &offset, int mx, int r); + + /*! \brief Function to decode subexp. 5.9.28. decode_subexp() + */ + int DecodeSubexp(const uint8_t *p_stream, size_t &offset, int num_syms); + + /*! \brief Function to inverse recenter. 5.9.29. inverse_recenter() + */ + int InverseRecenter(int r, int v); + + /*! \brief Function to parse film grain parameters + * \param [in] p_stream Pointer to the bit stream + * \param [in] offset Starting bit offset + * \param [out] offset Updated bit offset + * \param [in] p_seq_header Pointer to sequence header struct + * \param [out] p_frame_header Pointer to frame header struct + * \return None + */ + void FilmGrainParams(const uint8_t *p_stream, size_t &offset, Av1SequenceHeader *p_seq_header, Av1FrameHeader *p_frame_header); + + /*! \brief Function to calculate the floor of the base 2 logarithm of the input x * \param [in] x A 32-bit unsigned integer * \return the location of the most significant bit in x */