|  | /* | 
|  | * Copyright (c) 2021, Alliance for Open Media. All rights reserved | 
|  | * | 
|  | * This source code is subject to the terms of the BSD 3-Clause Clear License | 
|  | * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear | 
|  | * License was not distributed with this source code in the LICENSE file, you | 
|  | * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the | 
|  | * Alliance for Open Media Patent License 1.0 was not distributed with this | 
|  | * source code in the PATENTS file, you can obtain it at | 
|  | * aomedia.org/license/patent-license/. | 
|  | */ | 
|  |  | 
|  | #include "config/aom_config.h" | 
|  |  | 
|  | #include "aom_ports/system_state.h" | 
|  |  | 
|  | #include "av1/encoder/encodemv.h" | 
|  | #include "av1/encoder/misc_model_weights.h" | 
|  | #include "av1/encoder/mv_prec.h" | 
|  | #include "av1/common/reconinter.h" | 
|  |  | 
|  | #include "av1/common/reconinter.h" | 
|  |  | 
|  | static AOM_INLINE int_mv get_ref_mv_for_mv_stats( | 
|  | const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame, | 
|  | int ref_idx) { | 
|  | #if CONFIG_SEP_COMP_DRL | 
|  | const int ref_mv_idx = get_ref_mv_idx(mbmi, ref_idx); | 
|  | #else | 
|  | const int ref_mv_idx = mbmi->ref_mv_idx; | 
|  | #endif  // CONFIG_SEP_COMP_DRL | 
|  | assert(IMPLIES(have_nearmv_newmv_in_inter_mode(mbmi->mode), | 
|  | has_second_ref(mbmi))); | 
|  |  | 
|  | const MV_REFERENCE_FRAME *ref_frames = mbmi->ref_frame; | 
|  | const int8_t ref_frame_type = av1_ref_frame_type(ref_frames); | 
|  | #if CONFIG_SEP_COMP_DRL | 
|  | const CANDIDATE_MV *curr_ref_mv_stack = | 
|  | has_second_drl(mbmi) ? mbmi_ext_frame->ref_mv_stack[ref_idx] | 
|  | : mbmi_ext_frame->ref_mv_stack[0]; | 
|  | #else | 
|  | const CANDIDATE_MV *curr_ref_mv_stack = mbmi_ext_frame->ref_mv_stack; | 
|  | #endif  // CONFIG_SEP_COMP_DRL | 
|  |  | 
|  | if (is_inter_ref_frame(ref_frames[1])) { | 
|  | assert(ref_idx == 0 || ref_idx == 1); | 
|  | #if CONFIG_SEP_COMP_DRL | 
|  | return ref_idx && !has_second_drl(mbmi) | 
|  | ? curr_ref_mv_stack[ref_mv_idx].comp_mv | 
|  | #else | 
|  | return ref_idx ? curr_ref_mv_stack[ref_mv_idx].comp_mv | 
|  | #endif  // CONFIG_SEP_COMP_DRL | 
|  | : curr_ref_mv_stack[ref_mv_idx].this_mv; | 
|  | } | 
|  |  | 
|  | assert(ref_idx == 0); | 
|  | #if CONFIG_SEP_COMP_DRL | 
|  | if (ref_mv_idx < mbmi_ext_frame->ref_mv_count[0]) { | 
|  | #else | 
|  | if (ref_mv_idx < mbmi_ext_frame->ref_mv_count) { | 
|  | #endif  // CONFIG_SEP_COMP_DRL | 
|  | return curr_ref_mv_stack[ref_mv_idx].this_mv; | 
|  | } else if (is_tip_ref_frame(ref_frame_type)) { | 
|  | int_mv zero_mv; | 
|  | zero_mv.as_int = 0; | 
|  | return zero_mv; | 
|  | } else { | 
|  | return mbmi_ext_frame->global_mvs[ref_frame_type]; | 
|  | } | 
|  | } | 
|  |  | 
|  | static AOM_INLINE int get_symbol_cost(const aom_cdf_prob *cdf, int symbol) { | 
|  | const aom_cdf_prob cur_cdf = AOM_ICDF(cdf[symbol]); | 
|  | const aom_cdf_prob prev_cdf = symbol ? AOM_ICDF(cdf[symbol - 1]) : 0; | 
|  | const aom_cdf_prob p15 = AOMMAX(cur_cdf - prev_cdf, EC_MIN_PROB); | 
|  |  | 
|  | return av1_cost_symbol(p15); | 
|  | } | 
|  | #if !CONFIG_VQ_MVD_CODING | 
|  | static AOM_INLINE int keep_one_comp_stat_low_precision( | 
|  | MV_STATS *mv_stats, int comp, int comp_idx, const AV1_COMP *cpi, int *rates, | 
|  | const MvSubpelPrecision pb_mv_precision) { | 
|  | assert(comp != 0 && "mv component should not have zero value!"); | 
|  | assert(pb_mv_precision < MV_PRECISION_ONE_PEL); | 
|  |  | 
|  | int offset; | 
|  | const int nonZero_offset = (1 << (MV_PRECISION_ONE_PEL - pb_mv_precision)); | 
|  | const int sign = comp < 0; | 
|  | const int mag_int_mv = (abs(comp) >> 3) - nonZero_offset; | 
|  | assert(mag_int_mv >= 0); | 
|  | const int mv_class = av1_get_mv_class_low_precision(mag_int_mv, &offset); | 
|  | const int has_offset = (mv_class >= min_class_with_offset[pb_mv_precision]); | 
|  | const int start_lsb = MV_PRECISION_ONE_PEL - pb_mv_precision; | 
|  |  | 
|  | int mv_class_coded_value = mv_class; | 
|  | // There is no valid value of MV_CLASS_1 for MV_PRECISION_FOUR_PEL. So | 
|  | // shifting the mv_class value before coding | 
|  | // There is no valid value of MV_CLASS_1 and MV_CLASS_2 for | 
|  | // MV_PRECISION_8_PEL. So shifting the mv_class value before coding | 
|  | if (pb_mv_precision == MV_PRECISION_FOUR_PEL && mv_class > MV_CLASS_1) | 
|  | mv_class_coded_value -= 1; | 
|  | else if (pb_mv_precision == MV_PRECISION_8_PEL && mv_class > MV_CLASS_2) | 
|  | mv_class_coded_value -= 2; | 
|  |  | 
|  | const int num_mv_classes = MV_CLASSES - | 
|  | (pb_mv_precision <= MV_PRECISION_FOUR_PEL) - | 
|  | (pb_mv_precision <= MV_PRECISION_8_PEL); | 
|  |  | 
|  | int r_idx = 0; | 
|  |  | 
|  | const MACROBLOCK *const x = &cpi->td.mb; | 
|  | const MACROBLOCKD *const xd = &x->e_mbd; | 
|  | FRAME_CONTEXT *ec_ctx = xd->tile_ctx; | 
|  | nmv_context *nmvc = &ec_ctx->nmvc; | 
|  | nmv_component *mvcomp_ctx = nmvc->comps; | 
|  | nmv_component *cur_mvcomp_ctx = &mvcomp_ctx[comp_idx]; | 
|  | aom_cdf_prob *sign_cdf = cur_mvcomp_ctx->sign_cdf; | 
|  | #if CONFIG_ENTROPY_PARA | 
|  | aom_cdf_prob(*bits_cdf)[CDF_SIZE(2)] = cur_mvcomp_ctx->bits_cdf; | 
|  | #else | 
|  | aom_cdf_prob(*bits_cdf)[3] = cur_mvcomp_ctx->bits_cdf; | 
|  | #endif  // CONFIG_ENTROPY_PARA | 
|  |  | 
|  | const int sign_rate = get_symbol_cost(sign_cdf, sign); | 
|  | rates[r_idx++] = sign_rate; | 
|  | update_cdf(sign_cdf, sign, 2); | 
|  |  | 
|  | // Class | 
|  | const int class_rate = get_symbol_cost( | 
|  | cur_mvcomp_ctx->classes_cdf[av1_get_mv_class_context(pb_mv_precision)], | 
|  | mv_class_coded_value); | 
|  | rates[r_idx++] = class_rate; | 
|  | update_cdf( | 
|  | cur_mvcomp_ctx->classes_cdf[av1_get_mv_class_context(pb_mv_precision)], | 
|  | mv_class_coded_value, num_mv_classes); | 
|  |  | 
|  | int int_bit_rate = 0; | 
|  | // Integer bits | 
|  | if (has_offset) { | 
|  | int i; | 
|  | const int n = (mv_class == MV_CLASS_0) ? 1 : mv_class; | 
|  | for (i = start_lsb; i < n; ++i) { | 
|  | int_bit_rate += get_symbol_cost(bits_cdf[i], (offset >> i) & 1); | 
|  | update_cdf(bits_cdf[i], (offset >> i) & 1, 2); | 
|  | } | 
|  | } | 
|  |  | 
|  | rates[r_idx++] = int_bit_rate; | 
|  |  | 
|  | mv_stats->last_bit_zero++;  // LSB of MV is always 0; | 
|  | mv_stats->last_bit_nonzero += 0; | 
|  | const int total_rate = (sign_rate + class_rate + int_bit_rate); | 
|  | return total_rate; | 
|  | } | 
|  |  | 
|  | static AOM_INLINE int keep_one_comp_stat(MV_STATS *mv_stats, int comp_val, | 
|  | int comp_idx, const AV1_COMP *cpi, | 
|  | int is_adaptive_mvd, int *rates | 
|  |  | 
|  | , | 
|  | const MvSubpelPrecision pb_mv_precision | 
|  |  | 
|  | ) { | 
|  | assert(comp_val != 0 && "mv component should not have zero value!"); | 
|  |  | 
|  | if (pb_mv_precision < MV_PRECISION_ONE_PEL) { | 
|  | assert(!is_adaptive_mvd); | 
|  | return keep_one_comp_stat_low_precision(mv_stats, comp_val, comp_idx, cpi, | 
|  | rates, pb_mv_precision); | 
|  | } | 
|  |  | 
|  | const int sign = comp_val < 0; | 
|  | const int mag = sign ? -comp_val : comp_val; | 
|  | const int mag_minus_1 = mag - 1; | 
|  | int offset; | 
|  | const int mv_class = av1_get_mv_class(mag_minus_1, &offset); | 
|  | const int int_part = offset >> 3;         // int mv data | 
|  | const int frac_part = (offset >> 1) & 3;  // fractional mv data | 
|  | const int high_part = offset & 1;         // high precision mv data | 
|  |  | 
|  | const int use_hp = pb_mv_precision > MV_PRECISION_QTR_PEL; | 
|  |  | 
|  | int r_idx = 0; | 
|  |  | 
|  | const MACROBLOCK *const x = &cpi->td.mb; | 
|  | const MACROBLOCKD *const xd = &x->e_mbd; | 
|  | FRAME_CONTEXT *ec_ctx = xd->tile_ctx; | 
|  | nmv_context *nmvc = &ec_ctx->nmvc; | 
|  | nmv_component *mvcomp_ctx = nmvc->comps; | 
|  | nmv_component *cur_mvcomp_ctx = &mvcomp_ctx[comp_idx]; | 
|  | aom_cdf_prob *sign_cdf = cur_mvcomp_ctx->sign_cdf; | 
|  |  | 
|  | aom_cdf_prob *class0_cdf = cur_mvcomp_ctx->class0_cdf; | 
|  | #if CONFIG_ENTROPY_PARA | 
|  | aom_cdf_prob(*bits_cdf)[CDF_SIZE(2)] = cur_mvcomp_ctx->bits_cdf; | 
|  | #else | 
|  | aom_cdf_prob(*bits_cdf)[3] = cur_mvcomp_ctx->bits_cdf; | 
|  | #endif  // CONFIG_ENTROPY_PARA | 
|  |  | 
|  | aom_cdf_prob *high_part_cdf = | 
|  | mv_class ? (cur_mvcomp_ctx->hp_cdf) : (cur_mvcomp_ctx->class0_hp_cdf); | 
|  |  | 
|  | const int sign_rate = get_symbol_cost(sign_cdf, sign); | 
|  | rates[r_idx++] = sign_rate;  // 0 | 
|  | update_cdf(sign_cdf, sign, 2); | 
|  |  | 
|  | const int class_rate = | 
|  | is_adaptive_mvd | 
|  | ? get_symbol_cost(cur_mvcomp_ctx->amvd_classes_cdf, mv_class) | 
|  | : get_symbol_cost( | 
|  | cur_mvcomp_ctx | 
|  | ->classes_cdf[av1_get_mv_class_context(pb_mv_precision)], | 
|  | mv_class); | 
|  |  | 
|  | rates[r_idx++] = class_rate;  // 1 | 
|  | if (is_adaptive_mvd) | 
|  | update_cdf(cur_mvcomp_ctx->amvd_classes_cdf, mv_class, MV_CLASSES); | 
|  | else | 
|  | update_cdf( | 
|  | cur_mvcomp_ctx->classes_cdf[av1_get_mv_class_context(pb_mv_precision)], | 
|  | mv_class, MV_CLASSES); | 
|  |  | 
|  | int int_bit_rate = 0; | 
|  | if (mv_class == MV_CLASS_0) { | 
|  | int_bit_rate = get_symbol_cost(class0_cdf, int_part); | 
|  | update_cdf(class0_cdf, int_part, CLASS0_SIZE); | 
|  | } else { | 
|  | if (!is_adaptive_mvd) { | 
|  | const int n = mv_class + CLASS0_BITS - 1;  // number of bits | 
|  | for (int i = 0; i < n; ++i) { | 
|  | int_bit_rate += get_symbol_cost(bits_cdf[i], (int_part >> i) & 1); | 
|  | update_cdf(bits_cdf[i], (int_part >> i) & 1, 2); | 
|  | } | 
|  | } | 
|  | } | 
|  | rates[r_idx++] = int_bit_rate; | 
|  | int use_fractional_mv = !cpi->common.features.cur_frame_force_integer_mv; | 
|  |  | 
|  | if (is_adaptive_mvd && (mv_class != MV_CLASS_0 || int_part > 0)) | 
|  | use_fractional_mv = 0; | 
|  | int frac_part_rate = 0, frac_part_rate_qpel = 0; | 
|  | aom_cdf_prob *frac_part_cdf = | 
|  | mv_class ? (cur_mvcomp_ctx->fp_cdf[0]) | 
|  | : (cur_mvcomp_ctx->class0_fp_cdf[int_part][0]); | 
|  | if (use_fractional_mv) { | 
|  | if (pb_mv_precision > MV_PRECISION_ONE_PEL) { | 
|  | frac_part_rate = get_symbol_cost(frac_part_cdf, frac_part >> 1); | 
|  | update_cdf(frac_part_cdf, frac_part >> 1, 2); | 
|  | } | 
|  |  | 
|  | if (pb_mv_precision > MV_PRECISION_HALF_PEL) { | 
|  | frac_part_cdf = | 
|  | mv_class | 
|  | ? (cur_mvcomp_ctx->fp_cdf[1 + (frac_part >> 1)]) | 
|  | : (cur_mvcomp_ctx->class0_fp_cdf[int_part][1 + (frac_part >> 1)]); | 
|  | frac_part_rate_qpel = get_symbol_cost(frac_part_cdf, frac_part & 1); | 
|  | frac_part_rate += frac_part_rate_qpel; | 
|  | update_cdf(frac_part_cdf, frac_part & 1, 2); | 
|  | } | 
|  | } | 
|  |  | 
|  | rates[r_idx++] = frac_part_rate; | 
|  | const int high_part_rate = (use_hp && use_fractional_mv) | 
|  | ? get_symbol_cost(high_part_cdf, high_part) | 
|  | : 0; | 
|  |  | 
|  | if (use_hp && use_fractional_mv) { | 
|  | update_cdf(high_part_cdf, high_part, 2); | 
|  | } | 
|  |  | 
|  | rates[r_idx++] = high_part_rate; | 
|  |  | 
|  | mv_stats->last_bit_zero += !high_part; | 
|  | mv_stats->last_bit_nonzero += high_part; | 
|  | const int total_rate = | 
|  | (sign_rate + class_rate + int_bit_rate + frac_part_rate + high_part_rate); | 
|  | return total_rate; | 
|  | } | 
|  |  | 
|  | static AOM_INLINE void keep_one_mv_stat( | 
|  | MV_STATS *mv_stats, const MV *ref_mv, const MV *cur_mv, const AV1_COMP *cpi, | 
|  | const MvSubpelPrecision max_mv_precision, const int allow_pb_mv_precision, | 
|  | const MvSubpelPrecision pb_mv_precision, | 
|  | const int most_probable_pb_mv_precision, const MB_MODE_INFO *mbmi) { | 
|  | const MACROBLOCK *const x = &cpi->td.mb; | 
|  | const MACROBLOCKD *const xd = &x->e_mbd; | 
|  | FRAME_CONTEXT *ec_ctx = xd->tile_ctx; | 
|  | nmv_context *nmvc = &ec_ctx->nmvc; | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi); | 
|  | aom_cdf_prob *joint_cdf = | 
|  | is_adaptive_mvd ? nmvc->amvd_joints_cdf : nmvc->joints_cdf; | 
|  |  | 
|  | const int use_hp = pb_mv_precision > MV_PRECISION_QTR_PEL; | 
|  |  | 
|  | const int pb_mv_precision_ctx = | 
|  | av1_get_pb_mv_precision_down_context(&cpi->common, xd); | 
|  |  | 
|  | aom_cdf_prob *pb_mv_precision_cdf = | 
|  | xd->tile_ctx | 
|  | ->pb_mv_precision_cdf[pb_mv_precision_ctx] | 
|  | [max_mv_precision - MV_PRECISION_HALF_PEL]; | 
|  |  | 
|  | MV low_prec_ref_mv = *ref_mv; | 
|  | #if BUGFIX_AMVD_AMVR | 
|  | if (!is_adaptive_mvd) | 
|  | #endif | 
|  | #if CONFIG_C071_SUBBLK_WARPMV | 
|  | if (pb_mv_precision < MV_PRECISION_HALF_PEL) | 
|  | #endif  // CONFIG_C071_SUBBLK_WARPMV | 
|  | lower_mv_precision(&low_prec_ref_mv, pb_mv_precision); | 
|  | const MV diff = { cur_mv->row - low_prec_ref_mv.row, | 
|  | cur_mv->col - low_prec_ref_mv.col }; | 
|  |  | 
|  | const int mv_joint = av1_get_mv_joint(&diff); | 
|  | // TODO(chiyotsai@google.com): Estimate hp_diff when we are using lp | 
|  | const MV hp_diff = diff; | 
|  | const int hp_mv_joint = av1_get_mv_joint(&hp_diff); | 
|  | const MV truncated_diff = { (diff.row / 2) * 2, (diff.col / 2) * 2 }; | 
|  | const MV lp_diff = use_hp ? truncated_diff : diff; | 
|  | const int lp_mv_joint = av1_get_mv_joint(&lp_diff); | 
|  |  | 
|  | aom_clear_system_state(); | 
|  | const int mv_joint_rate = get_symbol_cost(joint_cdf, mv_joint); | 
|  | const int hp_mv_joint_rate = get_symbol_cost(joint_cdf, hp_mv_joint); | 
|  | const int lp_mv_joint_rate = get_symbol_cost(joint_cdf, lp_mv_joint); | 
|  | if (is_adaptive_mvd) | 
|  | update_cdf(joint_cdf, mv_joint, MV_JOINTS); | 
|  | else | 
|  | update_cdf(joint_cdf, mv_joint, MV_JOINTS); | 
|  |  | 
|  | int flex_mv_rate = 0; | 
|  | if (allow_pb_mv_precision) { | 
|  | const int mpp_flag = (pb_mv_precision == most_probable_pb_mv_precision); | 
|  | const int mpp_flag_context = av1_get_mpp_flag_context(&cpi->common, xd); | 
|  | aom_cdf_prob *pb_mv_mpp_flag_cdf = | 
|  | xd->tile_ctx->pb_mv_mpp_flag_cdf[mpp_flag_context]; | 
|  | flex_mv_rate += get_symbol_cost(pb_mv_mpp_flag_cdf, mpp_flag); | 
|  | update_cdf(pb_mv_mpp_flag_cdf, mpp_flag, 2); | 
|  | if (!mpp_flag) { | 
|  | const PRECISION_SET *precision_def = | 
|  | &av1_mv_precision_sets[mbmi->mb_precision_set]; | 
|  | int down = av1_get_pb_mv_precision_index(mbmi); | 
|  | int nsymbs = precision_def->num_precisions - 1; | 
|  | flex_mv_rate += get_symbol_cost(pb_mv_precision_cdf, down); | 
|  | update_cdf(pb_mv_precision_cdf, down, nsymbs); | 
|  | } | 
|  |  | 
|  | mv_stats->precision_count[pb_mv_precision]++; | 
|  | } | 
|  |  | 
|  | mv_stats->total_mv_rate += flex_mv_rate; | 
|  | mv_stats->hp_total_mv_rate += flex_mv_rate; | 
|  | mv_stats->lp_total_mv_rate += flex_mv_rate; | 
|  | mv_stats->total_mv_rate += mv_joint_rate; | 
|  | mv_stats->hp_total_mv_rate += hp_mv_joint_rate; | 
|  | mv_stats->lp_total_mv_rate += lp_mv_joint_rate; | 
|  | mv_stats->mv_joint_count[mv_joint]++; | 
|  |  | 
|  | for (int comp_idx = 0; comp_idx < 2; comp_idx++) { | 
|  | const int comp_val = comp_idx ? diff.col : diff.row; | 
|  | const int hp_comp_val = comp_idx ? hp_diff.col : hp_diff.row; | 
|  | const int lp_comp_val = comp_idx ? lp_diff.col : lp_diff.row; | 
|  | int rates[5]; | 
|  | av1_zero_array(rates, 5); | 
|  | const int comp_rate = comp_val | 
|  | ? keep_one_comp_stat(mv_stats, comp_val, comp_idx, | 
|  | cpi, is_adaptive_mvd, rates | 
|  |  | 
|  | , | 
|  | pb_mv_precision | 
|  |  | 
|  | ) | 
|  | : 0; | 
|  |  | 
|  | // TODO(chiyotsai@google.com): Properly get hp rate when use_hp is false | 
|  | const int hp_rate = | 
|  | hp_comp_val ? rates[0] + rates[1] + rates[2] + rates[3] + rates[4] : 0; | 
|  | const int lp_rate = | 
|  | lp_comp_val ? rates[0] + rates[1] + rates[2] + rates[3] : 0; | 
|  |  | 
|  | mv_stats->total_mv_rate += comp_rate; | 
|  | mv_stats->hp_total_mv_rate += hp_rate; | 
|  | mv_stats->lp_total_mv_rate += lp_rate; | 
|  | } | 
|  | } | 
|  |  | 
|  | #else | 
|  | // MVCost for quasi-uniform code | 
|  | static INLINE int get_quniform_costs(uint16_t n, uint16_t v) { | 
|  | if (n <= 1) return 0; | 
|  | int total_bits = 0; | 
|  | const int l = get_msb(n) + 1; | 
|  | const int m = (1 << l) - n; | 
|  | total_bits += (l - 1); | 
|  | if (v >= m) { | 
|  | total_bits++; | 
|  | } | 
|  | return av1_cost_literal(total_bits); | 
|  | } | 
|  | static AOM_INLINE int get_vq_col_mvd_rate(nmv_context *mvctx, | 
|  | const int max_coded_value, int col, | 
|  | int max_trunc_unary_value) { | 
|  | int total_rate = 0; | 
|  | int max_idx_bits = AOMMIN(max_coded_value, max_trunc_unary_value); | 
|  | const int coded_col = | 
|  | col > max_trunc_unary_value ? max_trunc_unary_value : col; | 
|  | for (int bit_idx = 0; bit_idx < max_idx_bits; ++bit_idx) { | 
|  | int context_index = | 
|  | bit_idx < NUM_CTX_COL_MV_GTX ? bit_idx : NUM_CTX_COL_MV_GTX - 1; | 
|  | assert(context_index < NUM_CTX_COL_MV_GTX); | 
|  | total_rate += get_symbol_cost(mvctx->col_mv_greter_flags_cdf[context_index], | 
|  | coded_col != bit_idx); | 
|  | update_cdf(mvctx->col_mv_greter_flags_cdf[context_index], | 
|  | coded_col != bit_idx, 2); | 
|  | if (coded_col == bit_idx) break; | 
|  | } | 
|  |  | 
|  | if (max_coded_value > max_trunc_unary_value && col >= max_trunc_unary_value) { | 
|  | int remainder = col - max_trunc_unary_value; | 
|  | int remainder_max_value = max_coded_value - max_trunc_unary_value; | 
|  | total_rate += get_quniform_costs(remainder_max_value + 1, remainder); | 
|  | } | 
|  |  | 
|  | return total_rate; | 
|  | } | 
|  | static AOM_INLINE int get_truncated_unary_rate(nmv_context *mvctx, | 
|  | const int max_coded_value, | 
|  | int coded_value, int num_of_ctx, | 
|  | int low_shell_class) { | 
|  | (void)low_shell_class; | 
|  | int total_rate = 0; | 
|  | int max_idx_bits = max_coded_value; | 
|  | for (int bit_idx = 0; bit_idx < max_idx_bits; ++bit_idx) { | 
|  | int context_index = bit_idx < num_of_ctx ? bit_idx : num_of_ctx - 1; | 
|  | assert(context_index < num_of_ctx); | 
|  | aom_cdf_prob *cdf = mvctx->shell_offset_class2_cdf[context_index]; | 
|  | total_rate += get_symbol_cost(cdf, coded_value != bit_idx); | 
|  | update_cdf(cdf, coded_value != bit_idx, 2); | 
|  | if (coded_value == bit_idx) break; | 
|  | } | 
|  | return total_rate; | 
|  | } | 
|  |  | 
|  | static AOM_INLINE int get_vq_mvd_rate(nmv_context *mvctx, const MV mv_diff, | 
|  | MvSubpelPrecision pb_mv_precision) { | 
|  | int total_rate = 0; | 
|  | int start_lsb = (MV_PRECISION_ONE_EIGHTH_PEL - pb_mv_precision); | 
|  | const MV scaled_mv_diff = { abs(mv_diff.row) >> start_lsb, | 
|  | abs(mv_diff.col) >> start_lsb }; | 
|  |  | 
|  | int num_mv_class = get_default_num_shell_class(pb_mv_precision); | 
|  | int shell_cls_offset; | 
|  | const int shell_index = (scaled_mv_diff.row) + (scaled_mv_diff.col); | 
|  | const int shell_class = | 
|  | get_shell_class_with_precision(shell_index, &shell_cls_offset); | 
|  |  | 
|  | total_rate += get_symbol_cost(mvctx->joint_shell_class_cdf[pb_mv_precision], | 
|  | shell_class); | 
|  | update_cdf(mvctx->joint_shell_class_cdf[pb_mv_precision], shell_class, | 
|  | num_mv_class); | 
|  |  | 
|  | assert(shell_class >= 0 && shell_class < num_mv_class); | 
|  |  | 
|  | if (shell_class < 2) { | 
|  | assert(shell_cls_offset == 0 || shell_cls_offset == 1); | 
|  | total_rate += get_symbol_cost( | 
|  | mvctx->shell_offset_low_class_cdf[shell_class], shell_cls_offset); | 
|  | update_cdf(mvctx->shell_offset_low_class_cdf[shell_class], shell_cls_offset, | 
|  | 2); | 
|  |  | 
|  | } else if (shell_class == 2) { | 
|  | int max_coded_value = 3; | 
|  | int coded_value = shell_cls_offset; | 
|  | total_rate += | 
|  | get_truncated_unary_rate(mvctx, max_coded_value, coded_value, 3, 0); | 
|  | } else { | 
|  | const int num_of_bits_for_this_offset = shell_class; | 
|  | for (int i = 0; i < num_of_bits_for_this_offset; ++i) { | 
|  | total_rate += get_symbol_cost(mvctx->shell_offset_other_class_cdf[0][i], | 
|  | (shell_cls_offset >> i) & 1); | 
|  | update_cdf(mvctx->shell_offset_other_class_cdf[0][i], | 
|  | (shell_cls_offset >> i) & 1, 2); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(scaled_mv_diff.col <= shell_index); | 
|  | assert(IMPLIES(shell_index == 0, scaled_mv_diff.col == 0)); | 
|  | if (shell_index > 0) { | 
|  | int max_trunc_unary_value = MAX_COL_TRUNCATED_UNARY_VAL; | 
|  | // Coding the col here | 
|  | int maximum_pair_index = shell_index >> 1; | 
|  | int this_pair_index = scaled_mv_diff.col <= maximum_pair_index | 
|  | ? scaled_mv_diff.col | 
|  | : shell_index - scaled_mv_diff.col; | 
|  | assert(this_pair_index <= maximum_pair_index); | 
|  | // Encode the pair index | 
|  | if (maximum_pair_index > 0) { | 
|  | total_rate += get_vq_col_mvd_rate(mvctx, maximum_pair_index, | 
|  | this_pair_index, max_trunc_unary_value); | 
|  | } | 
|  | int skip_coding_col_bit = | 
|  | (this_pair_index == maximum_pair_index) && ((shell_index % 2 == 0)); | 
|  | assert( | 
|  | IMPLIES(skip_coding_col_bit, scaled_mv_diff.col == maximum_pair_index)); | 
|  | if (!skip_coding_col_bit) { | 
|  | // aom_write_literal(w, scaled_mv_diff.col > maximum_pair_index, 1); | 
|  | int context_index = shell_class < NUM_CTX_COL_MV_INDEX | 
|  | ? shell_class | 
|  | : NUM_CTX_COL_MV_INDEX - 1; | 
|  | assert(context_index < NUM_CTX_COL_MV_INDEX); | 
|  | total_rate += get_symbol_cost(mvctx->col_mv_index_cdf[context_index], | 
|  | scaled_mv_diff.col > maximum_pair_index); | 
|  | update_cdf(mvctx->col_mv_index_cdf[context_index], | 
|  | scaled_mv_diff.col > maximum_pair_index, 2); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Encode signs | 
|  | for (int component = 0; component < 2; component++) { | 
|  | int value = component == 0 ? mv_diff.row : mv_diff.col; | 
|  | if (value) { | 
|  | int sign = value < 0; | 
|  | total_rate += get_symbol_cost(mvctx->comps[component].sign_cdf, sign); | 
|  | update_cdf(mvctx->comps[component].sign_cdf, sign, 2); | 
|  | } | 
|  | } | 
|  | return total_rate; | 
|  | } | 
|  |  | 
|  | static AOM_INLINE void keep_vq_one_mv_stat( | 
|  | MV_STATS *mv_stats, const MV *ref_mv, const MV *cur_mv, const AV1_COMP *cpi, | 
|  | const MvSubpelPrecision max_mv_precision, const int allow_pb_mv_precision, | 
|  | const MvSubpelPrecision pb_mv_precision, | 
|  | const int most_probable_pb_mv_precision, const MB_MODE_INFO *mbmi) { | 
|  | const MACROBLOCK *const x = &cpi->td.mb; | 
|  | const MACROBLOCKD *const xd = &x->e_mbd; | 
|  | FRAME_CONTEXT *ec_ctx = xd->tile_ctx; | 
|  | nmv_context *nmvc = &ec_ctx->nmvc; | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | const int use_hp = pb_mv_precision > MV_PRECISION_QTR_PEL; | 
|  | const int is_adaptive_mvd = enable_adaptive_mvd_resolution(cm, mbmi); | 
|  | const int pb_mv_precision_ctx = | 
|  | av1_get_pb_mv_precision_down_context(&cpi->common, xd); | 
|  | aom_cdf_prob *pb_mv_precision_cdf = | 
|  | xd->tile_ctx | 
|  | ->pb_mv_precision_cdf[pb_mv_precision_ctx] | 
|  | [max_mv_precision - MV_PRECISION_HALF_PEL]; | 
|  |  | 
|  | MV low_prec_ref_mv = *ref_mv; | 
|  | #if BUGFIX_AMVD_AMVR | 
|  | if (!is_adaptive_mvd) | 
|  | #endif | 
|  | #if CONFIG_C071_SUBBLK_WARPMV | 
|  | if (pb_mv_precision < MV_PRECISION_HALF_PEL) | 
|  | #endif  // CONFIG_C071_SUBBLK_WARPMV | 
|  | lower_mv_precision(&low_prec_ref_mv, pb_mv_precision); | 
|  | const MV diff = { cur_mv->row - low_prec_ref_mv.row, | 
|  | cur_mv->col - low_prec_ref_mv.col }; | 
|  |  | 
|  | const int mv_joint = av1_get_mv_joint(&diff); | 
|  |  | 
|  | const MV hp_diff = diff; | 
|  | const MV truncated_diff = { (diff.row / 2) * 2, (diff.col / 2) * 2 }; | 
|  | const MV lp_diff = use_hp ? truncated_diff : diff; | 
|  |  | 
|  | aom_clear_system_state(); | 
|  | int flex_mv_rate = 0; | 
|  | if (allow_pb_mv_precision) { | 
|  | const int mpp_flag = (pb_mv_precision == most_probable_pb_mv_precision); | 
|  | const int mpp_flag_context = av1_get_mpp_flag_context(&cpi->common, xd); | 
|  | aom_cdf_prob *pb_mv_mpp_flag_cdf = | 
|  | xd->tile_ctx->pb_mv_mpp_flag_cdf[mpp_flag_context]; | 
|  | flex_mv_rate += get_symbol_cost(pb_mv_mpp_flag_cdf, mpp_flag); | 
|  | update_cdf(pb_mv_mpp_flag_cdf, mpp_flag, 2); | 
|  | if (!mpp_flag) { | 
|  | const PRECISION_SET *precision_def = | 
|  | &av1_mv_precision_sets[mbmi->mb_precision_set]; | 
|  | int down = av1_get_pb_mv_precision_index(mbmi); | 
|  | int nsymbs = precision_def->num_precisions - 1; | 
|  | flex_mv_rate += get_symbol_cost(pb_mv_precision_cdf, down); | 
|  | update_cdf(pb_mv_precision_cdf, down, nsymbs); | 
|  | } | 
|  | mv_stats->precision_count[pb_mv_precision]++; | 
|  | } | 
|  |  | 
|  | mv_stats->total_mv_rate += | 
|  | flex_mv_rate + get_vq_mvd_rate(nmvc, diff, pb_mv_precision); | 
|  | mv_stats->hp_total_mv_rate += | 
|  | flex_mv_rate + get_vq_mvd_rate(nmvc, hp_diff, pb_mv_precision); | 
|  | mv_stats->lp_total_mv_rate += | 
|  | flex_mv_rate + get_vq_mvd_rate(nmvc, lp_diff, pb_mv_precision); | 
|  | mv_stats->mv_joint_count[mv_joint]++; | 
|  |  | 
|  | for (int comp_idx = 0; comp_idx < 2; comp_idx++) { | 
|  | const int comp_val = comp_idx ? diff.col : diff.row; | 
|  | if (comp_val) { | 
|  | int high_part = (comp_val % 2) == 1; | 
|  | mv_stats->last_bit_zero += !high_part; | 
|  | mv_stats->last_bit_nonzero += high_part; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif  // !CONFIG_VQ_MVD_CODING | 
|  |  | 
|  | static AOM_INLINE void collect_mv_stats_b(MV_STATS *mv_stats, | 
|  | const AV1_COMP *cpi, int mi_row, | 
|  | int mi_col) { | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | const CommonModeInfoParams *const mi_params = &cm->mi_params; | 
|  |  | 
|  | if (mi_row >= mi_params->mi_rows || mi_col >= mi_params->mi_cols) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // While collecting the mv stats after encoding a frame, mbmi should be | 
|  | // derived from mi_grid_base instead of using xd->mi[0]. | 
|  | const MB_MODE_INFO *mbmi = | 
|  | mi_params->mi_grid_base[mi_row * mi_params->mi_stride + mi_col]; | 
|  | const MB_MODE_INFO_EXT_FRAME *mbmi_ext_frame = | 
|  | cpi->mbmi_ext_info.frame_base + | 
|  | get_mi_ext_idx(mi_row, mi_col, cm->mi_params.mi_alloc_bsize, | 
|  | cpi->mbmi_ext_info.stride); | 
|  | if (!is_inter_block(mbmi, SHARED_PART)) { | 
|  | mv_stats->intra_count++; | 
|  | return; | 
|  | } | 
|  | mv_stats->inter_count++; | 
|  |  | 
|  | const PREDICTION_MODE mode = mbmi->mode; | 
|  | const int is_compound = has_second_ref(mbmi); | 
|  |  | 
|  | const MvSubpelPrecision max_mv_precision = mbmi->max_mv_precision; | 
|  | const int allow_pb_mv_precision = | 
|  | is_pb_mv_precision_active(cm, mbmi, mbmi->sb_type[PLANE_TYPE_Y]); | 
|  | MvSubpelPrecision pb_mv_precision = mbmi->pb_mv_precision; | 
|  | const int most_probable_pb_mv_precision = mbmi->most_probable_pb_mv_precision; | 
|  |  | 
|  | if (mode == NEWMV || mode == AMVDNEWMV || mode == NEW_NEWMV_OPTFLOW || | 
|  | mode == NEW_NEWMV) { | 
|  | // All mvs are new | 
|  | for (int ref_idx = 0; ref_idx < 1 + is_compound; ++ref_idx) { | 
|  | const MV ref_mv = | 
|  | get_ref_mv_for_mv_stats(mbmi, mbmi_ext_frame, ref_idx).as_mv; | 
|  | const MV cur_mv = mbmi->mv[ref_idx].as_mv; | 
|  | #if CONFIG_VQ_MVD_CODING | 
|  | keep_vq_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi, max_mv_precision, | 
|  | allow_pb_mv_precision, pb_mv_precision, | 
|  | most_probable_pb_mv_precision, mbmi); | 
|  | #else | 
|  | keep_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi, max_mv_precision, | 
|  | allow_pb_mv_precision, pb_mv_precision, | 
|  | most_probable_pb_mv_precision | 
|  |  | 
|  | , | 
|  | mbmi); | 
|  | #endif  // CONFIG_VQ_MVD_CODING | 
|  | } | 
|  | } else if (have_nearmv_newmv_in_inter_mode(mode)) { | 
|  | // has exactly one new_mv | 
|  | mv_stats->default_mvs += 1; | 
|  | int ref_idx = is_joint_mvd_coding_mode(mbmi->mode) | 
|  | ? get_joint_mvd_base_ref_list(cm, mbmi) | 
|  | : (mode == NEAR_NEWMV || mode == NEAR_NEWMV_OPTFLOW); | 
|  |  | 
|  | const MV ref_mv = | 
|  | get_ref_mv_for_mv_stats(mbmi, mbmi_ext_frame, ref_idx).as_mv; | 
|  | const MV cur_mv = mbmi->mv[ref_idx].as_mv; | 
|  | #if CONFIG_VQ_MVD_CODING | 
|  | keep_vq_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi, max_mv_precision, | 
|  | allow_pb_mv_precision, pb_mv_precision, | 
|  | most_probable_pb_mv_precision, mbmi); | 
|  | #else | 
|  | keep_one_mv_stat(mv_stats, &ref_mv, &cur_mv, cpi | 
|  |  | 
|  | , | 
|  | max_mv_precision, allow_pb_mv_precision, pb_mv_precision, | 
|  | most_probable_pb_mv_precision | 
|  |  | 
|  | , | 
|  | mbmi); | 
|  | #endif  // CONFIG_VQ_MVD_CODING | 
|  | } else { | 
|  | // No new_mv | 
|  | mv_stats->default_mvs += 1 + is_compound; | 
|  | } | 
|  |  | 
|  | // Add texture information | 
|  | const BLOCK_SIZE bsize = mbmi->sb_type[PLANE_TYPE_Y]; | 
|  | const int num_rows = block_size_high[bsize]; | 
|  | const int num_cols = block_size_wide[bsize]; | 
|  | const int y_stride = cpi->source->y_stride; | 
|  | const int px_row = 4 * mi_row, px_col = 4 * mi_col; | 
|  | const int bd = cm->seq_params.bit_depth; | 
|  | uint16_t *source_buf = cpi->source->y_buffer + px_row * y_stride + px_col; | 
|  | for (int row = 0; row < num_rows - 1; row++) { | 
|  | for (int col = 0; col < num_cols - 1; col++) { | 
|  | const int offset = row * y_stride + col; | 
|  | const int horz_diff = | 
|  | abs(source_buf[offset + 1] - source_buf[offset]) >> (bd - 8); | 
|  | const int vert_diff = | 
|  | abs(source_buf[offset + y_stride] - source_buf[offset]) >> (bd - 8); | 
|  | mv_stats->horz_text += horz_diff; | 
|  | mv_stats->vert_text += vert_diff; | 
|  | mv_stats->diag_text += horz_diff * vert_diff; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Split block | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | static AOM_INLINE void collect_mv_stats_sb(MV_STATS *mv_stats, | 
|  | const AV1_COMP *cpi, int mi_row, | 
|  | int mi_col, BLOCK_SIZE bsize, | 
|  | PARTITION_TREE *ptree) { | 
|  | #else | 
|  | static AOM_INLINE void collect_mv_stats_sb(MV_STATS *mv_stats, | 
|  | const AV1_COMP *cpi, int mi_row, | 
|  | int mi_col, BLOCK_SIZE bsize) { | 
|  | #endif  // EXT_RECUR_PARTITIONS | 
|  | assert(bsize < BLOCK_SIZES_ALL); | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  |  | 
|  | if (mi_row >= cm->mi_params.mi_rows || mi_col >= cm->mi_params.mi_cols) | 
|  | return; | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | const PARTITION_TYPE partition = ptree->partition; | 
|  | #else | 
|  | const PARTITION_TYPE partition = | 
|  | get_partition(cm, SHARED_PART, mi_row, mi_col, bsize); | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  |  | 
|  | const BLOCK_SIZE subsize = get_partition_subsize(bsize, partition); | 
|  |  | 
|  | const int hbs_w = mi_size_wide[bsize] / 2; | 
|  | const int hbs_h = mi_size_high[bsize] / 2; | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | const int ebs_w = mi_size_wide[bsize] / 8; | 
|  | const int ebs_h = mi_size_high[bsize] / 8; | 
|  | #else | 
|  | const int qbs_w = mi_size_wide[bsize] / 4; | 
|  | const int qbs_h = mi_size_high[bsize] / 4; | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | switch (partition) { | 
|  | case PARTITION_NONE: | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | break; | 
|  | case PARTITION_HORZ: | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + hbs_h, mi_col, subsize, | 
|  | ptree->sub_tree[1]); | 
|  | #else | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col); | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | break; | 
|  | case PARTITION_VERT: | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + hbs_w, subsize, | 
|  | ptree->sub_tree[1]); | 
|  | #else | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs_w); | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | break; | 
|  | case PARTITION_SPLIT: | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | , | 
|  | ptree->sub_tree[0] | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | ); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + hbs_w, subsize | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | , | 
|  | ptree->sub_tree[1] | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | ); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + hbs_h, mi_col, subsize | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | , | 
|  | ptree->sub_tree[2] | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | ); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + hbs_h, mi_col + hbs_w, subsize | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | , | 
|  | ptree->sub_tree[0] | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | ); | 
|  | break; | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | case PARTITION_HORZ_4A: { | 
|  | const BLOCK_SIZE bsize_big = get_partition_subsize(bsize, PARTITION_HORZ); | 
|  | assert(bsize_big < BLOCK_SIZES_ALL); | 
|  | const BLOCK_SIZE bsize_med = subsize_lookup[PARTITION_HORZ][bsize_big]; | 
|  | assert(subsize == subsize_lookup[PARTITION_HORZ][bsize_med]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + ebs_h, mi_col, bsize_med, | 
|  | ptree->sub_tree[1]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + 3 * ebs_h, mi_col, bsize_big, | 
|  | ptree->sub_tree[2]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + 7 * ebs_h, mi_col, subsize, | 
|  | ptree->sub_tree[3]); | 
|  | break; | 
|  | } | 
|  | case PARTITION_HORZ_4B: { | 
|  | const BLOCK_SIZE bsize_big = get_partition_subsize(bsize, PARTITION_HORZ); | 
|  | assert(bsize_big < BLOCK_SIZES_ALL); | 
|  | const BLOCK_SIZE bsize_med = subsize_lookup[PARTITION_HORZ][bsize_big]; | 
|  | assert(subsize == subsize_lookup[PARTITION_HORZ][bsize_med]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + ebs_h, mi_col, bsize_big, | 
|  | ptree->sub_tree[1]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + 5 * ebs_h, mi_col, bsize_med, | 
|  | ptree->sub_tree[2]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + 7 * ebs_h, mi_col, subsize, | 
|  | ptree->sub_tree[3]); | 
|  | break; | 
|  | } | 
|  | case PARTITION_VERT_4A: { | 
|  | const BLOCK_SIZE bsize_big = get_partition_subsize(bsize, PARTITION_VERT); | 
|  | assert(bsize_big < BLOCK_SIZES_ALL); | 
|  | const BLOCK_SIZE bsize_med = subsize_lookup[PARTITION_VERT][bsize_big]; | 
|  | assert(subsize == subsize_lookup[PARTITION_VERT][bsize_med]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + ebs_w, bsize_med, | 
|  | ptree->sub_tree[1]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + 3 * ebs_w, bsize_big, | 
|  | ptree->sub_tree[2]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + 7 * ebs_w, subsize, | 
|  | ptree->sub_tree[3]); | 
|  | break; | 
|  | } | 
|  | case PARTITION_VERT_4B: { | 
|  | const BLOCK_SIZE bsize_big = get_partition_subsize(bsize, PARTITION_VERT); | 
|  | assert(bsize_big < BLOCK_SIZES_ALL); | 
|  | const BLOCK_SIZE bsize_med = subsize_lookup[PARTITION_VERT][bsize_big]; | 
|  | assert(subsize == subsize_lookup[PARTITION_VERT][bsize_med]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, subsize, | 
|  | ptree->sub_tree[0]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + ebs_w, bsize_big, | 
|  | ptree->sub_tree[1]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + 5 * ebs_w, bsize_med, | 
|  | ptree->sub_tree[2]); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col + 7 * ebs_w, subsize, | 
|  | ptree->sub_tree[3]); | 
|  | break; | 
|  | } | 
|  | case PARTITION_HORZ_3: | 
|  | case PARTITION_VERT_3: { | 
|  | for (int i = 0; i < 4; ++i) { | 
|  | const BLOCK_SIZE this_bsize = | 
|  | get_h_partition_subsize(bsize, i, partition); | 
|  | const int offset_mr = | 
|  | get_h_partition_offset_mi_row(bsize, i, partition); | 
|  | const int offset_mc = | 
|  | get_h_partition_offset_mi_col(bsize, i, partition); | 
|  |  | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row + offset_mr, | 
|  | mi_col + offset_mc, this_bsize, ptree->sub_tree[i]); | 
|  | } | 
|  | break; | 
|  | } | 
|  | #else   // CONFIG_EXT_RECUR_PARTITIONS | 
|  | case PARTITION_HORZ_A: | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs_w); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col); | 
|  | break; | 
|  | case PARTITION_HORZ_B: | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col + hbs_w); | 
|  | break; | 
|  | case PARTITION_VERT_A: | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs_w); | 
|  | break; | 
|  | case PARTITION_VERT_B: | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, mi_col + hbs_w); | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row + hbs_h, mi_col + hbs_w); | 
|  | break; | 
|  | case PARTITION_HORZ_4: | 
|  | for (int i = 0; i < 4; ++i) { | 
|  | const int this_mi_row = mi_row + i * qbs_h; | 
|  | collect_mv_stats_b(mv_stats, cpi, this_mi_row, mi_col); | 
|  | } | 
|  | break; | 
|  | case PARTITION_VERT_4: | 
|  | for (int i = 0; i < 4; ++i) { | 
|  | const int this_mi_col = mi_col + i * qbs_w; | 
|  | collect_mv_stats_b(mv_stats, cpi, mi_row, this_mi_col); | 
|  | } | 
|  | break; | 
|  | #endif  // CONFIG_EXT_RECUR_PARTITIONS | 
|  | default: assert(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | static AOM_INLINE void collect_mv_stats_tile(MV_STATS *mv_stats, | 
|  | const AV1_COMP *cpi, | 
|  | const TileInfo *tile_info) { | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | const int mi_row_start = tile_info->mi_row_start; | 
|  | const int mi_row_end = tile_info->mi_row_end; | 
|  | const int mi_col_start = tile_info->mi_col_start; | 
|  | const int mi_col_end = tile_info->mi_col_end; | 
|  | const int sb_size_mi = cm->mib_size; | 
|  | BLOCK_SIZE sb_size = cm->sb_size; | 
|  | for (int mi_row = mi_row_start; mi_row < mi_row_end; mi_row += sb_size_mi) { | 
|  | for (int mi_col = mi_col_start; mi_col < mi_col_end; mi_col += sb_size_mi) { | 
|  | #if CONFIG_EXT_RECUR_PARTITIONS | 
|  | const SB_INFO *sb_info = av1_get_sb_info(cm, mi_row, mi_col); | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, sb_size, | 
|  | sb_info->ptree_root[0]); | 
|  | #else | 
|  | collect_mv_stats_sb(mv_stats, cpi, mi_row, mi_col, sb_size); | 
|  | #endif  // EXT_RECUR_PARTITIONS | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void av1_collect_mv_stats(AV1_COMP *cpi, int current_q) { | 
|  | MV_STATS *mv_stats = &cpi->mv_stats; | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | const int tile_cols = cm->tiles.cols; | 
|  | const int tile_rows = cm->tiles.rows; | 
|  |  | 
|  | for (int tile_row = 0; tile_row < tile_rows; tile_row++) { | 
|  | TileInfo tile_info; | 
|  | av1_tile_set_row(&tile_info, cm, tile_row); | 
|  | for (int tile_col = 0; tile_col < tile_cols; tile_col++) { | 
|  | const int tile_idx = tile_row * tile_cols + tile_col; | 
|  | av1_tile_set_col(&tile_info, cm, tile_col); | 
|  | cpi->tile_data[tile_idx].tctx = *cm->fc; | 
|  | cpi->td.mb.e_mbd.tile_ctx = &cpi->tile_data[tile_idx].tctx; | 
|  | collect_mv_stats_tile(mv_stats, cpi, &tile_info); | 
|  | } | 
|  | } | 
|  |  | 
|  | mv_stats->q = current_q; | 
|  | #if CONFIG_EXPLICIT_TEMPORAL_DIST_CALC | 
|  | mv_stats->order = cpi->common.current_frame.display_order_hint; | 
|  | #else | 
|  | mv_stats->order = cpi->common.current_frame.order_hint; | 
|  | #endif  // CONFIG_EXPLICIT_TEMPORAL_DIST_CALC | 
|  | mv_stats->valid = 1; | 
|  | } | 
|  |  | 
|  | static AOM_INLINE int get_smart_mv_prec(AV1_COMP *cpi, const MV_STATS *mv_stats, | 
|  | int current_q) { | 
|  | const AV1_COMMON *cm = &cpi->common; | 
|  | #if CONFIG_EXPLICIT_TEMPORAL_DIST_CALC | 
|  | const int order_hint = cpi->common.current_frame.display_order_hint; | 
|  | #else | 
|  | const int order_hint = cpi->common.current_frame.order_hint; | 
|  | #endif  // CONFIG_EXPLICIT_TEMPORAL_DIST_CALC | 
|  | const int order_diff = order_hint - mv_stats->order; | 
|  | aom_clear_system_state(); | 
|  | const float area = (float)(cm->width * cm->height); | 
|  | float features[MV_PREC_FEATURE_SIZE] = { | 
|  | (float)current_q, | 
|  | (float)mv_stats->q, | 
|  | (float)order_diff, | 
|  | mv_stats->inter_count / area, | 
|  | mv_stats->intra_count / area, | 
|  | mv_stats->default_mvs / area, | 
|  | mv_stats->mv_joint_count[0] / area, | 
|  | mv_stats->mv_joint_count[1] / area, | 
|  | mv_stats->mv_joint_count[2] / area, | 
|  | mv_stats->mv_joint_count[3] / area, | 
|  | mv_stats->last_bit_zero / area, | 
|  | mv_stats->last_bit_nonzero / area, | 
|  | mv_stats->total_mv_rate / area, | 
|  | mv_stats->hp_total_mv_rate / area, | 
|  | mv_stats->lp_total_mv_rate / area, | 
|  | mv_stats->horz_text / area, | 
|  | mv_stats->vert_text / area, | 
|  | mv_stats->diag_text / area, | 
|  | }; | 
|  |  | 
|  | for (int f_idx = 0; f_idx < MV_PREC_FEATURE_SIZE; f_idx++) { | 
|  | features[f_idx] = | 
|  | (features[f_idx] - av1_mv_prec_mean[f_idx]) / av1_mv_prec_std[f_idx]; | 
|  | } | 
|  | float score = 0.0f; | 
|  |  | 
|  | av1_nn_predict(features, &av1_mv_prec_dnn_config, 1, &score); | 
|  |  | 
|  | const int use_high_hp = score >= 0.0f; | 
|  | return use_high_hp; | 
|  | } | 
|  |  | 
|  | void av1_pick_and_set_high_precision_mv(AV1_COMP *cpi, int qindex) { | 
|  | int use_hp = qindex < HIGH_PRECISION_MV_QTHRESH; | 
|  |  | 
|  | if (cpi->sf.hl_sf.high_precision_mv_usage == QTR_ONLY) { | 
|  | use_hp = 0; | 
|  | } else if (cpi->sf.hl_sf.high_precision_mv_usage == LAST_MV_DATA && | 
|  | av1_frame_allows_smart_mv(cpi) && cpi->mv_stats.valid) { | 
|  | use_hp = get_smart_mv_prec(cpi, &cpi->mv_stats, qindex); | 
|  | } | 
|  |  | 
|  | MvSubpelPrecision prec = MV_PRECISION_QTR_PEL + use_hp; | 
|  | if (cpi->common.features.cur_frame_force_integer_mv) { | 
|  | prec = MV_PRECISION_ONE_PEL; | 
|  | } | 
|  | av1_set_high_precision_mv(cpi, prec); | 
|  | cpi->common.features.use_pb_mv_precision = | 
|  | cpi->common.seq_params.enable_flex_mvres; | 
|  | cpi->common.features.most_probable_fr_mv_precision = | 
|  | cpi->common.features.fr_mv_precision; | 
|  | } |