Commit 01cafaab authored by Deb Mukherjee's avatar Deb Mukherjee

Adds an error-resilient mode with test

Adds an error-resilient mode where frames can be continued
to be decoded even when there are errors (due to network losses)
on a prior frame. Specifically, backward updates are turned off
and probabilities of various symbols are reset to defaults at
the beginning of each frame. Further, the last frame's mvs are
not used for the mv reference list, and the sorting of the
initial list based on search on previous frames is turned off
as well.

Also adds a test where an arbitrary set of frames are skipped
from decoding to simulate errors. The test verifies (1) that if
the error frames are droppable - i.e. frame buffer updates have
been turned off - there are no mismatch errors for the remaining
frames after the error frames; and (2) if the error-frames are non
droppable, there are not only no decoding errors but the mismatch
PSNR between the decoder's version of the post-error frames and the
encoder's version is at least 20 dB.

Change-Id: Ie6e2bcd436b1e8643270356d3a930e8989ff52a5
parent 8410582b
......@@ -81,7 +81,7 @@ class Decoder {
// Common test functionality for all Decoder tests.
class DecoderTest {
public:
// Main loop.
// Main decoding loop
virtual void RunLoop(CompressedVideoSource *video);
// Hook to be called on every decompressed frame.
......
......@@ -7,6 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "vpx_config.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
......@@ -129,6 +130,11 @@ static bool compare_img(const vpx_image_t *img1,
return match;
}
void EncoderTest::MismatchHook(const vpx_image_t *img1,
const vpx_image_t *img2) {
ASSERT_TRUE(0) << "Encode/Decode mismatch found";
}
void EncoderTest::RunLoop(VideoSource *video) {
vpx_codec_dec_cfg_t dec_cfg = {0};
......@@ -149,7 +155,6 @@ void EncoderTest::RunLoop(VideoSource *video) {
&stats_);
ASSERT_TRUE(encoder != NULL);
Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0);
bool has_cxdata = false;
bool again;
for (again = true, video->Begin(); again; video->Next()) {
again = video->img() != NULL;
......@@ -160,15 +165,18 @@ void EncoderTest::RunLoop(VideoSource *video) {
CxDataIterator iter = encoder->GetCxData();
bool has_cxdata = false;
bool has_dxdata = false;
while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
again = true;
switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT:
has_cxdata = true;
if (decoder)
if (decoder && DoDecode()) {
decoder->DecodeFrame((const uint8_t*)pkt->data.frame.buf,
pkt->data.frame.sz);
has_dxdata = true;
}
ASSERT_GE(pkt->data.frame.pts, last_pts_);
last_pts_ = pkt->data.frame.pts;
FramePktHook(pkt);
......@@ -183,16 +191,17 @@ void EncoderTest::RunLoop(VideoSource *video) {
}
}
if (decoder && has_cxdata) {
if (has_dxdata && has_cxdata) {
const vpx_image_t *img_enc = encoder->GetPreviewFrame();
DxDataIterator dec_iter = decoder->GetDxData();
const vpx_image_t *img_dec = dec_iter.Next();
if(img_enc && img_dec) {
if (img_enc && img_dec) {
const bool res = compare_img(img_enc, img_dec);
ASSERT_TRUE(res)<< "Encoder/Decoder mismatch found.";
if (!res) { // Mismatch
MismatchHook(img_enc, img_dec);
}
}
}
if (!Continue())
break;
}
......@@ -207,4 +216,5 @@ void EncoderTest::RunLoop(VideoSource *video) {
break;
}
}
} // namespace libvpx_test
......@@ -9,6 +9,8 @@
*/
#ifndef TEST_ENCODE_TEST_DRIVER_H_
#define TEST_ENCODE_TEST_DRIVER_H_
#include "./vpx_config.h"
#include <string>
#include <vector>
#include "third_party/googletest/src/include/gtest/gtest.h"
......@@ -162,7 +164,7 @@ class EncoderTest {
// Map the TestMode enum to the deadline_ and passes_ variables.
void SetMode(TestMode mode);
// Main loop.
// Main loop
virtual void RunLoop(VideoSource *video);
// Hook to be called at the beginning of a pass.
......@@ -185,6 +187,13 @@ class EncoderTest {
virtual bool Continue() const { return !abort_; }
const CodecFactory *codec_;
// Hook to determine whether to decode frame after encoding
virtual bool DoDecode() const { return 1; }
// Hook to handle encode/decode mismatch
virtual void MismatchHook(const vpx_image_t *img1,
const vpx_image_t *img2);
bool abort_;
vpx_codec_enc_cfg_t cfg_;
unsigned int passes_;
......
......@@ -7,6 +7,7 @@
in the file PATENTS. All contributing project authors may
be found in the AUTHORS file in the root of the source tree.
*/
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
......@@ -15,14 +16,28 @@
namespace {
const int kMaxErrorFrames = 8;
const int kMaxDroppableFrames = 8;
class ErrorResilienceTest : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
protected:
ErrorResilienceTest() : EncoderTest(GET_PARAM(0)), psnr_(0.0), nframes_(0),
encoding_mode_(GET_PARAM(1)) {}
ErrorResilienceTest() : EncoderTest(GET_PARAM(0)),
psnr_(0.0),
nframes_(0),
mismatch_psnr_(0.0),
mismatch_nframes_(0),
encoding_mode_(GET_PARAM(1)) {
Reset();
}
virtual ~ErrorResilienceTest() {}
void Reset() {
error_nframes_ = 0;
droppable_nframes_ = 0;
}
virtual void SetUp() {
InitializeConfig();
SetMode(encoding_mode_);
......@@ -31,6 +46,8 @@ class ErrorResilienceTest : public ::libvpx_test::EncoderTest,
virtual void BeginPassHook(unsigned int /*pass*/) {
psnr_ = 0.0;
nframes_ = 0;
mismatch_psnr_ = 0.0;
mismatch_nframes_ = 0;
}
virtual bool Continue() const {
......@@ -42,15 +59,92 @@ class ErrorResilienceTest : public ::libvpx_test::EncoderTest,
nframes_++;
}
virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video) {
frame_flags_ &= ~(VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF);
if (droppable_nframes_ > 0 &&
(cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) {
for (unsigned int i = 0; i < droppable_nframes_; ++i) {
if (droppable_frames_[i] == nframes_) {
std::cout << " Encoding droppable frame: "
<< droppable_frames_[i] << "\n";
frame_flags_ |= (VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF);
return;
}
}
}
}
double GetAveragePsnr() const {
if (nframes_)
return psnr_ / nframes_;
return 0.0;
}
double GetAverageMismatchPsnr() const {
if (mismatch_nframes_)
return mismatch_psnr_ / mismatch_nframes_;
return 0.0;
}
virtual bool DoDecode() const {
if (error_nframes_ > 0 &&
(cfg_.g_pass == VPX_RC_LAST_PASS || cfg_.g_pass == VPX_RC_ONE_PASS)) {
for (unsigned int i = 0; i < error_nframes_; ++i) {
if (error_frames_[i] == nframes_ - 1) {
std::cout << " Skipping decoding frame: "
<< error_frames_[i] << "\n";
return 0;
}
}
}
return 1;
}
virtual void MismatchHook(const vpx_image_t *img1,
const vpx_image_t *img2) {
double mismatch_psnr = compute_psnr(img1, img2);
mismatch_psnr_ += mismatch_psnr;
++mismatch_nframes_;
// std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n";
}
void SetErrorFrames(int num, unsigned int *list) {
if (num > kMaxErrorFrames)
num = kMaxErrorFrames;
else if (num < 0)
num = 0;
error_nframes_ = num;
for (unsigned int i = 0; i < error_nframes_; ++i)
error_frames_[i] = list[i];
}
void SetDroppableFrames(int num, unsigned int *list) {
if (num > kMaxDroppableFrames)
num = kMaxDroppableFrames;
else if (num < 0)
num = 0;
droppable_nframes_ = num;
for (unsigned int i = 0; i < droppable_nframes_; ++i)
droppable_frames_[i] = list[i];
}
unsigned int GetMismatchFrames() {
return mismatch_nframes_;
}
private:
double psnr_;
unsigned int nframes_;
unsigned int error_nframes_;
unsigned int droppable_nframes_;
double mismatch_psnr_;
unsigned int mismatch_nframes_;
unsigned int error_frames_[kMaxErrorFrames];
unsigned int droppable_frames_[kMaxDroppableFrames];
libvpx_test::TestMode encoding_mode_;
};
......@@ -85,5 +179,50 @@ TEST_P(ErrorResilienceTest, OnVersusOff) {
}
}
TEST_P(ErrorResilienceTest, DropFramesWithoutRecovery) {
const vpx_rational timebase = { 33333333, 1000000000 };
cfg_.g_timebase = timebase;
cfg_.rc_target_bitrate = 2000;
cfg_.g_lag_in_frames = 5;
init_flags_ = VPX_CODEC_USE_PSNR;
libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
timebase.den, timebase.num, 0, 30);
// Error resilient mode ON.
cfg_.g_error_resilient = 1;
// Set an arbitrary set of error frames same as droppable frames
unsigned int num_droppable_frames = 2;
unsigned int droppable_frame_list[] = {5, 16};
SetDroppableFrames(num_droppable_frames, droppable_frame_list);
SetErrorFrames(num_droppable_frames, droppable_frame_list);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that no mismatches have been found
std::cout << " Mismatch frames: "
<< GetMismatchFrames() << "\n";
EXPECT_EQ(GetMismatchFrames(), (unsigned int) 0);
// reset previously set error/droppable frames
Reset();
// Now set an arbitrary set of error frames that are non-droppable
unsigned int num_error_frames = 3;
unsigned int error_frame_list[] = {3, 10, 20};
SetErrorFrames(num_error_frames, error_frame_list);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
// Test that dropping an arbitrary set of inter frames does not hurt too much
// Note the Average Mismatch PSNR is the average of the PSNR between
// decoded frame and encoder's version of the same frame for all frames
// with mismatch.
const double psnr_resilience_mismatch = GetAverageMismatchPsnr();
std::cout << " Mismatch PSNR: "
<< psnr_resilience_mismatch << "\n";
EXPECT_GT(psnr_resilience_mismatch, 20.0);
}
VP8_INSTANTIATE_TEST_CASE(ErrorResilienceTest, ONE_PASS_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(ErrorResilienceTest, ONE_PASS_TEST_MODES);
} // namespace
......@@ -15,9 +15,10 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += altref_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += config_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += cq_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += datarate_test.cc
LIBVPX_TEST_SRCS-yes += encode_test_driver.cc
LIBVPX_TEST_SRCS-yes += encode_test_driver.h
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += error_resilience_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += error_resilience_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += i420_video_source.h
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += resize_test.cc
......@@ -26,6 +27,8 @@ LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../md5_utils.h ../md5_utils.c
LIBVPX_TEST_SRCS-yes += decode_test_driver.cc
LIBVPX_TEST_SRCS-yes += decode_test_driver.h
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h
LIBVPX_TEST_SRCS-$(CONFIG_VP8_DECODER) += test_vector_test.cc
##
## WHITE BOX TESTS
......@@ -70,6 +73,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += fdct8x8_test.cc
#LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct16x16_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += variance_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct32x32_test.cc
endif # VP9
......@@ -79,7 +83,8 @@ endif
##
## TEST DATA
##
LIBVPX_TEST_DATA-$(CONFIG_VP8_ENCODER) += hantro_collage_w352h288.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv
LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-001.ivf
LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-002.ivf
LIBVPX_TEST_DATA-$(CONFIG_VP8_DECODER) += vp80-00-comprehensive-003.ivf
......
......@@ -11,8 +11,38 @@
#ifndef TEST_UTIL_H_
#define TEST_UTIL_H_
#include <stdio.h>
#include <math.h>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "vpx/vpx_image.h"
// Macros
#define PARAMS(...) ::testing::TestWithParam< std::tr1::tuple< __VA_ARGS__ > >
#define GET_PARAM(k) std::tr1::get< k >(GetParam())
static double compute_psnr(const vpx_image_t *img1,
const vpx_image_t *img2) {
assert((img1->fmt == img2->fmt) &&
(img1->d_w == img2->d_w) &&
(img1->d_h == img2->d_h));
const unsigned int width_y = img1->d_w;
const unsigned int height_y = img1->d_h;
unsigned int i, j;
int64_t sqrerr = 0;
for (i = 0; i < height_y; ++i)
for (j = 0; j < width_y; ++j) {
int64_t d = img1->planes[VPX_PLANE_Y][i * img1->stride[VPX_PLANE_Y] + j] -
img2->planes[VPX_PLANE_Y][i * img2->stride[VPX_PLANE_Y] + j];
sqrerr += d * d;
}
double mse = sqrerr / (width_y * height_y);
double psnr = 100.0;
if (mse > 0.0) {
psnr = 10 * log10(255.0 * 255.0 / mse);
}
return psnr;
}
#endif // TEST_UTIL_H_
......@@ -146,6 +146,7 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) {
return 0;
}
void vp9_setup_version(VP9_COMMON *cm) {
if (cm->version & 0x4) {
if (!CONFIG_EXPERIMENTAL)
......
......@@ -11,9 +11,10 @@
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_modecont.h"
#include "vp9/common/vp9_seg_common.h"
#include "vp9/common/vp9_alloccommon.h"
#include "vpx_mem/vpx_mem.h"
static const unsigned int kf_y_mode_cts[8][VP9_YMODES] = {
/* DC V H D45 135 117 153 D27 D63 TM i8x8 BPRED */
{12, 6, 5, 5, 5, 5, 5, 5, 5, 2, 22, 200},
......@@ -344,6 +345,9 @@ void vp9_init_mbmode_probs(VP9_COMMON *x) {
#if CONFIG_COMP_INTERINTRA_PRED
x->fc.interintra_prob = VP9_DEF_INTERINTRA_PROB;
#endif
x->ref_pred_probs[0] = 120;
x->ref_pred_probs[1] = 80;
x->ref_pred_probs[2] = 40;
}
......@@ -480,7 +484,7 @@ void vp9_accum_mv_refs(VP9_COMMON *pc,
#define MVREF_COUNT_SAT 20
#define MVREF_MAX_UPDATE_FACTOR 128
void vp9_update_mode_context(VP9_COMMON *pc) {
void vp9_adapt_mode_context(VP9_COMMON *pc) {
int i, j;
unsigned int (*mv_ref_ct)[4][2];
int (*mode_context)[4];
......@@ -631,3 +635,65 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) {
}
#endif
}
static void set_default_lf_deltas(MACROBLOCKD *xd) {
xd->mode_ref_lf_delta_enabled = 1;
xd->mode_ref_lf_delta_update = 1;
xd->ref_lf_deltas[INTRA_FRAME] = 2;
xd->ref_lf_deltas[LAST_FRAME] = 0;
xd->ref_lf_deltas[GOLDEN_FRAME] = -2;
xd->ref_lf_deltas[ALTREF_FRAME] = -2;
xd->mode_lf_deltas[0] = 4; // BPRED
xd->mode_lf_deltas[1] = -2; // Zero
xd->mode_lf_deltas[2] = 2; // New mv
xd->mode_lf_deltas[3] = 4; // Split mv
}
void vp9_setup_past_independence(VP9_COMMON *cm, MACROBLOCKD *xd) {
// Reset the segment feature data to the default stats:
// Features disabled, 0, with delta coding (Default state).
int i;
vp9_clearall_segfeatures(xd);
xd->mb_segment_abs_delta = SEGMENT_DELTADATA;
if (cm->last_frame_seg_map)
vpx_memset(cm->last_frame_seg_map, 0, (cm->mb_rows * cm->mb_cols));
/* reset the mode ref deltas for loop filter */
vpx_memset(xd->last_ref_lf_deltas, 0, sizeof(xd->last_ref_lf_deltas));
vpx_memset(xd->last_mode_lf_deltas, 0, sizeof(xd->last_mode_lf_deltas));
set_default_lf_deltas(xd);
vp9_default_coef_probs(cm);
vp9_init_mbmode_probs(cm);
vp9_default_bmode_probs(cm->fc.bmode_prob);
vp9_kf_default_bmode_probs(cm->kf_bmode_prob);
vp9_init_mv_probs(cm);
// To force update of the sharpness
cm->last_sharpness_level = -1;
vp9_init_mode_contexts(cm);
for (i = 0; i < NUM_FRAME_CONTEXTS; i++) {
vpx_memcpy(&cm->frame_contexts[i], &cm->fc, sizeof(cm->fc));
}
vpx_memset(cm->prev_mip, 0,
(cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO));
vpx_memset(cm->mip, 0,
(cm->mb_cols + 1) * (cm->mb_rows + 1)* sizeof(MODE_INFO));
vp9_update_mode_info_border(cm, cm->mip);
vp9_update_mode_info_in_image(cm, cm->mi);
#if CONFIG_NEW_MVREF
// Defaults probabilities for encoding the MV ref id signal
vpx_memset(xd->mb_mv_ref_probs, VP9_DEFAULT_MV_REF_PROB,
sizeof(xd->mb_mv_ref_probs));
#endif
cm->ref_frame_sign_bias[GOLDEN_FRAME] = 0;
cm->ref_frame_sign_bias[ALTREF_FRAME] = 0;
cm->frame_context_idx = 0;
}
......@@ -76,11 +76,14 @@ void vp9_entropy_mode_init(void);
struct VP9Common;
/* sets up common features to forget past dependence */
void vp9_setup_past_independence(struct VP9Common *cm, MACROBLOCKD *xd);
void vp9_init_mbmode_probs(struct VP9Common *x);
extern void vp9_init_mode_contexts(struct VP9Common *pc);
extern void vp9_update_mode_context(struct VP9Common *pc);
extern void vp9_adapt_mode_context(struct VP9Common *pc);
extern void vp9_accum_mv_refs(struct VP9Common *pc,
MB_PREDICTION_MODE m,
......
......@@ -141,130 +141,136 @@ void vp9_find_best_ref_mvs(MACROBLOCKD *xd,
int_mv sorted_mvs[MAX_MV_REF_CANDIDATES];
int zero_seen = FALSE;
// Default all to 0,0 if nothing else available
nearest->as_int = near->as_int = 0;
vpx_memset(sorted_mvs, 0, sizeof(sorted_mvs));
if (ref_y_buffer) {
above_src = xd->dst.y_buffer - xd->dst.y_stride * 2;
above_ref = ref_y_buffer - ref_y_stride * 2;
// Default all to 0,0 if nothing else available
nearest->as_int = near->as_int = 0;
vpx_memset(sorted_mvs, 0, sizeof(sorted_mvs));
above_src = xd->dst.y_buffer - xd->dst.y_stride * 2;
above_ref = ref_y_buffer - ref_y_stride * 2;
#if CONFIG_ABOVESPREFMV
above_src -= 4;
above_ref -= 4;
above_src -= 4;
above_ref -= 4;
#else
left_src = xd->dst.y_buffer - 2;
left_ref = ref_y_buffer - 2;
left_src = xd->dst.y_buffer - 2;
left_ref = ref_y_buffer - 2;
#endif
// Limit search to the predicted best few candidates
for(i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
int_mv this_mv;
int offset = 0;
int row_offset, col_offset;
// Limit search to the predicted best few candidates
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
int_mv this_mv;
int offset = 0;
int row_offset, col_offset;
this_mv.as_int = mvlist[i].as_int;
this_mv.as_int = mvlist[i].as_int;
// If we see a 0,0 vector for a second time we have reached the end of
// the list of valid candidate vectors.
if (!this_mv.as_int && zero_seen)
break;
// If we see a 0,0 vector for a second time we have reached the end of
// the list of valid candidate vectors.
if (!this_mv.as_int && zero_seen)
break;
zero_seen = zero_seen || !this_mv.as_int;
zero_seen = zero_seen || !this_mv.as_int;
#if !CONFIG_ABOVESPREFMV
clamp_mv(&this_mv,
xd->mb_to_left_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
clamp_mv(&this_mv,
xd->mb_to_left_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
#else
clamp_mv(&this_mv,
xd->mb_to_left_edge - LEFT_TOP_MARGIN + 32,
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
clamp_mv(&this_mv,
xd->mb_to_left_edge - LEFT_TOP_MARGIN + 32,
xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
xd->mb_to_top_edge - LEFT_TOP_MARGIN + 24,
xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);
#endif
row_offset = this_mv.as_mv.row >> 3;
col_offset = this_mv.as_mv.col >> 3;
offset = ref_y_stride * row_offset + col_offset;
score = 0;
if (xd->up_available) {
vp9_sub_pixel_variance16x2(above_ref + offset, ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
above_src, xd->dst.y_stride, &sse);
score += sse;
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) {
vp9_sub_pixel_variance16x2(above_ref + offset + 16,
ref_y_stride,
row_offset = this_mv.as_mv.row >> 3;
col_offset = this_mv.as_mv.col >> 3;
offset = ref_y_stride * row_offset + col_offset;
score = 0;
if (xd->up_available) {
vp9_sub_pixel_variance16x2(above_ref + offset, ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
above_src + 16, xd->dst.y_stride, &sse);
above_src, xd->dst.y_stride, &sse);
score += sse;
}
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) {
vp9_sub_pixel_variance16x2(above_ref + offset + 32,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
above_src + 32, xd->dst.y_stride, &sse);
score += sse;
vp9_sub_pixel_variance16x2(above_ref + offset + 48,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
above_src + 48, xd->dst.y_stride, &sse);
score += sse;
}
}
#if !CONFIG_ABOVESPREFMV
if (xd->left_available) {
vp9_sub_pixel_variance2x16_c(left_ref + offset, ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src, xd->dst.y_stride, &sse);
score += sse;
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) {
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 16,
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) {
vp9_sub_pixel_variance16x2(above_ref + offset + 16,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 16,
xd->dst.y_stride, &sse);
score += sse;
}
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) {
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 32,
above_src + 16, xd->dst.y_stride, &sse);
score += sse;
}
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) {
vp9_sub_pixel_variance16x2(above_ref + offset + 32,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 32,
xd->dst.y_stride, &sse);
score += sse;
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 48,
above_src + 32, xd->dst.y_stride, &sse);
score += sse;
vp9_sub_pixel_variance16x2(above_ref + offset + 48,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 48,
xd->dst.y_stride, &sse);
above_src + 48, xd->dst.y_stride, &sse);
score += sse;
}
}
#if !CONFIG_ABOVESPREFMV
if (xd->left_available) {
vp9_sub_pixel_variance2x16_c(left_ref + offset, ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src, xd->dst.y_stride, &sse);
score += sse;
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB32X32) {
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 16,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 16,
xd->dst.y_stride, &sse);
score += sse;
}
if (xd->mode_info_context->mbmi.sb_type >= BLOCK_SIZE_SB64X64) {
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 32,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 32,
xd->dst.y_stride, &sse);
score += sse;
vp9_sub_pixel_variance2x16_c(left_ref + offset + ref_y_stride * 48,
ref_y_stride,
SP(this_mv.as_mv.col),
SP(this_mv.as_mv.row),
left_src + xd->dst.y_stride * 48,
xd->dst.y_stride, &sse);
score += sse;
}
}
}
#endif
// Add the entry to our list and then resort the list on score.
ref_scores[i] = score;
sorted_mvs[i].as_int = this_mv.as_int;
j = i;
while (j > 0) {
if (ref_scores[j] < ref_scores[j-1]) {
ref_scores[j] = ref_scores[j-1];
sorted_mvs[j].as_int = sorted_mvs[j-1].as_int;
ref_scores[j-1] = score;
sorted_mvs[j-1].as_int = this_mv.as_int;
j--;
} else
break;
// Add the entry to our list and then resort the list on score.
ref_scores[i