diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index 60ef9c207..d117e771b 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -19,9 +19,9 @@ #include "vp9/common/vp9_common.h" #include "vp9/common/vp9_common_data.h" -#include "vp9/common/vp9_convolve.h" #include "vp9/common/vp9_enums.h" #include "vp9/common/vp9_mv.h" +#include "vp9/common/vp9_scale.h" #include "vp9/common/vp9_seg_common.h" #include "vp9/common/vp9_treecoder.h" @@ -171,24 +171,6 @@ enum mv_precision { MV_PRECISION_Q4 }; -#define VP9_REF_SCALE_SHIFT 14 -#define VP9_REF_NO_SCALE (1 << VP9_REF_SCALE_SHIFT) - -struct scale_factors { - int x_scale_fp; // horizontal fixed point scale factor - int y_scale_fp; // vertical fixed point scale factor - int x_offset_q4; - int x_step_q4; - int y_offset_q4; - int y_step_q4; - - int (*scale_value_x)(int val, const struct scale_factors *scale); - int (*scale_value_y)(int val, const struct scale_factors *scale); - void (*set_scaled_offsets)(struct scale_factors *scale, int row, int col); - MV32 (*scale_mv)(const MV *mv, const struct scale_factors *scale); - - convolve_fn_t predict[2][2][2]; // horiz, vert, avg -}; #if CONFIG_ALPHA enum { MAX_MB_PLANE = 4 }; diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c index a163106a0..cb746c7f3 100644 --- a/vp9/common/vp9_reconinter.c +++ b/vp9/common/vp9_reconinter.c @@ -10,140 +10,16 @@ #include +#include "./vpx_scale_rtcd.h" #include "./vpx_config.h" + #include "vpx/vpx_integer.h" + #include "vp9/common/vp9_blockd.h" #include "vp9/common/vp9_filter.h" #include "vp9/common/vp9_reconinter.h" #include "vp9/common/vp9_reconintra.h" -#include "./vpx_scale_rtcd.h" -static int scale_value_x_with_scaling(int val, - const struct scale_factors *scale) { - return (val * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT); -} - -static int scale_value_y_with_scaling(int val, - const struct scale_factors *scale) { - return (val * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT); -} - -static int unscaled_value(int val, const struct scale_factors *scale) { - (void) scale; - return val; -} - -static MV32 mv_with_scaling(const MV *mv, - const struct scale_factors *scale) { - const MV32 res = { - (mv->row * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT) + scale->y_offset_q4, - (mv->col * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT) + scale->x_offset_q4 - }; - return res; -} - -static MV32 mv_without_scaling(const MV *mv, - const struct scale_factors *scale) { - const MV32 res = { - mv->row, - mv->col - }; - return res; -} - -static void set_offsets_with_scaling(struct scale_factors *scale, - int row, int col) { - const int x_q4 = 16 * col; - const int y_q4 = 16 * row; - - scale->x_offset_q4 = (x_q4 * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT) & 0xf; - scale->y_offset_q4 = (y_q4 * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT) & 0xf; -} - -static void set_offsets_without_scaling(struct scale_factors *scale, - int row, int col) { - scale->x_offset_q4 = 0; - scale->y_offset_q4 = 0; -} - -static int get_fixed_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 << VP9_REF_SCALE_SHIFT) / this_size; -} - -void vp9_setup_scale_factors_for_frame(struct scale_factors *scale, - int other_w, int other_h, - int this_w, int this_h) { - scale->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w); - scale->x_offset_q4 = 0; // calculated per-mb - scale->x_step_q4 = (16 * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT); - - scale->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h); - scale->y_offset_q4 = 0; // calculated per-mb - scale->y_step_q4 = (16 * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT); - - if ((other_w == this_w) && (other_h == this_h)) { - scale->scale_value_x = unscaled_value; - scale->scale_value_y = unscaled_value; - scale->set_scaled_offsets = set_offsets_without_scaling; - scale->scale_mv = mv_without_scaling; - } else { - scale->scale_value_x = scale_value_x_with_scaling; - scale->scale_value_y = scale_value_y_with_scaling; - scale->set_scaled_offsets = set_offsets_with_scaling; - scale->scale_mv = mv_with_scaling; - } - - // TODO(agrange): Investigate the best choice of functions to use here - // for EIGHTTAP_SMOOTH. Since it is not interpolating, need to choose what - // to do at full-pel offsets. The current selection, where the filter is - // applied in one direction only, and not at all for 0,0, seems to give the - // best quality, but it may be worth trying an additional mode that does - // do the filtering on full-pel. - if (scale->x_step_q4 == 16) { - if (scale->y_step_q4 == 16) { - // No scaling in either direction. - scale->predict[0][0][0] = vp9_convolve_copy; - scale->predict[0][0][1] = vp9_convolve_avg; - scale->predict[0][1][0] = vp9_convolve8_vert; - scale->predict[0][1][1] = vp9_convolve8_avg_vert; - scale->predict[1][0][0] = vp9_convolve8_horiz; - scale->predict[1][0][1] = vp9_convolve8_avg_horiz; - } else { - // No scaling in x direction. Must always scale in the y direction. - scale->predict[0][0][0] = vp9_convolve8_vert; - scale->predict[0][0][1] = vp9_convolve8_avg_vert; - scale->predict[0][1][0] = vp9_convolve8_vert; - scale->predict[0][1][1] = vp9_convolve8_avg_vert; - scale->predict[1][0][0] = vp9_convolve8; - scale->predict[1][0][1] = vp9_convolve8_avg; - } - } else { - if (scale->y_step_q4 == 16) { - // No scaling in the y direction. Must always scale in the x direction. - scale->predict[0][0][0] = vp9_convolve8_horiz; - scale->predict[0][0][1] = vp9_convolve8_avg_horiz; - scale->predict[0][1][0] = vp9_convolve8; - scale->predict[0][1][1] = vp9_convolve8_avg; - scale->predict[1][0][0] = vp9_convolve8_horiz; - scale->predict[1][0][1] = vp9_convolve8_avg_horiz; - } else { - // Must always scale in both directions. - scale->predict[0][0][0] = vp9_convolve8; - scale->predict[0][0][1] = vp9_convolve8_avg; - scale->predict[0][1][0] = vp9_convolve8; - scale->predict[0][1][1] = vp9_convolve8_avg; - scale->predict[1][0][0] = vp9_convolve8; - scale->predict[1][0][1] = vp9_convolve8_avg; - } - } - // 2D subpel motion always gets filtered in both directions - scale->predict[1][1][0] = vp9_convolve8; - scale->predict[1][1][1] = vp9_convolve8_avg; -} void vp9_setup_interp_filters(MACROBLOCKD *xd, INTERPOLATIONFILTERTYPE mcomp_filter_type, diff --git a/vp9/common/vp9_reconinter.h b/vp9/common/vp9_reconinter.h index 6ec7323e1..82c0796dc 100644 --- a/vp9/common/vp9_reconinter.h +++ b/vp9/common/vp9_reconinter.h @@ -33,10 +33,6 @@ void vp9_setup_interp_filters(MACROBLOCKD *xd, INTERPOLATIONFILTERTYPE filter, VP9_COMMON *cm); -void vp9_setup_scale_factors_for_frame(struct scale_factors *scale, - int other_w, int other_h, - int this_w, int this_h); - void vp9_build_inter_predictor(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, const MV *mv_q3, diff --git a/vp9/common/vp9_scale.c b/vp9/common/vp9_scale.c new file mode 100644 index 000000000..80137e547 --- /dev/null +++ b/vp9/common/vp9_scale.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "./vp9_rtcd.h" +#include "vp9/common/vp9_scale.h" + +static int scaled_x(int val, const struct scale_factors *scale) { + return val * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT; +} + +static int scaled_y(int val, const struct scale_factors *scale) { + return val * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT; +} + +static int unscaled_value(int val, const struct scale_factors *scale) { + (void) scale; + return val; +} + +static MV32 scaled_mv(const MV *mv, const struct scale_factors *scale) { + const MV32 res = { + (mv->row * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT) + scale->y_offset_q4, + (mv->col * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT) + scale->x_offset_q4 + }; + return res; +} + +static MV32 unscaled_mv(const MV *mv, const struct scale_factors *scale) { + const MV32 res = { + mv->row, + mv->col + }; + return res; +} + +static void set_offsets_with_scaling(struct scale_factors *scale, + int row, int col) { + const int x_q4 = 16 * col; + const int y_q4 = 16 * row; + + scale->x_offset_q4 = (x_q4 * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT) & 0xF; + scale->y_offset_q4 = (y_q4 * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT) & 0xF; +} + +static void set_offsets_without_scaling(struct scale_factors *scale, + int row, int col) { + scale->x_offset_q4 = 0; + scale->y_offset_q4 = 0; +} + +static int get_fixed_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 << VP9_REF_SCALE_SHIFT) / this_size; +} + +void vp9_setup_scale_factors_for_frame(struct scale_factors *scale, + int other_w, int other_h, + int this_w, int this_h) { + scale->x_scale_fp = get_fixed_point_scale_factor(other_w, this_w); + scale->x_offset_q4 = 0; // calculated per-mb + scale->x_step_q4 = (16 * scale->x_scale_fp >> VP9_REF_SCALE_SHIFT); + + scale->y_scale_fp = get_fixed_point_scale_factor(other_h, this_h); + scale->y_offset_q4 = 0; // calculated per-mb + scale->y_step_q4 = (16 * scale->y_scale_fp >> VP9_REF_SCALE_SHIFT); + + if (other_w == this_w && other_h == this_h) { + scale->scale_value_x = unscaled_value; + scale->scale_value_y = unscaled_value; + scale->set_scaled_offsets = set_offsets_without_scaling; + scale->scale_mv = unscaled_mv; + } else { + scale->scale_value_x = scaled_x; + scale->scale_value_y = scaled_y; + scale->set_scaled_offsets = set_offsets_with_scaling; + scale->scale_mv = scaled_mv; + } + + // TODO(agrange): Investigate the best choice of functions to use here + // for EIGHTTAP_SMOOTH. Since it is not interpolating, need to choose what + // to do at full-pel offsets. The current selection, where the filter is + // applied in one direction only, and not at all for 0,0, seems to give the + // best quality, but it may be worth trying an additional mode that does + // do the filtering on full-pel. + if (scale->x_step_q4 == 16) { + if (scale->y_step_q4 == 16) { + // No scaling in either direction. + scale->predict[0][0][0] = vp9_convolve_copy; + scale->predict[0][0][1] = vp9_convolve_avg; + scale->predict[0][1][0] = vp9_convolve8_vert; + scale->predict[0][1][1] = vp9_convolve8_avg_vert; + scale->predict[1][0][0] = vp9_convolve8_horiz; + scale->predict[1][0][1] = vp9_convolve8_avg_horiz; + } else { + // No scaling in x direction. Must always scale in the y direction. + scale->predict[0][0][0] = vp9_convolve8_vert; + scale->predict[0][0][1] = vp9_convolve8_avg_vert; + scale->predict[0][1][0] = vp9_convolve8_vert; + scale->predict[0][1][1] = vp9_convolve8_avg_vert; + scale->predict[1][0][0] = vp9_convolve8; + scale->predict[1][0][1] = vp9_convolve8_avg; + } + } else { + if (scale->y_step_q4 == 16) { + // No scaling in the y direction. Must always scale in the x direction. + scale->predict[0][0][0] = vp9_convolve8_horiz; + scale->predict[0][0][1] = vp9_convolve8_avg_horiz; + scale->predict[0][1][0] = vp9_convolve8; + scale->predict[0][1][1] = vp9_convolve8_avg; + scale->predict[1][0][0] = vp9_convolve8_horiz; + scale->predict[1][0][1] = vp9_convolve8_avg_horiz; + } else { + // Must always scale in both directions. + scale->predict[0][0][0] = vp9_convolve8; + scale->predict[0][0][1] = vp9_convolve8_avg; + scale->predict[0][1][0] = vp9_convolve8; + scale->predict[0][1][1] = vp9_convolve8_avg; + scale->predict[1][0][0] = vp9_convolve8; + scale->predict[1][0][1] = vp9_convolve8_avg; + } + } + // 2D subpel motion always gets filtered in both directions + scale->predict[1][1][0] = vp9_convolve8; + scale->predict[1][1][1] = vp9_convolve8_avg; +} diff --git a/vp9/common/vp9_scale.h b/vp9/common/vp9_scale.h new file mode 100644 index 000000000..0414dde5e --- /dev/null +++ b/vp9/common/vp9_scale.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VP9_COMMON_VP9_SCALE_H_ +#define VP9_COMMON_VP9_SCALE_H_ + +#include "vp9/common/vp9_mv.h" +#include "vp9/common/vp9_convolve.h" + +#define VP9_REF_SCALE_SHIFT 14 +#define VP9_REF_NO_SCALE (1 << VP9_REF_SCALE_SHIFT) + +struct scale_factors { + int x_scale_fp; // horizontal fixed point scale factor + int y_scale_fp; // vertical fixed point scale factor + int x_offset_q4; + int x_step_q4; + int y_offset_q4; + int y_step_q4; + + int (*scale_value_x)(int val, const struct scale_factors *scale); + int (*scale_value_y)(int val, const struct scale_factors *scale); + void (*set_scaled_offsets)(struct scale_factors *scale, int row, int col); + MV32 (*scale_mv)(const MV *mv, const struct scale_factors *scale); + + convolve_fn_t predict[2][2][2]; // horiz, vert, avg +}; + +void vp9_setup_scale_factors_for_frame(struct scale_factors *scale, + int other_w, int other_h, + int this_w, int this_h); + +#endif // VP9_COMMON_VP9_SCALE_H_ diff --git a/vp9/vp9_common.mk b/vp9/vp9_common.mk index f9ad4bedd..d6b3ec087 100644 --- a/vp9/vp9_common.mk +++ b/vp9/vp9_common.mk @@ -49,6 +49,8 @@ VP9_COMMON_SRCS-yes += common/vp9_rtcd.c VP9_COMMON_SRCS-yes += common/vp9_rtcd_defs.sh VP9_COMMON_SRCS-yes += common/vp9_sadmxn.h VP9_COMMON_SRCS-yes += common/vp9_subpelvar.h +VP9_COMMON_SRCS-yes += common/vp9_scale.h +VP9_COMMON_SRCS-yes += common/vp9_scale.c VP9_COMMON_SRCS-yes += common/vp9_seg_common.h VP9_COMMON_SRCS-yes += common/vp9_seg_common.c VP9_COMMON_SRCS-yes += common/vp9_systemdependent.h