// Setup cyclic background refresh: set delta q and segmentation map.
void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
  VP9_COMMON *const cm = &cpi->common;
  const RATE_CONTROL *const rc = &cpi->rc;
  CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
  struct segmentation *const seg = &cm->seg;
  const int apply_cyclic_refresh  = apply_cyclic_refresh_bitrate(cm, rc);
  if (cm->current_video_frame == 0)
    cr->low_content_avg = 0.0;
  // Don't apply refresh on key frame or temporal enhancement layer frames.
  if (!apply_cyclic_refresh ||
      (cm->frame_type == KEY_FRAME) ||
      (cpi->svc.temporal_layer_id > 0)) {
    // Set segmentation map to 0 and disable.
    unsigned char *const seg_map = cpi->segmentation_map;
    memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
    vp9_disable_segmentation(&cm->seg);
    if (cm->frame_type == KEY_FRAME) {
      memset(cr->last_coded_q_map, MAXQ,
             cm->mi_rows * cm->mi_cols * sizeof(*cr->last_coded_q_map));
      memset(cr->consec_zero_mv, 0,
             cm->mi_rows * cm->mi_cols * sizeof(*cr->consec_zero_mv));
      cr->sb_index = 0;
    }
    return;
  } else {
    int qindex_delta = 0;
    int qindex2;
    const double q = vp9_convert_qindex_to_q(cm->base_qindex, cm->bit_depth);
    vpx_clear_system_state();
    // Set rate threshold to some multiple (set to 2 for now) of the target
    // rate (target is given by sb64_target_rate and scaled by 256).
    cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 2;
    // Distortion threshold, quadratic in Q, scale factor to be adjusted.
    // q will not exceed 457, so (q * q) is within 32bit; see:
    // vp9_convert_qindex_to_q(), vp9_ac_quant(), ac_qlookup*[].
    cr->thresh_dist_sb = ((int64_t)(q * q)) << 2;

    // Set up segmentation.
    // Clear down the segment map.
    vp9_enable_segmentation(&cm->seg);
    vp9_clearall_segfeatures(seg);
    // Select delta coding method.
    seg->abs_delta = SEGMENT_DELTADATA;

    // Note: setting temporal_update has no effect, as the seg-map coding method
    // (temporal or spatial) is determined in vp9_choose_segmap_coding_method(),
    // based on the coding cost of each method. For error_resilient mode on the
    // last_frame_seg_map is set to 0, so if temporal coding is used, it is
    // relative to 0 previous map.
    // seg->temporal_update = 0;

    // Segment BASE "Q" feature is disabled so it defaults to the baseline Q.
    vp9_disable_segfeature(seg, CR_SEGMENT_ID_BASE, SEG_LVL_ALT_Q);
    // Use segment BOOST1 for in-frame Q adjustment.
    vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q);
    // Use segment BOOST2 for more aggressive in-frame Q adjustment.
    vp9_enable_segfeature(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q);

    // Set the q delta for segment BOOST1.
    qindex_delta = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta);
    cr->qindex_delta[1] = qindex_delta;

    // Compute rd-mult for segment BOOST1.
    qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ);

    cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);

    vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta);

    // Set a more aggressive (higher) q delta for segment BOOST2.
    qindex_delta = compute_deltaq(
        cpi, cm->base_qindex,
        VPXMIN(CR_MAX_RATE_TARGET_RATIO,
               0.1 * cr->rate_boost_fac * cr->rate_ratio_qdelta));
    cr->qindex_delta[2] = qindex_delta;
    vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q, qindex_delta);

    // Reset if resoluton change has occurred.
    if (cpi->resize_pending != 0)
      vp9_cyclic_refresh_reset_resize(cpi);

    // Update the segmentation and refresh map.
    cyclic_refresh_update_map(cpi);
  }
}
示例#2
0
void vp9_vaq_frame_setup(VP9_COMP *cpi) {
  VP9_COMMON *cm = &cpi->common;
  struct segmentation *seg = &cm->seg;
  int base_q = vp9_convert_qindex_to_q(cm->base_qindex);
  int base_rdmult = vp9_compute_rd_mult(cpi, cm->base_qindex +
                                        cm->y_dc_delta_q);
  int i;

  if (cm->frame_type == KEY_FRAME ||
      cpi->refresh_alt_ref_frame ||
      (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
    vp9_enable_segmentation((VP9_PTR)cpi);
    vp9_clearall_segfeatures(seg);

    seg->abs_delta = SEGMENT_DELTADATA;

    vp9_clear_system_state();  // __asm emms;

    for (i = ENERGY_MIN; i <= ENERGY_MAX; i++) {
      int qindex_delta, segment_rdmult;

      if (Q_RATIO(i) == 1) {
        // No need to enable SEG_LVL_ALT_Q for this segment
        RDMULT_RATIO(i) = 1;
        continue;
      }

      qindex_delta = vp9_compute_qdelta(cpi, base_q, base_q * Q_RATIO(i));
      vp9_set_segdata(seg, SEGMENT_ID(i), SEG_LVL_ALT_Q, qindex_delta);
      vp9_enable_segfeature(seg, SEGMENT_ID(i), SEG_LVL_ALT_Q);

      segment_rdmult = vp9_compute_rd_mult(cpi, cm->base_qindex + qindex_delta +
                                           cm->y_dc_delta_q);

      RDMULT_RATIO(i) = (double) segment_rdmult / base_rdmult;
    }
  }
}
// Setup cyclic background refresh: set delta q and segmentation map.
void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
    VP9_COMMON *const cm = &cpi->common;
    const RATE_CONTROL *const rc = &cpi->rc;
    CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
    struct segmentation *const seg = &cm->seg;
    unsigned char *const seg_map = cpi->segmentation_map;
    const int apply_cyclic_refresh  = apply_cyclic_refresh_bitrate(cm, rc);
    // Don't apply refresh on key frame or enhancement layer frames.
    if (!apply_cyclic_refresh ||
            (cm->frame_type == KEY_FRAME) ||
            (cpi->svc.temporal_layer_id > 0)) {
        // Set segmentation map to 0 and disable.
        vpx_memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
        vp9_disable_segmentation(&cm->seg);
        if (cm->frame_type == KEY_FRAME)
            cr->sb_index = 0;
        return;
    } else {
        int qindex_delta = 0;
        int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
        int xmis, ymis, x, y, qindex2;

        // Rate target ratio to set q delta.
        const float rate_ratio_qdelta = 2.0;
        const double q = vp9_convert_qindex_to_q(cm->base_qindex);
        vp9_clear_system_state();
        // Some of these parameters may be set via codec-control function later.
        cr->max_sbs_perframe = 10;
        cr->max_qdelta_perc = 50;
        cr->min_block_size = BLOCK_8X8;
        cr->time_for_refresh = 1;
        // Set rate threshold to some fraction of target (and scaled by 256).
        cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 2;
        // Distortion threshold, quadratic in Q, scale factor to be adjusted.
        cr->thresh_dist_sb = 8 * (int)(q * q);
        if (cpi->sf.use_nonrd_pick_mode) {
            // May want to be more conservative with thresholds in non-rd mode for now
            // as rate/distortion are derived from model based on prediction residual.
            cr->thresh_rate_sb = (rc->sb64_target_rate * 256) >> 3;
            cr->thresh_dist_sb = 4 * (int)(q * q);
        }

        cr->num_seg_blocks = 0;
        // Set up segmentation.
        // Clear down the segment map.
        vpx_memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
        vp9_enable_segmentation(&cm->seg);
        vp9_clearall_segfeatures(seg);
        // Select delta coding method.
        seg->abs_delta = SEGMENT_DELTADATA;

        // Note: setting temporal_update has no effect, as the seg-map coding method
        // (temporal or spatial) is determined in vp9_choose_segmap_coding_method(),
        // based on the coding cost of each method. For error_resilient mode on the
        // last_frame_seg_map is set to 0, so if temporal coding is used, it is
        // relative to 0 previous map.
        // seg->temporal_update = 0;

        // Segment 0 "Q" feature is disabled so it defaults to the baseline Q.
        vp9_disable_segfeature(seg, 0, SEG_LVL_ALT_Q);
        // Use segment 1 for in-frame Q adjustment.
        vp9_enable_segfeature(seg, 1, SEG_LVL_ALT_Q);

        // Set the q delta for segment 1.
        qindex_delta = vp9_compute_qdelta_by_rate(rc, cm->frame_type,
                       cm->base_qindex,
                       rate_ratio_qdelta);
        // TODO(marpan): Incorporate the actual-vs-target rate over/undershoot from
        // previous encoded frame.
        if (-qindex_delta > cr->max_qdelta_perc * cm->base_qindex / 100)
            qindex_delta = -cr->max_qdelta_perc * cm->base_qindex / 100;

        // Compute rd-mult for segment 1.
        qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ);
        cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);

        vp9_set_segdata(seg, 1, SEG_LVL_ALT_Q, qindex_delta);

        sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
        sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
        sbs_in_frame = sb_cols * sb_rows;
        // Number of target superblocks to get the q delta (segment 1).
        block_count = cr->max_sbs_perframe * sbs_in_frame / 100;
        // Set the segmentation map: cycle through the superblocks, starting at
        // cr->mb_index, and stopping when either block_count blocks have been found
        // to be refreshed, or we have passed through whole frame.
        assert(cr->sb_index < sbs_in_frame);
        i = cr->sb_index;
        do {
            int sum_map = 0;
            // Get the mi_row/mi_col corresponding to superblock index i.
            int sb_row_index = (i / sb_cols);
            int sb_col_index = i - sb_row_index * sb_cols;
            int mi_row = sb_row_index * MI_BLOCK_SIZE;
            int mi_col = sb_col_index * MI_BLOCK_SIZE;
            assert(mi_row >= 0 && mi_row < cm->mi_rows);
            assert(mi_col >= 0 && mi_col < cm->mi_cols);
            bl_index = mi_row * cm->mi_cols + mi_col;
            // Loop through all 8x8 blocks in superblock and update map.
            xmis = MIN(cm->mi_cols - mi_col,
                       num_8x8_blocks_wide_lookup[BLOCK_64X64]);
            ymis = MIN(cm->mi_rows - mi_row,
                       num_8x8_blocks_high_lookup[BLOCK_64X64]);
            for (y = 0; y < ymis; y++) {
                for (x = 0; x < xmis; x++) {
                    const int bl_index2 = bl_index + y * cm->mi_cols + x;
                    // If the block is as a candidate for clean up then mark it
                    // for possible boost/refresh (segment 1). The segment id may get
                    // reset to 0 later if block gets coded anything other than ZEROMV.
                    if (cr->map[bl_index2] == 0) {
                        seg_map[bl_index2] = 1;
                        sum_map++;
                    } else if (cr->map[bl_index2] < 0) {
                        cr->map[bl_index2]++;
                    }
                }
            }
            // Enforce constant segment over superblock.
            // If segment is partial over superblock, reset to either all 1 or 0.
            if (sum_map > 0 && sum_map < xmis * ymis) {
                const int new_value = (sum_map >= xmis * ymis / 2);
                for (y = 0; y < ymis; y++)
                    for (x = 0; x < xmis; x++)
                        seg_map[bl_index + y * cm->mi_cols + x] = new_value;
            }
            i++;
            if (i == sbs_in_frame) {
                i = 0;
            }
            if (sum_map >= xmis * ymis /2)
                block_count--;
        } while (block_count && i != cr->sb_index);
        cr->sb_index = i;
    }