Commit eb939f45 authored by John Koleszar's avatar John Koleszar

Spatial resamping of ZEROMV predictors

This patch allows coding frames using references of different
resolution, in ZEROMV mode. For compound prediction, either
reference may be scaled.

To test, I use the resize_test and enable WRITE_RECON_BUFFER
in vp9_onyxd_if.c. It's also useful to apply this patch to
test/i420_video_source.h:

  --- a/test/i420_video_source.h
  +++ b/test/i420_video_source.h
  @@ -93,6 +93,7 @@ class I420VideoSource : public VideoSource {

     virtual void FillFrame() {
       // Read a frame from input_file.
  +    if (frame_ != 3)
       if (fread(img_->img_data, raw_sz_, 1, input_file_) == 0) {
         limit_ = frame_;
       }

This forces the frame that the resolution changes on to be coded
with no motion, only scaling, and improves the quality of the
result.

Change-Id: I1ee75d19a437ff801192f767fd02a36bcbd1d496
parent c7805395
......@@ -114,7 +114,8 @@ class ResizeInternalTest : public ResizeTest {
TEST_P(ResizeInternalTest, TestInternalResizeWorks) {
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 5);
30, 1, 0, 6);
cfg_.rc_target_bitrate = 5000;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (std::vector<FrameInfo>::iterator info = frame_info_list_.begin();
......
......@@ -292,9 +292,12 @@ struct scale_factors {
int x_num;
int x_den;
int x_offset_q4;
int x_step_q4;
int y_num;
int y_den;
int y_offset_q4;
int y_step_q4;
convolve_fn_t predict[2][2][2]; // horiz, vert, avg
};
typedef struct macroblockd {
......
......@@ -206,16 +206,25 @@ static void convolve_c(const uint8_t *src, int src_stride,
const int16_t *filter_x, int x_step_q4,
const int16_t *filter_y, int y_step_q4,
int w, int h, int taps) {
/* Fixed size intermediate buffer places limits on parameters. */
uint8_t temp[16 * 23];
/* Fixed size intermediate buffer places limits on parameters.
* Maximum intermediate_height is 39, for y_step_q4 == 32,
* h == 16, taps == 8.
*/
uint8_t temp[16 * 39];
int intermediate_height = ((h * y_step_q4) >> 4) + taps - 1;
assert(w <= 16);
assert(h <= 16);
assert(taps <= 8);
assert(y_step_q4 <= 32);
if (intermediate_height < h)
intermediate_height = h;
convolve_horiz_c(src - src_stride * (taps / 2 - 1), src_stride,
temp, 16,
filter_x, x_step_q4, filter_y, y_step_q4,
w, h + taps - 1, taps);
w, intermediate_height, taps);
convolve_vert_c(temp + 16 * (taps / 2 - 1), 16, dst, dst_stride,
filter_x, x_step_q4, filter_y, y_step_q4,
w, h, taps);
......@@ -226,16 +235,25 @@ static void convolve_avg_c(const uint8_t *src, int src_stride,
const int16_t *filter_x, int x_step_q4,
const int16_t *filter_y, int y_step_q4,
int w, int h, int taps) {
/* Fixed size intermediate buffer places limits on parameters. */
uint8_t temp[16 * 23];
/* Fixed size intermediate buffer places limits on parameters.
* Maximum intermediate_height is 39, for y_step_q4 == 32,
* h == 16, taps == 8.
*/
uint8_t temp[16 * 39];
int intermediate_height = ((h * y_step_q4) >> 4) + taps - 1;
assert(w <= 16);
assert(h <= 16);
assert(taps <= 8);
assert(y_step_q4 <= 32);
if (intermediate_height < h)
intermediate_height = h;
convolve_horiz_c(src - src_stride * (taps / 2 - 1), src_stride,
temp, 16,
filter_x, x_step_q4, filter_y, y_step_q4,
w, h + taps - 1, taps);
w, intermediate_height, taps);
convolve_avg_vert_c(temp + 16 * (taps / 2 - 1), 16, dst, dst_stride,
filter_x, x_step_q4, filter_y, y_step_q4,
w, h, taps);
......
......@@ -33,11 +33,8 @@ void vp9_convolve_avg(const uint8_t *src, int src_stride,
int w, int h);
struct subpix_fn_table {
convolve_fn_t predict[2][2][2]; // horiz, vert, avg
const int16_t (*filter_x)[8];
const int16_t (*filter_y)[8];
int x_step_q4;
int y_step_q4;
};
#endif // VP9_COMMON_CONVOLVE_H_
......@@ -15,7 +15,26 @@
#include "vp9_rtcd.h"
#include "vp9/common/vp9_common.h"
DECLARE_ALIGNED(16, const int16_t, vp9_bilinear_filters[SUBPEL_SHIFTS][8]) = {
/* TODO(jkoleszar): We can avoid duplicating these tables 2X by forcing 256
* byte alignment of the table's base address.
*/
DECLARE_ALIGNED(16, const int16_t, vp9_bilinear_filters[SUBPEL_SHIFTS*2][8]) = {
{ 0, 0, 0, 128, 0, 0, 0, 0 },
{ 0, 0, 0, 120, 8, 0, 0, 0 },
{ 0, 0, 0, 112, 16, 0, 0, 0 },
{ 0, 0, 0, 104, 24, 0, 0, 0 },
{ 0, 0, 0, 96, 32, 0, 0, 0 },
{ 0, 0, 0, 88, 40, 0, 0, 0 },
{ 0, 0, 0, 80, 48, 0, 0, 0 },
{ 0, 0, 0, 72, 56, 0, 0, 0 },
{ 0, 0, 0, 64, 64, 0, 0, 0 },
{ 0, 0, 0, 56, 72, 0, 0, 0 },
{ 0, 0, 0, 48, 80, 0, 0, 0 },
{ 0, 0, 0, 40, 88, 0, 0, 0 },
{ 0, 0, 0, 32, 96, 0, 0, 0 },
{ 0, 0, 0, 24, 104, 0, 0, 0 },
{ 0, 0, 0, 16, 112, 0, 0, 0 },
{ 0, 0, 0, 8, 120, 0, 0, 0 },
{ 0, 0, 0, 128, 0, 0, 0, 0 },
{ 0, 0, 0, 120, 8, 0, 0, 0 },
{ 0, 0, 0, 112, 16, 0, 0, 0 },
......@@ -36,7 +55,8 @@ DECLARE_ALIGNED(16, const int16_t, vp9_bilinear_filters[SUBPEL_SHIFTS][8]) = {
#define FILTER_ALPHA 0
#define FILTER_ALPHA_SHARP 1
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8[SUBPEL_SHIFTS][8]) = {
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8[SUBPEL_SHIFTS*2][8])
= {
#if FILTER_ALPHA == 0
/* Lagrangian interpolation filter */
{ 0, 0, 0, 128, 0, 0, 0, 0},
......@@ -54,6 +74,22 @@ DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8[SUBPEL_SHIFTS][8]) = {
{ -1, 4, -11, 37, 112, -16, 4, -1},
{ -1, 3, -9, 27, 118, -13, 4, -1},
{ 0, 2, -6, 18, 122, -10, 3, -1},
{ 0, 1, -3, 8, 126, -5, 1, 0},
{ 0, 0, 0, 128, 0, 0, 0, 0},
{ 0, 1, -5, 126, 8, -3, 1, 0},
{ -1, 3, -10, 122, 18, -6, 2, 0},
{ -1, 4, -13, 118, 27, -9, 3, -1},
{ -1, 4, -16, 112, 37, -11, 4, -1},
{ -1, 5, -18, 105, 48, -14, 4, -1},
{ -1, 5, -19, 97, 58, -16, 5, -1},
{ -1, 6, -19, 88, 68, -18, 5, -1},
{ -1, 6, -19, 78, 78, -19, 6, -1},
{ -1, 5, -18, 68, 88, -19, 6, -1},
{ -1, 5, -16, 58, 97, -19, 5, -1},
{ -1, 4, -14, 48, 105, -18, 5, -1},
{ -1, 4, -11, 37, 112, -16, 4, -1},
{ -1, 3, -9, 27, 118, -13, 4, -1},
{ 0, 2, -6, 18, 122, -10, 3, -1},
{ 0, 1, -3, 8, 126, -5, 1, 0}
#elif FILTER_ALPHA == 50
/* Generated using MATLAB:
......@@ -82,7 +118,8 @@ DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8[SUBPEL_SHIFTS][8]) = {
#endif /* FILTER_ALPHA */
};
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8s[SUBPEL_SHIFTS][8]) = {
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8s[SUBPEL_SHIFTS*2][8])
= {
#if FILTER_ALPHA_SHARP == 1
/* dct based filter */
{0, 0, 0, 128, 0, 0, 0, 0},
......@@ -100,6 +137,22 @@ DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8s[SUBPEL_SHIFTS][8]) = {
{-2, 6, -13, 37, 115, -20, 9, -4},
{-2, 5, -10, 27, 121, -17, 7, -3},
{-1, 3, -6, 17, 125, -13, 5, -2},
{0, 1, -3, 8, 127, -7, 3, -1},
{0, 0, 0, 128, 0, 0, 0, 0},
{-1, 3, -7, 127, 8, -3, 1, 0},
{-2, 5, -13, 125, 17, -6, 3, -1},
{-3, 7, -17, 121, 27, -10, 5, -2},
{-4, 9, -20, 115, 37, -13, 6, -2},
{-4, 10, -23, 108, 48, -16, 8, -3},
{-4, 10, -24, 100, 59, -19, 9, -3},
{-4, 11, -24, 90, 70, -21, 10, -4},
{-4, 11, -23, 80, 80, -23, 11, -4},
{-4, 10, -21, 70, 90, -24, 11, -4},
{-3, 9, -19, 59, 100, -24, 10, -4},
{-3, 8, -16, 48, 108, -23, 10, -4},
{-2, 6, -13, 37, 115, -20, 9, -4},
{-2, 5, -10, 27, 121, -17, 7, -3},
{-1, 3, -6, 17, 125, -13, 5, -2},
{0, 1, -3, 8, 127, -7, 3, -1}
#elif FILTER_ALPHA_SHARP == 75
/* alpha = 0.75 */
......@@ -123,7 +176,7 @@ DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_8s[SUBPEL_SHIFTS][8]) = {
};
DECLARE_ALIGNED(16, const int16_t,
vp9_sub_pel_filters_8lp[SUBPEL_SHIFTS][8]) = {
vp9_sub_pel_filters_8lp[SUBPEL_SHIFTS*2][8]) = {
/* 8-tap lowpass filter */
/* Hamming window */
{-1, -7, 32, 80, 32, -7, -1, 0},
......@@ -141,10 +194,43 @@ DECLARE_ALIGNED(16, const int16_t,
{ 1, -3, -4, 50, 76, 16, -8, 0},
{ 1, -3, -5, 45, 78, 20, -8, 0},
{ 1, -2, -7, 41, 79, 24, -8, 0},
{ 1, -2, -7, 37, 80, 28, -8, -1},
{-1, -7, 32, 80, 32, -7, -1, 0},
{-1, -8, 28, 80, 37, -7, -2, 1},
{ 0, -8, 24, 79, 41, -7, -2, 1},
{ 0, -8, 20, 78, 45, -5, -3, 1},
{ 0, -8, 16, 76, 50, -4, -3, 1},
{ 0, -7, 13, 74, 54, -3, -4, 1},
{ 1, -7, 9, 71, 58, -1, -4, 1},
{ 1, -6, 6, 68, 62, 1, -5, 1},
{ 1, -6, 4, 65, 65, 4, -6, 1},
{ 1, -5, 1, 62, 68, 6, -6, 1},
{ 1, -4, -1, 58, 71, 9, -7, 1},
{ 1, -4, -3, 54, 74, 13, -7, 0},
{ 1, -3, -4, 50, 76, 16, -8, 0},
{ 1, -3, -5, 45, 78, 20, -8, 0},
{ 1, -2, -7, 41, 79, 24, -8, 0},
{ 1, -2, -7, 37, 80, 28, -8, -1}
};
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_6[SUBPEL_SHIFTS][8]) = {
DECLARE_ALIGNED(16, const int16_t, vp9_sub_pel_filters_6[SUBPEL_SHIFTS*2][8])
= {
{0, 0, 0, 128, 0, 0, 0, 0},
{0, 1, -5, 125, 8, -2, 1, 0},
{0, 1, -8, 122, 17, -5, 1, 0},
{0, 2, -11, 116, 27, -8, 2, 0},
{0, 3, -14, 110, 37, -10, 2, 0},
{0, 3, -15, 103, 47, -12, 2, 0},
{0, 3, -16, 95, 57, -14, 3, 0},
{0, 3, -16, 86, 67, -15, 3, 0},
{0, 3, -16, 77, 77, -16, 3, 0},
{0, 3, -15, 67, 86, -16, 3, 0},
{0, 3, -14, 57, 95, -16, 3, 0},
{0, 2, -12, 47, 103, -15, 3, 0},
{0, 2, -10, 37, 110, -14, 3, 0},
{0, 2, -8, 27, 116, -11, 2, 0},
{0, 1, -5, 17, 122, -8, 1, 0},
{0, 1, -2, 8, 125, -5, 1, 0},
{0, 0, 0, 128, 0, 0, 0, 0},
{0, 1, -5, 125, 8, -2, 1, 0},
{0, 1, -8, 122, 17, -5, 1, 0},
......
......@@ -21,11 +21,11 @@
#define SUBPEL_SHIFTS 16
extern const int16_t vp9_bilinear_filters[SUBPEL_SHIFTS][8];
extern const int16_t vp9_sub_pel_filters_6[SUBPEL_SHIFTS][8];
extern const int16_t vp9_sub_pel_filters_8[SUBPEL_SHIFTS][8];
extern const int16_t vp9_sub_pel_filters_8s[SUBPEL_SHIFTS][8];
extern const int16_t vp9_sub_pel_filters_8lp[SUBPEL_SHIFTS][8];
extern const int16_t vp9_bilinear_filters[SUBPEL_SHIFTS*2][8];
extern const int16_t vp9_sub_pel_filters_6[SUBPEL_SHIFTS*2][8];
extern const int16_t vp9_sub_pel_filters_8[SUBPEL_SHIFTS*2][8];
extern const int16_t vp9_sub_pel_filters_8s[SUBPEL_SHIFTS*2][8];
extern const int16_t vp9_sub_pel_filters_8lp[SUBPEL_SHIFTS*2][8];
// The VP9_BILINEAR_FILTERS_2TAP macro returns a pointer to the bilinear
// filter kernel as a 2 tap filter.
......
......@@ -71,17 +71,6 @@ static void setup_macroblock(MACROBLOCKD *xd, BLOCKSET bs) {
setup_block(&blockd[block + 4], stride, v, v2, stride,
((block - 16) >> 1) * 4 * stride + (block & 1) * 4, bs);
}
// TODO(jkoleszar): this will move once we're actually scaling.
xd->scale_factor[0].x_num = 1;
xd->scale_factor[0].x_den = 1;
xd->scale_factor[0].y_num = 1;
xd->scale_factor[0].y_den = 1;
xd->scale_factor[0].x_offset_q4 = 0;
xd->scale_factor[0].y_offset_q4 = 0;
xd->scale_factor[1]= xd->scale_factor[0];
xd->scale_factor_uv[0] = xd->scale_factor[0];
xd->scale_factor_uv[1] = xd->scale_factor[1];
}
void vp9_setup_block_dptrs(MACROBLOCKD *xd) {
......
......@@ -145,6 +145,7 @@ typedef struct VP9Common {
*/
int active_ref_idx[3]; /* each frame can reference 3 buffers */
int new_fb_idx;
struct scale_factors active_ref_scale[3];
YV12_BUFFER_CONFIG post_proc_buffer;
YV12_BUFFER_CONFIG temp_scale_frame;
......
......@@ -17,26 +17,97 @@
#include "vp9/common/vp9_reconinter.h"
#include "vp9/common/vp9_reconintra.h"
void vp9_setup_interp_filters(MACROBLOCKD *xd,
INTERPOLATIONFILTERTYPE mcomp_filter_type,
VP9_COMMON *cm) {
void vp9_setup_scale_factors_for_frame(struct scale_factors *scale,
YV12_BUFFER_CONFIG *other,
int this_w, int this_h) {
int other_w, other_h;
other_h = other->y_height;
other_w = other->y_width;
scale->x_num = other_w;
scale->x_den = this_w;
scale->x_offset_q4 = 0; // calculated per-mb
scale->x_step_q4 = 16 * other_w / this_w;
scale->y_num = other_h;
scale->y_den = this_h;
scale->y_offset_q4 = 0; // calculated per-mb
scale->y_step_q4 = 16 * other_h / this_h;
// 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.
xd->subpix.predict[0][0][0] = vp9_convolve_copy;
xd->subpix.predict[0][0][1] = vp9_convolve_avg;
xd->subpix.predict[0][1][0] = vp9_convolve8_vert;
xd->subpix.predict[0][1][1] = vp9_convolve8_avg_vert;
xd->subpix.predict[1][0][0] = vp9_convolve8_horiz;
xd->subpix.predict[1][0][1] = vp9_convolve8_avg_horiz;
xd->subpix.predict[1][1][0] = vp9_convolve8;
xd->subpix.predict[1][1][1] = vp9_convolve8_avg;
xd->subpix.x_step_q4 = 16;
xd->subpix.y_step_q4 = 16;
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,
VP9_COMMON *cm) {
int i;
/* Calculate scaling factors for each of the 3 available references */
for (i = 0; i < 3; ++i) {
if (cm->active_ref_idx[i] >= NUM_YV12_BUFFERS) {
memset(&cm->active_ref_scale[i], 0, sizeof(cm->active_ref_scale[i]));
continue;
}
vp9_setup_scale_factors_for_frame(&cm->active_ref_scale[i],
&cm->yv12_fb[cm->active_ref_idx[i]],
cm->mb_cols * 16, cm->mb_rows * 16);
}
if (xd->mode_info_context) {
MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi;
set_scale_factors(xd,
mbmi->ref_frame - 1,
mbmi->second_ref_frame - 1,
cm->active_ref_scale);
}
switch (mcomp_filter_type) {
case EIGHTTAP:
case SWITCHABLE:
......@@ -146,30 +217,50 @@ void vp9_copy_mem8x4_c(const uint8_t *src,
}
}
static int32_t scale_motion_vector_component(int mv,
int num,
int den,
int offset_q4) {
static void set_scaled_offsets(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_num / scale->x_den) & 0xf;
scale->y_offset_q4 = (y_q4 * scale->y_num / scale->y_den) & 0xf;
}
static int32_t scale_motion_vector_component_q3(int mv_q3,
int num,
int den,
int offset_q4) {
// returns the scaled and offset value of the mv component.
const int32_t mv_q4 = mv_q3 << 1;
/* TODO(jkoleszar): make fixed point, or as a second multiply? */
return mv_q4 * num / den + offset_q4;
}
static int32_t scale_motion_vector_component_q4(int mv_q4,
int num,
int den,
int offset_q4) {
// returns the scaled and offset value of the mv component.
// input and output mv have the same units -- this would work with either q3
// or q4 motion vectors. Offset is given as a q4 fractional number.
const int32_t mv_q4 = mv * 16;
/* TODO(jkoleszar): make fixed point, or as a second multiply? */
return (mv_q4 * num / den + offset_q4 + 8) >> 4;
return mv_q4 * num / den + offset_q4;
}
static int_mv32 scale_motion_vector(const int_mv *src_mv,
const struct scale_factors *scale) {
static int_mv32 scale_motion_vector_q3_to_q4(
const int_mv *src_mv,
const struct scale_factors *scale) {
// returns mv * scale + offset
int_mv32 result;
result.as_mv.row = scale_motion_vector_component(src_mv->as_mv.row,
scale->y_num, scale->y_den,
scale->y_offset_q4);
result.as_mv.col = scale_motion_vector_component(src_mv->as_mv.col,
scale->x_num, scale->x_den,
scale->x_offset_q4);
result.as_mv.row = scale_motion_vector_component_q3(src_mv->as_mv.row,
scale->y_num,
scale->y_den,
scale->y_offset_q4);
result.as_mv.col = scale_motion_vector_component_q3(src_mv->as_mv.col,
scale->x_num,
scale->x_den,
scale->x_offset_q4);
return result;
}
......@@ -181,12 +272,13 @@ void vp9_build_inter_predictor(const uint8_t *src, int src_stride,
const struct subpix_fn_table *subpix) {
int_mv32 mv;
mv = scale_motion_vector(mv_q3, scale);
src = src + (mv.as_mv.row >> 3) * src_stride + (mv.as_mv.col >> 3);
subpix->predict[!!(mv.as_mv.col & 7)][!!(mv.as_mv.row & 7)][do_avg](
mv = scale_motion_vector_q3_to_q4(mv_q3, scale);
src = src + (mv.as_mv.row >> 4) * src_stride + (mv.as_mv.col >> 4);
scale->predict[!!(mv.as_mv.col & 15)][!!(mv.as_mv.row & 15)][do_avg](
src, src_stride, dst, dst_stride,
subpix->filter_x[(mv.as_mv.col & 7) << 1], subpix->x_step_q4,
subpix->filter_y[(mv.as_mv.row & 7) << 1], subpix->y_step_q4,
subpix->filter_x[mv.as_mv.col & 15], scale->x_step_q4,
subpix->filter_y[mv.as_mv.row & 15], scale->y_step_q4,
w, h);
}
......@@ -205,19 +297,19 @@ void vp9_build_inter_predictor_q4(const uint8_t *src, int src_stride,
const int mv_col_q4 = ((fullpel_mv_q3->as_mv.col >> 3) << 4)
+ (frac_mv_q4->as_mv.col & 0xf);
const int scaled_mv_row_q4 =
scale_motion_vector_component(mv_row_q4, scale->y_num, scale->y_den,
scale->y_offset_q4);
scale_motion_vector_component_q4(mv_row_q4, scale->y_num, scale->y_den,
scale->y_offset_q4);
const int scaled_mv_col_q4 =
scale_motion_vector_component(mv_col_q4, scale->x_num, scale->x_den,
scale->x_offset_q4);
scale_motion_vector_component_q4(mv_col_q4, scale->x_num, scale->x_den,
scale->x_offset_q4);
const int subpel_x = scaled_mv_col_q4 & 15;
const int subpel_y = scaled_mv_row_q4 & 15;
src = src + (scaled_mv_row_q4 >> 4) * src_stride + (scaled_mv_col_q4 >> 4);
subpix->predict[!!subpel_x][!!subpel_y][do_avg](
scale->predict[!!subpel_x][!!subpel_y][do_avg](
src, src_stride, dst, dst_stride,
subpix->filter_x[subpel_x], subpix->x_step_q4,
subpix->filter_y[subpel_y], subpix->y_step_q4,
subpix->filter_x[subpel_x], scale->x_step_q4,
subpix->filter_y[subpel_y], scale->y_step_q4,
w, h);
}
......@@ -261,7 +353,9 @@ static void build_2x1_inter_predictor(const BLOCKD *d0, const BLOCKD *d1,
}
/*encoder only*/
void vp9_build_inter4x4_predictors_mbuv(MACROBLOCKD *xd) {
void vp9_build_inter4x4_predictors_mbuv(MACROBLOCKD *xd,
int mb_row,
int mb_col) {
int i, j;
BLOCKD *blockd = xd->block;
......@@ -339,11 +433,17 @@ void vp9_build_inter4x4_predictors_mbuv(MACROBLOCKD *xd) {
for (i = 16; i < 24; i += 2) {
const int use_second_ref = xd->mode_info_context->mbmi.second_ref_frame > 0;
const int x = 4 * (i & 1);
const int y = ((i - 16) >> 1) * 4;
int which_mv;
BLOCKD *d0 = &blockd[i];
BLOCKD *d1 = &blockd[i + 1];
for (which_mv = 0; which_mv < 1 + use_second_ref; ++which_mv) {
set_scaled_offsets(&xd->scale_factor_uv[which_mv],
mb_row * 8 + y, mb_col * 8 + x);
build_2x1_inter_predictor(d0, d1, xd->scale_factor_uv, 4, 8, which_mv,
&xd->subpix);
}
......@@ -389,7 +489,9 @@ static void clamp_uvmv_to_umv_border(MV *mv, const MACROBLOCKD *xd) {
/*encoder only*/
void vp9_build_inter16x16_predictors_mby(MACROBLOCKD *xd,
uint8_t *dst_y,
int dst_ystride) {
int dst_ystride,
int mb_row,
int mb_col) {
const int use_second_ref = xd->mode_info_context->mbmi.second_ref_frame > 0;
int which_mv;
......@@ -399,14 +501,19 @@ void vp9_build_inter16x16_predictors_mby(MACROBLOCKD *xd,
: xd->mode_info_context->mbmi.need_to_clamp_mvs;
uint8_t *base_pre;
int_mv ymv;
int pre_stride;
ymv.as_int = xd->mode_info_context->mbmi.mv[which_mv].as_int;
base_pre = which_mv ? xd->second_pre.y_buffer
: xd->pre.y_buffer;
pre_stride = which_mv ? xd->second_pre.y_stride
: xd->pre.y_stride;
if (clamp_mvs)
clamp_mv_to_umv_border(&ymv.as_mv, xd);
vp9_build_inter_predictor(base_pre, xd->block[0].pre_stride,
set_scaled_offsets(&xd->scale_factor[which_mv], mb_row * 16, mb_col * 16);
vp9_build_inter_predictor(base_pre, pre_stride,
dst_y, dst_ystride,
&ymv, &xd->scale_factor[which_mv],
16, 16, which_mv, &xd->subpix);
......@@ -416,7 +523,9 @@ void vp9_build_inter16x16_predictors_mby(MACROBLOCKD *xd,
void vp9_build_inter16x16_predictors_mbuv(MACROBLOCKD *xd,
uint8_t *dst_u,
uint8_t *dst_v,
int dst_uvstride) {
int dst_uvstride,
int mb_row,
int mb_col) {
const int use_second_ref = xd->mode_info_context->mbmi.second_ref_frame > 0;
int which_mv;
......@@ -425,7 +534,8 @@ void vp9_build_inter16x16_predictors_mbuv(MACROBLOCKD *xd,
which_mv ? xd->mode_info_context->mbmi.need_to_clamp_secondmv
: xd->mode_info_context->mbmi.need_to_clamp_mvs;
uint8_t *uptr, *vptr;
int pre_stride = xd->block[0].pre_stride;
int pre_stride = which_mv ? xd->second_pre.y_stride
: xd->pre.y_stride;
int_mv _o16x16mv;
int_mv _16x16mv;
......@@ -456,6 +566,9 @@ void vp9_build_inter16x16_predictors_mbuv(MACROBLOCKD *xd,
uptr = (which_mv ? xd->second_pre.u_buffer : xd->pre.u_buffer);
vptr = (which_mv ? xd->second_pre.v_buffer : xd->pre.v_buffer);
set_scaled_offsets(&xd->scale_factor_uv[which_mv],
mb_row * 16, mb_col * 16);