av1代码学习12--encode_sb_row()

1,函数功能

配置tile中superblock的属性,配置编码顺序,inter编码初始化运动搜索,rd_pick_partition()进入下一层编码

2,代码学习

static void encode_sb_row(AV1_COMP *cpi, ThreadData *td, TileDataEnc *tile_data,
                          int mi_row, TOKENEXTRA **tp, int use_nonrd_mode) {
  AV1_COMMON *const cm = &cpi->common;
  const int num_planes = av1_num_planes(cm);//平面
  const TileInfo *const tile_info = &tile_data->tile_info;//tile信息
  MACROBLOCK *const x = &td->mb;//Ymode
  MACROBLOCKD *const xd = &x->e_mbd;
  const SPEED_FEATURES *const sf = &cpi->sf;
  const int sb_cols_in_tile = av1_get_sb_cols_in_tile(cm, tile_data->tile_info);//列位置
  const BLOCK_SIZE sb_size = cm->seq_params.sb_size;//本帧用的sb大小
  const int mib_size = cm->seq_params.mib_size;//以MI块大小为单位的super块的MI块大小
  const int mib_size_log2 = cm->seq_params.mib_size_log2;//MI块大小的对数值
  const int sb_row = (mi_row - tile_info->mi_row_start) >> mib_size_log2;//行位置

#if CONFIG_COLLECT_COMPONENT_TIMING
  start_timing(cpi, encode_sb_time);
#endif

  // Initialize the left context for the new SB row
  av1_zero_left_context(xd);

  // Reset delta for every tile,初始化qp
  if (mi_row == tile_info->mi_row_start || cpi->row_mt) {
    if (cm->delta_q_info.delta_q_present_flag)
      xd->current_qindex = cm->base_qindex;
    if (cm->delta_q_info.delta_lf_present_flag) {
      av1_reset_loop_filter_delta(xd, av1_num_planes(cm));
    }
  }
  reset_thresh_freq_fact(x);//Ymode

  // Code each SB in the row
  for (int mi_col = tile_info->mi_col_start, sb_col_in_tile = 0;
       mi_col < tile_info->mi_col_end; mi_col += mib_size, sb_col_in_tile++) {
    (*(cpi->row_mt_sync_read_ptr))(&tile_data->row_mt_sync, sb_row,
                                   sb_col_in_tile);
    if (tile_data->allow_update_cdf && (cpi->row_mt == 1) &&
        (tile_info->mi_row_start != mi_row)) {
      if ((tile_info->mi_col_start == mi_col)) {
        // restore frame context of 1st column sb
        memcpy(xd->tile_ctx, x->row_ctx, sizeof(*xd->tile_ctx));
      } else {
        int wt_left = AVG_CDF_WEIGHT_LEFT;
        int wt_tr = AVG_CDF_WEIGHT_TOP_RIGHT;
        if (tile_info->mi_col_end > (mi_col + mib_size))
          avg_cdf_symbols(xd->tile_ctx, x->row_ctx + sb_col_in_tile, wt_left,
                          wt_tr);
        else
          avg_cdf_symbols(xd->tile_ctx, x->row_ctx + sb_col_in_tile - 1,
                          wt_left, wt_tr);
      }
    }

    switch (cpi->oxcf.coeff_cost_upd_freq) {
      case COST_UPD_TILE:  // Tile level
        if (mi_row != tile_info->mi_row_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SBROW:  // SB row level in tile
        if (mi_col != tile_info->mi_col_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SB:  // SB level//系数填充
        av1_fill_coeff_costs(&td->mb, xd->tile_ctx, num_planes);
        break;
      default: assert(0);
    }

    switch (cpi->oxcf.mode_cost_upd_freq) {//
      case COST_UPD_TILE:  // Tile level
        if (mi_row != tile_info->mi_row_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SBROW:  // SB row level in tile
        if (mi_col != tile_info->mi_col_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SB:  // SB level模式填充
        av1_fill_mode_rates(cm, x, xd->tile_ctx);
        break;
      default: assert(0);
    }

    switch (cpi->oxcf.mv_cost_upd_freq) {
      case COST_UPD_TILE:  // Tile level
        if (mi_row != tile_info->mi_row_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SBROW:  // SB row level in tile
        if (mi_col != tile_info->mi_col_start) break;
        AOM_FALLTHROUGH_INTENDED;
      case COST_UPD_SB:  // SB level运动填充
        av1_fill_mv_costs(xd->tile_ctx, cm, x);
        break;
      default: assert(0);
    }

    x->mb_rd_record.num = x->mb_rd_record.index_start = 0;

    if (!use_nonrd_mode) {
      av1_zero(x->txb_rd_record_8X8);
      av1_zero(x->txb_rd_record_16X16);
      av1_zero(x->txb_rd_record_32X32);
      av1_zero(x->txb_rd_record_64X64);
      av1_zero(x->txb_rd_record_intra);

      av1_zero(x->picked_ref_frames_mask);

      av1_zero(x->pred_mv);
    }
    PC_TREE *const pc_root = td->pc_root[mib_size_log2 - MIN_MIB_SIZE_LOG2];
    pc_root->index = 0;
    //初始化运动向量
    if ((sf->simple_motion_search_split ||
         sf->simple_motion_search_prune_rect ||
         sf->simple_motion_search_early_term_none) &&
        !frame_is_intra_only(cm) && !use_nonrd_mode) {
      init_simple_motion_search_mvs(pc_root);
    }
#if !CONFIG_REALTIME_ONLY
    td->mb.cnn_output_valid = 0;
#endif

    xd->cur_frame_force_integer_mv = cm->cur_frame_force_integer_mv;//获取运动矢量(整数)

    x->sb_energy_level = 0;
    if (cm->delta_q_info.delta_q_present_flag)
      setup_delta_q(cpi, td, x, tile_info, mi_row, mi_col, num_planes);//qp

    td->mb.cb_coef_buff = av1_get_cb_coeff_buffer(cpi, mi_row, mi_col);

    const int idx_str = cm->mi_stride * mi_row + mi_col;
    MB_MODE_INFO **mi = cm->mi_grid_base + idx_str;
    x->source_variance = UINT_MAX;
    x->simple_motion_pred_sse = UINT_MAX;
    const struct segmentation *const seg = &cm->seg;
    int seg_skip = 0;
    if (seg->enabled) {//划分
      const uint8_t *const map =
          seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map;
      const int segment_id =
          map ? get_segment_id(cm, map, sb_size, mi_row, mi_col) : 0;
      seg_skip = segfeature_active(seg, segment_id, SEG_LVL_SKIP);
    }

    // Realtime non-rd path.
    if (!(sf->partition_search_type == FIXED_PARTITION || seg_skip) &&
        !cpi->partition_search_skippable_frame &&
        sf->partition_search_type == VAR_BASED_PARTITION && use_nonrd_mode) {
      set_offsets_without_segment_id(cpi, tile_info, x, mi_row, mi_col,
                                     sb_size);
      av1_choose_var_based_partitioning(cpi, tile_info, x, mi_row, mi_col);
      td->mb.cb_offset = 0;
      nonrd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size,
                          pc_root);
    } else {
#if !CONFIG_REALTIME_ONLY
      int dummy_rate;
      int64_t dummy_dist;
      RD_STATS dummy_rdc;
      av1_invalid_rd_stats(&dummy_rdc);
      adjust_rdmult_tpl_model(cpi, x, mi_row, mi_col);
      if (sf->partition_search_type == FIXED_PARTITION || seg_skip) {//根据划分模式遍历划分
        set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size);
        const BLOCK_SIZE bsize =
            seg_skip ? sb_size : sf->always_this_block_size;
        set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize);
        //遍历所有划分和模式
        rd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size,
                         &dummy_rate, &dummy_dist, 1, pc_root);
      } else if (cpi->partition_search_skippable_frame) {
        set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size);
        const BLOCK_SIZE bsize =
            get_rd_var_based_fixed_partition(cpi, x, mi_row, mi_col);
        set_fixed_partitioning(cpi, tile_info, mi, mi_row, mi_col, bsize);
        rd_use_partition(cpi, td, tile_data, mi, tp, mi_row, mi_col, sb_size,
                         &dummy_rate, &dummy_dist, 1, pc_root);
      } else {
        reset_partition(pc_root, sb_size);

#if CONFIG_COLLECT_COMPONENT_TIMING
        start_timing(cpi, rd_pick_partition_time);
#endif
        BLOCK_SIZE max_sq_size = BLOCK_128X128;
        switch (cpi->oxcf.max_partition_size) {//确定最大划分
          case 4: max_sq_size = BLOCK_4X4; break;
          case 8: max_sq_size = BLOCK_8X8; break;
          case 16: max_sq_size = BLOCK_16X16; break;
          case 32: max_sq_size = BLOCK_32X32; break;
          case 64: max_sq_size = BLOCK_64X64; break;
          case 128: max_sq_size = BLOCK_128X128; break;
          default: assert(0); break;
        }
        max_sq_size = AOMMIN(max_sq_size, sb_size);

        BLOCK_SIZE min_sq_size = BLOCK_4X4;
        switch (cpi->oxcf.min_partition_size) {//确定最小划分
          case 4: min_sq_size = BLOCK_4X4; break;
          case 8: min_sq_size = BLOCK_8X8; break;
          case 16: min_sq_size = BLOCK_16X16; break;
          case 32: min_sq_size = BLOCK_32X32; break;
          case 64: min_sq_size = BLOCK_64X64; break;
          case 128: min_sq_size = BLOCK_128X128; break;
          default: assert(0); break;
        }

        if (use_auto_max_partition(cpi, sb_size, mi_row, mi_col)) {//自动划分
          float features[FEATURE_SIZE_MAX_MIN_PART_PRED] = { 0.0f };

          av1_get_max_min_partition_features(cpi, x, mi_row, mi_col, features);
          max_sq_size =
              AOMMIN(av1_predict_max_partition(cpi, x, features), max_sq_size);
        }

        min_sq_size = AOMMIN(min_sq_size, max_sq_size);

        //划分完下一层入口
        rd_pick_partition(cpi, td, tile_data, tp, mi_row, mi_col, sb_size,
                          max_sq_size, min_sq_size, &dummy_rdc, dummy_rdc,
                          pc_root, NULL);
#if CONFIG_COLLECT_COMPONENT_TIMING
        end_timing(cpi, rd_pick_partition_time);
#endif
      }
#endif  // !CONFIG_REALTIME_ONLY
    }

    // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile.
    if (cpi->sf.inter_mode_rd_model_estimation == 1 && cm->tile_cols == 1 &&
        cm->tile_rows == 1) {
      av1_inter_mode_data_fit(tile_data, x->rdmult);
    }
    if (tile_data->allow_update_cdf && (cpi->row_mt == 1) &&
        (tile_info->mi_row_end > (mi_row + mib_size))) {
      if (sb_cols_in_tile == 1)
        memcpy(x->row_ctx, xd->tile_ctx, sizeof(*xd->tile_ctx));
      else if (sb_col_in_tile >= 1)
        memcpy(x->row_ctx + sb_col_in_tile - 1, xd->tile_ctx,
               sizeof(*xd->tile_ctx));
    }
    (*(cpi->row_mt_sync_write_ptr))(&tile_data->row_mt_sync, sb_row,
                                    sb_col_in_tile, sb_cols_in_tile);
  }
#if CONFIG_COLLECT_COMPONENT_TIMING
  end_timing(cpi, encode_sb_time);
#endif
}