blob: fc0bd706063b8458728a6ab21343e740c59cb81e [file] [log] [blame] [edit]
/*
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* aomedia.org/license/patent-license/.
*/
#include <assert.h>
#include <math.h>
#include <string.h>
#include "config/aom_scale_rtcd.h"
#include "aom/aom_integer.h"
#include "av1/common/ccso.h"
#include "av1/common/reconinter.h"
/* Pad the border of a frame */
#if CONFIG_F054_PIC_BOUNDARY
void extend_ccso_border(const YV12_BUFFER_CONFIG *frame, uint16_t *buf,
const int d) {
#else
void extend_ccso_border(uint16_t *buf, const int d, MACROBLOCKD *xd) {
#endif // CONFIG_F054_PIC_BOUNDARY
#if CONFIG_F054_PIC_BOUNDARY
int s = frame->y_width + (CCSO_PADDING_SIZE << 1);
int h = frame->y_height;
int w = frame->y_width;
#else
int s = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
int h = xd->plane[0].dst.height;
int w = xd->plane[0].dst.width;
#endif // CONFIG_F054_PIC_BOUNDARY
uint16_t *p = &buf[d * s + d];
for (int y = 0; y < h; y++) {
for (int x = 0; x < d; x++) {
*(p - d + x) = p[0];
p[w + x] = p[w - 1];
}
p += s;
}
p -= (s + d);
for (int y = 0; y < d; y++) {
memcpy(p + (y + 1) * s, p, sizeof(uint16_t) * (w + (d << 1)));
}
p -= ((h - 1) * s);
for (int y = 0; y < d; y++) {
memcpy(p - (y + 1) * s, p, sizeof(uint16_t) * (w + (d << 1)));
}
}
/* Derive the quantized index, later it can be used for retriving offset values
* from the look-up table */
void cal_filter_support(int *rec_luma_idx, const uint16_t *rec_y,
const int quant_step_size, const int inv_quant_step,
const int *rec_idx, const int edge_clf) {
if (edge_clf == 0) {
for (int i = 0; i < 2; i++) {
int d = rec_y[rec_idx[i]] - rec_y[0];
if (d > quant_step_size)
rec_luma_idx[i] = 2;
else if (d < inv_quant_step)
rec_luma_idx[i] = 0;
else
rec_luma_idx[i] = 1;
}
} else { // if (edge_clf == 1)
for (int i = 0; i < 2; i++) {
int d = rec_y[rec_idx[i]] - rec_y[0];
if (d < inv_quant_step)
rec_luma_idx[i] = 0;
else
rec_luma_idx[i] = 1;
}
}
}
/* Derive sample locations for CCSO */
void derive_ccso_sample_pos(int *rec_idx, const int ccso_stride,
const uint8_t ext_filter_support) {
// Input sample locations for CCSO
// 4 2 0 3 5
// 6 1 x 1 6
// 5 3 0 2 4
assert(ext_filter_support < 7);
if (ext_filter_support == 0) {
rec_idx[0] = -1 * ccso_stride;
rec_idx[1] = 1 * ccso_stride;
} else if (ext_filter_support == 1) {
rec_idx[0] = -1;
rec_idx[1] = 1;
} else if (ext_filter_support == 4) {
rec_idx[0] = -ccso_stride - 2;
rec_idx[1] = ccso_stride + 2;
} else if (ext_filter_support == 5) {
rec_idx[0] = ccso_stride - 2;
rec_idx[1] = -ccso_stride + 2;
} else if (ext_filter_support == 2) {
rec_idx[0] = -1 * ccso_stride - 1;
rec_idx[1] = 1 * ccso_stride + 1;
} else if (ext_filter_support == 3) {
rec_idx[0] = -1 * ccso_stride + 1;
rec_idx[1] = 1 * ccso_stride - 1;
} else { // ext_filter_support == 6
rec_idx[0] = 2;
rec_idx[1] = -2;
}
}
void ccso_filter_block_hbd_wo_buf_c(
const uint16_t *src_y, uint16_t *dst_yuv, const int x, const int y,
const int pic_width, const int pic_height, int *src_cls,
const int8_t *offset_buf, const int src_y_stride, const int dst_stride,
const int y_uv_hscale, const int y_uv_vscale, const int thr,
const int neg_thr, const int *src_loc, const int max_val,
#if CONFIG_CCSO_FU_BUGFIX
const int blk_size_x, const int blk_size_y,
#else
const int blk_size,
#endif // CONFIG_CCSO_FU_BUGFIX
const bool isSingleBand, const uint8_t shift_bits, const int edge_clf,
const uint8_t ccso_bo_only) {
#if CONFIG_CCSO_FU_BUGFIX
const int y_end = AOMMIN(pic_height - y, blk_size_y);
const int x_end = AOMMIN(pic_width - x, blk_size_x);
#else
const int y_end = AOMMIN(pic_height - y, blk_size);
const int x_end = AOMMIN(pic_width - x, blk_size);
#endif // CONFIG_CCSO_FU_BUGFIX
for (int y_start = 0; y_start < y_end; y_start++) {
const int y_pos = y_start;
for (int x_start = 0; x_start < x_end; x_start++) {
const int x_pos = x + x_start;
if (!ccso_bo_only) {
cal_filter_support(src_cls,
&src_y[(y_pos << y_uv_vscale) * src_y_stride +
(x_pos << y_uv_hscale)],
thr, neg_thr, src_loc, edge_clf);
} else {
src_cls[0] = 0;
src_cls[1] = 0;
}
const int band_num = isSingleBand
? 0
: src_y[(y_pos << y_uv_vscale) * src_y_stride +
(x_pos << y_uv_hscale)] >>
shift_bits;
const int lut_idx_ext = (band_num << 4) + (src_cls[0] << 2) + src_cls[1];
const int offset_val = offset_buf[lut_idx_ext];
dst_yuv[y_pos * dst_stride + x_pos] =
clamp(offset_val + dst_yuv[y_pos * dst_stride + x_pos], 0, max_val);
}
}
}
/* Apply CCSO on luma component when multiple bands are applied */
void ccso_apply_luma_mb_filter(AV1_COMMON *cm, MACROBLOCKD *xd, const int plane,
const uint16_t *src_y, uint16_t *dst_yuv,
const int dst_stride,
#if CCSO_REFACTORING
const int proc_unit_log2,
#endif // CCSO_REFACTORING
const uint16_t thr, const uint8_t filter_sup,
const uint8_t max_band_log2,
const int edge_clf) {
const CommonModeInfoParams *const mi_params = &cm->mi_params;
const int ccso_ext_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
const int pic_height = xd->plane[plane].dst.height;
const int pic_width = xd->plane[plane].dst.width;
const uint8_t shift_bits = cm->seq_params.bit_depth - max_band_log2;
const int max_val = (1 << cm->seq_params.bit_depth) - 1;
int src_cls[2];
const int neg_thr = thr * -1;
int src_loc[2];
derive_ccso_sample_pos(src_loc, ccso_ext_stride, filter_sup);
#if CONFIG_CCSO_FU_BUGFIX
assert(plane == 0); // function must only be called for plane == 0
const int blk_log2 = CCSO_BLK_SIZE;
#else
const int blk_log2 = plane > 0 ? CCSO_BLK_SIZE : CCSO_BLK_SIZE + 1;
#endif // CONFIG_CCSO_FU_BUGFIX
const int blk_size = 1 << blk_log2;
src_y += CCSO_PADDING_SIZE * ccso_ext_stride + CCSO_PADDING_SIZE;
#if CCSO_REFACTORING
int unit_log2 = proc_unit_log2 > blk_log2 ? blk_log2 : proc_unit_log2;
const int unit_size = 1 << (unit_log2);
#endif // CCSO_REFACTORING
for (int y = 0; y < pic_height; y += blk_size) {
for (int x = 0; x < pic_width; x += blk_size) {
#if CONFIG_CCSO_FU_BUGFIX
const int ccso_blk_idx =
(blk_size >> MI_SIZE_LOG2) * (y >> blk_log2) * mi_params->mi_stride +
(blk_size >> MI_SIZE_LOG2) * (x >> blk_log2);
#else
const int ccso_blk_idx =
(blk_size >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_y)) *
(y >> blk_log2) * mi_params->mi_stride +
(blk_size >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_x)) *
(x >> blk_log2);
#endif // CONFIG_CCSO_FU_BUGFIX
const bool use_ccso = mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_y;
if (!use_ccso) continue;
#if CCSO_REFACTORING
const uint16_t *src_unit_y = src_y;
uint16_t *dst_unit_yuv = dst_yuv;
const int y_end = AOMMIN(pic_height - y, blk_size);
const int x_end = AOMMIN(pic_width - x, blk_size);
for (int unit_y = 0; unit_y < y_end; unit_y += unit_size) {
for (int unit_x = 0; unit_x < x_end; unit_x += unit_size) {
#if CONFIG_BRU
// FPU level skip
const int mbmi_idx =
get_mi_grid_idx(mi_params, (y + unit_y) >> MI_SIZE_LOG2,
(x + unit_x) >> MI_SIZE_LOG2);
const int use_ccso_local =
mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
if (!use_ccso_local) {
continue;
}
if (cm->bru.enabled &&
mi_params->mi_grid_base[mbmi_idx]->sb_active_mode !=
BRU_ACTIVE_SB) {
aom_internal_error(
&cm->error, AOM_CODEC_ERROR,
"Invalid BRU activity in CCSO: only active SB can be filtered");
return;
}
#endif // CONFIG_BRU
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, 0, 0, thr, neg_thr, src_loc,
max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size,
#endif // CONFIG_CCSO_FU_BUGFIX
unit_size, false, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, 0, 0, thr, neg_thr, src_loc,
max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size,
#endif // CONFIG_CCSO_FU_BUGFIX
unit_size, false, shift_bits, edge_clf, 0);
}
}
dst_unit_yuv += (dst_stride << unit_log2);
src_unit_y += (ccso_ext_stride << unit_log2);
}
#else
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride, 0,
0, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size, false, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride, 0,
0, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size, false, shift_bits, edge_clf, 0);
}
#endif // CCSO_REFACTORING
}
dst_yuv += (dst_stride << blk_log2);
src_y += (ccso_ext_stride << blk_log2);
}
}
/* Apply CCSO on luma component when single band is applied */
void ccso_apply_luma_sb_filter(AV1_COMMON *cm, MACROBLOCKD *xd, const int plane,
const uint16_t *src_y, uint16_t *dst_yuv,
const int dst_stride,
#if CCSO_REFACTORING
const int proc_unit_log2,
#endif // CCSO_REFACTORING
const uint16_t thr, const uint8_t filter_sup,
const uint8_t max_band_log2,
const int edge_clf) {
(void)max_band_log2;
const CommonModeInfoParams *const mi_params = &cm->mi_params;
const int ccso_ext_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
const int pic_height = xd->plane[plane].dst.height;
const int pic_width = xd->plane[plane].dst.width;
const uint8_t shift_bits = cm->seq_params.bit_depth;
const int max_val = (1 << cm->seq_params.bit_depth) - 1;
int src_cls[2];
const int neg_thr = thr * -1;
int src_loc[2];
derive_ccso_sample_pos(src_loc, ccso_ext_stride, filter_sup);
#if CONFIG_CCSO_FU_BUGFIX
assert(plane == 0); // function must only be called for plane == 0
const int blk_log2 = CCSO_BLK_SIZE;
#else
const int blk_log2 = plane > 0 ? CCSO_BLK_SIZE : CCSO_BLK_SIZE + 1;
#endif // CONFIG_CCSO_FU_BUGFIX
const int blk_size = 1 << blk_log2;
src_y += CCSO_PADDING_SIZE * ccso_ext_stride + CCSO_PADDING_SIZE;
#if CCSO_REFACTORING
int unit_log2 = proc_unit_log2 > blk_log2 ? blk_log2 : proc_unit_log2;
const int unit_size = 1 << (unit_log2);
#endif // CCSO_REFACTORING
for (int y = 0; y < pic_height; y += blk_size) {
for (int x = 0; x < pic_width; x += blk_size) {
#if CONFIG_CCSO_FU_BUGFIX
const int ccso_blk_idx =
(blk_size >> MI_SIZE_LOG2) * (y >> blk_log2) * mi_params->mi_stride +
(blk_size >> MI_SIZE_LOG2) * (x >> blk_log2);
#else
const int ccso_blk_idx =
(blk_size >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_y)) *
(y >> blk_log2) * mi_params->mi_stride +
(blk_size >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_x)) *
(x >> blk_log2);
#endif // CONFIG_CCSO_FU_BUGFIX
const bool use_ccso = mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_y;
if (!use_ccso) continue;
#if CCSO_REFACTORING
const uint16_t *src_unit_y = src_y;
uint16_t *dst_unit_yuv = dst_yuv;
const int y_end = AOMMIN(pic_height - y, blk_size);
const int x_end = AOMMIN(pic_width - x, blk_size);
for (int unit_y = 0; unit_y < y_end; unit_y += unit_size) {
for (int unit_x = 0; unit_x < x_end; unit_x += unit_size) {
#if CONFIG_BRU
// FPU level skip
const int mbmi_idx =
get_mi_grid_idx(mi_params, (y + unit_y) >> MI_SIZE_LOG2,
(x + unit_x) >> MI_SIZE_LOG2);
const int use_ccso_local =
mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
if (!use_ccso_local) {
continue;
}
if (cm->bru.enabled &&
mi_params->mi_grid_base[mbmi_idx]->sb_active_mode !=
BRU_ACTIVE_SB) {
aom_internal_error(
&cm->error, AOM_CODEC_ERROR,
"Invalid BRU activity in CCSO: only active SB can be filtered");
return;
}
#endif // CONFIG_BRU
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, 0, 0, thr, neg_thr, src_loc,
max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size,
#endif
unit_size, true, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, 0, 0, thr, neg_thr, src_loc,
max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size,
#endif
unit_size, true, shift_bits, edge_clf, 0);
}
}
dst_unit_yuv += (dst_stride << unit_log2);
src_unit_y += (ccso_ext_stride << unit_log2);
}
#else
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride, 0,
0, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size, true, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride, 0,
0, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size, true, shift_bits, edge_clf, 0);
}
#endif // CCSO_REFACTORING
}
dst_yuv += (dst_stride << blk_log2);
src_y += (ccso_ext_stride << blk_log2);
}
}
/* Apply CCSO on chroma component when multiple bands are applied */
void ccso_apply_chroma_mb_filter(AV1_COMMON *cm, MACROBLOCKD *xd,
const int plane, const uint16_t *src_y,
uint16_t *dst_yuv, const int dst_stride,
#if CCSO_REFACTORING
const int proc_unit_log2,
#endif // CCSO_REFACTORING
const uint16_t thr, const uint8_t filter_sup,
const uint8_t max_band_log2,
const int edge_clf) {
const CommonModeInfoParams *const mi_params = &cm->mi_params;
const int ccso_ext_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
const int pic_height = xd->plane[plane].dst.height;
const int pic_width = xd->plane[plane].dst.width;
const int y_uv_hscale = xd->plane[plane].subsampling_x;
const int y_uv_vscale = xd->plane[plane].subsampling_y;
const uint8_t shift_bits = cm->seq_params.bit_depth - max_band_log2;
const int max_val = (1 << cm->seq_params.bit_depth) - 1;
int src_cls[2];
const int neg_thr = thr * -1;
int src_loc[2];
derive_ccso_sample_pos(src_loc, ccso_ext_stride, filter_sup);
#if CONFIG_CCSO_FU_BUGFIX
assert(plane > 0); // function must only be called for plane > 0
const int blk_size = 1 << CCSO_BLK_SIZE;
const int blk_log2_y = CCSO_BLK_SIZE - cm->seq_params.subsampling_y;
const int blk_log2_x = CCSO_BLK_SIZE - cm->seq_params.subsampling_x;
const int blk_size_y = 1 << blk_log2_y;
const int blk_size_x = 1 << blk_log2_x;
#else
const int blk_log2_y = plane > 0 ? CCSO_BLK_SIZE : CCSO_BLK_SIZE + 1;
const int blk_log2_x = blk_log2_y;
const int blk_size_y = 1 << blk_log2_y;
const int blk_size_x = 1 << blk_log2_y;
#endif // CONFIG_CCSO_FU_BUGFIX
src_y += CCSO_PADDING_SIZE * ccso_ext_stride + CCSO_PADDING_SIZE;
#if CCSO_REFACTORING
const int unit_log2_x =
proc_unit_log2 > blk_log2_x ? blk_log2_x : proc_unit_log2;
const int unit_size_x = 1 << (unit_log2_x);
const int unit_log2_y =
proc_unit_log2 > blk_log2_y ? blk_log2_y : proc_unit_log2;
const int unit_size_y = 1 << (unit_log2_y);
#endif // CCSO_REFACTORING
for (int y = 0; y < pic_height; y += blk_size_y) {
for (int x = 0; x < pic_width; x += blk_size_x) {
#if CONFIG_CCSO_FU_BUGFIX
const int ccso_blk_idx = (blk_size >> MI_SIZE_LOG2) * (y >> blk_log2_y) *
mi_params->mi_stride +
(blk_size >> MI_SIZE_LOG2) * (x >> blk_log2_x);
#else
const int ccso_blk_idx =
(blk_size_y >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_y)) *
(y >> blk_log2_y) * mi_params->mi_stride +
(blk_size_x >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_x)) *
(x >> blk_log2_y);
#endif // CONFIG_CCSO_FU_BUGFIX
const bool use_ccso =
(plane == 1) ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_u
: mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_v;
if (!use_ccso) continue;
#if CCSO_REFACTORING
const uint16_t *src_unit_y = src_y;
uint16_t *dst_unit_yuv = dst_yuv;
const int y_end = AOMMIN(pic_height - y, blk_size_y);
const int x_end = AOMMIN(pic_width - x, blk_size_x);
for (int unit_y = 0; unit_y < y_end; unit_y += unit_size_y) {
for (int unit_x = 0; unit_x < x_end; unit_x += unit_size_x) {
#if CONFIG_BRU
// FPU level skip
const int mbmi_idx = get_mi_grid_idx(
mi_params, (y + unit_y) >> (MI_SIZE_LOG2 - y_uv_vscale),
(x + unit_x) >> (MI_SIZE_LOG2 - y_uv_hscale));
const int use_ccso_local =
mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
if (!use_ccso_local) {
continue;
}
if (cm->bru.enabled &&
mi_params->mi_grid_base[mbmi_idx]->sb_active_mode !=
BRU_ACTIVE_SB) {
aom_internal_error(
&cm->error, AOM_CODEC_ERROR,
"Invalid BRU activity in CCSO: only active SB can be filtered");
return;
}
#endif // CONFIG_BRU
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, y_uv_hscale, y_uv_vscale, thr,
neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size_x,
#endif
unit_size_y, false, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, y_uv_hscale, y_uv_vscale, thr,
neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size_x,
#endif
unit_size_y, false, shift_bits, edge_clf, 0);
}
}
dst_unit_yuv += (dst_stride << unit_log2_y);
src_unit_y += (ccso_ext_stride << (unit_log2_y + y_uv_vscale));
}
#else
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride,
y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size_x,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size_y, false, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride,
y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size_x,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size_y, false, shift_bits, edge_clf, 0);
}
#endif // CCSO_REFACTORING
}
dst_yuv += (dst_stride << blk_log2_y);
src_y += (ccso_ext_stride << (blk_log2_y + y_uv_vscale));
}
}
/* Apply CCSO on chroma component when single bands is applied */
void ccso_apply_chroma_sb_filter(AV1_COMMON *cm, MACROBLOCKD *xd,
const int plane, const uint16_t *src_y,
uint16_t *dst_yuv, const int dst_stride,
#if CCSO_REFACTORING
const int proc_unit_log2,
#endif // CCSO_REFACTORING
const uint16_t thr, const uint8_t filter_sup,
const uint8_t max_band_log2,
const int edge_clf) {
(void)max_band_log2;
const CommonModeInfoParams *const mi_params = &cm->mi_params;
const int ccso_ext_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
const int pic_height = xd->plane[plane].dst.height;
const int pic_width = xd->plane[plane].dst.width;
const uint8_t shift_bits = cm->seq_params.bit_depth;
const int y_uv_hscale = xd->plane[plane].subsampling_x;
const int y_uv_vscale = xd->plane[plane].subsampling_y;
const int max_val = (1 << cm->seq_params.bit_depth) - 1;
int src_cls[2];
const int neg_thr = thr * -1;
int src_loc[2];
derive_ccso_sample_pos(src_loc, ccso_ext_stride, filter_sup);
#if CONFIG_CCSO_FU_BUGFIX
assert(plane > 0); // function must only be called for plane > 0
const int blk_size = 1 << CCSO_BLK_SIZE;
const int blk_log2_y = CCSO_BLK_SIZE - cm->seq_params.subsampling_y;
const int blk_log2_x = CCSO_BLK_SIZE - cm->seq_params.subsampling_x;
const int blk_size_y = 1 << blk_log2_y;
const int blk_size_x = 1 << blk_log2_x;
#else
const int blk_log2_y = plane > 0 ? CCSO_BLK_SIZE : CCSO_BLK_SIZE + 1;
const int blk_log2_x = blk_log2_y;
const int blk_size_y = 1 << blk_log2_y;
const int blk_size_x = 1 << blk_log2_y;
#endif // CONFIG_CCSO_FU_BUGFIX
src_y += CCSO_PADDING_SIZE * ccso_ext_stride + CCSO_PADDING_SIZE;
#if CCSO_REFACTORING
const int unit_log2_x =
proc_unit_log2 > blk_log2_x ? blk_log2_x : proc_unit_log2;
const int unit_size_x = 1 << (unit_log2_x);
const int unit_log2_y =
proc_unit_log2 > blk_log2_y ? blk_log2_y : proc_unit_log2;
const int unit_size_y = 1 << (unit_log2_y);
#endif // CCSO_REFACTORING
for (int y = 0; y < pic_height; y += blk_size_y) {
for (int x = 0; x < pic_width; x += blk_size_x) {
#if CONFIG_CCSO_FU_BUGFIX
const int ccso_blk_idx = (blk_size >> MI_SIZE_LOG2) * (y >> blk_log2_y) *
mi_params->mi_stride +
(blk_size >> MI_SIZE_LOG2) * (x >> blk_log2_x);
#else
const int ccso_blk_idx =
(blk_size_y >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_y)) *
(y >> blk_log2_y) * mi_params->mi_stride +
(blk_size_x >> (MI_SIZE_LOG2 - xd->plane[plane].subsampling_x)) *
(x >> blk_log2_y);
#endif // CONFIG_CCSO_FU_BUGFIX
const bool use_ccso =
(plane == 1) ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_u
: mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_v;
if (!use_ccso) continue;
#if CCSO_REFACTORING
const uint16_t *src_unit_y = src_y;
uint16_t *dst_unit_yuv = dst_yuv;
const int y_end = AOMMIN(pic_height - y, blk_size_y);
const int x_end = AOMMIN(pic_width - x, blk_size_x);
for (int unit_y = 0; unit_y < y_end; unit_y += unit_size_y) {
for (int unit_x = 0; unit_x < x_end; unit_x += unit_size_x) {
#if CONFIG_BRU
// FPU level skip
const int mbmi_idx = get_mi_grid_idx(
mi_params, (y + unit_y) >> (MI_SIZE_LOG2 - y_uv_vscale),
(x + unit_x) >> (MI_SIZE_LOG2 - y_uv_hscale));
const int use_ccso_local =
mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
if (!use_ccso_local) {
continue;
}
if (cm->bru.enabled &&
mi_params->mi_grid_base[mbmi_idx]->sb_active_mode !=
BRU_ACTIVE_SB) {
aom_internal_error(
&cm->error, AOM_CODEC_ERROR,
"Invalid BRU activity in CCSO: only active SB can be filtered");
return;
}
#endif // CONFIG_BRU
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, y_uv_hscale, y_uv_vscale, thr,
neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size_x,
#endif
unit_size_y, true, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_unit_y, dst_unit_yuv, x + unit_x, y + unit_y, pic_width,
pic_height, src_cls, cm->ccso_info.filter_offset[plane],
ccso_ext_stride, dst_stride, y_uv_hscale, y_uv_vscale, thr,
neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
unit_size_x,
#endif
unit_size_y, true, shift_bits, edge_clf, 0);
}
}
dst_unit_yuv += (dst_stride << unit_log2_y);
src_unit_y += (ccso_ext_stride << (unit_log2_y + y_uv_vscale));
}
#else
if (cm->ccso_info.ccso_bo_only[plane]) {
ccso_filter_block_hbd_wo_buf_c(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride,
y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size_x,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size_y, true, shift_bits, edge_clf,
cm->ccso_info.ccso_bo_only[plane]);
} else {
ccso_filter_block_hbd_wo_buf(
src_y, dst_yuv, x, y, pic_width, pic_height, src_cls,
cm->ccso_info.filter_offset[plane], ccso_ext_stride, dst_stride,
y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
#if CONFIG_CCSO_FU_BUGFIX
blk_size_x,
#endif // CONFIG_CCSO_FU_BUGFIX
blk_size_y, true, shift_bits, edge_clf, 0);
}
#endif // CCSO_REFACTORING
}
dst_yuv += (dst_stride << blk_log2_y);
src_y += (ccso_ext_stride << (blk_log2_y + y_uv_vscale));
}
}
/* Apply CCSO for one frame */
void ccso_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm, MACROBLOCKD *xd,
uint16_t *ext_rec_y) {
const int num_planes = av1_num_planes(cm);
av1_setup_dst_planes(xd->plane, frame, 0, 0, 0, num_planes, NULL);
const uint16_t quant_sz[4][4] = { { 16, 8, 32, 0 },
{ 32, 16, 64, 128 },
{ 48, 24, 96, 192 },
{ 64, 32, 128, 256 } };
for (int plane = 0; plane < num_planes; plane++) {
const int dst_stride = xd->plane[plane].dst.stride;
const uint16_t quant_step_size = quant_sz[cm->ccso_info.scale_idx[plane]]
[cm->ccso_info.quant_idx[plane]];
if (cm->ccso_info.ccso_enable[plane]) {
CCSO_FILTER_FUNC apply_ccso_filter_func =
cm->ccso_info.max_band_log2[plane]
? (plane > 0 ? ccso_apply_chroma_mb_filter
: ccso_apply_luma_mb_filter)
: (plane > 0 ? ccso_apply_chroma_sb_filter
: ccso_apply_luma_sb_filter);
apply_ccso_filter_func(
cm, xd, plane, ext_rec_y, &(xd->plane[plane].dst.buf)[0], dst_stride,
#if CCSO_REFACTORING
cm->mib_size_log2 -
AOMMAX(xd->plane[plane].subsampling_x,
xd->plane[plane].subsampling_y) +
MI_SIZE_LOG2,
#endif // CCSO_REFACTORING
quant_step_size, cm->ccso_info.ext_filter_support[plane],
cm->ccso_info.max_band_log2[plane], cm->ccso_info.edge_clf[plane]);
}
}
}
// This function is to copy ccso filter parameters between frames when
// ccso_reuse is true.
void av1_copy_ccso_filters(CcsoInfo *to, CcsoInfo *from, int plane,
bool frame_level, bool block_level, int sb_count) {
if (frame_level) {
memcpy(to->filter_offset[plane], from->filter_offset[plane],
sizeof(to->filter_offset[plane]));
to->quant_idx[plane] = from->quant_idx[plane];
to->ext_filter_support[plane] = from->ext_filter_support[plane];
to->edge_clf[plane] = from->edge_clf[plane];
to->ccso_bo_only[plane] = from->ccso_bo_only[plane];
to->max_band_log2[plane] = from->max_band_log2[plane];
to->scale_idx[plane] = from->scale_idx[plane];
}
if (block_level) {
if (to->sb_filter_control[plane]) {
memcpy(to->sb_filter_control[plane], from->sb_filter_control[plane],
sizeof(*from->sb_filter_control[plane]) * sb_count);
}
}
to->ccso_enable[plane] = from->ccso_enable[plane];
}