AV1代码学习5:函数av1_encode_strategy

函数av1_encode_strategy会执行一些high-level的编码策略,包括选择帧的类型等。其中函数choose_frame_source,会根据当前帧是否为ARF or internal ARF,来对原始帧进行时域滤波,如果不是则用LAST代替或者从lookahead从得到。

show_existing_frame代表这一帧已经编码过.

tpl_model在第二次编码才会使用,是通过Look-ahead的方式记录inter和intra的cost, 通过类似MB-Tree的方法对实际编码的QP和lambda进行调整以提高性能。

 av1_configure_buffer_updates,用于更新参考帧类型的数据,比如对于LAST_FRAME, 会被初始化为   

      case LF_UPDATE:
      frame_params->refresh_last_frame = 1;
      frame_params->refresh_golden_frame = 0;
      frame_params->refresh_bwd_ref_frame = 0;
      frame_params->refresh_alt2_ref_frame = 0;
      frame_params->refresh_alt_ref_frame = 0;

而KEY_FRAME会把const int force_refresh_all设为1 ,结果就变成了

  if (force_refresh_all) {
    frame_params->refresh_last_frame = 1;
    frame_params->refresh_golden_frame = 1;
    frame_params->refresh_bwd_ref_frame = 1;
    frame_params->refresh_alt2_ref_frame = 1;
    frame_params->refresh_alt_ref_frame = 1;
  }

函数的下一个入口是av1_encode

