shithub: libvpx

Download patch

ref: 6c86ef2ea45a136e63c068b1b5966ec81573ad77
parent: d67acd870a469857c38f89427c06f4f6bfa46e2b
parent: a441b60aa07326898099e41afaa5fd043c14922c
author: Jim Bankoski <jimbankoski@google.com>
date: Mon Jun 25 10:46:45 EDT 2012

Merge "Add unit test for intra prediction."

--- /dev/null
+++ b/test/intrapred_test.cc
@@ -1,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
--- a/test/test.mk
+++ b/test/test.mk
@@ -5,6 +5,7 @@
 LIBVPX_TEST_SRCS-yes += encode_test_driver.h
 LIBVPX_TEST_SRCS-yes += i420_video_source.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