void av1_convolve_horiz_rs_c(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const int16_t *x_filters, int x0_qn,
int x_step_qn) {
src -= UPSCALE_NORMATIVE_TAPS / 2 - 1;
for (int y = 0; y < h; ++y) {
int x_qn = x0_qn;
for (int x = 0; x < w; ++x) { const uint8_t *const src_x = &src[x_qn >> RS_SCALE_SUBPEL_BITS]; const int x_filter_idx =
(x_qn & RS_SCALE_SUBPEL_MASK) >> RS_SCALE_EXTRA_BITS;
assert(x_filter_idx <= RS_SUBPEL_MASK); const int16_t *const x_filter =
&x_filters[x_filter_idx * UPSCALE_NORMATIVE_TAPS];
int sum = 0;
for (int k = 0; k < UPSCALE_NORMATIVE_TAPS; ++k)
sum += src_x[k] * x_filter[k];
dst[x] = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
x_qn += x_step_qn;
}
src += src_stride;
dst += dst_stride;
}
}
#if CONFIG_AV1_HIGHBITDEPTH void av1_highbd_convolve_horiz_rs_c(const uint16_t *src, int src_stride,
uint16_t *dst, int dst_stride, int w, int h, const int16_t *x_filters, int x0_qn,
int x_step_qn, int bd) {
src -= UPSCALE_NORMATIVE_TAPS / 2 - 1;
for (int y = 0; y < h; ++y) {
int x_qn = x0_qn;
for (int x = 0; x < w; ++x) { const uint16_t *const src_x = &src[x_qn >> RS_SCALE_SUBPEL_BITS]; const int x_filter_idx =
(x_qn & RS_SCALE_SUBPEL_MASK) >> RS_SCALE_EXTRA_BITS;
assert(x_filter_idx <= RS_SUBPEL_MASK); const int16_t *const x_filter =
&x_filters[x_filter_idx * UPSCALE_NORMATIVE_TAPS];
int sum = 0;
for (int k = 0; k < UPSCALE_NORMATIVE_TAPS; ++k)
sum += src_x[k] * x_filter[k];
dst[x] = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
x_qn += x_step_qn;
}
src += src_stride;
dst += dst_stride;
}
} #endif// CONFIG_AV1_HIGHBITDEPTH
void av1_convolve_2d_sr_c(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, const InterpFilterParams *filter_params_y, const int subpel_x_qn, const int subpel_y_qn,
ConvolveParams *conv_params) {
int16_t im_block[(MAX_SB_SIZE + MAX_FILTER_TAP - 1) * MAX_SB_SIZE];
int im_h = h + filter_params_y->taps - 1;
int im_stride = w;
assert(w <= MAX_SB_SIZE && h <= MAX_SB_SIZE); const int fo_vert = filter_params_y->taps / 2 - 1; const int fo_horiz = filter_params_x->taps / 2 - 1; const int bd = 8; const int bits =
FILTER_BITS * 2 - conv_params->round_0 - conv_params->round_1;
// horizontal filter const uint8_t *src_horiz = src - fo_vert * src_stride; const int16_t *x_filter = av1_get_interp_filter_subpel_kernel(
filter_params_x, subpel_x_qn & SUBPEL_MASK);
for (int y = 0; y < im_h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t sum = (1 << (bd + FILTER_BITS - 1));
for (int k = 0; k < filter_params_x->taps; ++k) {
sum += x_filter[k] * src_horiz[y * src_stride + x - fo_horiz + k];
}
// TODO(aomedia:3393): for 12-tap filter, in extreme cases, the result can // be beyond the following range. For better prediction, a clamping can be // added for 12 tap filter to ensure the horizontal filtering result is // within 16 bit. The same applies to the vertical filtering.
assert(filter_params_x->taps > 8 ||
(0 <= sum && sum < (1 << (bd + FILTER_BITS + 1))));
im_block[y * im_stride + x] =
(int16_t)ROUND_POWER_OF_TWO(sum, conv_params->round_0);
}
}
// vertical filter
int16_t *src_vert = im_block + fo_vert * im_stride; const int16_t *y_filter = av1_get_interp_filter_subpel_kernel(
filter_params_y, subpel_y_qn & SUBPEL_MASK); const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t sum = 1 << offset_bits;
for (int k = 0; k < filter_params_y->taps; ++k) {
sum += y_filter[k] * src_vert[(y - fo_vert + k) * im_stride + x];
}
assert(filter_params_y->taps > 8 ||
(0 <= sum && sum < (1 << (offset_bits + 2))));
int16_t res = ROUND_POWER_OF_TWO(sum, conv_params->round_1) -
((1 << (offset_bits - conv_params->round_1)) +
(1 << (offset_bits - conv_params->round_1 - 1)));
dst[y * dst_stride + x] = clip_pixel(ROUND_POWER_OF_TWO(res, bits));
}
}
}
void av1_convolve_y_sr_c(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const InterpFilterParams *filter_params_y, const int subpel_y_qn) { const int fo_vert = filter_params_y->taps / 2 - 1;
// vertical filter const int16_t *y_filter = av1_get_interp_filter_subpel_kernel(
filter_params_y, subpel_y_qn & SUBPEL_MASK);
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t res = 0;
for (int k = 0; k < filter_params_y->taps; ++k) {
res += y_filter[k] * src[(y - fo_vert + k) * src_stride + x];
}
dst[y * dst_stride + x] =
clip_pixel(ROUND_POWER_OF_TWO(res, FILTER_BITS));
}
}
}
void av1_convolve_x_sr_c(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, const int subpel_x_qn, ConvolveParams *conv_params) { const int fo_horiz = filter_params_x->taps / 2 - 1; const int bits = FILTER_BITS - conv_params->round_0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t res = 0;
for (int k = 0; k < filter_params_x->taps; ++k) {
res += x_filter[k] * src[y * src_stride + x - fo_horiz + k];
}
res = ROUND_POWER_OF_TWO(res, conv_params->round_0);
dst[y * dst_stride + x] = clip_pixel(ROUND_POWER_OF_TWO(res, bits));
}
}
}
// This function is exactly the same as av1_convolve_2d_sr_c, and is an // optimized version for intrabc. Use the following 2-tap filter: // DECLARE_ALIGNED(256, static const int16_t, // av1_intrabc_bilinear_filter[2 * SUBPEL_SHIFTS]) = { // 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // }; void av1_convolve_2d_sr_intrabc_c(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, const InterpFilterParams *filter_params_y, const int subpel_x_qn, const int subpel_y_qn,
ConvolveParams *conv_params) {
assert(subpel_x_qn == 8);
assert(subpel_y_qn == 8);
assert(filter_params_x->taps == 2 && filter_params_y->taps == 2);
assert((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS);
(void)filter_params_x;
(void)subpel_x_qn;
(void)filter_params_y;
(void)subpel_y_qn;
(void)conv_params;
int16_t im_block[(MAX_SB_SIZE + MAX_FILTER_TAP - 1) * MAX_SB_SIZE];
int im_h = h + 1;
int im_stride = w;
assert(w <= MAX_SB_SIZE && h <= MAX_SB_SIZE); const int bd = 8;
// horizontal filter // explicitly operate for subpel_x_qn = 8.
int16_t *im = im_block;
for (int y = 0; y < im_h; ++y) {
for (int x = 0; x < w; ++x) { const int32_t sum = (1 << bd) + src[x] + src[x + 1];
assert(0 <= sum && sum < (1 << (bd + 2)));
im[x] = sum;
}
src += src_stride;
im += im_stride;
}
// vertical filter // explicitly operate for subpel_y_qn = 8.
int16_t *src_vert = im_block;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { const int32_t sum =
(1 << (bd + 2)) + src_vert[x] + src_vert[im_stride + x];
assert(0 <= sum && sum < (1 << (bd + 4))); const int16_t res =
ROUND_POWER_OF_TWO(sum, 2) - ((1 << bd) + (1 << (bd - 1)));
dst[x] = clip_pixel(res);
}
src_vert += im_stride;
dst += dst_stride;
}
}
// This function is exactly the same as av1_convolve_y_sr_c, and is an // optimized version for intrabc. void av1_convolve_y_sr_intrabc_c(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_y, const int subpel_y_qn) {
assert(subpel_y_qn == 8);
assert(filter_params_y->taps == 2);
(void)filter_params_y;
(void)subpel_y_qn;
// vertical filter // explicitly operate for subpel_y_qn = 8.
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { const int32_t res = src[x] + src[src_stride + x];
dst[x] = clip_pixel(ROUND_POWER_OF_TWO(res, 1));
}
src += src_stride;
dst += dst_stride;
}
}
// This function is exactly the same as av1_convolve_x_sr_c, and is an // optimized version for intrabc. void av1_convolve_x_sr_intrabc_c(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, const int subpel_x_qn,
ConvolveParams *conv_params) {
assert(subpel_x_qn == 8);
assert(filter_params_x->taps == 2);
assert((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS);
(void)filter_params_x;
(void)subpel_x_qn;
(void)conv_params;
// horizontal filter // explicitly operate for subpel_x_qn = 8.
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { const int32_t res = src[x] + src[x + 1];
dst[x] = clip_pixel(ROUND_POWER_OF_TWO(res, 1));
}
src += src_stride;
dst += dst_stride;
}
}
void av1_dist_wtd_convolve_2d_c(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, const InterpFilterParams *filter_params_y, const int subpel_x_qn, const int subpel_y_qn,
ConvolveParams *conv_params) {
CONV_BUF_TYPE *dst16 = conv_params->dst;
int dst16_stride = conv_params->dst_stride;
int16_t im_block[(MAX_SB_SIZE + MAX_FILTER_TAP - 1) * MAX_SB_SIZE];
int im_h = h + filter_params_y->taps - 1;
int im_stride = w; const int fo_vert = filter_params_y->taps / 2 - 1; const int fo_horiz = filter_params_x->taps / 2 - 1; const int bd = 8; const int round_bits = 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
// horizontal filter const uint8_t *src_horiz = src - fo_vert * src_stride; const int16_t *x_filter = av1_get_interp_filter_subpel_kernel(
filter_params_x, subpel_x_qn & SUBPEL_MASK);
for (int y = 0; y < im_h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t sum = (1 << (bd + FILTER_BITS - 1));
for (int k = 0; k < filter_params_x->taps; ++k) {
sum += x_filter[k] * src_horiz[y * src_stride + x - fo_horiz + k];
}
assert(filter_params_x->taps > 8 ||
(0 <= sum && sum < (1 << (bd + FILTER_BITS + 1))));
im_block[y * im_stride + x] =
(int16_t)ROUND_POWER_OF_TWO(sum, conv_params->round_0);
}
}
// vertical filter
int16_t *src_vert = im_block + fo_vert * im_stride; const int16_t *y_filter = av1_get_interp_filter_subpel_kernel(
filter_params_y, subpel_y_qn & SUBPEL_MASK); const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t sum = 1 << offset_bits;
for (int k = 0; k < filter_params_y->taps; ++k) {
sum += y_filter[k] * src_vert[(y - fo_vert + k) * im_stride + x];
}
assert(filter_params_y->taps > 8 ||
(0 <= sum && sum < (1 << (offset_bits + 2))));
CONV_BUF_TYPE res = ROUND_POWER_OF_TWO(sum, conv_params->round_1);
if (conv_params->do_average) {
int32_t tmp = dst16[y * dst16_stride + x];
if (conv_params->use_dist_wtd_comp_avg) {
tmp = tmp * conv_params->fwd_offset + res * conv_params->bck_offset;
tmp = tmp >> DIST_PRECISION_BITS;
} else {
tmp += res;
tmp = tmp >> 1;
}
tmp -= (1 << (offset_bits - conv_params->round_1)) +
(1 << (offset_bits - conv_params->round_1 - 1));
dst[y * dst_stride + x] =
clip_pixel(ROUND_POWER_OF_TWO(tmp, round_bits));
} else {
dst16[y * dst16_stride + x] = res;
}
}
}
}
void av1_dist_wtd_convolve_y_c(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const InterpFilterParams *filter_params_y, const int subpel_y_qn,
ConvolveParams *conv_params) {
CONV_BUF_TYPE *dst16 = conv_params->dst;
int dst16_stride = conv_params->dst_stride; const int fo_vert = filter_params_y->taps / 2 - 1; const int bits = FILTER_BITS - conv_params->round_0; const int bd = 8; const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0; const int round_offset = (1 << (offset_bits - conv_params->round_1)) +
(1 << (offset_bits - conv_params->round_1 - 1)); const int round_bits = 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
// vertical filter const int16_t *y_filter = av1_get_interp_filter_subpel_kernel(
filter_params_y, subpel_y_qn & SUBPEL_MASK);
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t res = 0;
for (int k = 0; k < filter_params_y->taps; ++k) {
res += y_filter[k] * src[(y - fo_vert + k) * src_stride + x];
}
res *= (1 << bits);
res = ROUND_POWER_OF_TWO(res, conv_params->round_1) + round_offset;
void av1_convolve_2d_facade(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h, const InterpFilterParams *interp_filters[2], const int subpel_x_qn, int x_step_q4, const int subpel_y_qn, int y_step_q4, int scaled,
ConvolveParams *conv_params) {
(void)x_step_q4;
(void)y_step_q4;
(void)dst;
(void)dst_stride;
// This function is exactly the same as av1_highbd_convolve_y_sr_c, and is an // optimized version for intrabc. void av1_highbd_convolve_y_sr_intrabc_c( const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w,
int h, const InterpFilterParams *filter_params_y, const int subpel_y_qn,
int bd) {
assert(subpel_y_qn == 8);
assert(filter_params_y->taps == 2);
(void)filter_params_y;
(void)subpel_y_qn;
// vertical filter // explicitly operate for subpel_y_qn = 8.
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) { const int32_t res = src[x] + src[src_stride + x];
dst[x] = clip_pixel_highbd(ROUND_POWER_OF_TWO(res, 1), bd);
}
src += src_stride;
dst += dst_stride;
}
}
// This function is exactly the same as av1_highbd_convolve_x_sr_c, and is an // optimized version for intrabc. void av1_highbd_convolve_x_sr_intrabc_c( const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w,
int h, const InterpFilterParams *filter_params_x, const int subpel_x_qn,
ConvolveParams *conv_params, int bd) { const int bits = FILTER_BITS - conv_params->round_0;
assert(bits >= 0);
assert(subpel_x_qn == 8);
assert(filter_params_x->taps == 2);
assert((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS);
(void)filter_params_x;
(void)subpel_x_qn;
// horizontal filter // explicitly operate for subpel_x_qn = 8.
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
int32_t res = 64 * (src[x] + src[x + 1]);
res = ROUND_POWER_OF_TWO(res, conv_params->round_0);
dst[x] = clip_pixel_highbd(ROUND_POWER_OF_TWO(res, bits), bd);
}
src += src_stride;
dst += dst_stride;
}
}
void av1_highbd_dist_wtd_convolve_2d_c( const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w,
int h, const InterpFilterParams *filter_params_x, const InterpFilterParams *filter_params_y, const int subpel_x_qn, const int subpel_y_qn, ConvolveParams *conv_params, int bd) {
int x, y, k;
int16_t im_block[(MAX_SB_SIZE + MAX_FILTER_TAP - 1) * MAX_SB_SIZE];
CONV_BUF_TYPE *dst16 = conv_params->dst;
int dst16_stride = conv_params->dst_stride;
int im_h = h + filter_params_y->taps - 1;
int im_stride = w; const int fo_vert = filter_params_y->taps / 2 - 1; const int fo_horiz = filter_params_x->taps / 2 - 1; const int round_bits = 2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
assert(round_bits >= 0);
// horizontal filter const uint16_t *src_horiz = src - fo_vert * src_stride; const int16_t *x_filter = av1_get_interp_filter_subpel_kernel(
filter_params_x, subpel_x_qn & SUBPEL_MASK);
for (y = 0; y < im_h; ++y) {
for (x = 0; x < w; ++x) {
int32_t sum = (1 << (bd + FILTER_BITS - 1));
for (k = 0; k < filter_params_x->taps; ++k) {
sum += x_filter[k] * src_horiz[y * src_stride + x - fo_horiz + k];
}
assert(filter_params_x->taps > 8 ||
(0 <= sum && sum < (1 << (bd + FILTER_BITS + 1))));
(void)bd;
im_block[y * im_stride + x] =
(int16_t)ROUND_POWER_OF_TWO(sum, conv_params->round_0);
}
}
void av1_highbd_convolve_2d_facade(const uint8_t *src8, int src_stride,
uint8_t *dst8, int dst_stride, int w, int h, const InterpFilterParams *interp_filters[2], const int subpel_x_qn, int x_step_q4, const int subpel_y_qn, int y_step_q4,
int scaled, ConvolveParams *conv_params,
int bd) {
(void)x_step_q4;
(void)y_step_q4;
(void)dst_stride; const uint16_t *src = CONVERT_TO_SHORTPTR(src8);
// Note: Fixed size intermediate buffers, place limits on parameters // of some functions. 2d filtering proceeds in 2 steps: // (1) Interpolate horizontally into an intermediate buffer, temp. // (2) Interpolate temp vertically to derive the sub-pixel result. // Deriving the maximum number of rows in the temp buffer (135): // --Smallest scaling factor is x1/2 ==> y_step_q4 = 32 (Normative). // --Largest block size is 128x128 pixels. // --128 rows in the downscaled frame span a distance of (128 - 1) * 32 in the // original frame (in 1/16th pixel units). // --Must round-up because block may be located at sub-pixel position. // --Require an additional SUBPEL_TAPS rows for the 8-tap filter tails. // --((128 - 1) * 32 + 15) >> 4 + 8 = 263. #define WIENER_MAX_EXT_SIZE 263
#if !CONFIG_REALTIME_ONLY || CONFIG_AV1_DECODER static inline int horz_scalar_product(const uint8_t *a, const int16_t *b) {
int sum = 0;
for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k] * b[k]; return sum;
}
#if CONFIG_AV1_HIGHBITDEPTH static inline int highbd_horz_scalar_product(const uint16_t *a, const int16_t *b) {
int sum = 0;
for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k] * b[k]; return sum;
} #endif
static inline int highbd_vert_scalar_product(const uint16_t *a,
ptrdiff_t a_stride, const int16_t *b) {
int sum = 0;
for (int k = 0; k < SUBPEL_TAPS; ++k) sum += a[k * a_stride] * b[k]; return sum;
}
staticconst InterpKernel *get_filter_base(const int16_t *filter) { // NOTE: This assumes that the filter table is 256-byte aligned. // TODO(agrange) Modify to make independent of table alignment. return (const InterpKernel *)(((intptr_t)filter) & ~((intptr_t)0xFF));
}
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.