int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
                        uint8_t *const dest, unsigned int *frame_flags,
                        int64_t *const time_stamp, int64_t *const time_end,
                        const aom_rational64_t *const timestamp_ratio,
                        int flush) {
  const AV1EncoderConfig *const oxcf = &cpi->oxcf;
  AV1_COMMON *const cm = &cpi->common;

  EncodeFrameInput frame_input;
  EncodeFrameParams frame_params;
  EncodeFrameResults frame_results;
  memset(&frame_input, 0, sizeof(frame_input));
  memset(&frame_params, 0, sizeof(frame_params));
  memset(&frame_results, 0, sizeof(frame_results));

  if (oxcf->pass == 0 || oxcf->pass == 2) {
    check_show_existing_frame(cpi, &frame_params);
    frame_params.show_existing_frame &= allow_show_existing(cpi, *frame_flags);
  } else {
    frame_params.show_existing_frame = 0;
  }

  int temporal_filtered = 0;
  struct lookahead_entry *source = NULL;
  struct lookahead_entry *last_source = NULL;
  FRAME_UPDATE_TYPE frame_update_type;
  if (frame_params.show_existing_frame) {
    source = av1_lookahead_pop(cpi->lookahead, flush);
    frame_update_type = LF_UPDATE;
  } else {
    source = choose_frame_source(cpi, &temporal_filtered, &flush, &last_source,
                                 &frame_update_type, &frame_params);//根据当前帧的类型来决定是否需要temporal filter
  }

  // In pass 2 we get the frame_update_type from gf_group
  if (oxcf->pass == 2) {
    frame_update_type = get_frame_update_type(cpi);
  }

  if (source == NULL) {  // If no source was found, we can't encode a frame.
#if !CONFIG_REALTIME_ONLY
    if (flush && oxcf->pass == 1 && !cpi->twopass.first_pass_done) {
      av1_end_first_pass(cpi); /* get last stats packet */
      cpi->twopass.first_pass_done = 1;
    }
#endif
    return -1;
  }

  frame_input.source = temporal_filtered ? &cpi->alt_ref_buffer : &source->img;
  frame_input.last_source = last_source != NULL ? &last_source->img : NULL;
  frame_input.ts_duration = source->ts_end - source->ts_start;

  *time_stamp = source->ts_start;
  *time_end = source->ts_end;
  if (source->ts_start < cpi->first_time_stamp_ever) {
    cpi->first_time_stamp_ever = source->ts_start;
    cpi->last_end_time_stamp_seen = source->ts_start;
  }

  av1_apply_encoding_flags(cpi, source->flags);
  if (!frame_params.show_existing_frame)
    *frame_flags = (source->flags & AOM_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;

  const int is_overlay = frame_params.show_existing_frame &&
                         (frame_update_type == OVERLAY_UPDATE ||
                          frame_update_type == INTNL_OVERLAY_UPDATE);
  if (frame_params.show_frame || is_overlay) {
    // Shown frames and arf-overlay frames need frame-rate considering
    adjust_frame_rate(cpi, source);
  }

  if (frame_params.show_existing_frame) {
    // show_existing_frame implies this frame is shown!
    frame_params.show_frame = 1;
  } else {
    if (cpi->film_grain_table) {
      cm->cur_frame->film_grain_params_present = aom_film_grain_table_lookup(
          cpi->film_grain_table, *time_stamp, *time_end, 0 /* =erase */,
          &cm->film_grain_params);
    } else {
      cm->cur_frame->film_grain_params_present =
          cm->seq_params.film_grain_params_present;
    }
    // only one operating point supported now
    const int64_t pts64 = ticks_to_timebase_units(timestamp_ratio, *time_stamp);
    if (pts64 < 0 || pts64 > UINT32_MAX) return AOM_CODEC_ERROR;
    cpi->common.frame_presentation_time = (uint32_t)pts64;
  }

#if !CONFIG_REALTIME_ONLY
  if (oxcf->pass == 2 && (!frame_params.show_existing_frame || is_overlay)) {
    // GF_GROUP needs updating for arf overlays as well as non-show-existing
    av1_get_second_pass_params(cpi, &frame_params, *frame_flags);
    frame_update_type = get_frame_update_type(cpi);
  }
#endif

  if (frame_params.show_existing_frame &&
      frame_params.frame_type != KEY_FRAME) {
    // Force show-existing frames to be INTER, except forward keyframes
    frame_params.frame_type = INTER_FRAME;
  }

  // TODO([email protected]): Move all the encode strategy
  // (largely near av1_get_compressed_data) in here

  // TODO([email protected]): Change all the encode strategy to
  // modify frame_params instead of cm or cpi.

  // Per-frame encode speed.  In theory this can vary, but things may have been
  // written assuming speed-level will not change within a sequence, so this
  // parameter should be used with caution.
  frame_params.speed = oxcf->speed;

  if (!frame_params.show_existing_frame) {
    cm->using_qmatrix = cpi->oxcf.using_qm;
    cm->min_qmlevel = cpi->oxcf.qm_minlevel;
    cm->max_qmlevel = cpi->oxcf.qm_maxlevel;
    if (oxcf->pass == 2) {
      if (cpi->twopass.gf_group.index == 1 && cpi->oxcf.enable_tpl_model) {
        av1_configure_buffer_updates(cpi, &frame_params, frame_update_type, 0);
        av1_set_frame_size(cpi, cm->width, cm->height);
        av1_tpl_setup_stats(cpi, &frame_input);
        assert(cpi->num_gf_group_show_frames == 1);
      }
    }
  }

  // Work out some encoding parameters specific to the pass:
  if (oxcf->pass == 0) {
    if (cpi->oxcf.rc_mode == AOM_CBR) {
      av1_rc_get_one_pass_cbr_params(cpi, &frame_update_type, &frame_params,
                                     *frame_flags);
    } else {
      av1_rc_get_one_pass_vbr_params(cpi, &frame_update_type, &frame_params,
                                     *frame_flags);
    }
  } else if (oxcf->pass == 1) {
    cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf);
    const int kf_requested = (cm->current_frame.frame_number == 0 ||
                              (*frame_flags & FRAMEFLAGS_KEY));
    if (kf_requested && frame_update_type != OVERLAY_UPDATE &&
        frame_update_type != INTNL_OVERLAY_UPDATE) {
      frame_params.frame_type = KEY_FRAME;
    } else {
      frame_params.frame_type = INTER_FRAME;
    }
  } else if (oxcf->pass == 2) {
#if CONFIG_MISMATCH_DEBUG
    mismatch_move_frame_idx_w();
#endif
#if TXCOEFF_COST_TIMER
    cm->txcoeff_cost_timer = 0;
    cm->txcoeff_cost_count = 0;
#endif
  }

  if (oxcf->pass == 0 || oxcf->pass == 2) set_ext_overrides(cpi, &frame_params);

  // Shown keyframes and S frames refresh all reference buffers
  const int force_refresh_all =
      ((frame_params.frame_type == KEY_FRAME && frame_params.show_frame) ||
       frame_params.frame_type == S_FRAME) &&
      !frame_params.show_existing_frame;

  av1_configure_buffer_updates(cpi, &frame_params, frame_update_type,
                               force_refresh_all);

  if (oxcf->pass == 0 || oxcf->pass == 2) {
    // Work out which reference frame slots may be used.
    frame_params.ref_frame_flags = get_ref_frame_flags(cpi);

    frame_params.primary_ref_frame =
        choose_primary_ref_frame(cpi, &frame_params);
    frame_params.order_offset =
        get_order_offset(&cpi->twopass.gf_group, &frame_params);

    frame_params.refresh_frame_flags =
        get_refresh_frame_flags(cpi, &frame_params, frame_update_type);
  }

  // The way frame_params->remapped_ref_idx is setup is a placeholder.
  // Currently, reference buffer assignment is done by update_ref_frame_map()
  // which is called by high-level strategy AFTER encoding a frame.  It modifies
  // cm->remapped_ref_idx.  If you want to use an alternative method to
  // determine reference buffer assignment, just put your assignments into
  // frame_params->remapped_ref_idx here and they will be used when encoding
  // this frame.  If frame_params->remapped_ref_idx is setup independently of
  // cm->remapped_ref_idx then update_ref_frame_map() will have no effect.
  memcpy(frame_params.remapped_ref_idx, cm->remapped_ref_idx,
         REF_FRAMES * sizeof(*cm->remapped_ref_idx));

  if (av1_encode(cpi, dest, &frame_input, &frame_params, &frame_results) !=
      AOM_CODEC_OK) {
    return AOM_CODEC_ERROR;
  }
  if (oxcf->pass == 2) cpi->num_gf_group_show_frames += frame_params.show_frame;

  if (oxcf->pass == 0 || oxcf->pass == 2) {
    // First pass doesn't modify reference buffer assignment or produce frame
    // flags
    update_frame_flags(cpi, frame_flags);
    update_ref_frame_map(cpi, frame_update_type);
  }

#if !CONFIG_REALTIME_ONLY
  if (oxcf->pass == 2) {
#if TXCOEFF_COST_TIMER
    cm->cum_txcoeff_cost_timer += cm->txcoeff_cost_timer;
    fprintf(stderr,
            "\ntxb coeff cost block number: %ld, frame time: %ld, cum time %ld "
            "in us\n",
            cm->txcoeff_cost_count, cm->txcoeff_cost_timer,
            cm->cum_txcoeff_cost_timer);
#endif
    av1_twopass_postencode_update(cpi);
  }
#endif  // !CONFIG_REALTIME_ONLY

  if (oxcf->pass == 0 || oxcf->pass == 2) {
    update_fb_of_context_type(cpi, &frame_params, cpi->fb_of_context_type);
    set_additional_frame_flags(cm, frame_flags);
    update_rc_counts(cpi);
  }

  // Unpack frame_results:
  *size = frame_results.size;

  // Leave a signal for a higher level caller about if this frame is droppable
  if (*size > 0) {
    cpi->droppable = is_frame_droppable(cpi);
  }

  return AOM_CODEC_OK;
}

 

你可能感兴趣的:(AV1代码学习,Video,Coding)