blob: 1344fe5a84690adf8e796e2284aa8a070f974465 [file] [log] [blame]
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. 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 www.aomedia.org/license/patent.
*/
#include <math.h>
#include "aom_ports/system_state.h"
#include "av1/common/blockd.h"
#include "av1/common/onyxc_int.h"
PREDICTION_MODE av1_left_block_mode(const MB_MODE_INFO *left_mi) {
if (!left_mi) return DC_PRED;
#if CONFIG_DERIVED_INTRA_MODE
if (left_mi->use_derived_intra_mode[0]) return DC_PRED;
#endif // CONFIG_DERIVED_INTRA_MODE
assert(!is_inter_block(left_mi) || is_intrabc_block(left_mi));
return left_mi->mode;
}
PREDICTION_MODE av1_above_block_mode(const MB_MODE_INFO *above_mi) {
if (!above_mi) return DC_PRED;
#if CONFIG_DERIVED_INTRA_MODE
if (above_mi->use_derived_intra_mode[0]) return DC_PRED;
#endif // CONFIG_DERIVED_INTRA_MODE
assert(!is_inter_block(above_mi) || is_intrabc_block(above_mi));
return above_mi->mode;
}
void av1_reset_is_mi_coded_map(MACROBLOCKD *xd, int stride) {
av1_zero(xd->is_mi_coded);
xd->is_mi_coded_stride = stride;
}
void av1_mark_block_as_coded(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize, BLOCK_SIZE sb_size) {
const int sb_mi_size = mi_size_wide[sb_size];
const int mi_row_offset = mi_row & (sb_mi_size - 1);
const int mi_col_offset = mi_col & (sb_mi_size - 1);
for (int r = 0; r < mi_size_high[bsize]; ++r)
for (int c = 0; c < mi_size_wide[bsize]; ++c) {
const int pos =
(mi_row_offset + r) * xd->is_mi_coded_stride + mi_col_offset + c;
xd->is_mi_coded[pos] = 1;
}
}
void av1_mark_block_as_not_coded(MACROBLOCKD *xd, int mi_row, int mi_col,
BLOCK_SIZE bsize, BLOCK_SIZE sb_size) {
const int sb_mi_size = mi_size_wide[sb_size];
const int mi_row_offset = mi_row & (sb_mi_size - 1);
const int mi_col_offset = mi_col & (sb_mi_size - 1);
for (int r = 0; r < mi_size_high[bsize]; ++r) {
uint8_t *row_ptr =
&xd->is_mi_coded[(mi_row_offset + r) * xd->is_mi_coded_stride +
mi_col_offset];
memset(row_ptr, 0, mi_size_wide[bsize] * sizeof(xd->is_mi_coded[0]));
}
}
PARTITION_TREE *av1_alloc_ptree_node(PARTITION_TREE *parent, int index) {
PARTITION_TREE *ptree = NULL;
struct aom_internal_error_info error;
AOM_CHECK_MEM_ERROR(&error, ptree, aom_calloc(1, sizeof(*ptree)));
ptree->parent = parent;
ptree->index = index;
ptree->partition = PARTITION_NONE;
ptree->is_settled = 0;
for (int i = 0; i < 4; ++i) ptree->sub_tree[i] = NULL;
return ptree;
}
void av1_free_ptree_recursive(PARTITION_TREE *ptree) {
if (ptree == NULL) return;
for (int i = 0; i < 4; ++i) av1_free_ptree_recursive(ptree->sub_tree[i]);
aom_free(ptree);
}
void av1_reset_ptree_in_sbi(SB_INFO *sbi) {
if (sbi->ptree_root) av1_free_ptree_recursive(sbi->ptree_root);
sbi->ptree_root = av1_alloc_ptree_node(NULL, 0);
}
#if CONFIG_INTRA_ENTROPY
#if !CONFIG_USE_SMALL_MODEL
INLINE static void add_hist_features(const uint64_t *hist, float **features) {
float total = 0.0f;
if (hist) {
for (int i = 0; i < 8; ++i) {
total += (float)hist[i];
}
}
(*features)[0] = logf(total + 1.0f);
++*features;
float *feature_pt = *features;
if (total > 0.1f) {
for (int i = 0; i < 8; ++i) {
feature_pt[i] = (float)hist[i] / total;
}
} else {
for (int i = 0; i < 8; ++i) {
feature_pt[i] = 0.125f;
}
}
*features += 8;
}
static void add_onehot(float **features, int num, int n) {
float *feature_pt = *features;
memset(feature_pt, 0, sizeof(*feature_pt) * num);
if (n >= 0 && n < num) feature_pt[n] = 1.0f;
*features += num;
}
#endif // !CONFIG_USE_SMALL_MODEL
void av1_get_intra_block_feature(int *sparse_features, float *dense_features,
const MB_MODE_INFO *above_mi,
const MB_MODE_INFO *left_mi,
const MB_MODE_INFO *aboveleft_mi) {
const MB_MODE_INFO *mbmi_list[3] = { above_mi, left_mi, aboveleft_mi };
const int num_mbmi = CONFIG_USE_SMALL_MODEL ? 2 : 3;
for (int i = 0; i < num_mbmi; ++i) {
const MB_MODE_INFO *mbmi = mbmi_list[i];
const int data_available = mbmi != NULL;
#if CONFIG_USE_SMALL_MODEL
*(sparse_features++) = data_available ? mbmi->mode : INTRA_MODES;
#else
*(dense_features++) = data_available;
add_onehot(&dense_features, INTRA_MODES, data_available ? mbmi->mode : -1);
const float var = data_available ? (float)mbmi->y_recon_var : 0.0f;
*(dense_features++) = logf(var + 1.0f);
add_hist_features(data_available ? mbmi->y_gradient_hist : NULL,
&dense_features);
#endif
}
#if CONFIG_USE_SMALL_MODEL
(void)dense_features;
#else
(void)sparse_features;
#endif
}
void av1_pdf2icdf(float *pdf, aom_cdf_prob *cdf, int nsymbs) {
float accu = 0.0f; // AOM_ICDF
for (int i = 0; i < nsymbs - 1; ++i) {
accu += pdf[i];
cdf[i] = AOM_ICDF((aom_cdf_prob)(accu * CDF_PROB_TOP));
}
cdf[nsymbs - 1] = 0;
}
void av1_get_intra_uv_block_feature(int *sparse_features, float *features,
PREDICTION_MODE cur_y_mode,
int is_cfl_allowed,
const MB_MODE_INFO *above_mi,
const MB_MODE_INFO *left_mi) {
*(sparse_features++) = cur_y_mode;
*(sparse_features++) = !is_cfl_allowed;
(void)features;
(void)above_mi;
(void)left_mi;
}
void av1_get_kf_y_mode_cdf_ml(const MACROBLOCKD *xd, aom_cdf_prob *cdf) {
NN_CONFIG_EM *nn_model = &(xd->tile_ctx->intra_y_mode);
av1_get_intra_block_feature(nn_model->sparse_features,
nn_model->dense_features, xd->above_mbmi,
xd->left_mbmi, xd->aboveleft_mbmi);
av1_nn_predict_em(nn_model);
av1_pdf2icdf(nn_model->output, cdf, INTRA_MODES);
}
void av1_get_uv_mode_cdf_ml(const MACROBLOCKD *xd, PREDICTION_MODE y_mode,
aom_cdf_prob *cdf) {
NN_CONFIG_EM *nn_model = &(xd->tile_ctx->intra_uv_mode);
av1_get_intra_uv_block_feature(
nn_model->sparse_features, nn_model->dense_features, y_mode,
is_cfl_allowed(xd), xd->above_mbmi, xd->left_mbmi);
av1_nn_predict_em(nn_model);
av1_pdf2icdf(nn_model->output, cdf, UV_INTRA_MODES);
}
#endif // CONFIG_INTRA_ENTROPY
void av1_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
int plane, BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
int has_eob, int aoff, int loff) {
ENTROPY_CONTEXT *const a = pd->above_context + aoff;
ENTROPY_CONTEXT *const l = pd->left_context + loff;
const int txs_wide = tx_size_wide_unit[tx_size];
const int txs_high = tx_size_high_unit[tx_size];
// above
if (has_eob && xd->mb_to_right_edge < 0) {
const int blocks_wide = max_block_wide(xd, plane_bsize, plane);
const int above_contexts = AOMMIN(txs_wide, blocks_wide - aoff);
memset(a, has_eob, sizeof(*a) * above_contexts);
memset(a + above_contexts, 0, sizeof(*a) * (txs_wide - above_contexts));
} else {
memset(a, has_eob, sizeof(*a) * txs_wide);
}
// left
if (has_eob && xd->mb_to_bottom_edge < 0) {
const int blocks_high = max_block_high(xd, plane_bsize, plane);
const int left_contexts = AOMMIN(txs_high, blocks_high - loff);
memset(l, has_eob, sizeof(*l) * left_contexts);
memset(l + left_contexts, 0, sizeof(*l) * (txs_high - left_contexts));
} else {
memset(l, has_eob, sizeof(*l) * txs_high);
}
}
void av1_reset_skip_context(MACROBLOCKD *xd, BLOCK_SIZE bsize,
const int num_planes) {
int i;
int nplanes;
assert(bsize < BLOCK_SIZES_ALL);
nplanes = 1 + (num_planes - 1) * xd->mi[0]->chroma_ref_info.is_chroma_ref;
for (i = 0; i < nplanes; i++) {
struct macroblockd_plane *const pd = &xd->plane[i];
const BLOCK_SIZE bsize_base =
i ? xd->mi[0]->chroma_ref_info.bsize_base : bsize;
const BLOCK_SIZE plane_bsize =
get_plane_block_size(bsize_base, pd->subsampling_x, pd->subsampling_y);
assert(plane_bsize < BLOCK_SIZES_ALL);
const int txs_wide = block_size_wide[plane_bsize] >> tx_size_wide_log2[0];
const int txs_high = block_size_high[plane_bsize] >> tx_size_high_log2[0];
memset(pd->above_context, 0, sizeof(ENTROPY_CONTEXT) * txs_wide);
memset(pd->left_context, 0, sizeof(ENTROPY_CONTEXT) * txs_high);
}
}
void av1_reset_loop_filter_delta(MACROBLOCKD *xd, int num_planes) {
xd->delta_lf_from_base = 0;
const int frame_lf_count =
num_planes > 1 ? FRAME_LF_COUNT : FRAME_LF_COUNT - 2;
for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id) xd->delta_lf[lf_id] = 0;
}
void av1_reset_loop_restoration(MACROBLOCKD *xd, const int num_planes) {
for (int p = 0; p < num_planes; ++p) {
set_default_wiener(xd->wiener_info + p);
set_default_sgrproj(xd->sgrproj_info + p);
#if CONFIG_WIENER_NONSEP
set_default_wiener_nonsep(xd->wiener_nonsep_info + p);
#endif // CONFIG_WIENER_NONSEP
#if CONFIG_CNN_CRLC_GUIDED
set_default_crlc(xd->crlc_unitinfo + p);
#endif // CONFIG_CNN_CRLC_GUIDED
}
}
void av1_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y,
const int num_planes) {
int i;
for (i = 0; i < num_planes; i++) {
xd->plane[i].plane_type = get_plane_type(i);
xd->plane[i].subsampling_x = i ? ss_x : 0;
xd->plane[i].subsampling_y = i ? ss_y : 0;
}
for (i = num_planes; i < MAX_MB_PLANE; i++) {
xd->plane[i].subsampling_x = 1;
xd->plane[i].subsampling_y = 1;
}
}
void av1_get_unit_width_height_coeff(const MACROBLOCKD *const xd, int plane,
BLOCK_SIZE plane_bsize, int row_plane,
int col_plane, int *unit_width,
int *unit_height) {
const int is_inter = is_inter_block(xd->mi[0]);
const int max_blocks_wide_plane =
is_inter ? block_size_wide[plane_bsize] >> tx_size_wide_log2[0]
: max_block_wide(xd, plane_bsize, plane);
const int max_blocks_high_plane =
is_inter ? block_size_high[plane_bsize] >> tx_size_high_log2[0]
: max_block_high(xd, plane_bsize, plane);
const struct macroblockd_plane *const pd = &xd->plane[plane];
const BLOCK_SIZE max_unit_bsize_plane =
get_plane_block_size(BLOCK_64X64, pd->subsampling_x, pd->subsampling_y);
int mu_blocks_wide_plane =
block_size_wide[max_unit_bsize_plane] >> tx_size_wide_log2[0];
int mu_blocks_high_plane =
block_size_high[max_unit_bsize_plane] >> tx_size_high_log2[0];
mu_blocks_wide_plane = AOMMIN(max_blocks_wide_plane, mu_blocks_wide_plane);
mu_blocks_high_plane = AOMMIN(max_blocks_high_plane, mu_blocks_high_plane);
assert(mu_blocks_wide_plane > 0);
assert(mu_blocks_high_plane > 0);
*unit_height =
AOMMIN(mu_blocks_high_plane + row_plane, max_blocks_high_plane);
*unit_width = AOMMIN(mu_blocks_wide_plane + col_plane, max_blocks_wide_plane);
assert(*unit_height > 0);
assert(*unit_width > 0);
}
#if CONFIG_INTRA_ENTROPY && !CONFIG_USE_SMALL_MODEL
static const int16_t cos_angle[8] = {
// 45 degrees
45,
// 22.5 degrees
59,
// 0 degrees
64,
// -22.5 degrees,
59,
// -45 degrees
45,
// -67.5 degrees
24,
// -90 degrees
0,
// 67.5 degrees
24,
};
static const int16_t sin_angle[8] = {
// 45 degrees
45,
// 22.5 degrees
24,
// 0 degrees
0,
// -22.5 degrees,
-24,
// -45 degrees
-45,
// -67.5 degrees
-59,
// -90 degrees
64,
// 67.5 degrees
59,
};
static INLINE uint8_t get_angle_idx(int dx, int dy) {
int max_response = 0;
int max_angle = 0;
for (int angle_idx = 0; angle_idx < 8; angle_idx++) {
const int cos = cos_angle[angle_idx];
const int sin = sin_angle[angle_idx];
const int64_t dot_prod = cos * dx + sin * dy;
const int64_t response = labs(dot_prod);
if (response > max_response) {
max_response = response;
max_angle = angle_idx;
}
}
return max_angle;
}
void av1_get_gradient_hist_lbd_c(const uint8_t *dst, int stride, int rows,
int cols, uint64_t *hist) {
dst += stride;
for (int r = 1; r < rows; ++r) {
int c;
for (c = 1; c < cols; c += 1) {
const int dx = dst[c] - dst[c - 1];
const int dy = dst[c] - dst[c - stride];
const int mag = dx * dx + dy * dy;
const uint8_t index = get_angle_idx(dx, dy);
hist[index] += mag;
}
dst += stride;
}
}
static void get_highbd_gradient_hist(const uint8_t *dst8, int stride, int rows,
int cols, uint64_t *hist) {
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
dst += stride;
for (int r = 1; r < rows; ++r) {
for (int c = 1; c < cols; ++c) {
const int dx = dst[c] - dst[c - 1];
const int dy = dst[c] - dst[c - stride];
const int mag = dx * dx + dy * dy;
const uint8_t index = get_angle_idx(dx, dy);
hist[index] += mag;
}
dst += stride;
}
}
void av1_get_gradient_hist(const MACROBLOCKD *const xd,
MB_MODE_INFO *const mbmi, BLOCK_SIZE bsize) {
const int y_stride = xd->plane[0].dst.stride;
const uint8_t *y_dst = xd->plane[0].dst.buf;
const int rows = block_size_high[bsize];
const int cols = block_size_wide[bsize];
const int y_block_rows =
xd->mb_to_bottom_edge >= 0 ? rows : (xd->mb_to_bottom_edge >> 3) + rows;
const int y_block_cols =
xd->mb_to_right_edge >= 0 ? cols : (xd->mb_to_right_edge >> 3) + cols;
av1_zero(mbmi->y_gradient_hist);
if (is_cur_buf_hbd(xd)) {
get_highbd_gradient_hist(y_dst, y_stride, y_block_rows, y_block_cols,
mbmi->y_gradient_hist);
} else {
av1_get_gradient_hist_lbd(y_dst, y_stride, y_block_rows, y_block_cols,
mbmi->y_gradient_hist);
}
}
static int64_t variance(const uint8_t *dst, int stride, int w, int h) {
int64_t sum = 0;
int64_t sum_square = 0;
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
const int v = dst[j];
sum += v;
sum_square += v * v;
}
dst += stride;
}
const int n = w * h;
const int64_t var = (n * sum_square - sum * sum) / n / n;
return var < 0 ? 0 : var;
}
static int64_t highbd_variance(const uint8_t *dst8, int stride, int w, int h) {
const uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
int64_t sum = 0;
int64_t sum_square = 0;
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
const int v = dst[j];
sum += v;
sum_square += v * v;
}
dst += stride;
}
const int n = w * h;
const int64_t var = (n * sum_square - sum * sum) / n / n;
return var < 0 ? 0 : var;
}
void av1_get_recon_var(const MACROBLOCKD *const xd, MB_MODE_INFO *const mbmi,
BLOCK_SIZE bsize) {
const int y_stride = xd->plane[0].dst.stride;
const uint8_t *y_dst = xd->plane[0].dst.buf;
const int rows = block_size_high[bsize];
const int cols = block_size_wide[bsize];
const int y_block_rows =
xd->mb_to_bottom_edge >= 0 ? rows : (xd->mb_to_bottom_edge >> 3) + rows;
const int y_block_cols =
xd->mb_to_right_edge >= 0 ? cols : (xd->mb_to_right_edge >> 3) + cols;
if (is_cur_buf_hbd(xd)) {
mbmi->y_recon_var =
highbd_variance(y_dst, y_stride, y_block_cols, y_block_rows);
} else {
mbmi->y_recon_var = variance(y_dst, y_stride, y_block_cols, y_block_rows);
}
}
#endif // CONFIG_INTRA_ENTROPY && !CONFIG_USE_SMALL_MODEL
#if CONFIG_DERIVED_INTRA_MODE
// BIN_WIDTH * BINS should be equal to 180.
#define BINS 36
#define BIN_WIDTH 5
static int get_bin_index_from_angle(int angle) {
angle = AOMMAX(0, AOMMIN(angle, 179));
return angle / BIN_WIDTH;
}
static INLINE int get_angle_from_index(int index) {
return index * BIN_WIDTH + (BIN_WIDTH >> 1);
}
static void get_gradient_hist(const uint8_t *src, int src_stride, int rows,
int cols, int *hist) {
float angle;
src += src_stride;
for (int r = 1; r < rows - 1; ++r) {
for (int c = 1; c < cols - 1; ++c) {
const uint8_t *above = &src[c - src_stride];
const uint8_t *below = &src[c + src_stride];
const uint8_t *left = &src[c - 1];
const uint8_t *right = &src[c + 1];
const int dx = (right[-src_stride] + 2 * right[0] + right[src_stride]) -
(left[-src_stride] + 2 * left[0] + left[src_stride]);
const int dy = (below[-1] + 2 * below[0] + below[1]) -
(above[-1] + 2 * above[0] + above[1]);
if (dx == 0 && dy == 0) continue;
if (dx == 0) {
angle = 0.0f;
} else {
angle = atanf(dy * 1.0f / dx);
}
int int_angle = 90 - (int)roundf(180 * angle / (float)PI);
if (int_angle >= 180) int_angle = 0;
int_angle = AOMMAX(int_angle, 0);
const int temp = abs(dx) + abs(dy);
const int bin_index = get_bin_index_from_angle(int_angle);
hist[bin_index] += temp;
if (bin_index > 0) hist[bin_index - 1] += temp / 2;
if (bin_index < BINS - 1) hist[bin_index + 1] += temp / 2;
}
src += src_stride;
}
}
static void get_highbd_gradient_hist(const uint8_t *src8, int src_stride,
int rows, int cols, int *hist) {
float angle;
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
src += src_stride;
for (int r = 1; r < rows - 1; ++r) {
for (int c = 1; c < cols - 1; ++c) {
const uint16_t *above = &src[c - src_stride];
const uint16_t *below = &src[c + src_stride];
const uint16_t *left = &src[c - 1];
const uint16_t *right = &src[c + 1];
const int dx = (right[-src_stride] + 2 * right[0] + right[src_stride]) -
(left[-src_stride] + 2 * left[0] + left[src_stride]);
const int dy = (below[-1] + 2 * below[0] + below[1]) -
(above[-1] + 2 * above[0] + above[1]);
if (dx == 0 && dy == 0) continue;
if (dx == 0) {
angle = 0.0f;
} else {
angle = atanf(dy * 1.0f / dx);
}
int int_angle = 90 - (int)roundf(180 * angle / (float)PI);
if (int_angle >= 180) int_angle = 0;
int_angle = AOMMAX(int_angle, 0);
const int temp = abs(dx) + abs(dy);
const int bin_index = get_bin_index_from_angle(int_angle);
hist[bin_index] += temp;
if (bin_index > 0) hist[bin_index - 1] += temp / 2;
if (bin_index < BINS - 1) hist[bin_index + 1] += temp / 2;
}
src += src_stride;
}
}
static void generate_hog(const MACROBLOCKD *xd, int *hist) {
const int stride = xd->plane[0].dst.stride;
const uint8_t *buf = xd->plane[0].dst.buf;
const int bsize = xd->mi[0]->sb_type;
const int bh = block_size_high[bsize];
const int bw = block_size_wide[bsize];
const int rows =
(xd->mb_to_bottom_edge >= 0) ? bh : (xd->mb_to_bottom_edge >> 3) + bh;
const int cols =
(xd->mb_to_right_edge >= 0) ? bw : (xd->mb_to_right_edge >> 3) + bw;
const int lines = 3;
if (is_cur_buf_hbd(xd)) {
if (xd->above_mbmi) {
if (xd->left_mbmi) {
get_highbd_gradient_hist(buf - lines * stride - lines, stride, lines,
cols + lines, hist);
} else {
get_highbd_gradient_hist(buf - lines * stride, stride, lines, cols,
hist);
}
}
if (xd->left_mbmi) {
get_highbd_gradient_hist(buf - lines, stride, rows, lines, hist);
}
} else {
if (xd->above_mbmi) {
if (xd->left_mbmi) {
get_gradient_hist(buf - lines * stride - lines, stride, lines,
cols + lines, hist);
} else {
get_gradient_hist(buf - lines * stride, stride, lines, cols, hist);
}
}
if (xd->left_mbmi) {
get_gradient_hist(buf - lines, stride, rows, lines, hist);
}
}
}
int av1_enable_derived_intra_mode(const MACROBLOCKD *xd, int bsize) {
return bsize >= BLOCK_8X8 && (xd->above_mbmi || xd->left_mbmi);
}
static int angle_to_mode(int angle) {
if (angle < 56) return D45_PRED;
if (angle < 79) return D67_PRED;
if (angle < 102) return V_PRED;
if (angle < 124) return D113_PRED;
if (angle < 146) return D135_PRED;
if (angle < 169) return D157_PRED;
if (angle < 192) return H_PRED;
return D203_PRED;
}
int av1_get_derived_intra_mode(const MACROBLOCKD *xd, int bsize,
MB_MODE_INFO *mbmi) {
if (av1_enable_derived_intra_mode(xd, bsize)) {
int hist[BINS] = { 0 };
aom_clear_system_state();
generate_hog(xd, hist);
aom_clear_system_state();
#if FUSION_MODE
int total_weight = 1;
for (int i = 0; i < NUM_DERIVED_INTRA_MODES; ++i) {
int max_score = 0;
int best_idx = 0;
for (int idx = 0; idx < BINS; ++idx) {
const int this_score = hist[idx];
if (this_score > max_score) {
max_score = this_score;
best_idx = idx;
}
}
int angle = get_angle_from_index(best_idx);
if (angle < 36) angle += 180;
mbmi->derived_intra_angles[i] = angle;
mbmi->derived_intra_weights[i] = max_score;
total_weight += max_score;
hist[best_idx] = 0;
}
const int scale = 1 << DERIVED_INTRA_FUSION_SHIFT;
int sub_total_weight = 0;
for (int i = NUM_DERIVED_INTRA_MODES - 1; i > 0; --i) {
const int weight = mbmi->derived_intra_weights[i];
mbmi->derived_intra_weights[i] =
(weight * scale + (total_weight >> 1)) / total_weight;
sub_total_weight += mbmi->derived_intra_weights[i];
}
mbmi->derived_intra_weights[0] = scale - sub_total_weight;
mbmi->derived_angle = mbmi->derived_intra_angles[0];
return angle_to_mode(mbmi->derived_angle);
#else
int max_score = 0;
int best_idx = 0;
for (int i = 0; i < BINS; ++i) {
const int this_score = hist[i];
if (this_score > max_score) {
max_score = this_score;
best_idx = i;
}
}
int angle = get_angle_from_index(best_idx);
if (angle < 36) angle += 180;
mbmi->derived_angle = angle;
const int mode = angle_to_mode(angle);
return mode;
#endif
}
return INTRA_MODES;
}
#undef BINS
#undef BIN_WIDTH
#endif // CONFIG_DERIVED_INTRA_MODE
void av1_alloc_txk_skip_array(AV1_COMMON *cm) {
// allocate based on the MIN_TX_SIZE, which is 4x4 block
for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
int w = cm->mi_cols << MI_SIZE_LOG2;
int h = cm->mi_rows << MI_SIZE_LOG2;
w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
h >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
cm->tx_skip[plane] = aom_calloc(rows * stride, sizeof(uint8_t));
cm->tx_skip_buf_size[plane] = rows * stride;
}
}
void av1_dealloc_txk_skip_array(AV1_COMMON *cm) {
for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
aom_free(cm->tx_skip[plane]);
cm->tx_skip[plane] = NULL;
}
}
void av1_reset_txk_skip_array(AV1_COMMON *cm) {
// allocate based on the MIN_TX_SIZE, which is 4x4 block
for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
int w = cm->mi_cols << MI_SIZE_LOG2;
int h = cm->mi_rows << MI_SIZE_LOG2;
w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
h >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
memset(cm->tx_skip[plane], 0, rows * stride);
}
}
void av1_init_txk_skip_array(const AV1_COMMON *cm, MB_MODE_INFO *mbmi,
int mi_row, int mi_col, BLOCK_SIZE bsize,
uint8_t value, FILE *fLog) {
for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
const int is_chroma_ref = plane && mbmi->chroma_ref_info.is_chroma_ref;
int mi_row_plane =
is_chroma_ref ? mbmi->chroma_ref_info.mi_row_chroma_base : mi_row;
int mi_col_plane =
is_chroma_ref ? mbmi->chroma_ref_info.mi_col_chroma_base : mi_col;
BLOCK_SIZE bsize_plane =
is_chroma_ref ? mbmi->chroma_ref_info.bsize_base : bsize;
int w = ((cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2)
<< MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
int x = (mi_col_plane << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int y = (mi_row_plane << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_y);
int row = y >> MIN_TX_SIZE_LOG2;
int col = x >> MIN_TX_SIZE_LOG2;
int blk_w = block_size_wide[bsize_plane] >>
((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int blk_h = block_size_high[bsize_plane] >>
((plane == 0) ? 0 : cm->seq_params.subsampling_y);
blk_w >>= MIN_TX_SIZE_LOG2;
blk_h >>= MIN_TX_SIZE_LOG2;
for (int r = 0; r < blk_h; r++) {
for (int c = 0; c < blk_w; c++) {
uint32_t idx = (row + r) * stride + col + c;
assert(idx < cm->tx_skip_buf_size[plane]);
cm->tx_skip[plane][idx] = value;
}
}
}
if (fLog) {
int row = (mi_row << MI_SIZE_LOG2);
int col = (mi_col << MI_SIZE_LOG2);
int w = block_size_wide[bsize];
int h = block_size_high[bsize];
if (value != 0) {
fprintf(fLog,
"\n\tSkipped TxBlock: row = %d, col = %d, blk_width = %d, "
"blk_height = %d",
row, col, w, h);
} else {
fprintf(
fLog,
"\nrow = %d, col = %d, width = %d, height = %d, %s, blk skipped = %d",
row, col, w, h, is_inter_block(mbmi) ? "INTER" : "INTRA", value);
}
}
}
void av1_update_txk_skip_array(const AV1_COMMON *cm, int mi_row, int mi_col,
int plane, int blk_row, int blk_col,
TX_SIZE tx_size, FILE *fLog) {
blk_row *= 4;
blk_col *= 4;
int w = ((cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2)
<< MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
int tx_w = tx_size_wide[tx_size];
int tx_h = tx_size_high[tx_size];
int cols = tx_w >> MIN_TX_SIZE_LOG2;
int rows = tx_h >> MIN_TX_SIZE_LOG2;
int x = (mi_col << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int y = (mi_row << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_y);
x = (x + blk_col) >> MIN_TX_SIZE_LOG2;
y = (y + blk_row) >> MIN_TX_SIZE_LOG2;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
uint32_t idx = (y + r) * stride + x + c;
assert(idx < cm->tx_skip_buf_size[plane]);
cm->tx_skip[plane][idx] = 1;
}
}
if (fLog) {
fprintf(fLog,
"\n\tSkipped TxBlock: row = %d, col = %d, tx_width = %d, tx_height"
"= %d, plane = %d",
((mi_row << MI_SIZE_LOG2) + blk_row),
((mi_col << MI_SIZE_LOG2) + blk_col), tx_size_wide[tx_size],
tx_size_high[tx_size], plane);
}
}
uint8_t av1_get_txk_skip(const AV1_COMMON *cm, int mi_row, int mi_col,
int plane, int blk_row, int blk_col) {
blk_row *= 4;
blk_col *= 4;
int w = ((cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2)
<< MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
int x = (mi_col << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int y = (mi_row << MI_SIZE_LOG2) >>
((plane == 0) ? 0 : cm->seq_params.subsampling_y);
x = (x + blk_col) >> MIN_TX_SIZE_LOG2;
y = (y + blk_row) >> MIN_TX_SIZE_LOG2;
uint32_t idx = y * stride + x;
assert(idx < cm->tx_skip_buf_size[plane]);
return cm->tx_skip[plane][idx];
}
#if CONFIG_DBLK_TXSKIP
uint8_t av1_lpf_get_txk_skip(const AV1_COMMON *cm, int px, int py, int plane) {
int w = ((cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2)
<< MAX_SB_SIZE_LOG2;
w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
px >>= MIN_TX_SIZE_LOG2;
py >>= MIN_TX_SIZE_LOG2;
uint32_t idx = py * stride + px;
assert(idx < cm->tx_skip_buf_size[plane]);
return cm->tx_skip[plane][idx];
}
#endif