Add unit test for intra prediction.
Change-Id: I7dadadeb99bee5a51219f46fe11c760fc294c735
This commit is contained in:
Родитель
3897b48aba
Коммит
a441b60aa0
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* Copyright (c) 2012 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 <string.h>
|
||||
#include "third_party/googletest/src/include/gtest/gtest.h"
|
||||
extern "C" {
|
||||
#include "vpx_config.h"
|
||||
#include "vpx_rtcd.h"
|
||||
#include "vp8/common/blockd.h"
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class IntraPredBase {
|
||||
protected:
|
||||
void SetupMacroblock(uint8_t *data, int block_size, int stride,
|
||||
int num_planes) {
|
||||
memset(&mb_, 0, sizeof(mb_));
|
||||
memset(&mi_, 0, sizeof(mi_));
|
||||
mb_.up_available = 1;
|
||||
mb_.left_available = 1;
|
||||
mb_.mode_info_context = &mi_;
|
||||
stride_ = stride;
|
||||
block_size_ = block_size;
|
||||
num_planes_ = num_planes;
|
||||
for (int p = 0; p < num_planes; p++)
|
||||
data_ptr_[p] = data + stride * (block_size + 1) * p +
|
||||
stride + block_size;
|
||||
}
|
||||
|
||||
void FillRandom() {
|
||||
// Fill edges with random data
|
||||
for (int p = 0; p < num_planes_; p++) {
|
||||
for (int x = -1 ; x <= block_size_; x++)
|
||||
data_ptr_[p][x - stride_] = rand();
|
||||
for (int y = 0; y < block_size_; y++)
|
||||
data_ptr_[p][y * stride_ - 1] = rand();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Predict(MB_PREDICTION_MODE mode) = 0;
|
||||
|
||||
void SetLeftUnavailable() {
|
||||
mb_.left_available = 0;
|
||||
for (int p = 0; p < num_planes_; p++)
|
||||
for (int i = -1; i < block_size_; ++i)
|
||||
data_ptr_[p][stride_ * i - 1] = 129;
|
||||
}
|
||||
|
||||
void SetTopUnavailable() {
|
||||
mb_.up_available = 0;
|
||||
for (int p = 0; p < num_planes_; p++)
|
||||
memset(&data_ptr_[p][-1 - stride_], 127, block_size_ + 2);
|
||||
}
|
||||
|
||||
void SetTopLeftUnavailable() {
|
||||
SetLeftUnavailable();
|
||||
SetTopUnavailable();
|
||||
}
|
||||
|
||||
int BlockSizeLog2Min1() const {
|
||||
switch (block_size_) {
|
||||
case 16:
|
||||
return 3;
|
||||
case 8:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check DC prediction output against a reference
|
||||
void CheckDCPrediction() const {
|
||||
for (int p = 0; p < num_planes_; p++) {
|
||||
// calculate expected DC
|
||||
int expected;
|
||||
if (mb_.up_available || mb_.left_available) {
|
||||
int sum = 0, shift = BlockSizeLog2Min1() + mb_.up_available +
|
||||
mb_.left_available;
|
||||
if (mb_.up_available)
|
||||
for (int x = 0; x < block_size_; x++)
|
||||
sum += data_ptr_[p][x - stride_];
|
||||
if (mb_.left_available)
|
||||
for (int y = 0; y < block_size_; y++)
|
||||
sum += data_ptr_[p][y * stride_ - 1];
|
||||
expected = (sum + (1 << (shift - 1))) >> shift;
|
||||
} else
|
||||
expected = 0x80;
|
||||
|
||||
// check that all subsequent lines are equal to the first
|
||||
for (int y = 1; y < block_size_; ++y)
|
||||
ASSERT_EQ(0, memcmp(data_ptr_[p], &data_ptr_[p][y * stride_],
|
||||
block_size_));
|
||||
// within the first line, ensure that each pixel has the same value
|
||||
for (int x = 1; x < block_size_; ++x)
|
||||
ASSERT_EQ(data_ptr_[p][0], data_ptr_[p][x]);
|
||||
// now ensure that that pixel has the expected (DC) value
|
||||
ASSERT_EQ(expected, data_ptr_[p][0]);
|
||||
}
|
||||
}
|
||||
|
||||
// check V prediction output against a reference
|
||||
void CheckVPrediction() const {
|
||||
// check that all lines equal the top border
|
||||
for (int p = 0; p < num_planes_; p++)
|
||||
for (int y = 0; y < block_size_; y++)
|
||||
ASSERT_EQ(0, memcmp(&data_ptr_[p][-stride_],
|
||||
&data_ptr_[p][y * stride_], block_size_));
|
||||
}
|
||||
|
||||
// check H prediction output against a reference
|
||||
void CheckHPrediction() const {
|
||||
// for each line, ensure that each pixel is equal to the left border
|
||||
for (int p = 0; p < num_planes_; p++)
|
||||
for (int y = 0; y < block_size_; y++)
|
||||
for (int x = 0; x < block_size_; x++)
|
||||
ASSERT_EQ(data_ptr_[p][-1 + y * stride_],
|
||||
data_ptr_[p][x + y * stride_]);
|
||||
}
|
||||
|
||||
static int ClipByte(int value) {
|
||||
if (value > 255)
|
||||
return 255;
|
||||
else if (value < 0)
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
// check TM prediction output against a reference
|
||||
void CheckTMPrediction() const {
|
||||
for (int p = 0; p < num_planes_; p++)
|
||||
for (int y = 0; y < block_size_; y++)
|
||||
for (int x = 0; x < block_size_; x++) {
|
||||
const int expected = ClipByte(data_ptr_[p][x - stride_]
|
||||
+ data_ptr_[p][stride_ * y - 1]
|
||||
- data_ptr_[p][-1 - stride_]);
|
||||
ASSERT_EQ(expected, data_ptr_[p][y * stride_ + x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Actual test
|
||||
void RunTest() {
|
||||
{
|
||||
SCOPED_TRACE("DC_PRED");
|
||||
FillRandom();
|
||||
Predict(DC_PRED);
|
||||
CheckDCPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("DC_PRED LEFT");
|
||||
FillRandom();
|
||||
SetLeftUnavailable();
|
||||
Predict(DC_PRED);
|
||||
CheckDCPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("DC_PRED TOP");
|
||||
FillRandom();
|
||||
SetTopUnavailable();
|
||||
Predict(DC_PRED);
|
||||
CheckDCPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("DC_PRED TOP_LEFT");
|
||||
FillRandom();
|
||||
SetTopLeftUnavailable();
|
||||
Predict(DC_PRED);
|
||||
CheckDCPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("H_PRED");
|
||||
FillRandom();
|
||||
Predict(H_PRED);
|
||||
CheckHPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("V_PRED");
|
||||
FillRandom();
|
||||
Predict(V_PRED);
|
||||
CheckVPrediction();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("TM_PRED");
|
||||
FillRandom();
|
||||
Predict(TM_PRED);
|
||||
CheckTMPrediction();
|
||||
}
|
||||
}
|
||||
|
||||
MACROBLOCKD mb_;
|
||||
MODE_INFO mi_;
|
||||
uint8_t *data_ptr_[2]; // in the case of Y, only [0] is used
|
||||
int stride_;
|
||||
int block_size_;
|
||||
int num_planes_;
|
||||
};
|
||||
|
||||
typedef void (*intra_pred_y_fn_t)(MACROBLOCKD *x,
|
||||
uint8_t *yabove_row,
|
||||
uint8_t *yleft,
|
||||
int left_stride,
|
||||
uint8_t *ypred_ptr,
|
||||
int y_stride);
|
||||
|
||||
class IntraPredYTest : public ::testing::TestWithParam<intra_pred_y_fn_t>,
|
||||
protected IntraPredBase {
|
||||
protected:
|
||||
static const int kBlockSize = 16;
|
||||
static const int kStride = kBlockSize * 3;
|
||||
|
||||
virtual void SetUp() {
|
||||
pred_fn_ = GetParam();
|
||||
SetupMacroblock(data_array_, kBlockSize, kStride, 1);
|
||||
}
|
||||
|
||||
virtual void Predict(MB_PREDICTION_MODE mode) {
|
||||
mb_.mode_info_context->mbmi.mode = mode;
|
||||
pred_fn_(&mb_, data_ptr_[0] - kStride, data_ptr_[0] - 1, kStride,
|
||||
data_ptr_[0], kStride);
|
||||
}
|
||||
|
||||
intra_pred_y_fn_t pred_fn_;
|
||||
// We use 48 so that the data pointer of the first pixel in each row of
|
||||
// each macroblock is 16-byte aligned, and this gives us access to the
|
||||
// top-left and top-right corner pixels belonging to the top-left/right
|
||||
// macroblocks.
|
||||
// We use 17 lines so we have one line above us for top-prediction.
|
||||
DECLARE_ALIGNED(16, uint8_t, data_array_[kStride * (kBlockSize + 1)]);
|
||||
};
|
||||
|
||||
TEST_P(IntraPredYTest, IntraPredTests) {
|
||||
RunTest();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, IntraPredYTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mby_s_c));
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, IntraPredYTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mby_s_sse2));
|
||||
#endif
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredYTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mby_s_ssse3));
|
||||
#endif
|
||||
|
||||
typedef void (*intra_pred_uv_fn_t)(MACROBLOCKD *x,
|
||||
uint8_t *uabove_row,
|
||||
uint8_t *vabove_row,
|
||||
uint8_t *uleft,
|
||||
uint8_t *vleft,
|
||||
int left_stride,
|
||||
uint8_t *upred_ptr,
|
||||
uint8_t *vpred_ptr,
|
||||
int pred_stride);
|
||||
|
||||
class IntraPredUVTest : public ::testing::TestWithParam<intra_pred_uv_fn_t>,
|
||||
protected IntraPredBase {
|
||||
protected:
|
||||
static const int kBlockSize = 8;
|
||||
static const int kStride = kBlockSize * 3;
|
||||
|
||||
virtual void SetUp() {
|
||||
pred_fn_ = GetParam();
|
||||
SetupMacroblock(data_array_, kBlockSize, kStride, 2);
|
||||
}
|
||||
|
||||
virtual void Predict(MB_PREDICTION_MODE mode) {
|
||||
mb_.mode_info_context->mbmi.uv_mode = mode;
|
||||
pred_fn_(&mb_, data_ptr_[0] - kStride, data_ptr_[1] - kStride,
|
||||
data_ptr_[0] - 1, data_ptr_[1] - 1, kStride,
|
||||
data_ptr_[0], data_ptr_[1], kStride);
|
||||
}
|
||||
|
||||
intra_pred_uv_fn_t pred_fn_;
|
||||
// We use 24 so that the data pointer of the first pixel in each row of
|
||||
// each macroblock is 8-byte aligned, and this gives us access to the
|
||||
// top-left and top-right corner pixels belonging to the top-left/right
|
||||
// macroblocks.
|
||||
// We use 9 lines so we have one line above us for top-prediction.
|
||||
// [0] = U, [1] = V
|
||||
DECLARE_ALIGNED(8, uint8_t, data_array_[2 * kStride * (kBlockSize + 1)]);
|
||||
};
|
||||
|
||||
TEST_P(IntraPredUVTest, IntraPredTests) {
|
||||
RunTest();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, IntraPredUVTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mbuv_s_c));
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, IntraPredUVTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mbuv_s_sse2));
|
||||
#endif
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredUVTest,
|
||||
::testing::Values(
|
||||
vp8_build_intra_predictors_mbuv_s_ssse3));
|
||||
#endif
|
||||
|
||||
} // namespace
|
|
@ -4,6 +4,7 @@ LIBVPX_TEST_SRCS-yes += config_test.cc
|
|||
LIBVPX_TEST_SRCS-yes += encode_test_driver.cc
|
||||
LIBVPX_TEST_SRCS-yes += encode_test_driver.h
|
||||
LIBVPX_TEST_SRCS-yes += idctllm_test.cc
|
||||
LIBVPX_TEST_SRCS-yes += intrapred_test.cc
|
||||
LIBVPX_TEST_SRCS-yes += keyframe_test.cc
|
||||
LIBVPX_TEST_SRCS-yes += pp_filter_test.cc
|
||||
LIBVPX_TEST_SRCS-yes += resize_test.cc
|
||||
|
|
Загрузка…
Ссылка в новой задаче