16fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org/*
2d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *
4d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  Use of this source code is governed by a BSD-style license
5d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  that can be found in the LICENSE file in the root of the source
6d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  tree. An additional intellectual property rights grant can be found
7d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  in the file PATENTS.  All contributing project authors may
8d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  be found in the AUTHORS file in the root of the source tree.
9d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org */
106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <math.h>
126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <stddef.h>
136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <stdio.h>
146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <stdlib.h>
156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <string.h>
166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include <sys/types.h>
176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
18f9586bb54d74c97d07b09eb2512f8569c9c1c025fgalligan@chromium.org#include "./vp8_rtcd.h"
196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include "test/acm_random.h"
216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include "third_party/googletest/src/include/gtest/gtest.h"
226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org#include "vpx/vpx_integer.h"
236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgnamespace {
256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgconst int cospi8sqrt2minus1 = 20091;
276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgconst int sinpi8sqrt2 = 35468;
286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgvoid reference_idct4x4(const int16_t *input, int16_t *output) {
306fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  const int16_t *ip = input;
316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  int16_t *op = output;
326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int i = 0; i < 4; ++i) {
346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int a1 = ip[0] + ip[8];
356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int b1 = ip[0] - ip[8];
366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp1 = (ip[4] * sinpi8sqrt2) >> 16;
376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int c1 = temp1 - temp2;
396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp3 = ip[4] + ((ip[4] * cospi8sqrt2minus1) >> 16);
406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp4 = (ip[12] * sinpi8sqrt2) >> 16;
416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int d1 = temp3 + temp4;
426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[0] = a1 + d1;
436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[12] = a1 - d1;
446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[4] = b1 + c1;
456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[8] = b1 - c1;
466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    ++ip;
476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    ++op;
486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  }
496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  ip = output;
506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  op = output;
516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int i = 0; i < 4; ++i) {
526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int a1 = ip[0] + ip[2];
536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int b1 = ip[0] - ip[2];
546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp1 = (ip[1] * sinpi8sqrt2) >> 16;
556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp2 = ip[3] + ((ip[3] * cospi8sqrt2minus1) >> 16);
566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int c1 = temp1 - temp2;
576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp3 = ip[1] + ((ip[1] * cospi8sqrt2minus1) >> 16);
586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int temp4 = (ip[3] * sinpi8sqrt2) >> 16;
596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int d1 = temp3 + temp4;
606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[0] = (a1 + d1 + 4) >> 3;
616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[3] = (a1 - d1 + 4) >> 3;
626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[1] = (b1 + c1 + 4) >> 3;
636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op[2] = (b1 - c1 + 4) >> 3;
646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    ip += 4;
656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    op += 4;
666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  }
676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgusing libvpx_test::ACMRandom;
706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
7193a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgTEST(VP8FdctTest, SignBiasCheck) {
726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  ACMRandom rnd(ACMRandom::DeterministicSeed());
736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  int16_t test_input_block[16];
746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  int16_t test_output_block[16];
756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  const int pitch = 8;
766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  int count_sign_block[16][2];
776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  const int count_test_block = 1000000;
786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  memset(count_sign_block, 0, sizeof(count_sign_block));
806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int i = 0; i < count_test_block; ++i) {
826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    // Initialize a test block with input range [-255, 255].
836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j)
846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      test_input_block[j] = rnd.Rand8() - rnd.Rand8();
856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    vp8_short_fdct4x4_c(test_input_block, test_output_block, pitch);
876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j) {
896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      if (test_output_block[j] < 0)
906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        ++count_sign_block[j][0];
916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      else if (test_output_block[j] > 0)
926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        ++count_sign_block[j][1];
936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    }
946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  }
956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  bool bias_acceptable = true;
976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int j = 0; j < 16; ++j)
986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    bias_acceptable = bias_acceptable &&
996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 10000);
1006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  EXPECT_EQ(true, bias_acceptable)
1026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    << "Error: 4x4 FDCT has a sign bias > 1% for input range [-255, 255]";
1036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  memset(count_sign_block, 0, sizeof(count_sign_block));
1056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int i = 0; i < count_test_block; ++i) {
1076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    // Initialize a test block with input range [-15, 15].
1086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j)
1096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4);
1106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    vp8_short_fdct4x4_c(test_input_block, test_output_block, pitch);
1126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j) {
1146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      if (test_output_block[j] < 0)
1156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        ++count_sign_block[j][0];
1166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      else if (test_output_block[j] > 0)
1176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        ++count_sign_block[j][1];
1186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    }
1196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  }
1206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1216fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  bias_acceptable = true;
1226fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int j = 0; j < 16; ++j)
1236fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    bias_acceptable = bias_acceptable &&
1246fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    (abs(count_sign_block[j][0] - count_sign_block[j][1]) < 100000);
1256fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1266fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  EXPECT_EQ(true, bias_acceptable)
1276fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    << "Error: 4x4 FDCT has a sign bias > 10% for input range [-15, 15]";
1286fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org};
1296fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
13093a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.orgTEST(VP8FdctTest, RoundTripErrorCheck) {
1316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  ACMRandom rnd(ACMRandom::DeterministicSeed());
1326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  int max_error = 0;
1336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  double total_error = 0;
1346fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  const int count_test_block = 1000000;
1356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  for (int i = 0; i < count_test_block; ++i) {
1366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int16_t test_input_block[16];
1376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int16_t test_temp_block[16];
1386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int16_t test_output_block[16];
1396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    // Initialize a test block with input range [-255, 255].
1416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j)
1426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      test_input_block[j] = rnd.Rand8() - rnd.Rand8();
1436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    const int pitch = 8;
1456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    vp8_short_fdct4x4_c(test_input_block, test_temp_block, pitch);
1466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    reference_idct4x4(test_temp_block, test_output_block);
1476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    for (int j = 0; j < 16; ++j) {
1496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      const int diff = test_input_block[j] - test_output_block[j];
1506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      const int error = diff * diff;
1516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      if (max_error < error)
1526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        max_error = error;
1536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org      total_error += error;
1546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    }
1556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  }
1566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1576fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  EXPECT_GE(1, max_error )
1586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    << "Error: FDCT/IDCT has an individual roundtrip error > 1";
1596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1606fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org  EXPECT_GE(count_test_block, total_error)
1616fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    << "Error: FDCT/IDCT has average roundtrip error > 1 per block";
1626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org};
1636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}  // namespace
165