// Store CDEF filter strength calculated from strength index for given search // method #define STORE_CDEF_FILTER_STRENGTH(cdef_strength, pick_method, strength_idx) \ do { \
get_cdef_filter_strengths((pick_method), &pri_strength, &sec_strength, \
(strength_idx)); \
cdef_strength = pri_strength * CDEF_SEC_STRENGTHS + sec_strength; \
} while (0)
/* Search for the best strength to add as an option, knowing we
already selected nb_strengths options. */ static uint64_t search_one(int *lev, int nb_strengths,
uint64_t mse[][TOTAL_STRENGTHS], int sb_count,
CDEF_PICK_METHOD pick_method) {
uint64_t tot_mse[TOTAL_STRENGTHS]; constint total_strengths = nb_cdef_strengths[pick_method]; int i, j;
uint64_t best_tot_mse = (uint64_t)1 << 63; int best_id = 0;
memset(tot_mse, 0, sizeof(tot_mse)); for (i = 0; i < sb_count; i++) { int gi;
uint64_t best_mse = (uint64_t)1 << 63; /* Find best mse among already selected options. */ for (gi = 0; gi < nb_strengths; gi++) { if (mse[i][lev[gi]] < best_mse) {
best_mse = mse[i][lev[gi]];
}
} /* Find best mse when adding each possible new option. */ for (j = 0; j < total_strengths; j++) {
uint64_t best = best_mse; if (mse[i][j] < best) best = mse[i][j];
tot_mse[j] += best;
}
} for (j = 0; j < total_strengths; j++) { if (tot_mse[j] < best_tot_mse) {
best_tot_mse = tot_mse[j];
best_id = j;
}
}
lev[nb_strengths] = best_id; return best_tot_mse;
}
/* Search for the best luma+chroma strength to add as an option, knowing we
already selected nb_strengths options. */ static uint64_t search_one_dual(int *lev0, int *lev1, int nb_strengths,
uint64_t (**mse)[TOTAL_STRENGTHS], int sb_count,
CDEF_PICK_METHOD pick_method) {
uint64_t tot_mse[TOTAL_STRENGTHS][TOTAL_STRENGTHS]; int i, j;
uint64_t best_tot_mse = (uint64_t)1 << 63; int best_id0 = 0; int best_id1 = 0; constint total_strengths = nb_cdef_strengths[pick_method];
memset(tot_mse, 0, sizeof(tot_mse)); for (i = 0; i < sb_count; i++) { int gi;
uint64_t best_mse = (uint64_t)1 << 63; /* Find best mse among already selected options. */ for (gi = 0; gi < nb_strengths; gi++) {
uint64_t curr = mse[0][i][lev0[gi]];
curr += mse[1][i][lev1[gi]]; if (curr < best_mse) {
best_mse = curr;
}
} /* Find best mse when adding each possible new option. */ for (j = 0; j < total_strengths; j++) { int k; for (k = 0; k < total_strengths; k++) {
uint64_t best = best_mse;
uint64_t curr = mse[0][i][j];
curr += mse[1][i][k]; if (curr < best) best = curr;
tot_mse[j][k] += best;
}
}
} for (j = 0; j < total_strengths; j++) { int k; for (k = 0; k < total_strengths; k++) { if (tot_mse[j][k] < best_tot_mse) {
best_tot_mse = tot_mse[j][k];
best_id0 = j;
best_id1 = k;
}
}
}
lev0[nb_strengths] = best_id0;
lev1[nb_strengths] = best_id1; return best_tot_mse;
}
/* Search for the set of strengths that minimizes mse. */ static uint64_t joint_strength_search(int *best_lev, int nb_strengths,
uint64_t mse[][TOTAL_STRENGTHS], int sb_count,
CDEF_PICK_METHOD pick_method) {
uint64_t best_tot_mse; int fast = (pick_method >= CDEF_FAST_SEARCH_LVL1 &&
pick_method <= CDEF_FAST_SEARCH_LVL5); int i;
best_tot_mse = (uint64_t)1 << 63; /* Greedy search: add one strength options at a time. */ for (i = 0; i < nb_strengths; i++) {
best_tot_mse = search_one(best_lev, i, mse, sb_count, pick_method);
} /* Trying to refine the greedy search by reconsidering each
already-selected option. */ if (!fast) { for (i = 0; i < 4 * nb_strengths; i++) { int j; for (j = 0; j < nb_strengths - 1; j++) best_lev[j] = best_lev[j + 1];
best_tot_mse =
search_one(best_lev, nb_strengths - 1, mse, sb_count, pick_method);
}
} return best_tot_mse;
}
/* Search for the set of luma+chroma strengths that minimizes mse. */ static uint64_t joint_strength_search_dual(int *best_lev0, int *best_lev1, int nb_strengths,
uint64_t (**mse)[TOTAL_STRENGTHS], int sb_count,
CDEF_PICK_METHOD pick_method) {
uint64_t best_tot_mse; int i;
best_tot_mse = (uint64_t)1 << 63; /* Greedy search: add one strength options at a time. */ for (i = 0; i < nb_strengths; i++) {
best_tot_mse =
search_one_dual(best_lev0, best_lev1, i, mse, sb_count, pick_method);
} /* Trying to refine the greedy search by reconsidering each
already-selected option. */ for (i = 0; i < 4 * nb_strengths; i++) { int j; for (j = 0; j < nb_strengths - 1; j++) {
best_lev0[j] = best_lev0[j + 1];
best_lev1[j] = best_lev1[j + 1];
}
best_tot_mse = search_one_dual(best_lev0, best_lev1, nb_strengths - 1, mse,
sb_count, pick_method);
} return best_tot_mse;
}
staticinlinevoid init_src_params(int *src_stride, int *width, int *height, int *width_log2, int *height_log2,
BLOCK_SIZE bsize) {
*src_stride = block_size_wide[bsize];
*width = block_size_wide[bsize];
*height = block_size_high[bsize];
*width_log2 = MI_SIZE_LOG2 + mi_size_wide_log2[bsize];
*height_log2 = MI_SIZE_LOG2 + mi_size_high_log2[bsize];
} #if CONFIG_AV1_HIGHBITDEPTH /* Compute MSE only on the blocks we filtered. */ static uint64_t compute_cdef_dist_highbd(void *dst, int dstride, uint16_t *src,
cdef_list *dlist, int cdef_count,
BLOCK_SIZE bsize, int coeff_shift, int row, int col) {
assert(bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 ||
bsize == BLOCK_8X8);
uint64_t sum = 0; int bi, bx, by;
uint16_t *dst16 = CONVERT_TO_SHORTPTR((uint8_t *)dst);
uint16_t *dst_buff = &dst16[row * dstride + col]; int src_stride, width, height, width_log2, height_log2;
init_src_params(&src_stride, &width, &height, &width_log2, &height_log2,
bsize); for (bi = 0; bi < cdef_count; bi++) {
by = dlist[bi].by;
bx = dlist[bi].bx;
sum += aom_mse_wxh_16bit_highbd(
&dst_buff[(by << height_log2) * dstride + (bx << width_log2)], dstride,
&src[bi << (height_log2 + width_log2)], src_stride, width, height);
} return sum >> 2 * coeff_shift;
} #endif
// Checks dual and quad block processing is applicable for block widths 8 and 4 // respectively. staticinlineint is_dual_or_quad_applicable(cdef_list *dlist, int width, int cdef_count, int bi, int iter) {
assert(width == 8 || width == 4); constint blk_offset = (width == 8) ? 1 : 3; if ((iter + blk_offset) >= cdef_count) return0;
static uint64_t compute_cdef_dist(void *dst, int dstride, uint16_t *src,
cdef_list *dlist, int cdef_count,
BLOCK_SIZE bsize, int coeff_shift, int row, int col) {
assert(bsize == BLOCK_4X4 || bsize == BLOCK_4X8 || bsize == BLOCK_8X4 ||
bsize == BLOCK_8X8);
uint64_t sum = 0; int bi, bx, by; int iter = 0; int inc = 1;
uint8_t *dst8 = (uint8_t *)dst;
uint8_t *dst_buff = &dst8[row * dstride + col]; int src_stride, width, height, width_log2, height_log2;
init_src_params(&src_stride, &width, &height, &width_log2, &height_log2,
bsize);
constint num_blks = 16 / width; for (bi = 0; bi < cdef_count; bi += inc) {
by = dlist[bi].by;
bx = dlist[bi].bx;
uint16_t *src_tmp = &src[bi << (height_log2 + width_log2)];
uint8_t *dst_tmp =
&dst_buff[(by << height_log2) * dstride + (bx << width_log2)];
if (is_dual_or_quad_applicable(dlist, width, cdef_count, bi, iter)) {
sum += aom_mse_16xh_16bit(dst_tmp, dstride, src_tmp, width, height);
iter += num_blks;
inc = num_blks;
} else {
sum += aom_mse_wxh_16bit(dst_tmp, dstride, src_tmp, src_stride, width,
height);
iter += 1;
inc = 1;
}
}
return sum >> 2 * coeff_shift;
}
// Fill the boundary regions of the block with CDEF_VERY_LARGE, only if the // region is outside frame boundary staticinlinevoid fill_borders_for_fbs_on_frame_boundary(
uint16_t *inbuf, int hfilt_size, int vfilt_size, bool is_fb_on_frm_left_boundary, bool is_fb_on_frm_right_boundary, bool is_fb_on_frm_top_boundary, bool is_fb_on_frm_bottom_boundary) { if (!is_fb_on_frm_left_boundary && !is_fb_on_frm_right_boundary &&
!is_fb_on_frm_top_boundary && !is_fb_on_frm_bottom_boundary) return; if (is_fb_on_frm_bottom_boundary) { // Fill bottom region of the block constint buf_offset =
(vfilt_size + CDEF_VBORDER) * CDEF_BSTRIDE + CDEF_HBORDER;
fill_rect(&inbuf[buf_offset], CDEF_BSTRIDE, CDEF_VBORDER, hfilt_size,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_bottom_boundary || is_fb_on_frm_left_boundary) { constint buf_offset = (vfilt_size + CDEF_VBORDER) * CDEF_BSTRIDE; // Fill bottom-left region of the block
fill_rect(&inbuf[buf_offset], CDEF_BSTRIDE, CDEF_VBORDER, CDEF_HBORDER,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_bottom_boundary || is_fb_on_frm_right_boundary) { constint buf_offset =
(vfilt_size + CDEF_VBORDER) * CDEF_BSTRIDE + hfilt_size + CDEF_HBORDER; // Fill bottom-right region of the block
fill_rect(&inbuf[buf_offset], CDEF_BSTRIDE, CDEF_VBORDER, CDEF_HBORDER,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_top_boundary) { // Fill top region of the block
fill_rect(&inbuf[CDEF_HBORDER], CDEF_BSTRIDE, CDEF_VBORDER, hfilt_size,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_top_boundary || is_fb_on_frm_left_boundary) { // Fill top-left region of the block
fill_rect(inbuf, CDEF_BSTRIDE, CDEF_VBORDER, CDEF_HBORDER, CDEF_VERY_LARGE);
} if (is_fb_on_frm_top_boundary || is_fb_on_frm_right_boundary) { constint buf_offset = hfilt_size + CDEF_HBORDER; // Fill top-right region of the block
fill_rect(&inbuf[buf_offset], CDEF_BSTRIDE, CDEF_VBORDER, CDEF_HBORDER,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_left_boundary) { constint buf_offset = CDEF_VBORDER * CDEF_BSTRIDE; // Fill left region of the block
fill_rect(&inbuf[buf_offset], CDEF_BSTRIDE, vfilt_size, CDEF_HBORDER,
CDEF_VERY_LARGE);
} if (is_fb_on_frm_right_boundary) { constint buf_offset = CDEF_VBORDER * CDEF_BSTRIDE; // Fill right region of the block
fill_rect(&inbuf[buf_offset + hfilt_size + CDEF_HBORDER], CDEF_BSTRIDE,
vfilt_size, CDEF_HBORDER, CDEF_VERY_LARGE);
}
}
// Calculate the number of 8x8/4x4 filter units for which SSE can be calculated // after CDEF filtering in single function call static AOM_FORCE_INLINE int get_error_calc_width_in_filt_units(
cdef_list *dlist, int cdef_count, int bi, int subsampling_x, int subsampling_y) { // TODO(Ranjit): Extend the optimization for 422 if (subsampling_x != subsampling_y) return1;
// Combining more blocks seems to increase encode time due to increase in // control code if (bi + 3 < cdef_count && dlist[bi].by == dlist[bi + 3].by &&
dlist[bi].bx + 3 == dlist[bi + 3].bx) { /* Calculate error for four 8x8/4x4 blocks using 32x8/16x4 block specific *logicifyco-ordinatesmatchandxco-ordinatesare
* separated by 3 for first and fourth 8x8/4x4 blocks in dlist[]. */ return4;
} if (bi + 1 < cdef_count && dlist[bi].by == dlist[bi + 1].by &&
dlist[bi].bx + 1 == dlist[bi + 1].bx) { /* Calculate error for two 8x8/4x4 blocks using 16x8/8x4 block specific *logiciftheiryco-ordinatesmatchandxco-ordinatesare
* separated by 1 for first and second 8x8/4x4 blocks in dlist[]. */ return2;
} return1;
}
// Returns the block error after CDEF filtering for a given strength staticinline uint64_t get_filt_error( const CdefSearchCtx *cdef_search_ctx, conststruct macroblockd_plane *pd,
cdef_list *dlist, int dir[CDEF_NBLOCKS][CDEF_NBLOCKS], int *dirinit, int var[CDEF_NBLOCKS][CDEF_NBLOCKS], uint16_t *in, uint8_t *ref_buffer, int ref_stride, int row, int col, int pri_strength, int sec_strength, int cdef_count, int pli, int coeff_shift, BLOCK_SIZE bs) {
uint64_t curr_sse = 0; const BLOCK_SIZE plane_bsize =
get_plane_block_size(bs, pd->subsampling_x, pd->subsampling_y); constint bw_log2 = 3 - pd->subsampling_x; constint bh_log2 = 3 - pd->subsampling_y;
// TODO(Ranjit): Extend this optimization for HBD if (!cdef_search_ctx->use_highbitdepth) { // If all 8x8/4x4 blocks in CDEF block need to be filtered, calculate the // error at CDEF block level constint tot_blk_count =
(block_size_wide[plane_bsize] * block_size_high[plane_bsize]) >>
(bw_log2 + bh_log2); if (cdef_count == tot_blk_count) { const ptrdiff_t buf_offset = (ptrdiff_t)row * ref_stride + col; const ptrdiff_t dst_offset = (ptrdiff_t)row * pd->dst.stride + col; if (pri_strength == 0 && sec_strength == 0) { // When CDEF strength is zero, filtering is not applied. Hence // error is calculated between source and unfiltered pixels
curr_sse =
aom_sse(&ref_buffer[buf_offset], ref_stride,
&pd->dst.buf[dst_offset], pd->dst.stride,
block_size_wide[plane_bsize], block_size_high[plane_bsize]);
} else {
DECLARE_ALIGNED(32, uint8_t, tmp_dst8[1 << (MAX_SB_SIZE_LOG2 * 2)]);
av1_cdef_filter_fb(tmp_dst8, NULL, (1 << MAX_SB_SIZE_LOG2), in,
cdef_search_ctx->xdec[pli],
cdef_search_ctx->ydec[pli], dir, dirinit, var, pli,
dlist, cdef_count, pri_strength,
sec_strength + (sec_strength == 3),
cdef_search_ctx->damping, coeff_shift);
curr_sse =
aom_sse(&ref_buffer[buf_offset], ref_stride, tmp_dst8,
(1 << MAX_SB_SIZE_LOG2), block_size_wide[plane_bsize],
block_size_high[plane_bsize]);
}
} else { // If few 8x8/4x4 blocks in CDEF block need to be filtered, filtering // functions produce 8-bit output and the error is calculated in 8-bit // domain if (pri_strength == 0 && sec_strength == 0) { int num_error_calc_filt_units = 1; for (int bi = 0; bi < cdef_count; bi = bi + num_error_calc_filt_units) { const uint8_t by = dlist[bi].by; const uint8_t bx = dlist[bi].bx; constint by_pos = by << bh_log2; constint bx_pos = bx << bw_log2; const ptrdiff_t buf_offset =
(ptrdiff_t)(row + by_pos) * ref_stride + (col + bx_pos); const ptrdiff_t dst_offset =
(ptrdiff_t)(row + by_pos) * pd->dst.stride + (col + bx_pos);
num_error_calc_filt_units = get_error_calc_width_in_filt_units(
dlist, cdef_count, bi, pd->subsampling_x, pd->subsampling_y);
curr_sse +=
aom_sse(&ref_buffer[buf_offset], ref_stride,
&pd->dst.buf[dst_offset], pd->dst.stride,
num_error_calc_filt_units * (1 << bw_log2), 1 << bh_log2);
}
} else {
DECLARE_ALIGNED(32, uint8_t, tmp_dst8[1 << (MAX_SB_SIZE_LOG2 * 2)]);
av1_cdef_filter_fb(tmp_dst8, NULL, (1 << MAX_SB_SIZE_LOG2), in,
cdef_search_ctx->xdec[pli],
cdef_search_ctx->ydec[pli], dir, dirinit, var, pli,
dlist, cdef_count, pri_strength,
sec_strength + (sec_strength == 3),
cdef_search_ctx->damping, coeff_shift); int num_error_calc_filt_units = 1; for (int bi = 0; bi < cdef_count; bi = bi + num_error_calc_filt_units) { const uint8_t by = dlist[bi].by; const uint8_t bx = dlist[bi].bx; constint by_pos = by << bh_log2; constint bx_pos = bx << bw_log2; const ptrdiff_t buf_offset =
(ptrdiff_t)(row + by_pos) * ref_stride + (col + bx_pos); const ptrdiff_t tmp_buf_offset =
by_pos * (1 << MAX_SB_SIZE_LOG2) + bx_pos;
num_error_calc_filt_units = get_error_calc_width_in_filt_units(
dlist, cdef_count, bi, pd->subsampling_x, pd->subsampling_y);
curr_sse += aom_sse(
&ref_buffer[buf_offset], ref_stride, &tmp_dst8[tmp_buf_offset],
(1 << MAX_SB_SIZE_LOG2),
num_error_calc_filt_units * (1 << bw_log2), (1 << bh_log2));
}
}
}
} else {
DECLARE_ALIGNED(32, uint16_t, tmp_dst[1 << (MAX_SB_SIZE_LOG2 * 2)]);
// Calculates MSE at block level. // Inputs: // cdef_search_ctx: Pointer to the structure containing parameters related to // CDEF search context. // fbr: Row index in units of 64x64 block // fbc: Column index in units of 64x64 block // adaptive_cdef_mode: Speed feature to control CDEF adaptively. // Returns: // Nothing will be returned. Contents of cdef_search_ctx will be modified. void av1_cdef_mse_calc_block(CdefSearchCtx *cdef_search_ctx, struct aom_internal_error_info *error_info, int fbr, int fbc, int sb_count, int adaptive_cdef_mode) { // TODO(aomedia:3276): Pass error_info to the low-level functions as required // in future to handle error propagation.
(void)error_info; const CommonModeInfoParams *const mi_params = cdef_search_ctx->mi_params; const YV12_BUFFER_CONFIG *ref = cdef_search_ctx->ref; constint coeff_shift = cdef_search_ctx->coeff_shift; constint *mi_wide_l2 = cdef_search_ctx->mi_wide_l2; constint *mi_high_l2 = cdef_search_ctx->mi_high_l2;
// Declare and initialize the temporary buffers.
DECLARE_ALIGNED(32, uint16_t, inbuf[CDEF_INBUF_SIZE]);
cdef_list dlist[MI_SIZE_128X128 * MI_SIZE_128X128]; int dir[CDEF_NBLOCKS][CDEF_NBLOCKS] = { { 0 } }; int var[CDEF_NBLOCKS][CDEF_NBLOCKS] = { { 0 } };
uint16_t *const in = inbuf + CDEF_VBORDER * CDEF_BSTRIDE + CDEF_HBORDER; int nhb = AOMMIN(MI_SIZE_64X64, mi_params->mi_cols - MI_SIZE_64X64 * fbc); int nvb = AOMMIN(MI_SIZE_64X64, mi_params->mi_rows - MI_SIZE_64X64 * fbr); int hb_step = 1, vb_step = 1;
BLOCK_SIZE bs;
if (mbmi->bsize == BLOCK_128X128 || mbmi->bsize == BLOCK_128X64 ||
mbmi->bsize == BLOCK_64X128) {
bs = mbmi->bsize; if (bs == BLOCK_128X128 || bs == BLOCK_128X64) {
nhb = AOMMIN(MI_SIZE_128X128, mi_params->mi_cols - MI_SIZE_64X64 * fbc);
hb_step = 2;
} if (bs == BLOCK_128X128 || bs == BLOCK_64X128) {
nvb = AOMMIN(MI_SIZE_128X128, mi_params->mi_rows - MI_SIZE_64X64 * fbr);
vb_step = 2;
}
} else {
bs = BLOCK_64X64;
} // Get number of 8x8 blocks which are not skip. Cdef processing happens for // 8x8 blocks which are not skip. constint cdef_count = av1_cdef_compute_sb_list(
mi_params, fbr * MI_SIZE_64X64, fbc * MI_SIZE_64X64, dlist, bs); constbool is_fb_on_frm_left_boundary = (fbc == 0); constbool is_fb_on_frm_right_boundary =
(fbc + hb_step == cdef_search_ctx->nhfb); constbool is_fb_on_frm_top_boundary = (fbr == 0); constbool is_fb_on_frm_bottom_boundary =
(fbr + vb_step == cdef_search_ctx->nvfb); constint yoff = CDEF_VBORDER * (!is_fb_on_frm_top_boundary); constint xoff = CDEF_HBORDER * (!is_fb_on_frm_left_boundary); int dirinit = 0; for (int pli = 0; pli < cdef_search_ctx->num_planes; pli++) { // To disable CDEF filter of chroma, set MSE of chroma strength index 0 to // zero and all non-zero strength indices to 1, such that the joint // luma-chroma strength search always chooses filter strength 0 for chroma // due to least cost. if (adaptive_cdef_mode > 0 && pli > 0) {
cdef_search_ctx->mse[pli][sb_count][0] = 0; for (int gi = 1; gi < cdef_search_ctx->total_strengths; gi++)
cdef_search_ctx->mse[pli][sb_count][gi] = 1; break;
}
/* We avoid filtering the pixels for which some of the pixels to averageareoutsidetheframe.Wecouldchangethefilterinstead,
but it would add special cases for any future vectorization. */ constint hfilt_size = (nhb << mi_wide_l2[pli]); constint vfilt_size = (nvb << mi_high_l2[pli]); constint ysize =
vfilt_size + CDEF_VBORDER * (!is_fb_on_frm_bottom_boundary) + yoff; constint xsize =
hfilt_size + CDEF_HBORDER * (!is_fb_on_frm_right_boundary) + xoff; constint row = fbr * MI_SIZE_64X64 << mi_high_l2[pli]; constint col = fbc * MI_SIZE_64X64 << mi_wide_l2[pli]; struct macroblockd_plane pd = cdef_search_ctx->plane[pli];
cdef_search_ctx->copy_fn(&in[(-yoff * CDEF_BSTRIDE - xoff)], CDEF_BSTRIDE,
pd.dst.buf, row - yoff, col - xoff, pd.dst.stride,
ysize, xsize);
fill_borders_for_fbs_on_frame_boundary(
inbuf, hfilt_size, vfilt_size, is_fb_on_frm_left_boundary,
is_fb_on_frm_right_boundary, is_fb_on_frm_top_boundary,
is_fb_on_frm_bottom_boundary); for (int gi = 0; gi < cdef_search_ctx->total_strengths; gi++) { int pri_strength, sec_strength;
get_cdef_filter_strengths(cdef_search_ctx->pick_method, &pri_strength,
&sec_strength, gi); const uint64_t curr_mse = get_filt_error(
cdef_search_ctx, &pd, dlist, dir, &dirinit, var, in, ref_buffer[pli],
ref_stride[pli], row, col, pri_strength, sec_strength, cdef_count,
pli, coeff_shift, bs); if (pli < 2)
cdef_search_ctx->mse[pli][sb_count][gi] = curr_mse; else
cdef_search_ctx->mse[1][sb_count][gi] += curr_mse;
}
}
cdef_search_ctx->sb_index[sb_count] =
MI_SIZE_64X64 * fbr * mi_params->mi_stride + MI_SIZE_64X64 * fbc;
}
// MSE calculation at frame level. // Inputs: // cdef_search_ctx: Pointer to the structure containing parameters related to // CDEF search context. // adaptive_cdef_mode: Speed feature to control CDEF adaptively. // Returns: // Nothing will be returned. Contents of cdef_search_ctx will be modified. staticvoid cdef_mse_calc_frame(CdefSearchCtx *cdef_search_ctx, struct aom_internal_error_info *error_info, int adaptive_cdef_mode) { // Loop over each sb. for (int fbr = 0; fbr < cdef_search_ctx->nvfb; ++fbr) { for (int fbc = 0; fbc < cdef_search_ctx->nhfb; ++fbc) { // Checks if cdef processing can be skipped for particular sb. if (cdef_sb_skip(cdef_search_ctx->mi_params, fbr, fbc)) continue; // Calculate mse for each sb and store the relevant sb index.
av1_cdef_mse_calc_block(cdef_search_ctx, error_info, fbr, fbc,
cdef_search_ctx->sb_count, adaptive_cdef_mode);
cdef_search_ctx->sb_count++;
}
}
}
// Allocates memory for members of CdefSearchCtx. // Inputs: // cdef_search_ctx: Pointer to the structure containing parameters // related to CDEF search context. // Returns: // Nothing will be returned. Contents of cdef_search_ctx will be modified. staticvoid cdef_alloc_data(AV1_COMMON *cm, CdefSearchCtx *cdef_search_ctx) { constint nvfb = cdef_search_ctx->nvfb; constint nhfb = cdef_search_ctx->nhfb;
CHECK_MEM_ERROR(
cm, cdef_search_ctx->sb_index,
aom_malloc(nvfb * nhfb * sizeof(cdef_search_ctx->sb_index[0])));
cdef_search_ctx->sb_count = 0;
CHECK_MEM_ERROR(cm, cdef_search_ctx->mse[0],
aom_malloc(sizeof(**cdef_search_ctx->mse) * nvfb * nhfb));
CHECK_MEM_ERROR(cm, cdef_search_ctx->mse[1],
aom_malloc(sizeof(**cdef_search_ctx->mse) * nvfb * nhfb));
}
// Deallocates the memory allocated for members of CdefSearchCtx. // Inputs: // cdef_search_ctx: Pointer to the structure containing parameters // related to CDEF search context. // Returns: // Nothing will be returned. void av1_cdef_dealloc_data(CdefSearchCtx *cdef_search_ctx) { if (cdef_search_ctx) {
aom_free(cdef_search_ctx->mse[0]);
cdef_search_ctx->mse[0] = NULL;
aom_free(cdef_search_ctx->mse[1]);
cdef_search_ctx->mse[1] = NULL;
aom_free(cdef_search_ctx->sb_index);
cdef_search_ctx->sb_index = NULL;
}
}
// Initialize the parameters related to CDEF search context. // Inputs: // frame: Pointer to compressed frame buffer // ref: Pointer to the frame buffer holding the source frame // cm: Pointer to top level common structure // xd: Pointer to common current coding block structure // cdef_search_ctx: Pointer to the structure containing parameters related to // CDEF search context. // pick_method: Search method used to select CDEF parameters // Returns: // Nothing will be returned. Contents of cdef_search_ctx will be modified. staticinlinevoid cdef_params_init(const YV12_BUFFER_CONFIG *frame, const YV12_BUFFER_CONFIG *ref,
AV1_COMMON *cm, MACROBLOCKD *xd,
CdefSearchCtx *cdef_search_ctx,
CDEF_PICK_METHOD pick_method) { const CommonModeInfoParams *const mi_params = &cm->mi_params; constint num_planes = av1_num_planes(cm);
cdef_search_ctx->mi_params = &cm->mi_params;
cdef_search_ctx->ref = ref;
cdef_search_ctx->nvfb =
(mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64;
cdef_search_ctx->nhfb =
(mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64;
cdef_search_ctx->coeff_shift = AOMMAX(cm->seq_params->bit_depth - 8, 0);
cdef_search_ctx->damping = 3 + (cm->quant_params.base_qindex >> 6);
cdef_search_ctx->total_strengths = nb_cdef_strengths[pick_method];
cdef_search_ctx->num_planes = num_planes;
cdef_search_ctx->pick_method = pick_method;
cdef_search_ctx->sb_count = 0;
cdef_search_ctx->use_highbitdepth = cm->seq_params->use_highbitdepth;
av1_setup_dst_planes(xd->plane, cm->seq_params->sb_size, frame, 0, 0, 0,
num_planes); // Initialize plane wise information. for (int pli = 0; pli < num_planes; pli++) {
cdef_search_ctx->xdec[pli] = xd->plane[pli].subsampling_x;
cdef_search_ctx->ydec[pli] = xd->plane[pli].subsampling_y;
cdef_search_ctx->bsize[pli] =
cdef_search_ctx->ydec[pli]
? (cdef_search_ctx->xdec[pli] ? BLOCK_4X4 : BLOCK_8X4)
: (cdef_search_ctx->xdec[pli] ? BLOCK_4X8 : BLOCK_8X8);
cdef_search_ctx->mi_wide_l2[pli] =
MI_SIZE_LOG2 - xd->plane[pli].subsampling_x;
cdef_search_ctx->mi_high_l2[pli] =
MI_SIZE_LOG2 - xd->plane[pli].subsampling_y;
cdef_search_ctx->plane[pli] = xd->plane[pli];
} // Function pointer initialization. #if CONFIG_AV1_HIGHBITDEPTH if (cm->seq_params->use_highbitdepth) {
cdef_search_ctx->copy_fn = av1_cdef_copy_sb8_16_highbd;
cdef_search_ctx->compute_cdef_dist_fn = compute_cdef_dist_highbd;
} else {
cdef_search_ctx->copy_fn = av1_cdef_copy_sb8_16_lowbd;
cdef_search_ctx->compute_cdef_dist_fn = compute_cdef_dist;
} #else
cdef_search_ctx->copy_fn = av1_cdef_copy_sb8_16_lowbd;
cdef_search_ctx->compute_cdef_dist_fn = compute_cdef_dist; #endif
}
void av1_pick_cdef_from_qp(AV1_COMMON *const cm, int skip_cdef, int is_screen_content, bool avoid_uv_cdef) { constint bd = cm->seq_params->bit_depth; constint q =
av1_ac_quant_QTX(cm->quant_params.base_qindex, 0, bd) >> (bd - 8);
CdefInfo *const cdef_info = &cm->cdef_info; // Check the speed feature to avoid extra signaling. if (skip_cdef) {
cdef_info->cdef_bits = 1;
cdef_info->nb_cdef_strengths = 2;
} else {
cdef_info->cdef_bits = 0;
cdef_info->nb_cdef_strengths = 1;
}
cdef_info->cdef_damping = 3 + (cm->quant_params.base_qindex >> 6);
// mbmi->cdef_strength is already set in the encoding stage. We don't need to // set it again here. if (skip_cdef) {
cdef_info->cdef_strengths[1] = 0;
cdef_info->cdef_uv_strengths[1] = 0; return;
}
const CommonModeInfoParams *const mi_params = &cm->mi_params; constint nvfb = (mi_params->mi_rows + MI_SIZE_64X64 - 1) / MI_SIZE_64X64; constint nhfb = (mi_params->mi_cols + MI_SIZE_64X64 - 1) / MI_SIZE_64X64;
MB_MODE_INFO **mbmi = mi_params->mi_grid_base; // mbmi is NULL when real-time rate control library is used. if (!mbmi) return; for (int r = 0; r < nvfb; ++r) { for (int c = 0; c < nhfb; ++c) {
MB_MODE_INFO *current_mbmi = mbmi[MI_SIZE_64X64 * c];
current_mbmi->cdef_strength = 0;
}
mbmi += MI_SIZE_64X64 * mi_params->mi_stride;
}
}
assert(cdef_control != CDEF_NONE); // For CDEF_ADAPTIVE, turning off CDEF around qindex 32 was best for still // pictures if ((cdef_control == CDEF_REFERENCE &&
cpi->ppi->rtc_ref.non_reference_frame) ||
(apply_adaptive_cdef && cpi->oxcf.rc_cfg.cq_level <= 32)) {
CdefInfo *const cdef_info = &cm->cdef_info;
cdef_info->nb_cdef_strengths = 1;
cdef_info->cdef_bits = 0;
cdef_info->cdef_strengths[0] = 0;
cdef_info->cdef_uv_strengths[0] = 0; return;
}
// Indicate if external RC is used for testing constint rtc_ext_rc = cpi->rc.rtc_external_ratectrl; if (rtc_ext_rc) {
av1_pick_cdef_from_qp(cm, /*skip_cdef=*/0, /*is_screen_content=*/0, /*avoid_uv_cdef=*/false); return;
}
CDEF_PICK_METHOD pick_method = cpi->sf.lpf_sf.cdef_pick_method; if (pick_method == CDEF_PICK_FROM_Q) { constint use_screen_content_model =
cm->quant_params.base_qindex >
AOMMAX(cpi->sf.rt_sf.screen_content_cdef_filter_qindex_thresh,
cpi->rc.best_quality + 5) &&
cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN;
// For adaptive CDEF, do not apply CDEF to chroma channels. // This is done to reduce decode time, as CDEF is a relatively-expensive // filter to compute. constbool avoid_uv_cdef = apply_adaptive_cdef;
if (!cpi->cdef_search_ctx)
CHECK_MEM_ERROR(cm, cpi->cdef_search_ctx,
aom_calloc(1, sizeof(*cpi->cdef_search_ctx)));
CdefSearchCtx *cdef_search_ctx = cpi->cdef_search_ctx;
// Initialize parameters related to CDEF search context.
cdef_params_init(&cm->cur_frame->buf, cpi->source, cm, xd, cdef_search_ctx,
pick_method); // Allocate CDEF search context buffers.
cdef_alloc_data(cm, cdef_search_ctx); // Frame level mse calculation. if (cpi->mt_info.num_workers > 1) {
av1_cdef_mse_calc_frame_mt(cpi);
} else {
cdef_mse_calc_frame(cdef_search_ctx, cm->error, adaptive_cdef_mode);
}
/* Search for different number of signaling bits. */ int nb_strength_bits = 0;
uint64_t best_rd = UINT64_MAX;
CdefInfo *const cdef_info = &cm->cdef_info; int sb_count = cdef_search_ctx->sb_count;
uint64_t(*mse[2])[TOTAL_STRENGTHS];
mse[0] = cdef_search_ctx->mse[0];
mse[1] = cdef_search_ctx->mse[1]; /* Calculate the maximum number of bits required to signal CDEF strengths at
* block level */ constint total_strengths = nb_cdef_strengths[pick_method]; constint joint_strengths =
num_planes > 1 ? total_strengths * total_strengths : total_strengths; constint max_signaling_bits =
joint_strengths == 1 ? 0 : get_msb(joint_strengths - 1) + 1; int rdmult = cpi->td.mb.rdmult;
// For adaptive CDEF, reduce primary and secondary CDEF strengths for // qindexes up to 220. constbool should_reduce_cdef_strengths =
apply_adaptive_cdef && cpi->oxcf.rc_cfg.cq_level <= 220; // For adaptive CDEF with strength reduction, zero out CDEF strengths with // low values (luma and/or chroma). This is done to reduce decode time, as // CDEF is a relatively-expensive filter to compute. constbool should_zero_cdef_strengths =
should_reduce_cdef_strengths && cpi->sf.lpf_sf.zero_low_cdef_strengths; // If running adaptive CDEF with strength zeroing, let search derive at least // two CDEF strengths (i.e. at least 1 CDEF signaling bit), unless search was // explicitly set to search for 1 strength only (i.e. 0 CDEF signaling bits). // Doing so will help find opportunities to zero out low strengths to reduce // overall decode time. constint min_signaling_bits =
(should_zero_cdef_strengths && max_signaling_bits > 0) ? 1 : 0;
for (int i = min_signaling_bits; i <= 3; i++) { if (i > max_signaling_bits) break; int best_lev0[CDEF_MAX_STRENGTHS] = { 0 }; int best_lev1[CDEF_MAX_STRENGTHS] = { 0 }; constint nb_strengths = 1 << i;
uint64_t tot_mse; if (num_planes > 1) {
tot_mse = joint_strength_search_dual(best_lev0, best_lev1, nb_strengths,
mse, sb_count, pick_method);
} else {
tot_mse = joint_strength_search(best_lev0, nb_strengths, mse[0], sb_count,
pick_method);
}
// Perform CDEF strength reduction. // Note 1: for odd strengths, the 0.5 discarded by ">> 1" is a significant // part of the strength when the strength is small, and because there are // few strength levels, odd strengths are reduced significantly more than a // half. This is intended behavior for reduced strength. // For example: a pri strength of 3 becomes 1, and a sec strength of 1 // becomes 0. // Note 2: a (signaled) sec strength value of 3 is special as it results in an // actual sec strength of 4. We tried adding +1 to the sec strength 3 so it // maps to a reduced sec strength of 2. However, on Daala's subset1, the // resulting SSIMULACRA 2 scores were either exactly the same (at cpu-used 6), // or within noise level (at cpu-used 3). Given that there were no discernible // improvements, this special mapping was left out for reduced strength. if (should_reduce_cdef_strengths) { for (int j = 0; j < cdef_info->nb_cdef_strengths; j++) { constint luma_strength = cdef_info->cdef_strengths[j]; constint new_pri_luma_strength =
(luma_strength / CDEF_SEC_STRENGTHS) >> 1; constint new_sec_luma_strength =
(luma_strength % CDEF_SEC_STRENGTHS) >> 1;
// Zero out entries with low CDEF luma (and optional chroma) strengths. // The low-strength thresholds were empirically derived from subjective // testing and SSIMULACRA 2 scores. These strike a balance between // perceptual quality gains and a reasonable single-threaded decode time // increase (~10%) over --enable-cdef 0. There's an overall 0.18 point // loss in SSIMULACRA 2 scores over no CDEF strength zeroing at speed 6, // QP 30 on the CLIC 2020 dataset. if (should_zero_cdef_strengths) { constbool is_low_luma_strength =
new_pri_luma_strength <= 4 && new_sec_luma_strength <= 1;
if (is_low_luma_strength || is_low_chroma_strength) { // Disable CDEF on chroma if we've disabled it on luma
cdef_info->cdef_uv_strengths[j] = 0;
}
}
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.