// 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); } }
int vp9_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex, double correction_factor) { const double q = vp9_convert_qindex_to_q(qindex); int enumerator = frame_type == KEY_FRAME ? 3300000 : 2250000; // q based adjustment to baseline enumerator enumerator += (int)(enumerator * q) >> 12; return (int)(0.5 + (enumerator * correction_factor / q)); }
int vp9_gfboost_qadjust(int qindex) { int retval; double q; q = vp9_convert_qindex_to_q(qindex); retval = (int)((0.00000828 * q * q * q) + (-0.0055 * q * q) + (1.32 * q) + 79.3); return retval; }
static int kfboost_qadjust(int qindex) { int retval; double q; q = vp9_convert_qindex_to_q(qindex); retval = (int)((0.00000973 * q * q * q) + (-0.00613 * q * q) + (1.316 * q) + 121.2); return retval; }
static void init_me_luts_bd(int *bit16lut, int *bit4lut, int range, vpx_bit_depth_t bit_depth) { int i; // Initialize the sad lut tables using a formulaic calculation for now. // This is to make it easier to resolve the impact of experimental changes // to the quantizer tables. for (i = 0; i < range; i++) { const double q = vp9_convert_qindex_to_q(i, bit_depth); bit16lut[i] = (int)(0.0418 * q + 2.4107); bit4lut[i] = (int)(0.063 * q + 2.742); } }
void vp9_rc_init_minq_luts(void) { int i; for (i = 0; i < QINDEX_RANGE; i++) { const double maxq = vp9_convert_qindex_to_q(i); kf_low_motion_minq[i] = calculate_minq_index(maxq, 0.000001, -0.0004, 0.15, 0.0); kf_high_motion_minq[i] = calculate_minq_index(maxq, 0.000002, -0.0012, 0.50, 0.0); gf_low_motion_minq[i] = calculate_minq_index(maxq, 0.0000015, -0.0009, 0.32, 0.0); gf_high_motion_minq[i] = calculate_minq_index(maxq, 0.0000021, -0.00125, 0.50, 0.0); afq_low_motion_minq[i] = calculate_minq_index(maxq, 0.0000015, -0.0009, 0.33, 0.0); afq_high_motion_minq[i] = calculate_minq_index(maxq, 0.0000021, -0.00125, 0.55, 0.0); inter_minq[i] = calculate_minq_index(maxq, 0.00000271, -0.00113, 0.75, 0.0); } }
// Functions to compute the active minq lookup table entries based on a // formulaic approach to facilitate easier adjustment of the Q tables. // The formulae were derived from computing a 3rd order polynomial best // fit to the original data (after plotting real maxq vs minq (not q index)) static int calculate_minq_index(double maxq, double x3, double x2, double x1, double c) { int i; const double minqtarget = MIN(((x3 * maxq + x2) * maxq + x1) * maxq + c, maxq); // Special case handling to deal with the step from q2.0 // down to lossless mode represented by q 1.0. if (minqtarget <= 2.0) return 0; for (i = 0; i < QINDEX_RANGE; i++) { if (minqtarget <= vp9_convert_qindex_to_q(i)) return i; } return QINDEX_RANGE - 1; }
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; } } }
int vp9_bits_per_mb(FRAME_TYPE frame_type, int qindex) { if (frame_type == KEY_FRAME) return (int)(4500000 / vp9_convert_qindex_to_q(qindex)); else return (int)(2850000 / vp9_convert_qindex_to_q(qindex)); }
// 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; }