av1代码学习8---av1_encode_frame()

2020-06-23  本文已影响0人  青吟乐

1,函数功能

主要进行参考帧相关设置后进行编码调用encode_frame_internal(cpi)进行编码

2,代码学习

void av1_encode_frame(AV1_COMP *cpi) {
  AV1_COMMON *const cm = &cpi->common;
  CurrentFrame *const current_frame = &cm->current_frame;
  const int num_planes = av1_num_planes(cm);
  // Indicates whether or not to use a default reduced set for ext-tx
  // rather than the potential full set of 16 transforms
  cm->reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set;

  // Make sure segment_id is no larger than last_active_segid.
  if (cm->seg.enabled && cm->seg.update_map) {
    const int mi_rows = cm->mi_rows;
    const int mi_cols = cm->mi_cols;
    const int last_active_segid = cm->seg.last_active_segid;
    uint8_t *map = cpi->segmentation_map;
    for (int mi_row = 0; mi_row < mi_rows; ++mi_row) {
      for (int mi_col = 0; mi_col < mi_cols; ++mi_col) {
        map[mi_col] = AOMMIN(map[mi_col], last_active_segid);
      }
      map += mi_cols;
    }
  }

  av1_setup_frame_buf_refs(cm);//参考帧
  enforce_max_ref_frames(cpi);//强制参考帧引用数
  set_rel_frame_dist(cpi);//设置参考帧w.r.t.与当前帧的相对距离
  av1_setup_frame_sign_bias(cm);//设置标志位偏移量

#if CHECK_PRECOMPUTED_REF_FRAME_MAP
  GF_GROUP *gf_group = &cpi->gf_group;
  // TODO(yuec): The check is disabled on OVERLAY frames for now, because info
  // in cpi->gf_group has been refreshed for the next GOP when the check is
  // performed for OVERLAY frames. Since we have not support inter-GOP ref
  // frame map computation, the precomputed ref map for an OVERLAY frame is all
  // -1 at this point (although it is meaning before gf_group is refreshed).
  if (!frame_is_intra_only(cm) && gf_group->index != 0) {
    const RefCntBuffer *const golden_buf = get_ref_frame_buf(cm, GOLDEN_FRAME);

    if (golden_buf) {
      const int golden_order_hint = golden_buf->order_hint;

      for (int ref = LAST_FRAME; ref < EXTREF_FRAME; ++ref) {
        const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref);
        const int ref_disp_idx_precomputed =
            gf_group->ref_frame_disp_idx[gf_group->index][ref - LAST_FRAME];

        (void)ref_disp_idx_precomputed;

        if (buf != NULL) {
          const int ref_disp_idx =
              get_relative_dist(&cm->seq_params.order_hint_info,
                                buf->order_hint, golden_order_hint);

          if (ref_disp_idx >= 0)
            assert(ref_disp_idx == ref_disp_idx_precomputed);
          else
            assert(ref_disp_idx_precomputed == -1);
        } else {
          assert(ref_disp_idx_precomputed == -1);
        }
      }
    }
  }
#endif

#if CONFIG_MISMATCH_DEBUG
  mismatch_reset_frame(num_planes);
#else
  (void)num_planes;
#endif

  if (cpi->sf.frame_parameter_update) {//s帧,帧级编码参数
    int i;
    RD_OPT *const rd_opt = &cpi->rd;
    RD_COUNTS *const rdc = &cpi->td.rd_counts;

    // This code does a single RD pass over the whole frame assuming
    // either compound, single or hybrid prediction as per whatever has
    // worked best for that type of frame in the past.
    // It also predicts whether another coding mode would have worked
    // better than this coding mode. If that is the case, it remembers
    // that for subsequent frames.
    // It does the same analysis for transform size selection also.
    //这段代码在整个帧上执行一次RD传递,假设根据过去对该类型帧最有效的方法进行复合、单一或混合预测。
    //它还预测了另一种编码模式是否比这种编码模式工作得更好。
    //如果是这样的话,它会记住后面的帧。它对变换大小的选择也做同样的分析。
    // TODO(zoeliu): To investigate whether a frame_type other than
    // INTRA/ALTREF/GOLDEN/LAST needs to be specified seperately.
    const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi);
    int64_t *const mode_thrs = rd_opt->prediction_type_threshes[frame_type];
    const int is_alt_ref = frame_type == ALTREF_FRAME;

    /* prediction (compound, single or hybrid) mode selection */
    // NOTE: "is_alt_ref" is true only for OVERLAY/INTNL_OVERLAY frames
    /*预测模式选择*/
    if (is_alt_ref || frame_is_intra_only(cm))//只帧内单独预测,否则就要进行选择
      current_frame->reference_mode = SINGLE_REFERENCE;
    else
      current_frame->reference_mode = REFERENCE_MODE_SELECT;

    cm->interp_filter = SWITCHABLE;
    if (cm->large_scale_tile) cm->interp_filter = EIGHTTAP_REGULAR;

    cm->switchable_motion_mode = 1;//运动模式选择1

    rdc->compound_ref_used_flag = 0;//字面意思:复合参考帧使用标志?
    rdc->skip_mode_used_flag = 0;//跳过某些模式的标志

    encode_frame_internal(cpi);//编码入口

    for (i = 0; i < REFERENCE_MODES; ++i)
      mode_thrs[i] = (mode_thrs[i] + rdc->comp_pred_diff[i] / cm->MBs) / 2;
    //参考模式
    if (current_frame->reference_mode == REFERENCE_MODE_SELECT) {
      // Use a flag that includes 4x4 blocks
      if (rdc->compound_ref_used_flag == 0) {
        current_frame->reference_mode = SINGLE_REFERENCE;
#if CONFIG_ENTROPY_STATS
        av1_zero(cpi->td.counts->comp_inter);
#endif  // CONFIG_ENTROPY_STATS
      }
    }
    // Re-check on the skip mode status as reference mode may have been changed.
    // 重新检查跳过模式状态,因为参考模式可能已更改。
    SkipModeInfo *const skip_mode_info = &current_frame->skip_mode_info;
    if (frame_is_intra_only(cm) ||
        current_frame->reference_mode == SINGLE_REFERENCE) {
      skip_mode_info->skip_mode_allowed = 0;
      skip_mode_info->skip_mode_flag = 0;
    }
    if (skip_mode_info->skip_mode_flag && rdc->skip_mode_used_flag == 0)
      skip_mode_info->skip_mode_flag = 0;

    if (!cm->large_scale_tile) {
      if (cm->tx_mode == TX_MODE_SELECT && cpi->td.mb.txb_split_count == 0)
        cm->tx_mode = TX_MODE_LARGEST;
    }
  } else {
    encode_frame_internal(cpi);
  }
}
上一篇下一篇

猜你喜欢

热点阅读