Commit 505f0068 authored by Fergus Simpson's avatar Fergus Simpson Committed by Debargha Mukherjee

Fix frame scaling prediction

Use higher precision offsets for more accurate predictor
generation when references are at a different scale from
the coded frame.

Change-Id: I4c2c0ec67fa4824273cb3bd072211f41ac7802e8
parent 15836145
This diff is collapsed.
......@@ -164,6 +164,13 @@ add_proto qw/void aom_scaled_avg_2d/, "const uint8_t *src, ptrdiff_t src_s
add_proto qw/void aom_scaled_avg_horiz/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h";
add_proto qw/void aom_scaled_avg_vert/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4, const int16_t *filter_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_horiz_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_vert_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_avg_horiz_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_avg_vert_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
add_proto qw/void aom_convolve8_avg_scale/, "const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *filter_x, int subpel_x, int x_step_q4, const int16_t *filter_y, int subpel_y, int y_step_q4, int w, int h";
specialize qw/aom_convolve_copy sse2 /;
specialize qw/aom_convolve_avg sse2 /;
specialize qw/aom_convolve8 sse2 ssse3/, "$avx2_ssse3";
......
......@@ -25,6 +25,12 @@ extern "C" {
#define SUBPEL_SHIFTS (1 << SUBPEL_BITS)
#define SUBPEL_TAPS 8
#define SCALE_SUBPEL_BITS 10
#define SCALE_SUBPEL_SHIFTS (1 << SCALE_SUBPEL_BITS)
#define SCALE_SUBPEL_MASK (SCALE_SUBPEL_SHIFTS - 1)
#define SCALE_EXTRA_BITS (SCALE_SUBPEL_BITS - SUBPEL_BITS)
#define SCALE_EXTRA_OFF ((1 << SCALE_EXTRA_BITS) / 2)
typedef int16_t InterpKernel[SUBPEL_TAPS];
#define BIL_SUBPEL_BITS 3
......
This diff is collapsed.
......@@ -114,6 +114,16 @@ void av1_convolve_c(const uint8_t *src, int src_stride, uint8_t *dst,
const int subpel_x, int xstep, const int subpel_y,
int ystep, ConvolveParams *conv_params);
void av1_convolve_scale(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h,
#if CONFIG_DUAL_FILTER
const InterpFilter *interp_filter,
#else
const InterpFilter interp_filter,
#endif
const int subpel_x, int xstep, const int subpel_y,
int ystep, ConvolveParams *conv_params);
#if CONFIG_HIGHBITDEPTH
void av1_highbd_convolve(const uint8_t *src, int src_stride, uint8_t *dst,
int dst_stride, int w, int h,
......
......@@ -827,6 +827,8 @@ void av1_highbd_build_inter_predictor(
const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
is_q4 ? src_mv->col : src_mv->col * 2 };
MV32 mv = av1_scale_mv(&mv_q4, x, y, sf);
mv.col += SCALE_EXTRA_OFF;
mv.row += SCALE_EXTRA_OFF;
const int subpel_x = mv.col & SCALE_SUBPEL_MASK;
const int subpel_y = mv.row & SCALE_SUBPEL_MASK;
ConvolveParams conv_params = get_conv_params(ref, ref, plane);
......@@ -865,6 +867,8 @@ void av1_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst,
const MV mv_q4 = { is_q4 ? src_mv->row : src_mv->row * 2,
is_q4 ? src_mv->col : src_mv->col * 2 };
MV32 mv = av1_scale_mv(&mv_q4, x, y, sf);
mv.col += SCALE_EXTRA_OFF;
mv.row += SCALE_EXTRA_OFF;
const int subpel_x = mv.col & SCALE_SUBPEL_MASK;
const int subpel_y = mv.row & SCALE_SUBPEL_MASK;
......@@ -1039,6 +1043,8 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane,
orig_pos_x += mv.col * (1 << (1 - ssx));
int pos_y = sf->scale_value_y(orig_pos_y, sf);
int pos_x = sf->scale_value_x(orig_pos_x, sf);
pos_x += SCALE_EXTRA_OFF;
pos_y += SCALE_EXTRA_OFF;
const int top = -((AOM_INTERP_EXTEND + bh) << SCALE_SUBPEL_BITS);
const int bottom = (pre_buf->height + AOM_INTERP_EXTEND)
......@@ -1160,6 +1166,8 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane,
orig_pos_x += mv.col * (1 << (1 - ssx));
int pos_y = sf->scale_value_y(orig_pos_y, sf);
int pos_x = sf->scale_value_x(orig_pos_x, sf);
pos_x += SCALE_EXTRA_OFF;
pos_y += SCALE_EXTRA_OFF;
// Clamp against the reference frame borders, with enough extension
// that we don't force the reference block to be partially onscreen.
......@@ -3014,6 +3022,8 @@ static void build_inter_predictors_single_buf(MACROBLOCKD *xd, int plane,
orig_pos_x += mv.col * (1 << (1 - ssx));
int pos_y = sf->scale_value_y(orig_pos_y, sf);
int pos_x = sf->scale_value_x(orig_pos_x, sf);
pos_x += SCALE_EXTRA_OFF;
pos_y += SCALE_EXTRA_OFF;
const int top = -((AOM_INTERP_EXTEND + bh) << SCALE_SUBPEL_BITS);
const int bottom = (pre_buf->height + AOM_INTERP_EXTEND)
......
......@@ -66,10 +66,8 @@ static INLINE void inter_predictor(const uint8_t *src, int src_stride,
if (has_scale(xs, ys)) {
// TODO(afergs, debargha): Use a different scale convolve function
// that uses higher precision for subpel_x, subpel_y, xs, ys
av1_convolve_c(src, src_stride, dst, dst_stride, w, h, interp_filter,
subpel_x >> SCALE_EXTRA_BITS, xs >> SCALE_EXTRA_BITS,
subpel_y >> SCALE_EXTRA_BITS, ys >> SCALE_EXTRA_BITS,
conv_params);
av1_convolve_scale(src, src_stride, dst, dst_stride, w, h, interp_filter,
subpel_x, xs, subpel_y, ys, conv_params);
} else {
subpel_x >>= SCALE_EXTRA_BITS;
subpel_y >>= SCALE_EXTRA_BITS;
......
......@@ -1055,8 +1055,13 @@ YV12_BUFFER_CONFIG *av1_scale_if_required(AV1_COMMON *cm,
}
void av1_calculate_scaled_size(int *width, int *height, int num) {
if (num != SCALE_DENOMINATOR) {
*width = *width * num / SCALE_DENOMINATOR;
*height = *height * num / SCALE_DENOMINATOR;
// Make width and height even
*width += *width & 1;
*height += *height & 1;
}
}
#if CONFIG_FRAME_SUPERRES
......
......@@ -16,14 +16,20 @@
// Note: Expect val to be in q4 precision
static INLINE int scaled_x(int val, const struct scale_factors *sf) {
return (int)((int64_t)val * sf->x_scale_fp >>
(REF_SCALE_SHIFT - SCALE_EXTRA_BITS));
const int off = (sf->x_scale_fp - (1 << REF_SCALE_SHIFT))
<< (SUBPEL_BITS - 1);
const int64_t tval = (int64_t)val * sf->x_scale_fp + off;
return (int)ROUND_POWER_OF_TWO_SIGNED_64(tval,
REF_SCALE_SHIFT - SCALE_EXTRA_BITS);
}
// Note: Expect val to be in q4 precision
static INLINE int scaled_y(int val, const struct scale_factors *sf) {
return (int)((int64_t)val * sf->y_scale_fp >>
(REF_SCALE_SHIFT - SCALE_EXTRA_BITS));
const int off = (sf->y_scale_fp - (1 << REF_SCALE_SHIFT))
<< (SUBPEL_BITS - 1);
const int64_t tval = (int64_t)val * sf->y_scale_fp + off;
return (int)ROUND_POWER_OF_TWO_SIGNED_64(tval,
REF_SCALE_SHIFT - SCALE_EXTRA_BITS);
}
// Note: Expect val to be in q4 precision
......@@ -37,16 +43,24 @@ static int get_fixed_point_scale_factor(int other_size, int this_size) {
// and use fixed point scaling factors in decoding and encoding routines.
// Hardware implementations can calculate scale factor in device driver
// and use multiplication and shifting on hardware instead of division.
return (other_size << REF_SCALE_SHIFT) / this_size;
return ((other_size << REF_SCALE_SHIFT) + this_size / 2) / this_size;
}
// Note: x and y are integer precision, mv is g4 precision.
static int get_coarse_point_scale_factor(int other_size, int this_size) {
// Calculate scaling factor once for each reference frame
// and use fixed point scaling factors in decoding and encoding routines.
// Hardware implementations can calculate scale factor in device driver
// and use multiplication and shifting on hardware instead of division.
return ((other_size << SCALE_SUBPEL_BITS) + this_size / 2) / this_size;
}
// Note: x and y are integer precision, mvq4 is q4 precision.
MV32 av1_scale_mv(const MV *mvq4, int x, int y,
const struct scale_factors *sf) {
const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf) & SCALE_SUBPEL_MASK;
const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf) & SCALE_SUBPEL_MASK;
const MV32 res = { scaled_y(mvq4->row, sf) + y_off_q4,
scaled_x(mvq4->col, sf) + x_off_q4 };
const int x_off_q4 = scaled_x(x << SUBPEL_BITS, sf);
const int y_off_q4 = scaled_y(y << SUBPEL_BITS, sf);
const MV32 res = { scaled_y((y << SUBPEL_BITS) + mvq4->row, sf) - y_off_q4,
scaled_x((x << SUBPEL_BITS) + mvq4->col, sf) - x_off_q4 };
return res;
}
......@@ -66,8 +80,9 @@ void av1_setup_scale_factors_for_frame(struct scale_factors *sf, int other_w,
sf->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w);
sf->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h);
sf->x_step_q4 = scaled_x(SUBPEL_SHIFTS, sf);
sf->y_step_q4 = scaled_y(SUBPEL_SHIFTS, sf);
sf->x_step_q4 = get_coarse_point_scale_factor(other_w, this_w);
sf->y_step_q4 = get_coarse_point_scale_factor(other_h, this_h);
if (av1_is_scaled(sf)) {
sf->scale_value_x = scaled_x;
......
......@@ -21,11 +21,6 @@ extern "C" {
#define SCALE_DENOMINATOR 16
#define SCALE_SUBPEL_BITS 8
#define SCALE_SUBPEL_SHIFTS (1 << SCALE_SUBPEL_BITS)
#define SCALE_SUBPEL_MASK (SCALE_SUBPEL_SHIFTS - 1)
#define SCALE_EXTRA_BITS (SCALE_SUBPEL_BITS - SUBPEL_BITS)
#define REF_SCALE_SHIFT 14
#define REF_NO_SCALE (1 << REF_SCALE_SHIFT)
#define REF_INVALID_SCALE -1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment