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;
......
This diff is collapsed.
......@@ -18,42 +18,60 @@ struct subpix_fn_table;
void vp9_build_inter16x16_predictors_mby(MACROBLOCKD *xd,
uint8_t *dst_y,
int dst_ystride);
int dst_ystride,
int mb_row,
int mb_col);
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);
void vp9_build_inter16x16_predictors_mb(MACROBLOCKD *xd,
uint8_t *dst_y,
uint8_t *dst_u,
uint8_t *dst_v,
int dst_ystride,
int dst_uvstride);
int dst_uvstride,
int mb_row,
int mb_col);
void vp9_build_inter32x32_predictors_sb(MACROBLOCKD *x,
uint8_t *dst_y,
uint8_t *dst_u,
uint8_t *dst_v,
int dst_ystride,
int dst_uvstride);
int dst_uvstride,
int mb_row,
int mb_col);
void vp9_build_inter64x64_predictors_sb(MACROBLOCKD *x,
uint8_t *dst_y,
uint8_t *dst_u,
uint8_t *dst_v,
int dst_ystride,
int dst_uvstride);
int dst_uvstride,
int mb_row,
int mb_col);
void vp9_build_inter_predictors_mb(MACROBLOCKD *xd);
void vp9_build_inter_predictors_mb(MACROBLOCKD *xd,
int mb_row,
int mb_col);
void vp9_build_inter4x4_predictors_mbuv(MACROBLOCKD *xd);
void vp9_build_inter4x4_predictors_mbuv(MACROBLOCKD *xd,
int mb_row,
int mb_col);
void vp9_setup_interp_filters(MACROBLOCKD *xd,
INTERPOLATIONFILTERTYPE filter,
VP9_COMMON *cm);
void vp9_setup_scale_factors_for_frame(struct scale_factors *scale,
YV12_BUFFER_CONFIG *other,
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 int_mv *mv_q3,
......@@ -69,4 +87,55 @@ void vp9_build_inter_predictor_q4(const uint8_t *src, int src_stride,
int w, int h, int do_avg,
const struct subpix_fn_table *subpix);
static int scale_value_x(int val, const struct scale_factors *scale) {
return val * scale->x_num / scale->x_den;
}
static int scale_value_y(int val, const struct scale_factors *scale) {
return val * scale->y_num / scale->y_den;
}
static int scaled_buffer_offset(int x_offset,
int y_offset,
int stride,
const struct scale_factors *scale) {
return scale_value_y(y_offset, scale) * stride +
scale_value_x(x_offset, scale);
}
static void setup_pred_block(YV12_BUFFER_CONFIG *dst,
const YV12_BUFFER_CONFIG *src,
int mb_row, int mb_col,
const struct scale_factors *scale,
const struct scale_factors *scale_uv) {
const int recon_y_stride = src->y_stride;
const int recon_uv_stride = src->uv_stride;
int recon_yoffset;
int recon_uvoffset;
if (scale) {
recon_yoffset = scaled_buffer_offset(16 * mb_col, 16 * mb_row,
recon_y_stride, scale);
recon_uvoffset = scaled_buffer_offset(8 * mb_col, 8 * mb_row,
recon_uv_stride, scale_uv);
} else {
recon_yoffset = 16 * mb_row * recon_y_stride + 16 * mb_col;
recon_uvoffset = 8 * mb_row * recon_uv_stride + 8 * mb_col;
}
*dst = *src;
dst->y_buffer += recon_yoffset;
dst->u_buffer += recon_uvoffset;
dst->v_buffer += recon_uvoffset;
}
static void set_scale_factors(MACROBLOCKD *xd,
int ref0, int ref1,
struct scale_factors scale_factor[MAX_REF_FRAMES]) {
xd->scale_factor[0] = scale_factor[ref0 >= 0 ? ref0 : 0];
xd->scale_factor[1] = scale_factor[ref1 >= 0 ? ref1 : 0];
xd->scale_factor_uv[0] = xd->scale_factor[0];
xd->scale_factor_uv[1] = xd->scale_factor[1];
}
#endif // VP9_COMMON_VP9_RECONINTER_H_
......@@ -12,6 +12,7 @@
#include "vp9/decoder/vp9_treereader.h"
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_reconinter.h"
#include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/common/vp9_findnearmv.h"
#include "vp9/common/vp9_common.h"
......@@ -749,21 +750,25 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
int_mv nearest_second, nearby_second, best_mv_second;
vp9_prob mv_ref_p [VP9_MVREFS - 1];
int recon_y_stride, recon_yoffset;
int recon_uv_stride, recon_uvoffset;
MV_REFERENCE_FRAME ref_frame = mbmi->ref_frame;
{
int ref_fb_idx;
int recon_y_stride, recon_yoffset;
int recon_uv_stride, recon_uvoffset;
/* Select the appropriate reference frame for this MB */
ref_fb_idx = cm->active_ref_idx[ref_frame - 1];
recon_y_stride = cm->yv12_fb[ref_fb_idx].y_stride ;
recon_y_stride = cm->yv12_fb[ref_fb_idx].y_stride;
recon_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride;
recon_yoffset = (mb_row * recon_y_stride * 16) + (mb_col * 16);
recon_uvoffset = (mb_row * recon_uv_stride * 8) + (mb_col * 8);
recon_yoffset = scaled_buffer_offset(mb_col * 16, mb_row * 16,
recon_y_stride,
&xd->scale_factor[0]);
recon_uvoffset = scaled_buffer_offset(mb_col * 8, mb_row * 8,
recon_uv_stride,
&xd->scale_factor_uv[0]);
xd->pre.y_buffer = cm->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset;
xd->pre.u_buffer = cm->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
......@@ -853,9 +858,21 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
mbmi->second_ref_frame = 1;
if (mbmi->second_ref_frame > 0) {
int second_ref_fb_idx;
int recon_y_stride, recon_yoffset;
int recon_uv_stride, recon_uvoffset;
/* Select the appropriate reference frame for this MB */
second_ref_fb_idx = cm->active_ref_idx[mbmi->second_ref_frame - 1];
recon_y_stride = cm->yv12_fb[second_ref_fb_idx].y_stride;
recon_uv_stride = cm->yv12_fb[second_ref_fb_idx].uv_stride;
recon_yoffset = scaled_buffer_offset(mb_col * 16, mb_row * 16,
recon_y_stride,
&xd->scale_factor[1]);
recon_uvoffset = scaled_buffer_offset(mb_col * 8, mb_row * 8,
recon_uv_stride,
&xd->scale_factor_uv[1]);
xd->second_pre.y_buffer =
cm->yv12_fb[second_ref_fb_idx].y_buffer + recon_yoffset;
xd->second_pre.u_buffer =
......@@ -1089,7 +1106,6 @@ static void read_mb_modes_mv(VP9D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi,
break;
case NEWMV:
read_nmv(bc, &mv->as_mv, &best_mv.as_mv, nmvc);
read_nmv_fp(bc, &mv->as_mv, &best_mv.as_mv, nmvc,
xd->allow_high_precision_mv);
......@@ -1230,8 +1246,12 @@ void vp9_decode_mb_mode_mv(VP9D_COMP* const pbi,
MODE_INFO *mi = xd->mode_info_context;
MODE_INFO *prev_mi = xd->prev_mode_info_context;
if (pbi->common.frame_type == KEY_FRAME)
if (pbi->common.frame_type == KEY_FRAME) {
kfread_modes(pbi, mi, mb_row, mb_col, bc);
else
} else {
read_mb_modes_mv(pbi, mi, &mi->mbmi, prev_mi, mb_row, mb_col, bc);
set_scale_factors(xd,
mi->mbmi.ref_frame - 1, mi->mbmi.second_ref_frame - 1,
pbi->common.active_ref_scale);
}
}
......@@ -147,7 +147,8 @@ static void mb_init_dequantizer(VP9D_COMP *pbi, MACROBLOCKD *xd) {
/* skip_recon_mb() is Modified: Instead of writing the result to predictor buffer and then copying it
* to dst buffer, we can write the result directly to dst buffer. This eliminates unnecessary copy.
*/
static void skip_recon_mb(VP9D_COMP *pbi, MACROBLOCKD *xd) {
static void skip_recon_mb(VP9D_COMP *pbi, MACROBLOCKD *xd,
int mb_row, int mb_col) {
BLOCK_SIZE_TYPE sb_type = xd->mode_info_context->mbmi.sb_type;
if (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) {
......@@ -168,21 +169,24 @@ static void skip_recon_mb(VP9D_COMP *pbi, MACROBLOCKD *xd) {
xd->dst.u_buffer,
xd->dst.v_buffer,
xd->dst.y_stride,
xd->dst.uv_stride);
xd->dst.uv_stride,
mb_row, mb_col);
} else if (sb_type == BLOCK_SIZE_SB32X32) {
vp9_build_inter32x32_predictors_sb(xd,
xd->dst.y_buffer,
xd->dst.u_buffer,
xd->dst.v_buffer,
xd->dst.y_stride,
xd->dst.uv_stride);
xd->dst.uv_stride,
mb_row, mb_col);
} else {
vp9_build_inter16x16_predictors_mb(xd,
xd->dst.y_buffer,
xd->dst.u_buffer,
xd->dst.v_buffer,
xd->dst.y_stride,
xd->dst.uv_stride);
xd->dst.uv_stride,
mb_row, mb_col);
#if CONFIG_COMP_INTERINTRA_PRED
if (xd->mode_info_context->mbmi.second_ref_frame == INTRA_FRAME) {
vp9_build_interintra_16x16_predictors_mb(xd,
......@@ -599,7 +603,7 @@ static void decode_superblock64(VP9D_COMP *pbi, MACROBLOCKD *xd,
/* Special case: Force the loopfilter to skip when eobtotal and
* mb_skip_coeff are zero.
*/
skip_recon_mb(pbi, xd);
skip_recon_mb(pbi, xd, mb_row, mb_col);
return;
}
......@@ -610,7 +614,8 @@ static void decode_superblock64(VP9D_COMP *pbi, MACROBLOCKD *xd,
} else {
vp9_build_inter64x64_predictors_sb(xd, xd->dst.y_buffer,
xd->dst.u_buffer, xd->dst.v_buffer,
xd->dst.y_stride, xd->dst.uv_stride);
xd->dst.y_stride, xd->dst.uv_stride,
mb_row, mb_col);
}
/* dequantization and idct */
......@@ -720,7 +725,7 @@ static void decode_superblock32(VP9D_COMP *pbi, MACROBLOCKD *xd,
/* Special case: Force the loopfilter to skip when eobtotal and
* mb_skip_coeff are zero.
*/
skip_recon_mb(pbi, xd);
skip_recon_mb(pbi, xd, mb_row, mb_col);
return;
}
......@@ -731,7 +736,8 @@ static void decode_superblock32(VP9D_COMP *pbi, MACROBLOCKD *xd,
} else {
vp9_build_inter32x32_predictors_sb(xd, xd->dst.y_buffer,
xd->dst.u_buffer, xd->dst.v_buffer,
xd->dst.y_stride, xd->dst.uv_stride);
xd->dst.y_stride, xd->dst.uv_stride,
mb_row, mb_col);
}
/* dequantization and idct */
......@@ -832,7 +838,7 @@ static void decode_macroblock(VP9D_COMP *pbi, MACROBLOCKD *xd,
/* Special case: Force the loopfilter to skip when eobtotal and
mb_skip_coeff are zero. */
xd->mode_info_context->mbmi.mb_skip_coeff = 1;
skip_recon_mb(pbi, xd);
skip_recon_mb(pbi, xd, mb_row, mb_col);
return;
}
#ifdef DEC_DEBUG
......@@ -859,7 +865,7 @@ static void decode_macroblock(VP9D_COMP *pbi, MACROBLOCKD *xd,
xd->mode_info_context->mbmi.mode, tx_size,
xd->mode_info_context->mbmi.interp_filter);
#endif
vp9_build_inter_predictors_mb(xd);
vp9_build_inter_predictors_mb(xd, mb_row, mb_col);
}
if (tx_size == TX_16X16) {
......@@ -966,18 +972,14 @@ static void set_refs(VP9D_COMP *pbi, int block_size,
MB_MODE_INFO *const mbmi = &mi->mbmi;
if (mbmi->ref_frame > INTRA_FRAME) {
int ref_fb_idx, ref_yoffset, ref_uvoffset, ref_y_stride, ref_uv_stride;
int ref_fb_idx;
/* Select the appropriate reference frame for this MB */
ref_fb_idx = cm->active_ref_idx[mbmi->ref_frame - 1];
ref_y_stride = cm->yv12_fb[ref_fb_idx].y_stride;
ref_yoffset = mb_row * 16 * ref_y_stride + 16 * mb_col;
xd->pre.y_buffer = cm->yv12_fb[ref_fb_idx].y_buffer + ref_yoffset;
ref_uv_stride = cm->yv12_fb[ref_fb_idx].uv_stride;
ref_uvoffset = mb_row * 8 * ref_uv_stride + 8 * mb_col;
xd->pre.u_buffer = cm->yv12_fb[ref_fb_idx].u_buffer + ref_uvoffset;
xd->pre.v_buffer = cm->yv12_fb[ref_fb_idx].v_buffer + ref_uvoffset;
xd->scale_factor[0] = cm->active_ref_scale[mbmi->ref_frame - 1];
xd->scale_factor_uv[0] = cm->active_ref_scale[mbmi->ref_frame - 1];
setup_pred_block(&xd->pre, &cm->yv12_fb[ref_fb_idx], mb_row, mb_col,
&xd->scale_factor[0], &xd->scale_factor_uv[0]);
/* propagate errors from reference frames */
xd->corrupted |= cm->yv12_fb[ref_fb_idx].corrupted;
......@@ -988,12 +990,9 @@ static void set_refs(VP9D_COMP *pbi, int block_size,
/* Select the appropriate reference frame for this MB */
second_ref_fb_idx = cm->active_ref_idx[mbmi->second_ref_frame - 1];
xd->second_pre.y_buffer =
cm->yv12_fb[second_ref_fb_idx].y_buffer + ref_yoffset;
xd->second_pre.u_buffer =
cm->yv12_fb[second_ref_fb_idx].u_buffer + ref_uvoffset;
xd->second_pre.v_buffer =
cm->yv12_fb[second_ref_fb_idx].v_buffer + ref_uvoffset;
setup_pred_block(&xd->second_pre, &cm->yv12_fb[second_ref_fb_idx],
mb_row, mb_col,
&xd->scale_factor[1], &xd->scale_factor_uv[1]);
/* propagate errors from reference frames */
xd->corrupted |= cm->yv12_fb[second_ref_fb_idx].corrupted;
......@@ -1204,6 +1203,26 @@ static void read_coef_probs(VP9D_COMP *pbi, BOOL_DECODER* const bc) {
}
}
static void update_frame_size(VP9D_COMP *pbi) {
VP9_COMMON *cm = &pbi->common;
/* our internal buffers are always multiples of 16 */
int width = (cm->Width + 15) & ~15;
int height = (cm->Height + 15) & ~15;
cm->mb_rows = height >> 4;
cm->mb_cols = width >> 4;
cm->MBs = cm->mb_rows * cm->mb_cols;
cm->mode_info_stride = cm->mb_cols + 1;
memset(cm->mip, 0,
(cm->mb_cols + 1) * (cm->mb_rows + 1) * sizeof(MODE_INFO));
vp9_update_mode_info_border(cm, cm->mip);
cm->mi = cm->mip + cm->mode_info_stride + 1;
cm->prev_mi = cm->prev_mip + cm->mode_info_stride + 1;
vp9_update_mode_info_in_image(cm, cm->mi);
}
int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) {
BOOL_DECODER header_bc, residual_bc;
VP9_COMMON *const pc = &pbi->common;
......@@ -1281,9 +1300,25 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) {
"Invalid frame height");
}
if (vp9_alloc_frame_buffers(pc, pc->Width, pc->Height))
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffers");
if (!pbi->initial_width || !pbi->initial_height) {
if (vp9_alloc_frame_buffers(pc, pc->Width, pc->Height))
vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffers");
pbi->initial_width = pc->Width;
pbi->initial_height = pc->Height;
}
if (pc->Width > pbi->initial_width) {
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Frame width too large");
}
if (pc->Height > pbi->initial_height) {
vpx_internal_error(&pc->error, VPX_CODEC_CORRUPT_FRAME,
"Frame height too large");
}
update_frame_size(pbi);
}
}
}
......@@ -1295,6 +1330,11 @@ int vp9_decode_frame(VP9D_COMP *pbi, const unsigned char **p_data_end) {
init_frame(pbi);
/* Reset the frame pointers to the current frame size */
vp8_yv12_realloc_frame_buffer(&pc->yv12_fb[pc->new_fb_idx],
pc->mb_cols * 16, pc->mb_rows * 16,
VP9BORDERINPIXELS);
if (vp9_start_decode(&header_bc, data,
(unsigned int)first_partition_length_in_byte