mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-28 03:17:31 +09:00
Move aom source to a sub-directory under media/libaom
There is no damned reason to treat this differently than any other media lib given its license and there never was.
This commit is contained in:
parent
0b2694187d
commit
b746a4196a
1002 changed files with 517 additions and 517 deletions
75
media/libaom/src/test/accounting_test.cc
Normal file
75
media/libaom/src/test/accounting_test.cc
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/bitreader.h"
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
TEST(AV1, TestAccounting) {
|
||||
const int kBufferSize = 10000;
|
||||
const int kSymbols = 1024;
|
||||
aom_writer bw;
|
||||
uint8_t bw_buffer[kBufferSize];
|
||||
aom_start_encode(&bw, bw_buffer);
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_write(&bw, 0, 32);
|
||||
aom_write(&bw, 0, 32);
|
||||
aom_write(&bw, 0, 32);
|
||||
}
|
||||
aom_stop_encode(&bw);
|
||||
aom_reader br;
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
|
||||
Accounting accounting;
|
||||
aom_accounting_init(&accounting);
|
||||
br.accounting = &accounting;
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_read(&br, 32, "A");
|
||||
}
|
||||
// Consecutive symbols that are the same are coalesced.
|
||||
GTEST_ASSERT_EQ(accounting.syms.num_syms, 1);
|
||||
GTEST_ASSERT_EQ(accounting.syms.syms[0].samples, (unsigned int)kSymbols);
|
||||
|
||||
aom_accounting_reset(&accounting);
|
||||
GTEST_ASSERT_EQ(accounting.syms.num_syms, 0);
|
||||
|
||||
// Should record 2 * kSymbols accounting symbols.
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
br.accounting = &accounting;
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_read(&br, 32, "A");
|
||||
aom_read(&br, 32, "B");
|
||||
aom_read(&br, 32, "B");
|
||||
}
|
||||
GTEST_ASSERT_EQ(accounting.syms.num_syms, kSymbols * 2);
|
||||
uint32_t tell_frac = aom_reader_tell_frac(&br);
|
||||
for (int i = 0; i < accounting.syms.num_syms; i++) {
|
||||
tell_frac -= accounting.syms.syms[i].bits;
|
||||
}
|
||||
GTEST_ASSERT_EQ(tell_frac, 0U);
|
||||
|
||||
GTEST_ASSERT_EQ(aom_accounting_dictionary_lookup(&accounting, "A"),
|
||||
aom_accounting_dictionary_lookup(&accounting, "A"));
|
||||
|
||||
// Check for collisions. The current aom_accounting_hash function returns
|
||||
// the same hash code for AB and BA.
|
||||
GTEST_ASSERT_NE(aom_accounting_dictionary_lookup(&accounting, "AB"),
|
||||
aom_accounting_dictionary_lookup(&accounting, "BA"));
|
||||
}
|
||||
84
media/libaom/src/test/acm_random.h
Normal file
84
media/libaom/src/test/acm_random.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_ACM_RANDOM_H_
|
||||
#define AOM_TEST_ACM_RANDOM_H_
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
class ACMRandom {
|
||||
public:
|
||||
ACMRandom() : random_(DeterministicSeed()) {}
|
||||
|
||||
explicit ACMRandom(int seed) : random_(seed) {}
|
||||
|
||||
void Reset(int seed) { random_.Reseed(seed); }
|
||||
|
||||
uint32_t Rand31(void) {
|
||||
return random_.Generate(testing::internal::Random::kMaxRange);
|
||||
}
|
||||
|
||||
uint16_t Rand16(void) {
|
||||
const uint32_t value =
|
||||
random_.Generate(testing::internal::Random::kMaxRange);
|
||||
return (value >> 15) & 0xffff;
|
||||
}
|
||||
|
||||
int16_t Rand15Signed(void) {
|
||||
const uint32_t value =
|
||||
random_.Generate(testing::internal::Random::kMaxRange);
|
||||
return (value >> 17) & 0xffff;
|
||||
}
|
||||
|
||||
uint16_t Rand12(void) {
|
||||
const uint32_t value =
|
||||
random_.Generate(testing::internal::Random::kMaxRange);
|
||||
// There's a bit more entropy in the upper bits of this implementation.
|
||||
return (value >> 19) & 0xfff;
|
||||
}
|
||||
|
||||
int16_t Rand9Signed(void) {
|
||||
// Use 9 bits: values between 255 (0x0FF) and -256 (0x100).
|
||||
const uint32_t value = random_.Generate(512);
|
||||
return static_cast<int16_t>(value) - 256;
|
||||
}
|
||||
|
||||
uint8_t Rand8(void) {
|
||||
const uint32_t value =
|
||||
random_.Generate(testing::internal::Random::kMaxRange);
|
||||
// There's a bit more entropy in the upper bits of this implementation.
|
||||
return (value >> 23) & 0xff;
|
||||
}
|
||||
|
||||
uint8_t Rand8Extremes(void) {
|
||||
// Returns a random value near 0 or near 255, to better exercise
|
||||
// saturation behavior.
|
||||
const uint8_t r = Rand8();
|
||||
return r < 128 ? r << 4 : r >> 4;
|
||||
}
|
||||
|
||||
int PseudoUniform(int range) { return random_.Generate(range); }
|
||||
|
||||
int operator()(int n) { return PseudoUniform(n); }
|
||||
|
||||
static int DeterministicSeed(void) { return 0xbaba; }
|
||||
|
||||
private:
|
||||
testing::internal::Random random_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_ACM_RANDOM_H_
|
||||
103
media/libaom/src/test/active_map_test.cc
Normal file
103
media/libaom/src/test/active_map_test.cc
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class ActiveMapTest
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
static const int kWidth = 208;
|
||||
static const int kHeight = 144;
|
||||
|
||||
ActiveMapTest() : EncoderTest(GET_PARAM(0)) {}
|
||||
virtual ~ActiveMapTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(GET_PARAM(1));
|
||||
cpu_used_ = GET_PARAM(2);
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, cpu_used_);
|
||||
} else if (video->frame() == 3) {
|
||||
aom_active_map_t map = aom_active_map_t();
|
||||
/* clang-format off */
|
||||
uint8_t active_map[9 * 13] = {
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
};
|
||||
/* clang-format on */
|
||||
map.cols = (kWidth + 15) / 16;
|
||||
map.rows = (kHeight + 15) / 16;
|
||||
ASSERT_EQ(map.cols, 13u);
|
||||
ASSERT_EQ(map.rows, 9u);
|
||||
map.active_map = active_map;
|
||||
encoder->Control(AOME_SET_ACTIVEMAP, &map);
|
||||
} else if (video->frame() == 15) {
|
||||
aom_active_map_t map = aom_active_map_t();
|
||||
map.cols = (kWidth + 15) / 16;
|
||||
map.rows = (kHeight + 15) / 16;
|
||||
map.active_map = NULL;
|
||||
encoder->Control(AOME_SET_ACTIVEMAP, &map);
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest() {
|
||||
// Validate that this non multiple of 64 wide clip encodes
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_target_bitrate = 400;
|
||||
cfg_.rc_resize_mode = 0;
|
||||
cfg_.g_pass = AOM_RC_ONE_PASS;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.kf_max_dist = 90000;
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", kWidth, kHeight, 30,
|
||||
1, 0, 20);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
int cpu_used_;
|
||||
};
|
||||
|
||||
TEST_P(ActiveMapTest, Test) { DoTest(); }
|
||||
|
||||
class ActiveMapTestLarge : public ActiveMapTest {};
|
||||
|
||||
TEST_P(ActiveMapTestLarge, Test) { DoTest(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(ActiveMapTestLarge,
|
||||
::testing::Values(::libaom_test::kRealTime),
|
||||
::testing::Range(0, 5));
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(ActiveMapTest,
|
||||
::testing::Values(::libaom_test::kRealTime),
|
||||
::testing::Range(5, 9));
|
||||
|
||||
} // namespace
|
||||
97
media/libaom/src/test/altref_test.cc
Normal file
97
media/libaom/src/test/altref_test.cc
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
namespace {
|
||||
|
||||
class AltRefForcedKeyTestLarge
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AltRefForcedKeyTestLarge()
|
||||
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
|
||||
cpu_used_(GET_PARAM(2)), forced_kf_frame_num_(1), frame_num_(0) {}
|
||||
virtual ~AltRefForcedKeyTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.g_threads = 0;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) {
|
||||
encoder->Control(AOME_SET_CPUUSED, cpu_used_);
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
#if CONFIG_AV1_ENCODER
|
||||
// override test default for tile columns if necessary.
|
||||
if (GET_PARAM(0) == &libaom_test::kAV1) {
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 6);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
frame_flags_ =
|
||||
(video->frame() == forced_kf_frame_num_) ? AOM_EFLAG_FORCE_KF : 0;
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (frame_num_ == forced_kf_frame_num_) {
|
||||
ASSERT_TRUE(!!(pkt->data.frame.flags & AOM_FRAME_IS_KEY))
|
||||
<< "Frame #" << frame_num_ << " isn't a keyframe!";
|
||||
}
|
||||
++frame_num_;
|
||||
}
|
||||
|
||||
::libaom_test::TestMode encoding_mode_;
|
||||
int cpu_used_;
|
||||
unsigned int forced_kf_frame_num_;
|
||||
unsigned int frame_num_;
|
||||
};
|
||||
|
||||
TEST_P(AltRefForcedKeyTestLarge, Frame1IsKey) {
|
||||
const aom_rational timebase = { 1, 30 };
|
||||
const int lag_values[] = { 3, 15, 25, -1 };
|
||||
|
||||
forced_kf_frame_num_ = 1;
|
||||
for (int i = 0; lag_values[i] != -1; ++i) {
|
||||
frame_num_ = 0;
|
||||
cfg_.g_lag_in_frames = lag_values[i];
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
timebase.den, timebase.num, 0, 30);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AltRefForcedKeyTestLarge, ForcedFrameIsKey) {
|
||||
const aom_rational timebase = { 1, 30 };
|
||||
const int lag_values[] = { 3, 15, 25, -1 };
|
||||
|
||||
for (int i = 0; lag_values[i] != -1; ++i) {
|
||||
frame_num_ = 0;
|
||||
forced_kf_frame_num_ = lag_values[i] - 1;
|
||||
cfg_.g_lag_in_frames = lag_values[i];
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
timebase.den, timebase.num, 0, 30);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AltRefForcedKeyTestLarge,
|
||||
::testing::Values(::libaom_test::kOnePassGood),
|
||||
::testing::Values(2, 5));
|
||||
|
||||
} // namespace
|
||||
177
media/libaom/src/test/aom_integer_test.cc
Normal file
177
media/libaom/src/test/aom_integer_test.cc
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
const uint64_t kMaximumLeb128CodedSize = 8;
|
||||
const uint8_t kLeb128PadByte = 0x80; // Binary: 10000000
|
||||
const uint64_t kMaximumLeb128Value = UINT32_MAX;
|
||||
const uint32_t kSizeTestNumValues = 6;
|
||||
const uint32_t kSizeTestExpectedSizes[kSizeTestNumValues] = {
|
||||
1, 1, 2, 3, 4, 5
|
||||
};
|
||||
const uint64_t kSizeTestInputs[kSizeTestNumValues] = {
|
||||
0, 0x7f, 0x3fff, 0x1fffff, 0xffffff, 0x10000000
|
||||
};
|
||||
|
||||
const uint8_t kOutOfRangeLeb128Value[5] = { 0x80, 0x80, 0x80, 0x80,
|
||||
0x10 }; // UINT32_MAX + 1
|
||||
} // namespace
|
||||
|
||||
TEST(AomLeb128, DecodeTest) {
|
||||
const size_t num_leb128_bytes = 3;
|
||||
const uint8_t leb128_bytes[num_leb128_bytes] = { 0xE5, 0x8E, 0x26 };
|
||||
const uint64_t expected_value = 0x98765; // 624485
|
||||
const size_t expected_length = 3;
|
||||
uint64_t value = ~0ULL; // make sure value is cleared by the function
|
||||
size_t length;
|
||||
ASSERT_EQ(
|
||||
aom_uleb_decode(&leb128_bytes[0], num_leb128_bytes, &value, &length), 0);
|
||||
ASSERT_EQ(expected_value, value);
|
||||
ASSERT_EQ(expected_length, length);
|
||||
|
||||
// Make sure the decoder stops on the last marked LEB128 byte.
|
||||
aom_uleb_decode(&leb128_bytes[0], num_leb128_bytes + 1, &value, &length);
|
||||
ASSERT_EQ(expected_value, value);
|
||||
ASSERT_EQ(expected_length, length);
|
||||
}
|
||||
|
||||
TEST(AomLeb128, EncodeTest) {
|
||||
const uint32_t test_value = 0x98765; // 624485
|
||||
const uint8_t expected_bytes[3] = { 0xE5, 0x8E, 0x26 };
|
||||
const size_t kWriteBufferSize = 4;
|
||||
uint8_t write_buffer[kWriteBufferSize] = { 0 };
|
||||
size_t bytes_written = 0;
|
||||
ASSERT_EQ(aom_uleb_encode(test_value, kWriteBufferSize, &write_buffer[0],
|
||||
&bytes_written),
|
||||
0);
|
||||
ASSERT_EQ(bytes_written, 3u);
|
||||
for (size_t i = 0; i < bytes_written; ++i) {
|
||||
ASSERT_EQ(write_buffer[i], expected_bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AomLeb128, EncodeDecodeTest) {
|
||||
const uint32_t value = 0x98765; // 624485
|
||||
const size_t kWriteBufferSize = 4;
|
||||
uint8_t write_buffer[kWriteBufferSize] = { 0 };
|
||||
size_t bytes_written = 0;
|
||||
ASSERT_EQ(aom_uleb_encode(value, kWriteBufferSize, &write_buffer[0],
|
||||
&bytes_written),
|
||||
0);
|
||||
ASSERT_EQ(bytes_written, 3u);
|
||||
uint64_t decoded_value;
|
||||
size_t decoded_length;
|
||||
aom_uleb_decode(&write_buffer[0], bytes_written, &decoded_value,
|
||||
&decoded_length);
|
||||
ASSERT_EQ(value, decoded_value);
|
||||
ASSERT_EQ(bytes_written, decoded_length);
|
||||
}
|
||||
|
||||
TEST(AomLeb128, FixedSizeEncodeTest) {
|
||||
const uint32_t test_value = 0x123;
|
||||
const uint8_t expected_bytes[4] = { 0xa3, 0x82, 0x80, 0x00 };
|
||||
const size_t kWriteBufferSize = 4;
|
||||
uint8_t write_buffer[kWriteBufferSize] = { 0 };
|
||||
size_t bytes_written = 0;
|
||||
ASSERT_EQ(0, aom_uleb_encode_fixed_size(test_value, kWriteBufferSize,
|
||||
kWriteBufferSize, &write_buffer[0],
|
||||
&bytes_written));
|
||||
ASSERT_EQ(kWriteBufferSize, bytes_written);
|
||||
for (size_t i = 0; i < bytes_written; ++i) {
|
||||
ASSERT_EQ(write_buffer[i], expected_bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AomLeb128, FixedSizeEncodeDecodeTest) {
|
||||
const uint32_t value = 0x1;
|
||||
const size_t kWriteBufferSize = 4;
|
||||
uint8_t write_buffer[kWriteBufferSize] = { 0 };
|
||||
size_t bytes_written = 0;
|
||||
ASSERT_EQ(
|
||||
aom_uleb_encode_fixed_size(value, kWriteBufferSize, kWriteBufferSize,
|
||||
&write_buffer[0], &bytes_written),
|
||||
0);
|
||||
ASSERT_EQ(bytes_written, 4u);
|
||||
uint64_t decoded_value;
|
||||
size_t decoded_length;
|
||||
aom_uleb_decode(&write_buffer[0], bytes_written, &decoded_value,
|
||||
&decoded_length);
|
||||
ASSERT_EQ(value, decoded_value);
|
||||
ASSERT_EQ(bytes_written, decoded_length);
|
||||
}
|
||||
|
||||
TEST(AomLeb128, SizeTest) {
|
||||
for (size_t i = 0; i < kSizeTestNumValues; ++i) {
|
||||
ASSERT_EQ(kSizeTestExpectedSizes[i],
|
||||
aom_uleb_size_in_bytes(kSizeTestInputs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AomLeb128, DecodeFailTest) {
|
||||
// Input buffer containing what would be a valid 9 byte LEB128 encoded
|
||||
// unsigned integer.
|
||||
const uint8_t kAllPadBytesBuffer[kMaximumLeb128CodedSize + 1] = {
|
||||
kLeb128PadByte, kLeb128PadByte, kLeb128PadByte,
|
||||
kLeb128PadByte, kLeb128PadByte, kLeb128PadByte,
|
||||
kLeb128PadByte, kLeb128PadByte, 0
|
||||
};
|
||||
uint64_t decoded_value;
|
||||
|
||||
// Test that decode fails when result would be valid 9 byte integer.
|
||||
ASSERT_EQ(aom_uleb_decode(&kAllPadBytesBuffer[0], kMaximumLeb128CodedSize + 1,
|
||||
&decoded_value, NULL),
|
||||
-1);
|
||||
|
||||
// Test that encoded value missing terminator byte within available buffer
|
||||
// range causes decode error.
|
||||
ASSERT_EQ(aom_uleb_decode(&kAllPadBytesBuffer[0], kMaximumLeb128CodedSize,
|
||||
&decoded_value, NULL),
|
||||
-1);
|
||||
|
||||
// Test that LEB128 input that decodes to a value larger than 32-bits fails.
|
||||
size_t value_size = 0;
|
||||
ASSERT_EQ(aom_uleb_decode(&kOutOfRangeLeb128Value[0],
|
||||
sizeof(kOutOfRangeLeb128Value), &decoded_value,
|
||||
&value_size),
|
||||
-1);
|
||||
}
|
||||
|
||||
TEST(AomLeb128, EncodeFailTest) {
|
||||
const size_t kWriteBufferSize = 4;
|
||||
const uint32_t kValidTestValue = 1;
|
||||
uint8_t write_buffer[kWriteBufferSize] = { 0 };
|
||||
size_t coded_size = 0;
|
||||
ASSERT_EQ(
|
||||
aom_uleb_encode(kValidTestValue, kWriteBufferSize, NULL, &coded_size),
|
||||
-1);
|
||||
ASSERT_EQ(aom_uleb_encode(kValidTestValue, kWriteBufferSize, &write_buffer[0],
|
||||
NULL),
|
||||
-1);
|
||||
|
||||
const uint32_t kValueOutOfRangeForBuffer = 0xFFFFFFFF;
|
||||
ASSERT_EQ(aom_uleb_encode(kValueOutOfRangeForBuffer, kWriteBufferSize,
|
||||
&write_buffer[0], &coded_size),
|
||||
-1);
|
||||
|
||||
const uint64_t kValueOutOfRange = kMaximumLeb128Value + 1;
|
||||
ASSERT_EQ(aom_uleb_encode(kValueOutOfRange, kWriteBufferSize,
|
||||
&write_buffer[0], &coded_size),
|
||||
-1);
|
||||
|
||||
const size_t kPadSizeOutOfRange = 5;
|
||||
ASSERT_EQ(aom_uleb_encode_fixed_size(kValidTestValue, kWriteBufferSize,
|
||||
kPadSizeOutOfRange, &write_buffer[0],
|
||||
&coded_size),
|
||||
-1);
|
||||
}
|
||||
58
media/libaom/src/test/aomcx_set_ref.sh
Normal file
58
media/libaom/src/test/aomcx_set_ref.sh
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests the libaom aom_cx_set_ref example. To add new tests to this
|
||||
## file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to aom_cx_set_ref_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: $YUV_RAW_INPUT is required.
|
||||
aom_cx_set_ref_verify_environment() {
|
||||
if [ ! -e "${YUV_RAW_INPUT}" ]; then
|
||||
echo "Libaom test data must exist in LIBAOM_TEST_DATA_PATH."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Runs aom_cx_set_ref and updates the reference frame before encoding frame 90.
|
||||
# $1 is the codec name, which aom_cx_set_ref does not support at present: It's
|
||||
# currently used only to name the output file.
|
||||
# TODO(tomfinegan): Pass the codec param once the example is updated to support
|
||||
# AV1.
|
||||
aom_set_ref() {
|
||||
local encoder="${LIBAOM_BIN_PATH}/aom_cx_set_ref${AOM_TEST_EXE_SUFFIX}"
|
||||
local codec="$1"
|
||||
local output_file="${AOM_TEST_OUTPUT_DIR}/aom_cx_set_ref_${codec}.ivf"
|
||||
local ref_frame_num=4
|
||||
local limit=10
|
||||
if [ ! -x "${encoder}" ]; then
|
||||
elog "${encoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${encoder}" "${codec}" "${YUV_RAW_INPUT_WIDTH}" \
|
||||
"${YUV_RAW_INPUT_HEIGHT}" "${YUV_RAW_INPUT}" "${output_file}" \
|
||||
"${ref_frame_num}" "${limit}" ${devnull}
|
||||
|
||||
[ -e "${output_file}" ] || return 1
|
||||
}
|
||||
|
||||
aom_cx_set_ref_av1() {
|
||||
if [ "$(av1_encode_available)" = "yes" ]; then
|
||||
aom_set_ref av1 || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
aom_cx_set_ref_tests="aom_cx_set_ref_av1"
|
||||
|
||||
run_tests aom_cx_set_ref_verify_environment "${aom_cx_set_ref_tests}"
|
||||
|
||||
147
media/libaom/src/test/aomdec.sh
Normal file
147
media/libaom/src/test/aomdec.sh
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests aomdec. To add new tests to this file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to aomdec_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: Make sure input is available.
|
||||
aomdec_verify_environment() {
|
||||
if [ "$(av1_encode_available)" != "yes" ] ; then
|
||||
if [ ! -e "${AV1_IVF_FILE}" ] || \
|
||||
[ ! -e "${AV1_OBU_ANNEXB_FILE}" ] || \
|
||||
[ ! -e "${AV1_OBU_SEC5_FILE}" ] || \
|
||||
[ ! -e "${AV1_WEBM_FILE}" ]; then
|
||||
elog "Libaom test data must exist before running this test script when " \
|
||||
" encoding is disabled. "
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [ -z "$(aom_tool_path aomdec)" ]; then
|
||||
elog "aomdec not found. It must exist in LIBAOM_BIN_PATH or its parent."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Wrapper function for running aomdec with pipe input. Requires that
|
||||
# LIBAOM_BIN_PATH points to the directory containing aomdec. $1 is used as the
|
||||
# input file path and shifted away. All remaining parameters are passed through
|
||||
# to aomdec.
|
||||
aomdec_pipe() {
|
||||
local input="$1"
|
||||
shift
|
||||
if [ ! -e "${input}" ]; then
|
||||
elog "Input file ($input) missing in aomdec_pipe()"
|
||||
return 1
|
||||
fi
|
||||
cat "${file}" | aomdec - "$@" ${devnull}
|
||||
}
|
||||
|
||||
|
||||
# Wrapper function for running aomdec. Requires that LIBAOM_BIN_PATH points to
|
||||
# the directory containing aomdec. $1 one is used as the input file path and
|
||||
# shifted away. All remaining parameters are passed through to aomdec.
|
||||
aomdec() {
|
||||
local decoder="$(aom_tool_path aomdec)"
|
||||
local input="$1"
|
||||
shift
|
||||
eval "${AOM_TEST_PREFIX}" "${decoder}" "$input" "$@" ${devnull}
|
||||
}
|
||||
|
||||
aomdec_can_decode_av1() {
|
||||
if [ "$(av1_decode_available)" = "yes" ]; then
|
||||
echo yes
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_ivf() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="${AV1_IVF_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf
|
||||
fi
|
||||
aomdec "${AV1_IVF_FILE}" --summary --noblit
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_ivf_error_resilient() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="av1.error-resilient.ivf"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf --error-resilient=1
|
||||
fi
|
||||
aomdec "${file}" --summary --noblit
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_ivf_multithread() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="${AV1_IVF_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf
|
||||
fi
|
||||
for threads in 2 3 4 5 6 7 8; do
|
||||
aomdec "${file}" --summary --noblit --threads=$threads
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_aom_ivf_pipe_input() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="${AV1_IVF_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf
|
||||
fi
|
||||
aomdec_pipe "${AV1_IVF_FILE}" --summary --noblit
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_obu_annexb() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="${AV1_OBU_ANNEXB_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --obu --annexb=1
|
||||
fi
|
||||
aomdec "${file}" --summary --noblit --annexb
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_obu_section5() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ]; then
|
||||
local file="${AV1_OBU_SEC5_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}" --obu
|
||||
fi
|
||||
aomdec "${file}" --summary --noblit
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_av1_webm() {
|
||||
if [ "$(aomdec_can_decode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
local file="${AV1_WEBM_FILE}"
|
||||
if [ ! -e "${file}" ]; then
|
||||
encode_yuv_raw_input_av1 "${file}"
|
||||
fi
|
||||
aomdec "${AV1_WEBM_FILE}" --summary --noblit
|
||||
fi
|
||||
}
|
||||
|
||||
aomdec_tests="aomdec_av1_ivf
|
||||
aomdec_av1_ivf_error_resilient
|
||||
aomdec_av1_ivf_multithread
|
||||
aomdec_aom_ivf_pipe_input
|
||||
aomdec_av1_obu_annexb
|
||||
aomdec_av1_obu_section5
|
||||
aomdec_av1_webm"
|
||||
|
||||
run_tests aomdec_verify_environment "${aomdec_tests}"
|
||||
269
media/libaom/src/test/aomenc.sh
Normal file
269
media/libaom/src/test/aomenc.sh
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests aomenc using hantro_collage_w352h288.yuv as input. To add
|
||||
## new tests to this file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to aomenc_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: Make sure input is available.
|
||||
aomenc_verify_environment() {
|
||||
if [ ! -e "${YUV_RAW_INPUT}" ]; then
|
||||
elog "The file ${YUV_RAW_INPUT##*/} must exist in LIBAOM_TEST_DATA_PATH."
|
||||
return 1
|
||||
fi
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
if [ ! -e "${Y4M_NOSQ_PAR_INPUT}" ]; then
|
||||
elog "The file ${Y4M_NOSQ_PAR_INPUT##*/} must exist in"
|
||||
elog "LIBAOM_TEST_DATA_PATH."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
if [ -z "$(aom_tool_path aomenc)" ]; then
|
||||
elog "aomenc not found. It must exist in LIBAOM_BIN_PATH or its parent."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_can_encode_av1() {
|
||||
if [ "$(av1_encode_available)" = "yes" ]; then
|
||||
echo yes
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_can_encode_av1() {
|
||||
if [ "$(av1_encode_available)" = "yes" ]; then
|
||||
echo yes
|
||||
fi
|
||||
}
|
||||
|
||||
# Utilities that echo aomenc input file parameters.
|
||||
y4m_input_non_square_par() {
|
||||
echo ""${Y4M_NOSQ_PAR_INPUT}""
|
||||
}
|
||||
|
||||
y4m_input_720p() {
|
||||
echo ""${Y4M_720P_INPUT}""
|
||||
}
|
||||
|
||||
# Wrapper function for running aomenc with pipe input. Requires that
|
||||
# LIBAOM_BIN_PATH points to the directory containing aomenc. $1 is used as the
|
||||
# input file path and shifted away. All remaining parameters are passed through
|
||||
# to aomenc.
|
||||
aomenc_pipe() {
|
||||
local encoder="$(aom_tool_path aomenc)"
|
||||
local input="$1"
|
||||
shift
|
||||
cat "${input}" | eval "${AOM_TEST_PREFIX}" "${encoder}" - \
|
||||
--test-decode=fatal \
|
||||
"$@" ${devnull}
|
||||
}
|
||||
|
||||
# Wrapper function for running aomenc. Requires that LIBAOM_BIN_PATH points to
|
||||
# the directory containing aomenc. $1 one is used as the input file path and
|
||||
# shifted away. All remaining parameters are passed through to aomenc.
|
||||
aomenc() {
|
||||
local encoder="$(aom_tool_path aomenc)"
|
||||
local input="$1"
|
||||
shift
|
||||
eval "${AOM_TEST_PREFIX}" "${encoder}" "${input}" \
|
||||
--test-decode=fatal \
|
||||
"$@" ${devnull}
|
||||
}
|
||||
|
||||
aomenc_av1_ivf() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
local output="${AV1_IVF_FILE}"
|
||||
if [ -e "${AV1_IVF_FILE}" ]; then
|
||||
output="${AOM_TEST_OUTPUT_DIR}/av1_test.ivf"
|
||||
fi
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--ivf \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_obu_annexb() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
local output="${AV1_OBU_ANNEXB_FILE}"
|
||||
if [ -e "${AV1_OBU_ANNEXB_FILE}" ]; then
|
||||
output="${AOM_TEST_OUTPUT_DIR}/av1_test.annexb.obu"
|
||||
fi
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--obu \
|
||||
--annexb=1 \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_obu_section5() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
local output="${AV1_OBU_SEC5_FILE}"
|
||||
if [ -e "${AV1_OBU_SEC5_FILE}" ]; then
|
||||
output="${AOM_TEST_OUTPUT_DIR}/av1_test.section5.obu"
|
||||
fi
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--obu \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_webm() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
local output="${AV1_WEBM_FILE}"
|
||||
if [ -e "${AV1_WEBM_FILE}" ]; then
|
||||
output="${AOM_TEST_OUTPUT_DIR}/av1_test.webm"
|
||||
fi
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_webm_1pass() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/av1_test.webm"
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--passes=1 \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_ivf_lossless() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/av1_lossless.ivf"
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--ivf \
|
||||
--output="${output}" \
|
||||
--lossless=1
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_ivf_minq0_maxq0() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ]; then
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/av1_lossless_minq0_maxq0.ivf"
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--ivf \
|
||||
--output="${output}" \
|
||||
--min-q=0 \
|
||||
--max-q=0
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_webm_lag5_frames10() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
local lag_total_frames=10
|
||||
local lag_frames=5
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/av1_lag5_frames10.webm"
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--limit=${lag_total_frames} \
|
||||
--lag-in-frames=${lag_frames} \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO(fgalligan): Test that DisplayWidth is different than video width.
|
||||
aomenc_av1_webm_non_square_par() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/av1_non_square_par.webm"
|
||||
aomenc $(y4m_input_non_square_par) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_av1_webm_cdf_update_mode() {
|
||||
if [ "$(aomenc_can_encode_av1)" = "yes" ] && \
|
||||
[ "$(webm_io_available)" = "yes" ]; then
|
||||
for mode in 0 1 2; do
|
||||
local output="${AOM_TEST_OUTPUT_DIR}/cdf_mode_${mode}.webm"
|
||||
aomenc $(yuv_raw_input) \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
--cdf-update-mode=${mode} \
|
||||
--output="${output}"
|
||||
|
||||
if [ ! -e "${output}" ]; then
|
||||
elog "Output file does not exist."
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_tests="aomenc_av1_ivf
|
||||
aomenc_av1_obu_annexb
|
||||
aomenc_av1_obu_section5
|
||||
aomenc_av1_webm
|
||||
aomenc_av1_webm_1pass
|
||||
aomenc_av1_ivf_lossless
|
||||
aomenc_av1_ivf_minq0_maxq0
|
||||
aomenc_av1_webm_lag5_frames10
|
||||
aomenc_av1_webm_non_square_par
|
||||
aomenc_av1_webm_cdf_update_mode"
|
||||
|
||||
run_tests aomenc_verify_environment "${aomenc_tests}"
|
||||
108
media/libaom/src/test/aq_segment_test.cc
Normal file
108
media/libaom/src/test/aq_segment_test.cc
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class AqSegmentTest
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AqSegmentTest() : EncoderTest(GET_PARAM(0)) {}
|
||||
virtual ~AqSegmentTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(GET_PARAM(1));
|
||||
set_cpu_used_ = GET_PARAM(2);
|
||||
aq_mode_ = 0;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
encoder->Control(AV1E_SET_AQ_MODE, aq_mode_);
|
||||
encoder->Control(AV1E_SET_DELTAQ_MODE, deltaq_mode_);
|
||||
encoder->Control(AOME_SET_MAX_INTRA_BITRATE_PCT, 100);
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest(int aq_mode) {
|
||||
aq_mode_ = aq_mode;
|
||||
deltaq_mode_ = 0;
|
||||
cfg_.kf_max_dist = 12;
|
||||
cfg_.rc_min_quantizer = 8;
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.g_lag_in_frames = 6;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 500;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_target_bitrate = 300;
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352,
|
||||
288, 30, 1, 0, 15);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
int set_cpu_used_;
|
||||
int aq_mode_;
|
||||
int deltaq_mode_;
|
||||
};
|
||||
|
||||
// Validate that this AQ segmentation mode (AQ=1, variance_ap)
|
||||
// encodes and decodes without a mismatch.
|
||||
TEST_P(AqSegmentTest, TestNoMisMatchAQ1) { DoTest(1); }
|
||||
|
||||
// Validate that this AQ segmentation mode (AQ=2, complexity_aq)
|
||||
// encodes and decodes without a mismatch.
|
||||
TEST_P(AqSegmentTest, TestNoMisMatchAQ2) { DoTest(2); }
|
||||
|
||||
// Validate that this AQ segmentation mode (AQ=3, cyclic_refresh_aq)
|
||||
// encodes and decodes without a mismatch.
|
||||
TEST_P(AqSegmentTest, TestNoMisMatchAQ3) { DoTest(3); }
|
||||
|
||||
class AqSegmentTestLarge : public AqSegmentTest {};
|
||||
|
||||
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ1) { DoTest(1); }
|
||||
|
||||
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ2) { DoTest(2); }
|
||||
|
||||
TEST_P(AqSegmentTestLarge, TestNoMisMatchAQ3) { DoTest(3); }
|
||||
|
||||
// Validate that this delta q mode
|
||||
// encodes and decodes without a mismatch.
|
||||
TEST_P(AqSegmentTest, TestNoMisMatchExtDeltaQ) {
|
||||
cfg_.rc_end_usage = AOM_CQ;
|
||||
aq_mode_ = 0;
|
||||
deltaq_mode_ = 2;
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 15);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AqSegmentTest,
|
||||
::testing::Values(::libaom_test::kRealTime,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(5, 9));
|
||||
AV1_INSTANTIATE_TEST_CASE(AqSegmentTestLarge,
|
||||
::testing::Values(::libaom_test::kRealTime,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(3, 5));
|
||||
} // namespace
|
||||
223
media/libaom/src/test/arf_freq_test.cc
Normal file
223
media/libaom/src/test/arf_freq_test.cc
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
#include "test/yuv_video_source.h"
|
||||
#include "av1/encoder/ratectrl.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const unsigned int kFrames = 100;
|
||||
const int kBitrate = 500;
|
||||
|
||||
#define ARF_NOT_SEEN 1000001
|
||||
#define ARF_SEEN_ONCE 1000000
|
||||
|
||||
typedef struct {
|
||||
const char *filename;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int framerate_num;
|
||||
unsigned int framerate_den;
|
||||
unsigned int input_bit_depth;
|
||||
aom_img_fmt fmt;
|
||||
aom_bit_depth_t bit_depth;
|
||||
unsigned int profile;
|
||||
} TestVideoParam;
|
||||
|
||||
typedef struct {
|
||||
libaom_test::TestMode mode;
|
||||
int cpu_used;
|
||||
} TestEncodeParam;
|
||||
|
||||
const TestVideoParam kTestVectors[] = {
|
||||
// artificially increase framerate to trigger default check
|
||||
{ "hantro_collage_w352h288.yuv", 352, 288, 5000, 1, 8, AOM_IMG_FMT_I420,
|
||||
AOM_BITS_8, 0 },
|
||||
{ "hantro_collage_w352h288.yuv", 352, 288, 30, 1, 8, AOM_IMG_FMT_I420,
|
||||
AOM_BITS_8, 0 },
|
||||
{ "rush_hour_444.y4m", 352, 288, 30, 1, 8, AOM_IMG_FMT_I444, AOM_BITS_8, 1 },
|
||||
// Add list of profile 2/3 test videos here ...
|
||||
};
|
||||
|
||||
const TestEncodeParam kEncodeVectors[] = {
|
||||
{ ::libaom_test::kOnePassGood, 2 }, { ::libaom_test::kOnePassGood, 5 },
|
||||
{ ::libaom_test::kTwoPassGood, 1 }, { ::libaom_test::kTwoPassGood, 2 },
|
||||
{ ::libaom_test::kTwoPassGood, 5 }, { ::libaom_test::kRealTime, 5 },
|
||||
};
|
||||
|
||||
const int kMinArfVectors[] = {
|
||||
// NOTE: 0 refers to the default built-in logic in:
|
||||
// av1_rc_get_default_min_gf_interval(...)
|
||||
0, 4, 8, 12, 15
|
||||
};
|
||||
|
||||
int is_extension_y4m(const char *filename) {
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if (!dot || dot == filename)
|
||||
return 0;
|
||||
else
|
||||
return !strcmp(dot, ".y4m");
|
||||
}
|
||||
|
||||
class ArfFreqTestLarge
|
||||
: public ::libaom_test::CodecTestWith3Params<TestVideoParam,
|
||||
TestEncodeParam, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
ArfFreqTestLarge()
|
||||
: EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)),
|
||||
test_encode_param_(GET_PARAM(2)), min_arf_requested_(GET_PARAM(3)) {}
|
||||
|
||||
virtual ~ArfFreqTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(test_encode_param_.mode);
|
||||
if (test_encode_param_.mode != ::libaom_test::kRealTime) {
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
} else {
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int) {
|
||||
min_run_ = ARF_NOT_SEEN;
|
||||
run_of_visible_frames_ = 0;
|
||||
}
|
||||
|
||||
int GetNumFramesInPkt(const aom_codec_cx_pkt_t *pkt) {
|
||||
const uint8_t *buffer = reinterpret_cast<uint8_t *>(pkt->data.frame.buf);
|
||||
const uint8_t marker = buffer[pkt->data.frame.sz - 1];
|
||||
const int mag = ((marker >> 3) & 3) + 1;
|
||||
int frames = (marker & 0x7) + 1;
|
||||
const unsigned int index_sz = 2 + mag * frames;
|
||||
// Check for superframe or not.
|
||||
// Assume superframe has only one visible frame, the rest being
|
||||
// invisible. If superframe index is not found, then there is only
|
||||
// one frame.
|
||||
if (!((marker & 0xe0) == 0xc0 && pkt->data.frame.sz >= index_sz &&
|
||||
buffer[pkt->data.frame.sz - index_sz] == marker)) {
|
||||
frames = 1;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) return;
|
||||
const int frames = GetNumFramesInPkt(pkt);
|
||||
if (frames == 1) {
|
||||
run_of_visible_frames_++;
|
||||
} else if (frames == 2) {
|
||||
if (min_run_ == ARF_NOT_SEEN) {
|
||||
min_run_ = ARF_SEEN_ONCE;
|
||||
} else if (min_run_ == ARF_SEEN_ONCE ||
|
||||
run_of_visible_frames_ < min_run_) {
|
||||
min_run_ = run_of_visible_frames_;
|
||||
}
|
||||
run_of_visible_frames_ = 1;
|
||||
} else {
|
||||
min_run_ = 0;
|
||||
run_of_visible_frames_ = 1;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) {
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 4);
|
||||
encoder->Control(AOME_SET_CPUUSED, test_encode_param_.cpu_used);
|
||||
encoder->Control(AV1E_SET_MIN_GF_INTERVAL, min_arf_requested_);
|
||||
if (test_encode_param_.mode != ::libaom_test::kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GetMinVisibleRun() const { return min_run_; }
|
||||
|
||||
int GetMinArfDistanceRequested() const {
|
||||
if (min_arf_requested_)
|
||||
return min_arf_requested_;
|
||||
else
|
||||
return av1_rc_get_default_min_gf_interval(
|
||||
test_video_param_.width, test_video_param_.height,
|
||||
(double)test_video_param_.framerate_num /
|
||||
test_video_param_.framerate_den);
|
||||
}
|
||||
|
||||
TestVideoParam test_video_param_;
|
||||
TestEncodeParam test_encode_param_;
|
||||
|
||||
private:
|
||||
int min_arf_requested_;
|
||||
int min_run_;
|
||||
int run_of_visible_frames_;
|
||||
};
|
||||
|
||||
TEST_P(ArfFreqTestLarge, MinArfFreqTest) {
|
||||
cfg_.rc_target_bitrate = kBitrate;
|
||||
cfg_.g_error_resilient = 0;
|
||||
cfg_.g_profile = test_video_param_.profile;
|
||||
cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
|
||||
cfg_.g_bit_depth = test_video_param_.bit_depth;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH;
|
||||
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video;
|
||||
if (is_extension_y4m(test_video_param_.filename)) {
|
||||
video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0,
|
||||
kFrames));
|
||||
} else {
|
||||
video.reset(new libaom_test::YUVVideoSource(
|
||||
test_video_param_.filename, test_video_param_.fmt,
|
||||
test_video_param_.width, test_video_param_.height,
|
||||
test_video_param_.framerate_num, test_video_param_.framerate_den, 0,
|
||||
kFrames));
|
||||
}
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
const int min_run = GetMinVisibleRun();
|
||||
const int min_arf_dist_requested = GetMinArfDistanceRequested();
|
||||
if (min_run != ARF_NOT_SEEN && min_run != ARF_SEEN_ONCE) {
|
||||
const int min_arf_dist = min_run + 1;
|
||||
EXPECT_GE(min_arf_dist, min_arf_dist_requested);
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_AV1_ENCODER
|
||||
// TODO(angiebird): 25-29 fail in high bitdepth mode.
|
||||
// TODO(zoeliu): This ArfFreqTest does not work with BWDREF_FRAME, as
|
||||
// BWDREF_FRAME is also a non-show frame, and the minimum run between two
|
||||
// consecutive BWDREF_FRAME's may vary between 1 and any arbitrary positive
|
||||
// number as long as it does not exceed the gf_group interval.
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DISABLED_AV1, ArfFreqTestLarge,
|
||||
::testing::Combine(
|
||||
::testing::Values(
|
||||
static_cast<const libaom_test::CodecFactory *>(&libaom_test::kAV1)),
|
||||
::testing::ValuesIn(kTestVectors), ::testing::ValuesIn(kEncodeVectors),
|
||||
::testing::ValuesIn(kMinArfVectors)));
|
||||
#endif // CONFIG_AV1_ENCODER
|
||||
} // namespace
|
||||
164
media/libaom/src/test/av1_config_test.cc
Normal file
164
media/libaom/src/test/av1_config_test.cc
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "common/av1_config.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// Input buffers containing exactly one Sequence Header OBU.
|
||||
//
|
||||
// Each buffer is named according to the OBU storage format (Annex-B vs Low
|
||||
// Overhead Bitstream Format) and the type of Sequence Header OBU ("Full"
|
||||
// Sequence Header OBUs vs Sequence Header OBUs with the
|
||||
// reduced_still_image_flag set).
|
||||
//
|
||||
const uint8_t kAnnexBFullSequenceHeaderObu[] = {
|
||||
0x0c, 0x08, 0x00, 0x00, 0x00, 0x04, 0x45, 0x7e, 0x3e, 0xff, 0xfc, 0xc0, 0x20
|
||||
};
|
||||
const uint8_t kAnnexBReducedStillImageSequenceHeaderObu[] = {
|
||||
0x08, 0x08, 0x18, 0x22, 0x2b, 0xf1, 0xfe, 0xc0, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kLobfFullSequenceHeaderObu[] = {
|
||||
0x0a, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x45, 0x7e, 0x3e, 0xff, 0xfc, 0xc0, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kLobfReducedStillImageSequenceHeaderObu[] = {
|
||||
0x0a, 0x07, 0x18, 0x22, 0x2b, 0xf1, 0xfe, 0xc0, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kAv1cAllZero[] = { 0, 0, 0, 0 };
|
||||
|
||||
// The size of AV1 config when no configOBUs are present at the end of the
|
||||
// configuration structure.
|
||||
const size_t kAv1cNoConfigObusSize = 4;
|
||||
|
||||
bool VerifyAv1c(const uint8_t *const obu_buffer, size_t obu_buffer_length,
|
||||
bool is_annexb) {
|
||||
Av1Config av1_config;
|
||||
memset(&av1_config, 0, sizeof(av1_config));
|
||||
bool parse_ok = get_av1config_from_obu(obu_buffer, obu_buffer_length,
|
||||
is_annexb, &av1_config) == 0;
|
||||
if (parse_ok) {
|
||||
EXPECT_EQ(1, av1_config.marker);
|
||||
EXPECT_EQ(1, av1_config.version);
|
||||
EXPECT_EQ(0, av1_config.seq_profile);
|
||||
EXPECT_EQ(0, av1_config.seq_level_idx_0);
|
||||
EXPECT_EQ(0, av1_config.seq_tier_0);
|
||||
EXPECT_EQ(0, av1_config.high_bitdepth);
|
||||
EXPECT_EQ(0, av1_config.twelve_bit);
|
||||
EXPECT_EQ(0, av1_config.monochrome);
|
||||
EXPECT_EQ(1, av1_config.chroma_subsampling_x);
|
||||
EXPECT_EQ(1, av1_config.chroma_subsampling_y);
|
||||
EXPECT_EQ(0, av1_config.chroma_sample_position);
|
||||
EXPECT_EQ(0, av1_config.initial_presentation_delay_present);
|
||||
EXPECT_EQ(0, av1_config.initial_presentation_delay_minus_one);
|
||||
}
|
||||
return parse_ok && ::testing::Test::HasFailure() == false;
|
||||
}
|
||||
|
||||
TEST(Av1Config, ObuInvalidInputs) {
|
||||
Av1Config av1_config;
|
||||
memset(&av1_config, 0, sizeof(av1_config));
|
||||
ASSERT_EQ(-1, get_av1config_from_obu(NULL, 0, 0, NULL));
|
||||
ASSERT_EQ(-1,
|
||||
get_av1config_from_obu(&kLobfFullSequenceHeaderObu[0], 0, 0, NULL));
|
||||
ASSERT_EQ(
|
||||
-1, get_av1config_from_obu(&kLobfFullSequenceHeaderObu[0],
|
||||
sizeof(kLobfFullSequenceHeaderObu), 0, NULL));
|
||||
ASSERT_EQ(-1, get_av1config_from_obu(NULL, sizeof(kLobfFullSequenceHeaderObu),
|
||||
0, NULL));
|
||||
ASSERT_EQ(-1, get_av1config_from_obu(&kLobfFullSequenceHeaderObu[0], 0, 0,
|
||||
&av1_config));
|
||||
}
|
||||
|
||||
TEST(Av1Config, ReadInvalidInputs) {
|
||||
Av1Config av1_config;
|
||||
memset(&av1_config, 0, sizeof(av1_config));
|
||||
size_t bytes_read = 0;
|
||||
ASSERT_EQ(-1, read_av1config(NULL, 0, NULL, NULL));
|
||||
ASSERT_EQ(-1, read_av1config(NULL, 4, NULL, NULL));
|
||||
ASSERT_EQ(-1, read_av1config(&kAv1cAllZero[0], 0, NULL, NULL));
|
||||
ASSERT_EQ(-1, read_av1config(&kAv1cAllZero[0], 4, &bytes_read, NULL));
|
||||
ASSERT_EQ(-1, read_av1config(NULL, 4, &bytes_read, &av1_config));
|
||||
}
|
||||
|
||||
TEST(Av1Config, WriteInvalidInputs) {
|
||||
Av1Config av1_config;
|
||||
memset(&av1_config, 0, sizeof(av1_config));
|
||||
size_t bytes_written = 0;
|
||||
uint8_t av1c_buffer[4] = { 0 };
|
||||
ASSERT_EQ(-1, write_av1config(NULL, 0, NULL, NULL));
|
||||
ASSERT_EQ(-1, write_av1config(&av1_config, 0, NULL, NULL));
|
||||
ASSERT_EQ(-1, write_av1config(&av1_config, 0, &bytes_written, NULL));
|
||||
|
||||
ASSERT_EQ(-1,
|
||||
write_av1config(&av1_config, 0, &bytes_written, &av1c_buffer[0]));
|
||||
ASSERT_EQ(-1, write_av1config(&av1_config, 4, &bytes_written, NULL));
|
||||
}
|
||||
|
||||
TEST(Av1Config, GetAv1ConfigFromLobfObu) {
|
||||
// Test parsing of a Sequence Header OBU with the reduced_still_picture_header
|
||||
// unset-- aka a full Sequence Header OBU.
|
||||
ASSERT_TRUE(VerifyAv1c(kLobfFullSequenceHeaderObu,
|
||||
sizeof(kLobfFullSequenceHeaderObu), false));
|
||||
|
||||
// Test parsing of a reduced still image Sequence Header OBU.
|
||||
ASSERT_TRUE(VerifyAv1c(kLobfReducedStillImageSequenceHeaderObu,
|
||||
sizeof(kLobfReducedStillImageSequenceHeaderObu),
|
||||
false));
|
||||
}
|
||||
|
||||
TEST(Av1Config, GetAv1ConfigFromAnnexBObu) {
|
||||
// Test parsing of a Sequence Header OBU with the reduced_still_picture_header
|
||||
// unset-- aka a full Sequence Header OBU.
|
||||
ASSERT_TRUE(VerifyAv1c(kAnnexBFullSequenceHeaderObu,
|
||||
sizeof(kAnnexBFullSequenceHeaderObu), true));
|
||||
|
||||
// Test parsing of a reduced still image Sequence Header OBU.
|
||||
ASSERT_TRUE(VerifyAv1c(kAnnexBReducedStillImageSequenceHeaderObu,
|
||||
sizeof(kAnnexBReducedStillImageSequenceHeaderObu),
|
||||
true));
|
||||
}
|
||||
|
||||
TEST(Av1Config, ReadWriteConfig) {
|
||||
Av1Config av1_config;
|
||||
memset(&av1_config, 0, sizeof(av1_config));
|
||||
|
||||
// Test writing out the AV1 config.
|
||||
size_t bytes_written = 0;
|
||||
uint8_t av1c_buffer[4] = { 0 };
|
||||
ASSERT_EQ(0, write_av1config(&av1_config, sizeof(av1c_buffer), &bytes_written,
|
||||
&av1c_buffer[0]));
|
||||
ASSERT_EQ(kAv1cNoConfigObusSize, bytes_written);
|
||||
for (size_t i = 0; i < kAv1cNoConfigObusSize; ++i) {
|
||||
ASSERT_EQ(kAv1cAllZero[i], av1c_buffer[i])
|
||||
<< "Mismatch in output Av1Config at offset=" << i;
|
||||
}
|
||||
|
||||
// Test reading the AV1 config.
|
||||
size_t bytes_read = 0;
|
||||
ASSERT_EQ(0, read_av1config(&kAv1cAllZero[0], sizeof(kAv1cAllZero),
|
||||
&bytes_read, &av1_config));
|
||||
ASSERT_EQ(kAv1cNoConfigObusSize, bytes_read);
|
||||
ASSERT_EQ(0, write_av1config(&av1_config, sizeof(av1c_buffer), &bytes_written,
|
||||
&av1c_buffer[0]));
|
||||
for (size_t i = 0; i < kAv1cNoConfigObusSize; ++i) {
|
||||
ASSERT_EQ(kAv1cAllZero[i], av1c_buffer[i])
|
||||
<< "Mismatch in output Av1Config at offset=" << i;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
249
media/libaom/src/test/av1_convolve_2d_test.cc
Normal file
249
media/libaom/src/test/av1_convolve_2d_test.cc
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/av1_convolve_2d_test_util.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::AV1Convolve2D::AV1Convolve2DSrTest;
|
||||
using libaom_test::AV1Convolve2D::AV1JntConvolve2DTest;
|
||||
using libaom_test::AV1HighbdConvolve2D::AV1HighbdConvolve2DSrTest;
|
||||
using libaom_test::AV1HighbdConvolve2D::AV1HighbdJntConvolve2DTest;
|
||||
namespace {
|
||||
|
||||
TEST_P(AV1Convolve2DSrTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); }
|
||||
|
||||
TEST_P(AV1Convolve2DSrTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_COPY, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_copy_sr_c, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_X, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_c, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_Y, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_c, 0, 1));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_c, 1, 1));
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_convolve_2d_copy_sr_sse2, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2_X, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_sse2, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2_Y, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_sse2, 0, 1));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_sse2, 1, 1));
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_convolve_2d_copy_sr_avx2, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2_X, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_avx2, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2_Y, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_avx2, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_avx2, 1, 1));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON_X, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_x_sr_neon, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON_Y, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_y_sr_neon, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_convolve_2d_sr_neon, 1, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON_COPY, AV1Convolve2DSrTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_convolve_2d_copy_sr_neon, 0, 0));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
TEST_P(AV1JntConvolve2DTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); }
|
||||
TEST_P(AV1JntConvolve2DTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_COPY, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_2d_copy_c, 0, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_X, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_x_c, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C_Y, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_y_c, 0, 1));
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_jnt_convolve_2d_copy_sse2, 0, 0));
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2_X, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_x_sse2, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2_Y, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_y_sse2, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_2d_ssse3, 1, 1));
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_jnt_convolve_2d_copy_avx2, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2_X, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_x_avx2, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2_Y, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_y_avx2, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_2d_avx2, 1, 1));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // HAVE_SSE4_1
|
||||
#endif // HAVE_SSE2
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(NEON_COPY, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(
|
||||
av1_jnt_convolve_2d_copy_neon, 0, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_2d_neon, 1, 1));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON_X, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_x_neon, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON_Y, AV1JntConvolve2DTest,
|
||||
libaom_test::AV1Convolve2D::BuildParams(av1_jnt_convolve_y_neon, 0, 1));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
TEST_P(AV1HighbdConvolve2DSrTest, CheckOutput) { RunCheckOutput(GET_PARAM(1)); }
|
||||
TEST_P(AV1HighbdConvolve2DSrTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(1));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_X, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_x_sr_c, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_Y, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_y_sr_c, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_COPY, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_2d_copy_sr_c, 0, 0));
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2_COPY, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_2d_copy_sr_sse2, 0, 0));
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_2d_sr_ssse3, 1, 1));
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3_X, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_x_sr_ssse3, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3_Y, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_y_sr_ssse3, 0, 1));
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_2d_sr_avx2, 1, 1));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_X, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_x_sr_avx2, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_Y, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_y_sr_avx2, 0, 1));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1HighbdConvolve2DSrTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_convolve_2d_copy_sr_avx2, 0, 0));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // HAVE_SSSE3
|
||||
#endif // HAVE_SSE2
|
||||
TEST_P(AV1HighbdJntConvolve2DTest, CheckOutput) {
|
||||
RunCheckOutput(GET_PARAM(1));
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdJntConvolve2DTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(1));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_X, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_x_c, 1, 0));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_Y, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_y_c, 0, 1));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C_COPY, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_2d_copy_c, 0, 0));
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1_COPY, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_2d_copy_sse4_1, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_2d_sse4_1, 1, 1));
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1_X, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_x_sse4_1, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1_Y, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_y_sse4_1, 0, 1));
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_COPY, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_2d_copy_avx2, 0, 0));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_2d_avx2, 1, 1));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_X, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_x_avx2, 1, 0));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2_Y, AV1HighbdJntConvolve2DTest,
|
||||
libaom_test::AV1HighbdConvolve2D::BuildParams(
|
||||
av1_highbd_jnt_convolve_y_avx2, 0, 1));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // HAVE_SSE4_1
|
||||
} // namespace
|
||||
705
media/libaom/src/test/av1_convolve_2d_test_util.cc
Normal file
705
media/libaom/src/test/av1_convolve_2d_test_util.cc
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "test/av1_convolve_2d_test_util.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/common_data.h"
|
||||
#include "av1/common/convolve.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
const int kMaxSize = 128 + 32; // padding
|
||||
namespace AV1Convolve2D {
|
||||
|
||||
::testing::internal::ParamGenerator<Convolve2DParam> BuildParams(
|
||||
convolve_2d_func filter, int has_subx, int has_suby) {
|
||||
return ::testing::Combine(::testing::Values(filter),
|
||||
::testing::Values(has_subx),
|
||||
::testing::Values(has_suby),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
AV1Convolve2DSrTest::~AV1Convolve2DSrTest() {}
|
||||
void AV1Convolve2DSrTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1Convolve2DSrTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1Convolve2DSrTest::RunCheckOutput(convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int has_subx = GET_PARAM(1);
|
||||
const int has_suby = GET_PARAM(2);
|
||||
const int block_idx = GET_PARAM(3);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint8_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, uint8_t, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, output2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i)
|
||||
output[i] = output2[i] = rnd_.Rand31();
|
||||
|
||||
// Make sure that sizes 2xN and Nx2 are also tested for chroma.
|
||||
const int num_sizes =
|
||||
(block_size_wide[block_idx] == 4 || block_size_high[block_idx] == 4) ? 2
|
||||
: 1;
|
||||
for (int shift = 0; shift < num_sizes; ++shift) { // luma and chroma
|
||||
const int out_w = block_size_wide[block_idx] >> shift;
|
||||
const int out_h = block_size_high[block_idx] >> shift;
|
||||
for (hfilter = EIGHTTAP_REGULAR; hfilter < INTERP_FILTERS_ALL; ++hfilter) {
|
||||
for (vfilter = EIGHTTAP_REGULAR; vfilter < INTERP_FILTERS_ALL;
|
||||
++vfilter) {
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
for (int do_average = 0; do_average < 1; ++do_average) {
|
||||
ConvolveParams conv_params1 =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, 8);
|
||||
ConvolveParams conv_params2 =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, 8);
|
||||
|
||||
const int subx_range = has_subx ? 16 : 1;
|
||||
const int suby_range = has_suby ? 16 : 1;
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_convolve_2d_sr_c(input + offset_r * w + offset_c, w, output,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params1);
|
||||
test_impl(input + offset_r * w + offset_c, w, output2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2);
|
||||
|
||||
if (memcmp(output, output2, sizeof(output))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AV1Convolve2DSrTest::RunSpeedTest(convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int has_subx = GET_PARAM(1);
|
||||
const int has_suby = GET_PARAM(2);
|
||||
const int block_idx = GET_PARAM(3);
|
||||
|
||||
uint8_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, uint8_t, output[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
|
||||
int hfilter = EIGHTTAP_REGULAR, vfilter = EIGHTTAP_REGULAR;
|
||||
int subx = 0, suby = 0;
|
||||
|
||||
const int do_average = 0;
|
||||
ConvolveParams conv_params2 =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, 8);
|
||||
|
||||
// Make sure that sizes 2xN and Nx2 are also tested for chroma.
|
||||
const int num_sizes =
|
||||
(block_size_wide[block_idx] == 4 || block_size_high[block_idx] == 4) ? 2
|
||||
: 1;
|
||||
for (int shift = 0; shift < num_sizes; ++shift) { // luma and chroma
|
||||
const int out_w = block_size_wide[block_idx] >> shift;
|
||||
const int out_h = block_size_high[block_idx] >> shift;
|
||||
const int num_loops = 1000000000 / (out_w + out_h);
|
||||
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(input, w, output, MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("%d,%d convolve %3dx%-3d: %7.2f us\n", has_subx, has_suby, out_w,
|
||||
out_h, 1000.0 * elapsed_time / num_loops);
|
||||
}
|
||||
}
|
||||
|
||||
AV1JntConvolve2DTest::~AV1JntConvolve2DTest() {}
|
||||
void AV1JntConvolve2DTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1JntConvolve2DTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1JntConvolve2DTest::RunCheckOutput(convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int has_subx = GET_PARAM(1);
|
||||
const int has_suby = GET_PARAM(2);
|
||||
const int block_idx = GET_PARAM(3);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint8_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output2[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, output8_1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, output8_2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
output1[i] = output2[i] = rnd_.Rand16();
|
||||
output8_1[i] = output8_2[i] = rnd_.Rand8();
|
||||
}
|
||||
|
||||
const int out_w = block_size_wide[block_idx];
|
||||
const int out_h = block_size_high[block_idx];
|
||||
for (hfilter = EIGHTTAP_REGULAR; hfilter < INTERP_FILTERS_ALL; ++hfilter) {
|
||||
for (vfilter = EIGHTTAP_REGULAR; vfilter < INTERP_FILTERS_ALL; ++vfilter) {
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
for (int do_average = 0; do_average <= 1; ++do_average) {
|
||||
ConvolveParams conv_params1 =
|
||||
get_conv_params_no_round(do_average, 0, output1, MAX_SB_SIZE, 1, 8);
|
||||
ConvolveParams conv_params2 =
|
||||
get_conv_params_no_round(do_average, 0, output2, MAX_SB_SIZE, 1, 8);
|
||||
|
||||
// Test special case where jnt_comp_avg is not used
|
||||
conv_params1.use_jnt_comp_avg = 0;
|
||||
conv_params2.use_jnt_comp_avg = 0;
|
||||
|
||||
const int subx_range = has_subx ? 16 : 1;
|
||||
const int suby_range = has_suby ? 16 : 1;
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_jnt_convolve_2d_c(input + offset_r * w + offset_c, w, output8_1,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params1);
|
||||
test_impl(input + offset_r * w + offset_c, w, output8_2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2);
|
||||
|
||||
for (int i = 0; i < out_h; ++i) {
|
||||
for (int j = 0; j < out_w; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output1[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for av1_jnt_convolve_2d\n"
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx << ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(output8_1, output8_2, sizeof(output8_1))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output8_1[idx], output8_2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test different combination of fwd and bck offset weights
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 4; ++l) {
|
||||
conv_params1.use_jnt_comp_avg = 1;
|
||||
conv_params2.use_jnt_comp_avg = 1;
|
||||
conv_params1.fwd_offset = quant_dist_lookup_table[k][l][0];
|
||||
conv_params1.bck_offset = quant_dist_lookup_table[k][l][1];
|
||||
conv_params2.fwd_offset = quant_dist_lookup_table[k][l][0];
|
||||
conv_params2.bck_offset = quant_dist_lookup_table[k][l][1];
|
||||
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_jnt_convolve_2d_c(input + offset_r * w + offset_c, w,
|
||||
output8_1, MAX_SB_SIZE, out_w, out_h,
|
||||
filter_params_x, filter_params_y, subx,
|
||||
suby, &conv_params1);
|
||||
test_impl(input + offset_r * w + offset_c, w, output8_2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2);
|
||||
|
||||
for (int i = 0; i < out_h; ++i) {
|
||||
for (int j = 0; j < out_w; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output1[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for "
|
||||
"av1_jnt_convolve_2d\n"
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
if (memcmp(output8_1, output8_2, sizeof(output8_1))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output8_1[idx], output8_2[idx])
|
||||
<< out_w << "x" << out_h
|
||||
<< " Pixel mismatch at index " << idx << " = (" << i
|
||||
<< ", " << j << "), sub pixel offset = (" << suby
|
||||
<< ", " << subx << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AV1JntConvolve2DTest::RunSpeedTest(convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int has_subx = GET_PARAM(1);
|
||||
const int has_suby = GET_PARAM(2);
|
||||
const int block_idx = GET_PARAM(3);
|
||||
|
||||
int subx = 0, suby = 0;
|
||||
uint8_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, output8[MAX_SB_SQUARE]);
|
||||
int hfilter = EIGHTTAP_REGULAR, vfilter = EIGHTTAP_REGULAR;
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
output[i] = rnd_.Rand16();
|
||||
output8[i] = rnd_.Rand8();
|
||||
}
|
||||
|
||||
const int out_w = block_size_wide[block_idx];
|
||||
const int out_h = block_size_high[block_idx];
|
||||
const int num_loops = 1000000000 / (out_w + out_h);
|
||||
const int do_average = 0;
|
||||
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
|
||||
ConvolveParams conv_params =
|
||||
get_conv_params_no_round(do_average, 0, output, MAX_SB_SIZE, 1, 8);
|
||||
|
||||
conv_params.use_jnt_comp_avg = 0;
|
||||
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(input + offset_r * w + offset_c, w, output8, MAX_SB_SIZE, out_w,
|
||||
out_h, filter_params_x, filter_params_y, subx, suby,
|
||||
&conv_params);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("%d,%d convolve %3dx%-3d: %7.2f us\n", has_subx, has_suby, out_w,
|
||||
out_h, 1000.0 * elapsed_time / num_loops);
|
||||
}
|
||||
} // namespace AV1Convolve2D
|
||||
|
||||
namespace AV1HighbdConvolve2D {
|
||||
::testing::internal::ParamGenerator<HighbdConvolve2DParam> BuildParams(
|
||||
highbd_convolve_2d_func filter, int has_subx, int has_suby) {
|
||||
return ::testing::Combine(
|
||||
::testing::Range(8, 13, 2), ::testing::Values(filter),
|
||||
::testing::Values(has_subx), ::testing::Values(has_suby),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
AV1HighbdConvolve2DSrTest::~AV1HighbdConvolve2DSrTest() {}
|
||||
void AV1HighbdConvolve2DSrTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1HighbdConvolve2DSrTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1HighbdConvolve2DSrTest::RunSpeedTest(
|
||||
highbd_convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int bd = GET_PARAM(0);
|
||||
const int has_subx = GET_PARAM(2);
|
||||
const int has_suby = GET_PARAM(3);
|
||||
const int block_idx = GET_PARAM(4);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint16_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, uint16_t, output[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j)
|
||||
input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
|
||||
hfilter = EIGHTTAP_REGULAR;
|
||||
vfilter = EIGHTTAP_REGULAR;
|
||||
int do_average = 0;
|
||||
|
||||
const int offset_r = 3;
|
||||
const int offset_c = 3;
|
||||
subx = 0;
|
||||
suby = 0;
|
||||
|
||||
ConvolveParams conv_params =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, bd);
|
||||
|
||||
// Make sure that sizes 2xN and Nx2 are also tested for chroma.
|
||||
const int num_sizes =
|
||||
(block_size_wide[block_idx] == 4 || block_size_high[block_idx] == 4) ? 2
|
||||
: 1;
|
||||
|
||||
for (int shift = 0; shift < num_sizes; ++shift) { // luma and chroma
|
||||
const int out_w = block_size_wide[block_idx] >> shift;
|
||||
const int out_h = block_size_high[block_idx] >> shift;
|
||||
const int num_loops = 1000000000 / (out_w + out_h);
|
||||
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(input + offset_r * w + offset_c, w, output, MAX_SB_SIZE, out_w,
|
||||
out_h, filter_params_x, filter_params_y, subx, suby,
|
||||
&conv_params, bd);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("%d,%d convolve %3dx%-3d: %7.2f us\n", has_subx, has_suby, out_w,
|
||||
out_h, 1000.0 * elapsed_time / num_loops);
|
||||
}
|
||||
}
|
||||
|
||||
void AV1HighbdConvolve2DSrTest::RunCheckOutput(
|
||||
highbd_convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int bd = GET_PARAM(0);
|
||||
const int has_subx = GET_PARAM(2);
|
||||
const int has_suby = GET_PARAM(3);
|
||||
const int block_idx = GET_PARAM(4);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint16_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, uint16_t, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint16_t, output2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j)
|
||||
input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i)
|
||||
output[i] = output2[i] = rnd_.Rand31();
|
||||
|
||||
// Make sure that sizes 2xN and Nx2 are also tested for chroma.
|
||||
const int num_sizes =
|
||||
(block_size_wide[block_idx] == 4 || block_size_high[block_idx] == 4) ? 2
|
||||
: 1;
|
||||
for (int shift = 0; shift < num_sizes; ++shift) { // luma and chroma
|
||||
const int out_w = block_size_wide[block_idx] >> shift;
|
||||
const int out_h = block_size_high[block_idx] >> shift;
|
||||
for (hfilter = EIGHTTAP_REGULAR; hfilter < INTERP_FILTERS_ALL; ++hfilter) {
|
||||
for (vfilter = EIGHTTAP_REGULAR; vfilter < INTERP_FILTERS_ALL;
|
||||
++vfilter) {
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
for (int do_average = 0; do_average < 1; ++do_average) {
|
||||
ConvolveParams conv_params1 =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, bd);
|
||||
ConvolveParams conv_params2 =
|
||||
get_conv_params_no_round(do_average, 0, NULL, 0, 0, bd);
|
||||
|
||||
const int subx_range = has_subx ? 16 : 1;
|
||||
const int suby_range = has_suby ? 16 : 1;
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_highbd_convolve_2d_sr_c(input + offset_r * w + offset_c, w,
|
||||
output, MAX_SB_SIZE, out_w, out_h,
|
||||
filter_params_x, filter_params_y,
|
||||
subx, suby, &conv_params1, bd);
|
||||
test_impl(input + offset_r * w + offset_c, w, output2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2, bd);
|
||||
|
||||
if (memcmp(output, output2, sizeof(output))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AV1HighbdJntConvolve2DTest::~AV1HighbdJntConvolve2DTest() {}
|
||||
void AV1HighbdJntConvolve2DTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1HighbdJntConvolve2DTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1HighbdJntConvolve2DTest::RunSpeedTest(
|
||||
highbd_convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int bd = GET_PARAM(0);
|
||||
const int block_idx = GET_PARAM(4);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint16_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint16_t, output16[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j)
|
||||
input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) output[i] = rnd_.Rand16();
|
||||
hfilter = EIGHTTAP_REGULAR;
|
||||
vfilter = EIGHTTAP_REGULAR;
|
||||
int do_average = 0;
|
||||
const int out_w = block_size_wide[block_idx];
|
||||
const int out_h = block_size_high[block_idx];
|
||||
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
|
||||
ConvolveParams conv_params =
|
||||
get_conv_params_no_round(do_average, 0, output, MAX_SB_SIZE, 1, bd);
|
||||
|
||||
// Test special case where jnt_comp_avg is not used
|
||||
conv_params.use_jnt_comp_avg = 0;
|
||||
|
||||
subx = 0;
|
||||
suby = 0;
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3;
|
||||
const int offset_c = 3;
|
||||
|
||||
const int num_loops = 1000000000 / (out_w + out_h);
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(input + offset_r * w + offset_c, w, output16, MAX_SB_SIZE, out_w,
|
||||
out_h, filter_params_x, filter_params_y, subx, suby, &conv_params,
|
||||
bd);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("convolve %3dx%-3d: %7.2f us\n", out_w, out_h,
|
||||
1000.0 * elapsed_time / num_loops);
|
||||
}
|
||||
|
||||
void AV1HighbdJntConvolve2DTest::RunCheckOutput(
|
||||
highbd_convolve_2d_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int bd = GET_PARAM(0);
|
||||
const int has_subx = GET_PARAM(2);
|
||||
const int has_suby = GET_PARAM(3);
|
||||
const int block_idx = GET_PARAM(4);
|
||||
int hfilter, vfilter, subx, suby;
|
||||
uint16_t input[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, CONV_BUF_TYPE, output2[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint16_t, output16_1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint16_t, output16_2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j)
|
||||
input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
output1[i] = output2[i] = rnd_.Rand16();
|
||||
output16_1[i] = output16_2[i] = rnd_.Rand16();
|
||||
}
|
||||
|
||||
const int out_w = block_size_wide[block_idx];
|
||||
const int out_h = block_size_high[block_idx];
|
||||
for (hfilter = EIGHTTAP_REGULAR; hfilter < INTERP_FILTERS_ALL; ++hfilter) {
|
||||
for (vfilter = EIGHTTAP_REGULAR; vfilter < INTERP_FILTERS_ALL; ++vfilter) {
|
||||
const InterpFilterParams *filter_params_x =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)hfilter,
|
||||
out_w);
|
||||
const InterpFilterParams *filter_params_y =
|
||||
av1_get_interp_filter_params_with_block_size((InterpFilter)vfilter,
|
||||
out_h);
|
||||
for (int do_average = 0; do_average <= 1; ++do_average) {
|
||||
ConvolveParams conv_params1 = get_conv_params_no_round(
|
||||
do_average, 0, output1, MAX_SB_SIZE, 1, bd);
|
||||
ConvolveParams conv_params2 = get_conv_params_no_round(
|
||||
do_average, 0, output2, MAX_SB_SIZE, 1, bd);
|
||||
|
||||
// Test special case where jnt_comp_avg is not used
|
||||
conv_params1.use_jnt_comp_avg = 0;
|
||||
conv_params2.use_jnt_comp_avg = 0;
|
||||
|
||||
const int subx_range = has_subx ? 16 : 1;
|
||||
const int suby_range = has_suby ? 16 : 1;
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_highbd_jnt_convolve_2d_c(input + offset_r * w + offset_c, w,
|
||||
output16_1, MAX_SB_SIZE, out_w, out_h,
|
||||
filter_params_x, filter_params_y, subx,
|
||||
suby, &conv_params1, bd);
|
||||
test_impl(input + offset_r * w + offset_c, w, output16_2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2, bd);
|
||||
|
||||
for (int i = 0; i < out_h; ++i) {
|
||||
for (int j = 0; j < out_w; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output1[idx], output2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx << ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(output16_1, output16_2, sizeof(output16_1))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output16_1[idx], output16_2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test different combination of fwd and bck offset weights
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 4; ++l) {
|
||||
conv_params1.use_jnt_comp_avg = 1;
|
||||
conv_params2.use_jnt_comp_avg = 1;
|
||||
conv_params1.fwd_offset = quant_dist_lookup_table[k][l][0];
|
||||
conv_params1.bck_offset = quant_dist_lookup_table[k][l][1];
|
||||
conv_params2.fwd_offset = quant_dist_lookup_table[k][l][0];
|
||||
conv_params2.bck_offset = quant_dist_lookup_table[k][l][1];
|
||||
|
||||
const int subx_range = has_subx ? 16 : 1;
|
||||
const int suby_range = has_suby ? 16 : 1;
|
||||
for (subx = 0; subx < subx_range; ++subx) {
|
||||
for (suby = 0; suby < suby_range; ++suby) {
|
||||
// Choose random locations within the source block
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_highbd_jnt_convolve_2d_c(
|
||||
input + offset_r * w + offset_c, w, output16_1, MAX_SB_SIZE,
|
||||
out_w, out_h, filter_params_x, filter_params_y, subx, suby,
|
||||
&conv_params1, bd);
|
||||
test_impl(input + offset_r * w + offset_c, w, output16_2,
|
||||
MAX_SB_SIZE, out_w, out_h, filter_params_x,
|
||||
filter_params_y, subx, suby, &conv_params2, bd);
|
||||
|
||||
for (int i = 0; i < out_h; ++i) {
|
||||
for (int j = 0; j < out_w; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output1[idx], output2[idx])
|
||||
<< out_w << "x" << out_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << suby << ", " << subx
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(output16_1, output16_2, sizeof(output16_1))) {
|
||||
for (int i = 0; i < MAX_SB_SIZE; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE; ++j) {
|
||||
int idx = i * MAX_SB_SIZE + j;
|
||||
ASSERT_EQ(output16_1[idx], output16_2[idx])
|
||||
<< out_w << "x" << out_h
|
||||
<< " Pixel mismatch at index " << idx << " = (" << i
|
||||
<< ", " << j << "), sub pixel offset = (" << suby
|
||||
<< ", " << subx << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AV1HighbdConvolve2D
|
||||
} // namespace libaom_test
|
||||
117
media/libaom/src/test/av1_convolve_2d_test_util.h
Normal file
117
media/libaom/src/test/av1_convolve_2d_test_util.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_AV1_CONVOLVE_2D_TEST_UTIL_H_
|
||||
#define AOM_TEST_AV1_CONVOLVE_2D_TEST_UTIL_H_
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
namespace AV1Convolve2D {
|
||||
|
||||
typedef void (*convolve_2d_func)(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int w, int h,
|
||||
const InterpFilterParams *filter_params_x,
|
||||
const InterpFilterParams *filter_params_y,
|
||||
const int subpel_x_q4, const int subpel_y_q4,
|
||||
ConvolveParams *conv_params);
|
||||
|
||||
typedef ::testing::tuple<convolve_2d_func, int, int, BLOCK_SIZE>
|
||||
Convolve2DParam;
|
||||
|
||||
::testing::internal::ParamGenerator<Convolve2DParam> BuildParams(
|
||||
convolve_2d_func filter, int subx_exist, int suby_exist);
|
||||
|
||||
class AV1Convolve2DSrTest : public ::testing::TestWithParam<Convolve2DParam> {
|
||||
public:
|
||||
virtual ~AV1Convolve2DSrTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(convolve_2d_func test_impl);
|
||||
void RunSpeedTest(convolve_2d_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
class AV1JntConvolve2DTest : public ::testing::TestWithParam<Convolve2DParam> {
|
||||
public:
|
||||
virtual ~AV1JntConvolve2DTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(convolve_2d_func test_impl);
|
||||
void RunSpeedTest(convolve_2d_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
} // namespace AV1Convolve2D
|
||||
|
||||
namespace AV1HighbdConvolve2D {
|
||||
typedef void (*highbd_convolve_2d_func)(
|
||||
const uint16_t *src, int src_stride, uint16_t *dst, int dst_stride, int w,
|
||||
int h, const InterpFilterParams *filter_params_x,
|
||||
const InterpFilterParams *filter_params_y, const int subpel_x_q4,
|
||||
const int subpel_y_q4, ConvolveParams *conv_params, int bd);
|
||||
|
||||
typedef ::testing::tuple<int, highbd_convolve_2d_func, int, int, BLOCK_SIZE>
|
||||
HighbdConvolve2DParam;
|
||||
|
||||
::testing::internal::ParamGenerator<HighbdConvolve2DParam> BuildParams(
|
||||
highbd_convolve_2d_func filter, int subx_exist, int suby_exist);
|
||||
|
||||
class AV1HighbdConvolve2DSrTest
|
||||
: public ::testing::TestWithParam<HighbdConvolve2DParam> {
|
||||
public:
|
||||
virtual ~AV1HighbdConvolve2DSrTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbd_convolve_2d_func test_impl);
|
||||
void RunSpeedTest(highbd_convolve_2d_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
class AV1HighbdJntConvolve2DTest
|
||||
: public ::testing::TestWithParam<HighbdConvolve2DParam> {
|
||||
public:
|
||||
virtual ~AV1HighbdJntConvolve2DTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbd_convolve_2d_func test_impl);
|
||||
void RunSpeedTest(highbd_convolve_2d_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
} // namespace AV1HighbdConvolve2D
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_AV1_CONVOLVE_2D_TEST_UTIL_H_
|
||||
529
media/libaom/src/test/av1_convolve_scale_test.cc
Normal file
529
media/libaom/src/test/av1_convolve_scale_test.cc
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
#include "av1/common/common_data.h"
|
||||
|
||||
namespace {
|
||||
const int kTestIters = 10;
|
||||
const int kPerfIters = 1000;
|
||||
|
||||
const int kVPad = 32;
|
||||
const int kHPad = 32;
|
||||
const int kXStepQn = 16;
|
||||
const int kYStepQn = 20;
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
enum NTaps { EIGHT_TAP, TEN_TAP, TWELVE_TAP };
|
||||
int NTapsToInt(NTaps ntaps) { return 8 + static_cast<int>(ntaps) * 2; }
|
||||
|
||||
// A 16-bit filter with a configurable number of taps.
|
||||
class TestFilter {
|
||||
public:
|
||||
void set(NTaps ntaps, bool backwards);
|
||||
|
||||
InterpFilterParams params_;
|
||||
|
||||
private:
|
||||
std::vector<int16_t> coeffs_;
|
||||
};
|
||||
|
||||
void TestFilter::set(NTaps ntaps, bool backwards) {
|
||||
const int n = NTapsToInt(ntaps);
|
||||
assert(n >= 8 && n <= 12);
|
||||
|
||||
// The filter has n * SUBPEL_SHIFTS proper elements and an extra 8 bogus
|
||||
// elements at the end so that convolutions can read off the end safely.
|
||||
coeffs_.resize(n * SUBPEL_SHIFTS + 8);
|
||||
|
||||
// The coefficients are pretty much arbitrary, but convolutions shouldn't
|
||||
// over or underflow. For the first filter (subpels = 0), we use an
|
||||
// increasing or decreasing ramp (depending on the backwards parameter). We
|
||||
// don't want any zero coefficients, so we make it have an x-intercept at -1
|
||||
// or n. To ensure absence of under/overflow, we normalise the area under the
|
||||
// ramp to be I = 1 << FILTER_BITS (so that convolving a constant function
|
||||
// gives the identity).
|
||||
//
|
||||
// When increasing, the function has the form:
|
||||
//
|
||||
// f(x) = A * (x + 1)
|
||||
//
|
||||
// Summing and rearranging for A gives A = 2 * I / (n * (n + 1)). If the
|
||||
// filter is reversed, we have the same A but with formula
|
||||
//
|
||||
// g(x) = A * (n - x)
|
||||
const int I = 1 << FILTER_BITS;
|
||||
const float A = 2.f * I / (n * (n + 1.f));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
coeffs_[i] = static_cast<int16_t>(A * (backwards ? (n - i) : (i + 1)));
|
||||
}
|
||||
|
||||
// For the other filters, make them slightly different by swapping two
|
||||
// columns. Filter k will have the columns (k % n) and (7 * k) % n swapped.
|
||||
const size_t filter_size = sizeof(coeffs_[0] * n);
|
||||
int16_t *const filter0 = &coeffs_[0];
|
||||
for (int k = 1; k < SUBPEL_SHIFTS; ++k) {
|
||||
int16_t *filterk = &coeffs_[k * n];
|
||||
memcpy(filterk, filter0, filter_size);
|
||||
|
||||
const int idx0 = k % n;
|
||||
const int idx1 = (7 * k) % n;
|
||||
|
||||
const int16_t tmp = filterk[idx0];
|
||||
filterk[idx0] = filterk[idx1];
|
||||
filterk[idx1] = tmp;
|
||||
}
|
||||
|
||||
// Finally, write some rubbish at the end to make sure we don't use it.
|
||||
for (int i = 0; i < 8; ++i) coeffs_[n * SUBPEL_SHIFTS + i] = 123 + i;
|
||||
|
||||
// Fill in params
|
||||
params_.filter_ptr = &coeffs_[0];
|
||||
params_.taps = n;
|
||||
// These are ignored by the functions being tested. Set them to whatever.
|
||||
params_.subpel_shifts = SUBPEL_SHIFTS;
|
||||
params_.interp_filter = EIGHTTAP_REGULAR;
|
||||
}
|
||||
|
||||
template <typename SrcPixel>
|
||||
class TestImage {
|
||||
public:
|
||||
TestImage(int w, int h, int bd) : w_(w), h_(h), bd_(bd) {
|
||||
assert(bd < 16);
|
||||
assert(bd <= 8 * static_cast<int>(sizeof(SrcPixel)));
|
||||
|
||||
// Pad width by 2*kHPad and then round up to the next multiple of 16
|
||||
// to get src_stride_. Add another 16 for dst_stride_ (to make sure
|
||||
// something goes wrong if we use the wrong one)
|
||||
src_stride_ = (w_ + 2 * kHPad + 15) & ~15;
|
||||
dst_stride_ = src_stride_ + 16;
|
||||
|
||||
// Allocate image data
|
||||
src_data_.resize(2 * src_block_size());
|
||||
dst_data_.resize(2 * dst_block_size());
|
||||
dst_16_data_.resize(2 * dst_block_size());
|
||||
}
|
||||
|
||||
void Initialize(ACMRandom *rnd);
|
||||
void Check() const;
|
||||
|
||||
int src_stride() const { return src_stride_; }
|
||||
int dst_stride() const { return dst_stride_; }
|
||||
|
||||
int src_block_size() const { return (h_ + 2 * kVPad) * src_stride(); }
|
||||
int dst_block_size() const { return (h_ + 2 * kVPad) * dst_stride(); }
|
||||
|
||||
const SrcPixel *GetSrcData(bool ref, bool borders) const {
|
||||
const SrcPixel *block = &src_data_[ref ? 0 : src_block_size()];
|
||||
return borders ? block : block + kHPad + src_stride_ * kVPad;
|
||||
}
|
||||
|
||||
SrcPixel *GetDstData(bool ref, bool borders) {
|
||||
SrcPixel *block = &dst_data_[ref ? 0 : dst_block_size()];
|
||||
return borders ? block : block + kHPad + dst_stride_ * kVPad;
|
||||
}
|
||||
|
||||
CONV_BUF_TYPE *GetDst16Data(bool ref, bool borders) {
|
||||
CONV_BUF_TYPE *block = &dst_16_data_[ref ? 0 : dst_block_size()];
|
||||
return borders ? block : block + kHPad + dst_stride_ * kVPad;
|
||||
}
|
||||
|
||||
private:
|
||||
int w_, h_, bd_;
|
||||
int src_stride_, dst_stride_;
|
||||
|
||||
std::vector<SrcPixel> src_data_;
|
||||
std::vector<SrcPixel> dst_data_;
|
||||
std::vector<CONV_BUF_TYPE> dst_16_data_;
|
||||
};
|
||||
|
||||
template <typename Pixel>
|
||||
void FillEdge(ACMRandom *rnd, int num_pixels, int bd, bool trash, Pixel *data) {
|
||||
if (!trash) {
|
||||
memset(data, 0, sizeof(*data) * num_pixels);
|
||||
return;
|
||||
}
|
||||
const Pixel mask = (1 << bd) - 1;
|
||||
for (int i = 0; i < num_pixels; ++i) data[i] = rnd->Rand16() & mask;
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
void PrepBuffers(ACMRandom *rnd, int w, int h, int stride, int bd,
|
||||
bool trash_edges, Pixel *data) {
|
||||
assert(rnd);
|
||||
const Pixel mask = (1 << bd) - 1;
|
||||
|
||||
// Fill in the first buffer with random data
|
||||
// Top border
|
||||
FillEdge(rnd, stride * kVPad, bd, trash_edges, data);
|
||||
for (int r = 0; r < h; ++r) {
|
||||
Pixel *row_data = data + (kVPad + r) * stride;
|
||||
// Left border, contents, right border
|
||||
FillEdge(rnd, kHPad, bd, trash_edges, row_data);
|
||||
for (int c = 0; c < w; ++c) row_data[kHPad + c] = rnd->Rand16() & mask;
|
||||
FillEdge(rnd, kHPad, bd, trash_edges, row_data + kHPad + w);
|
||||
}
|
||||
// Bottom border
|
||||
FillEdge(rnd, stride * kVPad, bd, trash_edges, data + stride * (kVPad + h));
|
||||
|
||||
const int bpp = sizeof(*data);
|
||||
const int block_elts = stride * (h + 2 * kVPad);
|
||||
const int block_size = bpp * block_elts;
|
||||
|
||||
// Now copy that to the second buffer
|
||||
memcpy(data + block_elts, data, block_size);
|
||||
}
|
||||
|
||||
template <typename SrcPixel>
|
||||
void TestImage<SrcPixel>::Initialize(ACMRandom *rnd) {
|
||||
PrepBuffers(rnd, w_, h_, src_stride_, bd_, false, &src_data_[0]);
|
||||
PrepBuffers(rnd, w_, h_, dst_stride_, bd_, true, &dst_data_[0]);
|
||||
PrepBuffers(rnd, w_, h_, dst_stride_, bd_, true, &dst_16_data_[0]);
|
||||
}
|
||||
|
||||
template <typename SrcPixel>
|
||||
void TestImage<SrcPixel>::Check() const {
|
||||
// If memcmp returns 0, there's nothing to do.
|
||||
const int num_pixels = dst_block_size();
|
||||
const SrcPixel *ref_dst = &dst_data_[0];
|
||||
const SrcPixel *tst_dst = &dst_data_[num_pixels];
|
||||
|
||||
const CONV_BUF_TYPE *ref_16_dst = &dst_16_data_[0];
|
||||
const CONV_BUF_TYPE *tst_16_dst = &dst_16_data_[num_pixels];
|
||||
|
||||
if (0 == memcmp(ref_dst, tst_dst, sizeof(*ref_dst) * num_pixels)) {
|
||||
if (0 == memcmp(ref_16_dst, tst_16_dst, sizeof(*ref_16_dst) * num_pixels))
|
||||
return;
|
||||
}
|
||||
// Otherwise, iterate through the buffer looking for differences (including
|
||||
// the edges)
|
||||
const int stride = dst_stride_;
|
||||
for (int r = 0; r < h_ + 2 * kVPad; ++r) {
|
||||
for (int c = 0; c < w_ + 2 * kHPad; ++c) {
|
||||
const int32_t ref_value = ref_dst[r * stride + c];
|
||||
const int32_t tst_value = tst_dst[r * stride + c];
|
||||
|
||||
EXPECT_EQ(tst_value, ref_value)
|
||||
<< "Error at row: " << (r - kVPad) << ", col: " << (c - kHPad);
|
||||
}
|
||||
}
|
||||
|
||||
for (int r = 0; r < h_ + 2 * kVPad; ++r) {
|
||||
for (int c = 0; c < w_ + 2 * kHPad; ++c) {
|
||||
const int32_t ref_value = ref_16_dst[r * stride + c];
|
||||
const int32_t tst_value = tst_16_dst[r * stride + c];
|
||||
|
||||
EXPECT_EQ(tst_value, ref_value)
|
||||
<< "Error in 16 bit buffer "
|
||||
<< "Error at row: " << (r - kVPad) << ", col: " << (c - kHPad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef tuple<int, int> BlockDimension;
|
||||
|
||||
struct BaseParams {
|
||||
BaseParams(BlockDimension dims, NTaps ntaps_x, NTaps ntaps_y, bool avg)
|
||||
: dims(dims), ntaps_x(ntaps_x), ntaps_y(ntaps_y), avg(avg) {}
|
||||
|
||||
BlockDimension dims;
|
||||
NTaps ntaps_x, ntaps_y;
|
||||
bool avg;
|
||||
};
|
||||
|
||||
template <typename SrcPixel>
|
||||
class ConvolveScaleTestBase : public ::testing::Test {
|
||||
public:
|
||||
ConvolveScaleTestBase() : image_(NULL) {}
|
||||
virtual ~ConvolveScaleTestBase() { delete image_; }
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
// Implemented by subclasses (SetUp depends on the parameters passed
|
||||
// in and RunOne depends on the function to be tested. These can't
|
||||
// be templated for low/high bit depths because they have different
|
||||
// numbers of parameters)
|
||||
virtual void SetUp() = 0;
|
||||
virtual void RunOne(bool ref) = 0;
|
||||
|
||||
protected:
|
||||
void SetParams(const BaseParams ¶ms, int bd) {
|
||||
width_ = ::testing::get<0>(params.dims);
|
||||
height_ = ::testing::get<1>(params.dims);
|
||||
ntaps_x_ = params.ntaps_x;
|
||||
ntaps_y_ = params.ntaps_y;
|
||||
bd_ = bd;
|
||||
avg_ = params.avg;
|
||||
|
||||
filter_x_.set(ntaps_x_, false);
|
||||
filter_y_.set(ntaps_y_, true);
|
||||
convolve_params_ =
|
||||
get_conv_params_no_round(avg_ != false, 0, NULL, 0, 1, bd);
|
||||
|
||||
delete image_;
|
||||
image_ = new TestImage<SrcPixel>(width_, height_, bd_);
|
||||
}
|
||||
|
||||
void SetConvParamOffset(int i, int j, int is_compound, int do_average,
|
||||
int use_jnt_comp_avg) {
|
||||
if (i == -1 && j == -1) {
|
||||
convolve_params_.use_jnt_comp_avg = use_jnt_comp_avg;
|
||||
convolve_params_.is_compound = is_compound;
|
||||
convolve_params_.do_average = do_average;
|
||||
} else {
|
||||
convolve_params_.use_jnt_comp_avg = use_jnt_comp_avg;
|
||||
convolve_params_.fwd_offset = quant_dist_lookup_table[i][j][0];
|
||||
convolve_params_.bck_offset = quant_dist_lookup_table[i][j][1];
|
||||
convolve_params_.is_compound = is_compound;
|
||||
convolve_params_.do_average = do_average;
|
||||
}
|
||||
}
|
||||
|
||||
void Run() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int i = 0; i < kTestIters; ++i) {
|
||||
int is_compound = 0;
|
||||
SetConvParamOffset(-1, -1, is_compound, 0, 0);
|
||||
Prep(&rnd);
|
||||
RunOne(true);
|
||||
RunOne(false);
|
||||
image_->Check();
|
||||
|
||||
is_compound = 1;
|
||||
for (int do_average = 0; do_average < 2; do_average++) {
|
||||
for (int use_jnt_comp_avg = 0; use_jnt_comp_avg < 2;
|
||||
use_jnt_comp_avg++) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
SetConvParamOffset(j, k, is_compound, do_average,
|
||||
use_jnt_comp_avg);
|
||||
Prep(&rnd);
|
||||
RunOne(true);
|
||||
RunOne(false);
|
||||
image_->Check();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedTest() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
Prep(&rnd);
|
||||
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int i = 0; i < kPerfIters; ++i) RunOne(true);
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer tst_timer;
|
||||
aom_usec_timer_start(&tst_timer);
|
||||
for (int i = 0; i < kPerfIters; ++i) RunOne(false);
|
||||
aom_usec_timer_mark(&tst_timer);
|
||||
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
|
||||
|
||||
std::cout << "[ ] C time = " << ref_time / 1000
|
||||
<< " ms, SIMD time = " << tst_time / 1000 << " ms\n";
|
||||
|
||||
EXPECT_GT(ref_time, tst_time)
|
||||
<< "Error: CDEFSpeedTest, SIMD slower than C.\n"
|
||||
<< "C time: " << ref_time << " us\n"
|
||||
<< "SIMD time: " << tst_time << " us\n";
|
||||
}
|
||||
|
||||
static int RandomSubpel(ACMRandom *rnd) {
|
||||
const uint8_t subpel_mode = rnd->Rand8();
|
||||
if ((subpel_mode & 7) == 0) {
|
||||
return 0;
|
||||
} else if ((subpel_mode & 7) == 1) {
|
||||
return SCALE_SUBPEL_SHIFTS - 1;
|
||||
} else {
|
||||
return 1 + rnd->PseudoUniform(SCALE_SUBPEL_SHIFTS - 2);
|
||||
}
|
||||
}
|
||||
|
||||
void Prep(ACMRandom *rnd) {
|
||||
assert(rnd);
|
||||
|
||||
// Choose subpel_x_ and subpel_y_. They should be less than
|
||||
// SCALE_SUBPEL_SHIFTS; we also want to add extra weight to "interesting"
|
||||
// values: 0 and SCALE_SUBPEL_SHIFTS - 1
|
||||
subpel_x_ = RandomSubpel(rnd);
|
||||
subpel_y_ = RandomSubpel(rnd);
|
||||
|
||||
image_->Initialize(rnd);
|
||||
}
|
||||
|
||||
int width_, height_, bd_;
|
||||
NTaps ntaps_x_, ntaps_y_;
|
||||
bool avg_;
|
||||
int subpel_x_, subpel_y_;
|
||||
TestFilter filter_x_, filter_y_;
|
||||
TestImage<SrcPixel> *image_;
|
||||
ConvolveParams convolve_params_;
|
||||
};
|
||||
|
||||
typedef tuple<int, int> BlockDimension;
|
||||
|
||||
typedef void (*LowbdConvolveFunc)(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int w, int h,
|
||||
const InterpFilterParams *filter_params_x,
|
||||
const InterpFilterParams *filter_params_y,
|
||||
const int subpel_x_qn, const int x_step_qn,
|
||||
const int subpel_y_qn, const int y_step_qn,
|
||||
ConvolveParams *conv_params);
|
||||
|
||||
// Test parameter list:
|
||||
// <tst_fun, dims, ntaps_x, ntaps_y, avg>
|
||||
typedef tuple<LowbdConvolveFunc, BlockDimension, NTaps, NTaps, bool>
|
||||
LowBDParams;
|
||||
|
||||
class LowBDConvolveScaleTest
|
||||
: public ConvolveScaleTestBase<uint8_t>,
|
||||
public ::testing::WithParamInterface<LowBDParams> {
|
||||
public:
|
||||
virtual ~LowBDConvolveScaleTest() {}
|
||||
|
||||
void SetUp() {
|
||||
tst_fun_ = GET_PARAM(0);
|
||||
|
||||
const BlockDimension &block = GET_PARAM(1);
|
||||
const NTaps ntaps_x = GET_PARAM(2);
|
||||
const NTaps ntaps_y = GET_PARAM(3);
|
||||
const int bd = 8;
|
||||
const bool avg = GET_PARAM(4);
|
||||
|
||||
SetParams(BaseParams(block, ntaps_x, ntaps_y, avg), bd);
|
||||
}
|
||||
|
||||
void RunOne(bool ref) {
|
||||
const uint8_t *src = image_->GetSrcData(ref, false);
|
||||
uint8_t *dst = image_->GetDstData(ref, false);
|
||||
convolve_params_.dst = image_->GetDst16Data(ref, false);
|
||||
const int src_stride = image_->src_stride();
|
||||
const int dst_stride = image_->dst_stride();
|
||||
if (ref) {
|
||||
av1_convolve_2d_scale_c(src, src_stride, dst, dst_stride, width_, height_,
|
||||
&filter_x_.params_, &filter_y_.params_, subpel_x_,
|
||||
kXStepQn, subpel_y_, kYStepQn, &convolve_params_);
|
||||
} else {
|
||||
tst_fun_(src, src_stride, dst, dst_stride, width_, height_,
|
||||
&filter_x_.params_, &filter_y_.params_, subpel_x_, kXStepQn,
|
||||
subpel_y_, kYStepQn, &convolve_params_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LowbdConvolveFunc tst_fun_;
|
||||
};
|
||||
|
||||
const BlockDimension kBlockDim[] = {
|
||||
make_tuple(2, 2), make_tuple(2, 4), make_tuple(4, 4),
|
||||
make_tuple(4, 8), make_tuple(8, 4), make_tuple(8, 8),
|
||||
make_tuple(8, 16), make_tuple(16, 8), make_tuple(16, 16),
|
||||
make_tuple(16, 32), make_tuple(32, 16), make_tuple(32, 32),
|
||||
make_tuple(32, 64), make_tuple(64, 32), make_tuple(64, 64),
|
||||
make_tuple(64, 128), make_tuple(128, 64), make_tuple(128, 128),
|
||||
};
|
||||
|
||||
const NTaps kNTaps[] = { EIGHT_TAP };
|
||||
|
||||
TEST_P(LowBDConvolveScaleTest, Check) { Run(); }
|
||||
TEST_P(LowBDConvolveScaleTest, DISABLED_Speed) { SpeedTest(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, LowBDConvolveScaleTest,
|
||||
::testing::Combine(::testing::Values(av1_convolve_2d_scale_sse4_1),
|
||||
::testing::ValuesIn(kBlockDim),
|
||||
::testing::ValuesIn(kNTaps), ::testing::ValuesIn(kNTaps),
|
||||
::testing::Bool()));
|
||||
|
||||
typedef void (*HighbdConvolveFunc)(const uint16_t *src, int src_stride,
|
||||
uint16_t *dst, int dst_stride, int w, int h,
|
||||
const InterpFilterParams *filter_params_x,
|
||||
const InterpFilterParams *filter_params_y,
|
||||
const int subpel_x_qn, const int x_step_qn,
|
||||
const int subpel_y_qn, const int y_step_qn,
|
||||
ConvolveParams *conv_params, int bd);
|
||||
|
||||
// Test parameter list:
|
||||
// <tst_fun, dims, ntaps_x, ntaps_y, avg, bd>
|
||||
typedef tuple<HighbdConvolveFunc, BlockDimension, NTaps, NTaps, bool, int>
|
||||
HighBDParams;
|
||||
|
||||
class HighBDConvolveScaleTest
|
||||
: public ConvolveScaleTestBase<uint16_t>,
|
||||
public ::testing::WithParamInterface<HighBDParams> {
|
||||
public:
|
||||
virtual ~HighBDConvolveScaleTest() {}
|
||||
|
||||
void SetUp() {
|
||||
tst_fun_ = GET_PARAM(0);
|
||||
|
||||
const BlockDimension &block = GET_PARAM(1);
|
||||
const NTaps ntaps_x = GET_PARAM(2);
|
||||
const NTaps ntaps_y = GET_PARAM(3);
|
||||
const bool avg = GET_PARAM(4);
|
||||
const int bd = GET_PARAM(5);
|
||||
|
||||
SetParams(BaseParams(block, ntaps_x, ntaps_y, avg), bd);
|
||||
}
|
||||
|
||||
void RunOne(bool ref) {
|
||||
const uint16_t *src = image_->GetSrcData(ref, false);
|
||||
uint16_t *dst = image_->GetDstData(ref, false);
|
||||
convolve_params_.dst = image_->GetDst16Data(ref, false);
|
||||
const int src_stride = image_->src_stride();
|
||||
const int dst_stride = image_->dst_stride();
|
||||
|
||||
if (ref) {
|
||||
av1_highbd_convolve_2d_scale_c(
|
||||
src, src_stride, dst, dst_stride, width_, height_, &filter_x_.params_,
|
||||
&filter_y_.params_, subpel_x_, kXStepQn, subpel_y_, kYStepQn,
|
||||
&convolve_params_, bd_);
|
||||
} else {
|
||||
tst_fun_(src, src_stride, dst, dst_stride, width_, height_,
|
||||
&filter_x_.params_, &filter_y_.params_, subpel_x_, kXStepQn,
|
||||
subpel_y_, kYStepQn, &convolve_params_, bd_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HighbdConvolveFunc tst_fun_;
|
||||
};
|
||||
|
||||
const int kBDs[] = { 8, 10, 12 };
|
||||
|
||||
TEST_P(HighBDConvolveScaleTest, Check) { Run(); }
|
||||
TEST_P(HighBDConvolveScaleTest, DISABLED_Speed) { SpeedTest(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, HighBDConvolveScaleTest,
|
||||
::testing::Combine(::testing::Values(av1_highbd_convolve_2d_scale_sse4_1),
|
||||
::testing::ValuesIn(kBlockDim),
|
||||
::testing::ValuesIn(kNTaps), ::testing::ValuesIn(kNTaps),
|
||||
::testing::Bool(), ::testing::ValuesIn(kBDs)));
|
||||
} // namespace
|
||||
158
media/libaom/src/test/av1_encoder_parms_get_to_decoder.cc
Normal file
158
media/libaom/src/test/av1_encoder_parms_get_to_decoder.cc
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
|
||||
#include "aom/aom_decoder.h"
|
||||
#include "av1/decoder/decoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxPsnr = 100;
|
||||
|
||||
struct ParamPassingTestVideo {
|
||||
const char *name;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bitrate;
|
||||
int frames;
|
||||
};
|
||||
|
||||
const ParamPassingTestVideo kAV1ParamPassingTestVector = {
|
||||
"niklas_1280_720_30.y4m", 1280, 720, 600, 3
|
||||
};
|
||||
|
||||
struct EncodeParameters {
|
||||
int32_t lossless;
|
||||
aom_color_primaries_t color_primaries;
|
||||
aom_transfer_characteristics_t transfer_characteristics;
|
||||
aom_matrix_coefficients_t matrix_coefficients;
|
||||
aom_color_range_t color_range;
|
||||
aom_chroma_sample_position_t chroma_sample_position;
|
||||
int32_t render_size[2];
|
||||
};
|
||||
|
||||
const EncodeParameters kAV1EncodeParameterSet[] = {
|
||||
{ 1,
|
||||
AOM_CICP_CP_BT_709,
|
||||
AOM_CICP_TC_BT_709,
|
||||
AOM_CICP_MC_BT_709,
|
||||
AOM_CR_STUDIO_RANGE,
|
||||
AOM_CSP_UNKNOWN,
|
||||
{ 0, 0 } },
|
||||
{ 0,
|
||||
AOM_CICP_CP_BT_470_M,
|
||||
AOM_CICP_TC_BT_470_M,
|
||||
AOM_CICP_MC_BT_470_B_G,
|
||||
AOM_CR_FULL_RANGE,
|
||||
AOM_CSP_VERTICAL,
|
||||
{ 0, 0 } },
|
||||
{ 1,
|
||||
AOM_CICP_CP_BT_601,
|
||||
AOM_CICP_TC_BT_601,
|
||||
AOM_CICP_MC_BT_601,
|
||||
AOM_CR_STUDIO_RANGE,
|
||||
AOM_CSP_COLOCATED,
|
||||
{ 0, 0 } },
|
||||
{ 0,
|
||||
AOM_CICP_CP_BT_2020,
|
||||
AOM_CICP_TC_BT_2020_10_BIT,
|
||||
AOM_CICP_MC_BT_2020_NCL,
|
||||
AOM_CR_FULL_RANGE,
|
||||
AOM_CSP_RESERVED,
|
||||
{ 640, 480 } },
|
||||
};
|
||||
|
||||
class AVxEncoderParmsGetToDecoder
|
||||
: public ::libaom_test::EncoderTest,
|
||||
public ::libaom_test::CodecTestWithParam<EncodeParameters> {
|
||||
protected:
|
||||
AVxEncoderParmsGetToDecoder()
|
||||
: EncoderTest(GET_PARAM(0)), encode_parms(GET_PARAM(1)) {}
|
||||
|
||||
virtual ~AVxEncoderParmsGetToDecoder() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(::libaom_test::kTwoPassGood);
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
test_video_ = kAV1ParamPassingTestVector;
|
||||
cfg_.rc_target_bitrate = test_video_.bitrate;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AV1E_SET_COLOR_PRIMARIES, encode_parms.color_primaries);
|
||||
encoder->Control(AV1E_SET_TRANSFER_CHARACTERISTICS,
|
||||
encode_parms.transfer_characteristics);
|
||||
encoder->Control(AV1E_SET_MATRIX_COEFFICIENTS,
|
||||
encode_parms.matrix_coefficients);
|
||||
encoder->Control(AV1E_SET_COLOR_RANGE, encode_parms.color_range);
|
||||
encoder->Control(AV1E_SET_CHROMA_SAMPLE_POSITION,
|
||||
encode_parms.chroma_sample_position);
|
||||
encoder->Control(AV1E_SET_LOSSLESS, encode_parms.lossless);
|
||||
if (encode_parms.render_size[0] > 0 && encode_parms.render_size[1] > 0) {
|
||||
encoder->Control(AV1E_SET_RENDER_SIZE, encode_parms.render_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DecompressedFrameHook(const aom_image_t &img,
|
||||
aom_codec_pts_t pts) {
|
||||
(void)pts;
|
||||
if (encode_parms.render_size[0] > 0 && encode_parms.render_size[1] > 0) {
|
||||
EXPECT_EQ(encode_parms.render_size[0], (int)img.r_w);
|
||||
EXPECT_EQ(encode_parms.render_size[1], (int)img.r_h);
|
||||
}
|
||||
EXPECT_EQ(encode_parms.color_primaries, img.cp);
|
||||
EXPECT_EQ(encode_parms.transfer_characteristics, img.tc);
|
||||
EXPECT_EQ(encode_parms.matrix_coefficients, img.mc);
|
||||
EXPECT_EQ(encode_parms.color_range, img.range);
|
||||
EXPECT_EQ(encode_parms.chroma_sample_position, img.csp);
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (encode_parms.lossless) {
|
||||
EXPECT_EQ(kMaxPsnr, pkt->data.psnr.psnr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
|
||||
libaom_test::Decoder *decoder) {
|
||||
EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
|
||||
return AOM_CODEC_OK == res_dec;
|
||||
}
|
||||
|
||||
ParamPassingTestVideo test_video_;
|
||||
|
||||
private:
|
||||
EncodeParameters encode_parms;
|
||||
};
|
||||
|
||||
TEST_P(AVxEncoderParmsGetToDecoder, BitstreamParms) {
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video(
|
||||
new libaom_test::Y4mVideoSource(test_video_.name, 0, test_video_.frames));
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AVxEncoderParmsGetToDecoder,
|
||||
::testing::ValuesIn(kAV1EncodeParameterSet));
|
||||
} // namespace
|
||||
215
media/libaom/src/test/av1_ext_tile_test.cc
Normal file
215
media/libaom/src/test/av1_ext_tile_test.cc
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/md5_helper.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
// The number of frames to be encoded/decoded
|
||||
const int kLimit = 8;
|
||||
// Skip 1 frame to check the frame decoding independency.
|
||||
const int kSkip = 5;
|
||||
const int kTileSize = 1;
|
||||
const int kTIleSizeInPixels = (kTileSize << 6);
|
||||
// Fake width and height so that they can be multiples of the tile size.
|
||||
const int kImgWidth = 704;
|
||||
const int kImgHeight = 576;
|
||||
|
||||
// This test tests large scale tile coding case. Non-large-scale tile coding
|
||||
// is tested by the tile_independence test.
|
||||
class AV1ExtTileTest
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AV1ExtTileTest()
|
||||
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
|
||||
set_cpu_used_(GET_PARAM(2)) {
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.w = kImgWidth;
|
||||
cfg.h = kImgHeight;
|
||||
cfg.allow_lowbitdepth = 1;
|
||||
|
||||
decoder_ = codec_->CreateDecoder(cfg, 0);
|
||||
decoder_->Control(AV1_SET_TILE_MODE, 1);
|
||||
decoder_->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
|
||||
// Allocate buffer to store tile image.
|
||||
aom_img_alloc(&tile_img_, AOM_IMG_FMT_I420, kImgWidth, kImgHeight, 32);
|
||||
|
||||
md5_.clear();
|
||||
tile_md5_.clear();
|
||||
}
|
||||
|
||||
virtual ~AV1ExtTileTest() {
|
||||
aom_img_free(&tile_img_);
|
||||
delete decoder_;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.g_error_resilient = 1;
|
||||
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) {
|
||||
// Encode setting
|
||||
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
|
||||
// TODO(yunqingwang): test single_tile_decoding = 0.
|
||||
encoder->Control(AV1E_SET_SINGLE_TILE_DECODING, 1);
|
||||
// Always use 64x64 max partition.
|
||||
encoder->Control(AV1E_SET_SUPERBLOCK_SIZE, AOM_SUPERBLOCK_SIZE_64X64);
|
||||
// Set tile_columns and tile_rows to MAX values, which guarantees the tile
|
||||
// size of 64 x 64 pixels(i.e. 1 SB) for <= 4k resolution.
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 6);
|
||||
encoder->Control(AV1E_SET_TILE_ROWS, 6);
|
||||
}
|
||||
|
||||
if (video->frame() == 1) {
|
||||
frame_flags_ =
|
||||
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DecompressedFrameHook(const aom_image_t &img,
|
||||
aom_codec_pts_t pts) {
|
||||
// Skip 1 already decoded frame to be consistent with the decoder in this
|
||||
// test.
|
||||
if (pts == (aom_codec_pts_t)kSkip) return;
|
||||
|
||||
// Calculate MD5 as the reference.
|
||||
::libaom_test::MD5 md5_res;
|
||||
md5_res.Add(&img);
|
||||
md5_.push_back(md5_res.Get());
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
// Skip decoding 1 frame.
|
||||
if (pkt->data.frame.pts == (aom_codec_pts_t)kSkip) return;
|
||||
|
||||
bool IsLastFrame = (pkt->data.frame.pts == (aom_codec_pts_t)(kLimit - 1));
|
||||
|
||||
// Decode the first (kLimit - 1) frames as whole frame, and decode the last
|
||||
// frame in single tiles.
|
||||
for (int r = 0; r < kImgHeight / kTIleSizeInPixels; ++r) {
|
||||
for (int c = 0; c < kImgWidth / kTIleSizeInPixels; ++c) {
|
||||
if (!IsLastFrame) {
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
} else {
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_ROW, r);
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_COL, c);
|
||||
}
|
||||
|
||||
const aom_codec_err_t res = decoder_->DecodeFrame(
|
||||
reinterpret_cast<uint8_t *>(pkt->data.frame.buf),
|
||||
pkt->data.frame.sz);
|
||||
if (res != AOM_CODEC_OK) {
|
||||
abort_ = true;
|
||||
ASSERT_EQ(AOM_CODEC_OK, res);
|
||||
}
|
||||
const aom_image_t *img = decoder_->GetDxData().Next();
|
||||
|
||||
if (!IsLastFrame) {
|
||||
if (img) {
|
||||
::libaom_test::MD5 md5_res;
|
||||
md5_res.Add(img);
|
||||
tile_md5_.push_back(md5_res.Get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const int kMaxMBPlane = 3;
|
||||
for (int plane = 0; plane < kMaxMBPlane; ++plane) {
|
||||
const int shift = (plane == 0) ? 0 : 1;
|
||||
int tile_height = kTIleSizeInPixels >> shift;
|
||||
int tile_width = kTIleSizeInPixels >> shift;
|
||||
|
||||
for (int tr = 0; tr < tile_height; ++tr) {
|
||||
memcpy(tile_img_.planes[plane] +
|
||||
tile_img_.stride[plane] * (r * tile_height + tr) +
|
||||
c * tile_width,
|
||||
img->planes[plane] + img->stride[plane] * tr, tile_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsLastFrame) break;
|
||||
}
|
||||
|
||||
if (IsLastFrame) {
|
||||
::libaom_test::MD5 md5_res;
|
||||
md5_res.Add(&tile_img_);
|
||||
tile_md5_.push_back(md5_res.Get());
|
||||
}
|
||||
}
|
||||
|
||||
void TestRoundTrip() {
|
||||
::libaom_test::I420VideoSource video(
|
||||
"hantro_collage_w352h288.yuv", kImgWidth, kImgHeight, 30, 1, 0, kLimit);
|
||||
cfg_.rc_target_bitrate = 500;
|
||||
cfg_.g_error_resilient = AOM_ERROR_RESILIENT_DEFAULT;
|
||||
cfg_.large_scale_tile = 1;
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.g_threads = 1;
|
||||
|
||||
// Tile encoding
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
|
||||
// Compare to check if two vectors are equal.
|
||||
ASSERT_EQ(md5_, tile_md5_);
|
||||
}
|
||||
|
||||
::libaom_test::TestMode encoding_mode_;
|
||||
int set_cpu_used_;
|
||||
::libaom_test::Decoder *decoder_;
|
||||
aom_image_t tile_img_;
|
||||
std::vector<std::string> md5_;
|
||||
std::vector<std::string> tile_md5_;
|
||||
};
|
||||
|
||||
TEST_P(AV1ExtTileTest, DecoderResultTest) { TestRoundTrip(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(
|
||||
// Now only test 2-pass mode.
|
||||
AV1ExtTileTest, ::testing::Values(::libaom_test::kTwoPassGood),
|
||||
::testing::Range(1, 4));
|
||||
|
||||
class AV1ExtTileTestLarge : public AV1ExtTileTest {};
|
||||
|
||||
TEST_P(AV1ExtTileTestLarge, DecoderResultTest) { TestRoundTrip(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(
|
||||
// Now only test 2-pass mode.
|
||||
AV1ExtTileTestLarge, ::testing::Values(::libaom_test::kTwoPassGood),
|
||||
::testing::Range(0, 1));
|
||||
} // namespace
|
||||
105
media/libaom/src/test/av1_fwd_txfm1d_test.cc
Normal file
105
media/libaom/src/test/av1_fwd_txfm1d_test.cc
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/encoder/av1_fwd_txfm1d.h"
|
||||
#include "test/av1_txfm_test.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::TYPE_ADST;
|
||||
using libaom_test::TYPE_DCT;
|
||||
using libaom_test::TYPE_IDTX;
|
||||
using libaom_test::TYPE_TXFM;
|
||||
using libaom_test::input_base;
|
||||
using libaom_test::reference_hybrid_1d;
|
||||
|
||||
namespace {
|
||||
const int txfm_type_num = 3;
|
||||
const TYPE_TXFM txfm_type_ls[txfm_type_num] = { TYPE_DCT, TYPE_ADST,
|
||||
TYPE_IDTX };
|
||||
|
||||
const int txfm_size_num = 5;
|
||||
|
||||
const int txfm_size_ls[] = { 4, 8, 16, 32, 64 };
|
||||
|
||||
const TxfmFunc fwd_txfm_func_ls[][txfm_type_num] = {
|
||||
{ av1_fdct4_new, av1_fadst4_new, av1_fidentity4_c },
|
||||
{ av1_fdct8_new, av1_fadst8_new, av1_fidentity8_c },
|
||||
{ av1_fdct16_new, av1_fadst16_new, av1_fidentity16_c },
|
||||
{ av1_fdct32_new, NULL, av1_fidentity32_c },
|
||||
{ av1_fdct64_new, NULL, NULL },
|
||||
};
|
||||
|
||||
// the maximum stage number of fwd/inv 1d dct/adst txfm is 12
|
||||
const int8_t cos_bit = 14;
|
||||
const int8_t range_bit[12] = { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 };
|
||||
|
||||
TEST(av1_fwd_txfm1d, round_shift) {
|
||||
EXPECT_EQ(round_shift(7, 1), 4);
|
||||
EXPECT_EQ(round_shift(-7, 1), -3);
|
||||
|
||||
EXPECT_EQ(round_shift(7, 2), 2);
|
||||
EXPECT_EQ(round_shift(-7, 2), -2);
|
||||
|
||||
EXPECT_EQ(round_shift(8, 2), 2);
|
||||
EXPECT_EQ(round_shift(-8, 2), -2);
|
||||
}
|
||||
|
||||
TEST(av1_fwd_txfm1d, av1_cospi_arr_data) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int j = 0; j < 64; j++) {
|
||||
EXPECT_EQ(av1_cospi_arr_data[i][j],
|
||||
(int32_t)round(cos(M_PI * j / 128) * (1 << (cos_bit_min + i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(av1_fwd_txfm1d, accuracy) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int si = 0; si < txfm_size_num; ++si) {
|
||||
int txfm_size = txfm_size_ls[si];
|
||||
int32_t *input = new int32_t[txfm_size];
|
||||
int32_t *output = new int32_t[txfm_size];
|
||||
double *ref_input = new double[txfm_size];
|
||||
double *ref_output = new double[txfm_size];
|
||||
|
||||
for (int ti = 0; ti < txfm_type_num; ++ti) {
|
||||
TYPE_TXFM txfm_type = txfm_type_ls[ti];
|
||||
TxfmFunc fwd_txfm_func = fwd_txfm_func_ls[si][ti];
|
||||
int max_error = 7;
|
||||
|
||||
const int count_test_block = 5000;
|
||||
if (fwd_txfm_func != NULL) {
|
||||
for (int ti = 0; ti < count_test_block; ++ti) {
|
||||
for (int ni = 0; ni < txfm_size; ++ni) {
|
||||
input[ni] = rnd.Rand16() % input_base - rnd.Rand16() % input_base;
|
||||
ref_input[ni] = static_cast<double>(input[ni]);
|
||||
}
|
||||
|
||||
fwd_txfm_func(input, output, cos_bit, range_bit);
|
||||
reference_hybrid_1d(ref_input, ref_output, txfm_size, txfm_type);
|
||||
|
||||
for (int ni = 0; ni < txfm_size; ++ni) {
|
||||
ASSERT_LE(
|
||||
abs(output[ni] - static_cast<int32_t>(round(ref_output[ni]))),
|
||||
max_error)
|
||||
<< "tx size = " << txfm_size << ", tx type = " << txfm_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] input;
|
||||
delete[] output;
|
||||
delete[] ref_input;
|
||||
delete[] ref_output;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
511
media/libaom/src/test/av1_fwd_txfm2d_test.cc
Normal file
511
media/libaom/src/test/av1_fwd_txfm2d_test.cc
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
#include "test/av1_txfm_test.h"
|
||||
#include "av1/common/av1_txfm.h"
|
||||
#include "av1/encoder/hybrid_fwd_txfm.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::TYPE_TXFM;
|
||||
using libaom_test::bd;
|
||||
using libaom_test::compute_avg_abs_error;
|
||||
using libaom_test::input_base;
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
// tx_type_, tx_size_, max_error_, max_avg_error_
|
||||
typedef ::testing::tuple<TX_TYPE, TX_SIZE, double, double> AV1FwdTxfm2dParam;
|
||||
|
||||
class AV1FwdTxfm2d : public ::testing::TestWithParam<AV1FwdTxfm2dParam> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
tx_type_ = GET_PARAM(0);
|
||||
tx_size_ = GET_PARAM(1);
|
||||
max_error_ = GET_PARAM(2);
|
||||
max_avg_error_ = GET_PARAM(3);
|
||||
count_ = 500;
|
||||
TXFM_2D_FLIP_CFG fwd_txfm_flip_cfg;
|
||||
av1_get_fwd_txfm_cfg(tx_type_, tx_size_, &fwd_txfm_flip_cfg);
|
||||
amplify_factor_ = libaom_test::get_amplification_factor(tx_type_, tx_size_);
|
||||
tx_width_ = tx_size_wide[fwd_txfm_flip_cfg.tx_size];
|
||||
tx_height_ = tx_size_high[fwd_txfm_flip_cfg.tx_size];
|
||||
ud_flip_ = fwd_txfm_flip_cfg.ud_flip;
|
||||
lr_flip_ = fwd_txfm_flip_cfg.lr_flip;
|
||||
|
||||
fwd_txfm_ = libaom_test::fwd_txfm_func_ls[tx_size_];
|
||||
txfm2d_size_ = tx_width_ * tx_height_;
|
||||
input_ = reinterpret_cast<int16_t *>(
|
||||
aom_memalign(16, sizeof(input_[0]) * txfm2d_size_));
|
||||
output_ = reinterpret_cast<int32_t *>(
|
||||
aom_memalign(16, sizeof(output_[0]) * txfm2d_size_));
|
||||
ref_input_ = reinterpret_cast<double *>(
|
||||
aom_memalign(16, sizeof(ref_input_[0]) * txfm2d_size_));
|
||||
ref_output_ = reinterpret_cast<double *>(
|
||||
aom_memalign(16, sizeof(ref_output_[0]) * txfm2d_size_));
|
||||
}
|
||||
|
||||
void RunFwdAccuracyCheck() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
double avg_abs_error = 0;
|
||||
for (int ci = 0; ci < count_; ci++) {
|
||||
for (int ni = 0; ni < txfm2d_size_; ++ni) {
|
||||
input_[ni] = rnd.Rand16() % input_base;
|
||||
ref_input_[ni] = static_cast<double>(input_[ni]);
|
||||
output_[ni] = 0;
|
||||
ref_output_[ni] = 0;
|
||||
}
|
||||
|
||||
fwd_txfm_(input_, output_, tx_width_, tx_type_, bd);
|
||||
|
||||
if (lr_flip_ && ud_flip_) {
|
||||
libaom_test::fliplrud(ref_input_, tx_width_, tx_height_, tx_width_);
|
||||
} else if (lr_flip_) {
|
||||
libaom_test::fliplr(ref_input_, tx_width_, tx_height_, tx_width_);
|
||||
} else if (ud_flip_) {
|
||||
libaom_test::flipud(ref_input_, tx_width_, tx_height_, tx_width_);
|
||||
}
|
||||
|
||||
libaom_test::reference_hybrid_2d(ref_input_, ref_output_, tx_type_,
|
||||
tx_size_);
|
||||
|
||||
double actual_max_error = 0;
|
||||
for (int ni = 0; ni < txfm2d_size_; ++ni) {
|
||||
ref_output_[ni] = round(ref_output_[ni]);
|
||||
const double this_error =
|
||||
fabs(output_[ni] - ref_output_[ni]) / amplify_factor_;
|
||||
actual_max_error = AOMMAX(actual_max_error, this_error);
|
||||
}
|
||||
EXPECT_GE(max_error_, actual_max_error)
|
||||
<< "tx_size = " << tx_size_ << ", tx_type = " << tx_type_;
|
||||
if (actual_max_error > max_error_) { // exit early.
|
||||
break;
|
||||
}
|
||||
|
||||
avg_abs_error += compute_avg_abs_error<int32_t, double>(
|
||||
output_, ref_output_, txfm2d_size_);
|
||||
}
|
||||
|
||||
avg_abs_error /= amplify_factor_;
|
||||
avg_abs_error /= count_;
|
||||
EXPECT_GE(max_avg_error_, avg_abs_error)
|
||||
<< "tx_size = " << tx_size_ << ", tx_type = " << tx_type_;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
aom_free(input_);
|
||||
aom_free(output_);
|
||||
aom_free(ref_input_);
|
||||
aom_free(ref_output_);
|
||||
}
|
||||
|
||||
private:
|
||||
double max_error_;
|
||||
double max_avg_error_;
|
||||
int count_;
|
||||
double amplify_factor_;
|
||||
TX_TYPE tx_type_;
|
||||
TX_SIZE tx_size_;
|
||||
int tx_width_;
|
||||
int tx_height_;
|
||||
int txfm2d_size_;
|
||||
FwdTxfm2dFunc fwd_txfm_;
|
||||
int16_t *input_;
|
||||
int32_t *output_;
|
||||
double *ref_input_;
|
||||
double *ref_output_;
|
||||
int ud_flip_; // flip upside down
|
||||
int lr_flip_; // flip left to right
|
||||
};
|
||||
|
||||
static double avg_error_ls[TX_SIZES_ALL] = {
|
||||
0.5, // 4x4 transform
|
||||
0.5, // 8x8 transform
|
||||
1.2, // 16x16 transform
|
||||
6.1, // 32x32 transform
|
||||
3.4, // 64x64 transform
|
||||
0.57, // 4x8 transform
|
||||
0.68, // 8x4 transform
|
||||
0.92, // 8x16 transform
|
||||
1.1, // 16x8 transform
|
||||
4.1, // 16x32 transform
|
||||
6, // 32x16 transform
|
||||
3.5, // 32x64 transform
|
||||
5.7, // 64x32 transform
|
||||
0.6, // 4x16 transform
|
||||
0.9, // 16x4 transform
|
||||
1.2, // 8x32 transform
|
||||
1.7, // 32x8 transform
|
||||
2.0, // 16x64 transform
|
||||
4.7, // 64x16 transform
|
||||
};
|
||||
|
||||
static double max_error_ls[TX_SIZES_ALL] = {
|
||||
3, // 4x4 transform
|
||||
5, // 8x8 transform
|
||||
11, // 16x16 transform
|
||||
70, // 32x32 transform
|
||||
64, // 64x64 transform
|
||||
3.9, // 4x8 transform
|
||||
4.3, // 8x4 transform
|
||||
12, // 8x16 transform
|
||||
12, // 16x8 transform
|
||||
32, // 16x32 transform
|
||||
46, // 32x16 transform
|
||||
136, // 32x64 transform
|
||||
136, // 64x32 transform
|
||||
5, // 4x16 transform
|
||||
6, // 16x4 transform
|
||||
21, // 8x32 transform
|
||||
13, // 32x8 transform
|
||||
30, // 16x64 transform
|
||||
36, // 64x16 transform
|
||||
};
|
||||
|
||||
vector<AV1FwdTxfm2dParam> GetTxfm2dParamList() {
|
||||
vector<AV1FwdTxfm2dParam> param_list;
|
||||
for (int s = 0; s < TX_SIZES; ++s) {
|
||||
const double max_error = max_error_ls[s];
|
||||
const double avg_error = avg_error_ls[s];
|
||||
for (int t = 0; t < TX_TYPES; ++t) {
|
||||
const TX_TYPE tx_type = static_cast<TX_TYPE>(t);
|
||||
const TX_SIZE tx_size = static_cast<TX_SIZE>(s);
|
||||
if (libaom_test::IsTxSizeTypeValid(tx_size, tx_type)) {
|
||||
param_list.push_back(
|
||||
AV1FwdTxfm2dParam(tx_type, tx_size, max_error, avg_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
return param_list;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, AV1FwdTxfm2d,
|
||||
::testing::ValuesIn(GetTxfm2dParamList()));
|
||||
|
||||
TEST_P(AV1FwdTxfm2d, RunFwdAccuracyCheck) { RunFwdAccuracyCheck(); }
|
||||
|
||||
TEST(AV1FwdTxfm2d, CfgTest) {
|
||||
for (int bd_idx = 0; bd_idx < BD_NUM; ++bd_idx) {
|
||||
int bd = libaom_test::bd_arr[bd_idx];
|
||||
int8_t low_range = libaom_test::low_range_arr[bd_idx];
|
||||
int8_t high_range = libaom_test::high_range_arr[bd_idx];
|
||||
for (int tx_size = 0; tx_size < TX_SIZES_ALL; ++tx_size) {
|
||||
for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(tx_size),
|
||||
static_cast<TX_TYPE>(tx_type)) ==
|
||||
false) {
|
||||
continue;
|
||||
}
|
||||
TXFM_2D_FLIP_CFG cfg;
|
||||
av1_get_fwd_txfm_cfg(static_cast<TX_TYPE>(tx_type),
|
||||
static_cast<TX_SIZE>(tx_size), &cfg);
|
||||
int8_t stage_range_col[MAX_TXFM_STAGE_NUM];
|
||||
int8_t stage_range_row[MAX_TXFM_STAGE_NUM];
|
||||
av1_gen_fwd_stage_range(stage_range_col, stage_range_row, &cfg, bd);
|
||||
libaom_test::txfm_stage_range_check(stage_range_col, cfg.stage_num_col,
|
||||
cfg.cos_bit_col, low_range,
|
||||
high_range);
|
||||
libaom_test::txfm_stage_range_check(stage_range_row, cfg.stage_num_row,
|
||||
cfg.cos_bit_row, low_range,
|
||||
high_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*lowbd_fwd_txfm_func)(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param);
|
||||
|
||||
void AV1FwdTxfm2dMatchTest(TX_SIZE tx_size, lowbd_fwd_txfm_func target_func) {
|
||||
const int bd = 8;
|
||||
TxfmParam param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
const int rows = tx_size_high[tx_size];
|
||||
const int cols = tx_size_wide[tx_size];
|
||||
// printf("%d x %d\n", cols, rows);
|
||||
for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
|
||||
if (libaom_test::IsTxSizeTypeValid(
|
||||
tx_size, static_cast<TX_TYPE>(tx_type)) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FwdTxfm2dFunc ref_func = libaom_test::fwd_txfm_func_ls[tx_size];
|
||||
if (ref_func != NULL) {
|
||||
DECLARE_ALIGNED(32, int16_t, input[64 * 64]) = { 0 };
|
||||
DECLARE_ALIGNED(32, int32_t, output[64 * 64]);
|
||||
DECLARE_ALIGNED(32, int32_t, ref_output[64 * 64]);
|
||||
int input_stride = 64;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int cnt = 0; cnt < 500; ++cnt) {
|
||||
if (cnt == 0) {
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
input[r * input_stride + c] = (1 << bd) - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
input[r * input_stride + c] = rnd.Rand16() % (1 << bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
param.tx_type = (TX_TYPE)tx_type;
|
||||
param.tx_size = (TX_SIZE)tx_size;
|
||||
param.tx_set_type = EXT_TX_SET_ALL16;
|
||||
param.bd = bd;
|
||||
ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd);
|
||||
target_func(input, output, input_stride, ¶m);
|
||||
const int check_rows = AOMMIN(32, rows);
|
||||
const int check_cols = AOMMIN(32, rows * cols / check_rows);
|
||||
for (int r = 0; r < check_rows; ++r) {
|
||||
for (int c = 0; c < check_cols; ++c) {
|
||||
ASSERT_EQ(ref_output[r * check_cols + c],
|
||||
output[r * check_cols + c])
|
||||
<< "[" << r << "," << c << "] cnt:" << cnt
|
||||
<< " tx_size: " << tx_size << " tx_type: " << tx_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef ::testing::tuple<TX_SIZE, lowbd_fwd_txfm_func> LbdFwdTxfm2dParam;
|
||||
|
||||
class AV1FwdTxfm2dTest : public ::testing::TestWithParam<LbdFwdTxfm2dParam> {};
|
||||
|
||||
TEST_P(AV1FwdTxfm2dTest, match) {
|
||||
AV1FwdTxfm2dMatchTest(GET_PARAM(0), GET_PARAM(1));
|
||||
}
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
#if HAVE_SSE2
|
||||
static TX_SIZE fwd_txfm_for_sse2[] = {
|
||||
TX_4X4,
|
||||
TX_8X8,
|
||||
TX_16X16,
|
||||
TX_32X32,
|
||||
// TX_64X64,
|
||||
TX_4X8,
|
||||
TX_8X4,
|
||||
TX_8X16,
|
||||
TX_16X8,
|
||||
TX_16X32,
|
||||
TX_32X16,
|
||||
// TX_32X64,
|
||||
// TX_64X32,
|
||||
TX_4X16,
|
||||
TX_16X4,
|
||||
TX_8X32,
|
||||
TX_32X8,
|
||||
TX_16X64,
|
||||
TX_64X16,
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, AV1FwdTxfm2dTest,
|
||||
Combine(ValuesIn(fwd_txfm_for_sse2),
|
||||
Values(av1_lowbd_fwd_txfm_sse2)));
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
static TX_SIZE fwd_txfm_for_sse41[] = {
|
||||
TX_4X4,
|
||||
TX_64X64,
|
||||
TX_32X64,
|
||||
TX_64X32,
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1FwdTxfm2dTest,
|
||||
Combine(ValuesIn(fwd_txfm_for_sse41),
|
||||
Values(av1_lowbd_fwd_txfm_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
#if HAVE_AVX2
|
||||
static TX_SIZE fwd_txfm_for_avx2[] = {
|
||||
TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_64X64, TX_4X8, TX_8X4,
|
||||
TX_8X16, TX_16X8, TX_16X32, TX_32X16, TX_32X64, TX_64X32, TX_4X16,
|
||||
TX_16X4, TX_8X32, TX_32X8, TX_16X64, TX_64X16,
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1FwdTxfm2dTest,
|
||||
Combine(ValuesIn(fwd_txfm_for_avx2),
|
||||
Values(av1_lowbd_fwd_txfm_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
typedef void (*Highbd_fwd_txfm_func)(const int16_t *src_diff, tran_low_t *coeff,
|
||||
int diff_stride, TxfmParam *txfm_param);
|
||||
|
||||
void AV1HighbdFwdTxfm2dMatchTest(TX_SIZE tx_size,
|
||||
Highbd_fwd_txfm_func target_func) {
|
||||
const int bd_ar[2] = { 10, 12 };
|
||||
TxfmParam param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
const int rows = tx_size_high[tx_size];
|
||||
const int cols = tx_size_wide[tx_size];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const int bd = bd_ar[i];
|
||||
for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
|
||||
if (libaom_test::IsTxSizeTypeValid(
|
||||
tx_size, static_cast<TX_TYPE>(tx_type)) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FwdTxfm2dFunc ref_func = libaom_test::fwd_txfm_func_ls[tx_size];
|
||||
if (ref_func != NULL) {
|
||||
DECLARE_ALIGNED(32, int16_t, input[64 * 64]) = { 0 };
|
||||
DECLARE_ALIGNED(32, int32_t, output[64 * 64]);
|
||||
DECLARE_ALIGNED(32, int32_t, ref_output[64 * 64]);
|
||||
int input_stride = 64;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int cnt = 0; cnt < 500; ++cnt) {
|
||||
if (cnt == 0) {
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
input[r * input_stride + c] = (1 << bd) - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
input[r * input_stride + c] = rnd.Rand16() % (1 << bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
param.tx_type = (TX_TYPE)tx_type;
|
||||
param.tx_size = (TX_SIZE)tx_size;
|
||||
param.tx_set_type = EXT_TX_SET_ALL16;
|
||||
param.bd = bd;
|
||||
|
||||
ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd);
|
||||
target_func(input, output, input_stride, ¶m);
|
||||
const int check_rows = AOMMIN(32, rows);
|
||||
const int check_cols = AOMMIN(32, rows * cols / check_rows);
|
||||
for (int r = 0; r < check_rows; ++r) {
|
||||
for (int c = 0; c < check_cols; ++c) {
|
||||
ASSERT_EQ(ref_output[r * check_cols + c],
|
||||
output[r * check_cols + c])
|
||||
<< "[" << r << "," << c << "] cnt:" << cnt
|
||||
<< " tx_size: " << tx_size << " tx_type: " << tx_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AV1HighbdFwdTxfm2dSpeedTest(TX_SIZE tx_size,
|
||||
Highbd_fwd_txfm_func target_func) {
|
||||
const int bd_ar[2] = { 10, 12 };
|
||||
TxfmParam param;
|
||||
memset(¶m, 0, sizeof(param));
|
||||
const int rows = tx_size_high[tx_size];
|
||||
const int cols = tx_size_wide[tx_size];
|
||||
const int num_loops = 1000000 / (rows * cols);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
const int bd = bd_ar[i];
|
||||
for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
|
||||
if (libaom_test::IsTxSizeTypeValid(
|
||||
tx_size, static_cast<TX_TYPE>(tx_type)) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FwdTxfm2dFunc ref_func = libaom_test::fwd_txfm_func_ls[tx_size];
|
||||
if (ref_func != NULL) {
|
||||
DECLARE_ALIGNED(32, int16_t, input[64 * 64]) = { 0 };
|
||||
DECLARE_ALIGNED(32, int32_t, output[64 * 64]);
|
||||
DECLARE_ALIGNED(32, int32_t, ref_output[64 * 64]);
|
||||
int input_stride = 64;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
input[r * input_stride + c] = rnd.Rand16() % (1 << bd);
|
||||
}
|
||||
}
|
||||
|
||||
param.tx_type = (TX_TYPE)tx_type;
|
||||
param.tx_size = (TX_SIZE)tx_size;
|
||||
param.tx_set_type = EXT_TX_SET_ALL16;
|
||||
param.bd = bd;
|
||||
|
||||
aom_usec_timer ref_timer, test_timer;
|
||||
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int i = 0; i < num_loops; ++i) {
|
||||
ref_func(input, ref_output, input_stride, (TX_TYPE)tx_type, bd);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int elapsed_time_c =
|
||||
static_cast<int>(aom_usec_timer_elapsed(&ref_timer));
|
||||
|
||||
aom_usec_timer_start(&test_timer);
|
||||
for (int i = 0; i < num_loops; ++i) {
|
||||
target_func(input, output, input_stride, ¶m);
|
||||
}
|
||||
aom_usec_timer_mark(&test_timer);
|
||||
const int elapsed_time_simd =
|
||||
static_cast<int>(aom_usec_timer_elapsed(&test_timer));
|
||||
|
||||
printf(
|
||||
"txfm_size[%d] \t txfm_type[%d] \t c_time=%d \t simd_time=%d \t "
|
||||
"gain=%d \n",
|
||||
tx_size, tx_type, elapsed_time_c, elapsed_time_simd,
|
||||
(elapsed_time_c / elapsed_time_simd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef ::testing::tuple<TX_SIZE, Highbd_fwd_txfm_func> HighbdFwdTxfm2dParam;
|
||||
|
||||
class AV1HighbdFwdTxfm2dTest
|
||||
: public ::testing::TestWithParam<HighbdFwdTxfm2dParam> {};
|
||||
|
||||
TEST_P(AV1HighbdFwdTxfm2dTest, match) {
|
||||
AV1HighbdFwdTxfm2dMatchTest(GET_PARAM(0), GET_PARAM(1));
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdFwdTxfm2dTest, DISABLED_Speed) {
|
||||
AV1HighbdFwdTxfm2dSpeedTest(GET_PARAM(0), GET_PARAM(1));
|
||||
}
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
static TX_SIZE Highbd_fwd_txfm_for_sse4_1[] = {
|
||||
TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_64X64, TX_4X8, TX_8X4,
|
||||
TX_8X16, TX_16X8, TX_16X32, TX_32X16, TX_32X64, TX_64X32, TX_4X16,
|
||||
TX_16X4, TX_8X32, TX_32X8, TX_16X64, TX_64X16,
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdFwdTxfm2dTest,
|
||||
Combine(ValuesIn(Highbd_fwd_txfm_for_sse4_1),
|
||||
Values(av1_highbd_fwd_txfm)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
} // namespace
|
||||
315
media/libaom/src/test/av1_highbd_iht_test.cc
Normal file
315
media/libaom/src/test/av1_highbd_iht_test.cc
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/av1_txfm_test.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/enums.h"
|
||||
#include "av1/common/scan.h"
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
typedef void (*HbdHtFunc)(const int16_t *input, int32_t *output, int stride,
|
||||
TX_TYPE tx_type, int bd);
|
||||
|
||||
typedef void (*IHbdHtFunc)(const int32_t *coeff, uint16_t *output, int stride,
|
||||
TX_TYPE tx_type, int bd);
|
||||
|
||||
// Test parameter argument list:
|
||||
// <transform reference function,
|
||||
// optimized inverse transform function,
|
||||
// inverse transform reference function,
|
||||
// num_coeffs,
|
||||
// tx_type,
|
||||
// bit_depth>
|
||||
typedef tuple<HbdHtFunc, IHbdHtFunc, IHbdHtFunc, int, TX_TYPE, int> IHbdHtParam;
|
||||
|
||||
class AV1HighbdInvHTNxN : public ::testing::TestWithParam<IHbdHtParam> {
|
||||
public:
|
||||
virtual ~AV1HighbdInvHTNxN() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
txfm_ref_ = GET_PARAM(0);
|
||||
inv_txfm_ = GET_PARAM(1);
|
||||
inv_txfm_ref_ = GET_PARAM(2);
|
||||
num_coeffs_ = GET_PARAM(3);
|
||||
tx_type_ = GET_PARAM(4);
|
||||
bit_depth_ = GET_PARAM(5);
|
||||
|
||||
input_ = reinterpret_cast<int16_t *>(
|
||||
aom_memalign(16, sizeof(input_[0]) * num_coeffs_));
|
||||
|
||||
// Note:
|
||||
// Inverse transform input buffer is 32-byte aligned
|
||||
// Refer to <root>/av1/encoder/context_tree.c, function,
|
||||
// void alloc_mode_context().
|
||||
coeffs_ = reinterpret_cast<int32_t *>(
|
||||
aom_memalign(32, sizeof(coeffs_[0]) * num_coeffs_));
|
||||
output_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(32, sizeof(output_[0]) * num_coeffs_));
|
||||
output_ref_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(32, sizeof(output_ref_[0]) * num_coeffs_));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
aom_free(input_);
|
||||
aom_free(coeffs_);
|
||||
aom_free(output_);
|
||||
aom_free(output_ref_);
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
protected:
|
||||
void RunBitexactCheck();
|
||||
|
||||
private:
|
||||
int GetStride() const {
|
||||
if (16 == num_coeffs_) {
|
||||
return 4;
|
||||
} else if (64 == num_coeffs_) {
|
||||
return 8;
|
||||
} else if (256 == num_coeffs_) {
|
||||
return 16;
|
||||
} else if (1024 == num_coeffs_) {
|
||||
return 32;
|
||||
} else if (4096 == num_coeffs_) {
|
||||
return 64;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
HbdHtFunc txfm_ref_;
|
||||
IHbdHtFunc inv_txfm_;
|
||||
IHbdHtFunc inv_txfm_ref_;
|
||||
int num_coeffs_;
|
||||
TX_TYPE tx_type_;
|
||||
int bit_depth_;
|
||||
|
||||
int16_t *input_;
|
||||
int32_t *coeffs_;
|
||||
uint16_t *output_;
|
||||
uint16_t *output_ref_;
|
||||
};
|
||||
|
||||
void AV1HighbdInvHTNxN::RunBitexactCheck() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
const int stride = GetStride();
|
||||
const int num_tests = 20000;
|
||||
const uint16_t mask = (1 << bit_depth_) - 1;
|
||||
|
||||
for (int i = 0; i < num_tests; ++i) {
|
||||
for (int j = 0; j < num_coeffs_; ++j) {
|
||||
input_[j] = (rnd.Rand16() & mask) - (rnd.Rand16() & mask);
|
||||
output_ref_[j] = rnd.Rand16() & mask;
|
||||
output_[j] = output_ref_[j];
|
||||
}
|
||||
|
||||
txfm_ref_(input_, coeffs_, stride, tx_type_, bit_depth_);
|
||||
inv_txfm_ref_(coeffs_, output_ref_, stride, tx_type_, bit_depth_);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
inv_txfm_(coeffs_, output_, stride, tx_type_, bit_depth_));
|
||||
|
||||
for (int j = 0; j < num_coeffs_; ++j) {
|
||||
EXPECT_EQ(output_ref_[j], output_[j])
|
||||
<< "Not bit-exact result at index: " << j << " At test block: " << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdInvHTNxN, InvTransResultCheck) { RunBitexactCheck(); }
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
#define PARAM_LIST_4X4 \
|
||||
&av1_fwd_txfm2d_4x4_c, &av1_inv_txfm2d_add_4x4_sse4_1, \
|
||||
&av1_inv_txfm2d_add_4x4_c, 16
|
||||
|
||||
const IHbdHtParam kArrayIhtParam[] = {
|
||||
// 4x4
|
||||
make_tuple(PARAM_LIST_4X4, DCT_DCT, 10),
|
||||
make_tuple(PARAM_LIST_4X4, DCT_DCT, 12),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_DCT, 10),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_DCT, 12),
|
||||
make_tuple(PARAM_LIST_4X4, DCT_ADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, DCT_ADST, 12),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_ADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_ADST, 12),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_DCT, 10),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_DCT, 12),
|
||||
make_tuple(PARAM_LIST_4X4, DCT_FLIPADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, DCT_FLIPADST, 12),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_FLIPADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_FLIPADST, 12),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_FLIPADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, ADST_FLIPADST, 12),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_ADST, 10),
|
||||
make_tuple(PARAM_LIST_4X4, FLIPADST_ADST, 12),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdInvHTNxN,
|
||||
::testing::ValuesIn(kArrayIhtParam));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
typedef void (*HighbdInvTxfm2dFunc)(const int32_t *input, uint8_t *output,
|
||||
int stride, const TxfmParam *txfm_param);
|
||||
|
||||
typedef ::testing::tuple<const HighbdInvTxfm2dFunc> AV1HighbdInvTxfm2dParam;
|
||||
class AV1HighbdInvTxfm2d
|
||||
: public ::testing::TestWithParam<AV1HighbdInvTxfm2dParam> {
|
||||
public:
|
||||
virtual void SetUp() { target_func_ = GET_PARAM(0); }
|
||||
void RunAV1InvTxfm2dTest(TX_TYPE tx_type, TX_SIZE tx_size, int run_times,
|
||||
int bit_depth);
|
||||
|
||||
private:
|
||||
HighbdInvTxfm2dFunc target_func_;
|
||||
};
|
||||
|
||||
void AV1HighbdInvTxfm2d::RunAV1InvTxfm2dTest(TX_TYPE tx_type_, TX_SIZE tx_size_,
|
||||
int run_times, int bit_depth_) {
|
||||
FwdTxfm2dFunc fwd_func_ = libaom_test::fwd_txfm_func_ls[tx_size_];
|
||||
TxfmParam txfm_param;
|
||||
const int BLK_WIDTH = 64;
|
||||
const int BLK_SIZE = BLK_WIDTH * BLK_WIDTH;
|
||||
DECLARE_ALIGNED(16, int16_t, input[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(32, int32_t, inv_input[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(32, uint16_t, output[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(32, uint16_t, ref_output[BLK_SIZE]) = { 0 };
|
||||
int stride = BLK_WIDTH;
|
||||
int rows = tx_size_high[tx_size_];
|
||||
int cols = tx_size_wide[tx_size_];
|
||||
const int rows_nonezero = AOMMIN(32, rows);
|
||||
const int cols_nonezero = AOMMIN(32, cols);
|
||||
const uint16_t mask = (1 << bit_depth_) - 1;
|
||||
run_times /= (rows * cols);
|
||||
run_times = AOMMAX(1, run_times);
|
||||
const SCAN_ORDER *scan_order = get_default_scan(tx_size_, tx_type_);
|
||||
const int16_t *scan = scan_order->scan;
|
||||
const int16_t eobmax = rows_nonezero * cols_nonezero;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
int randTimes = run_times == 1 ? (eobmax) : 1;
|
||||
|
||||
txfm_param.tx_type = tx_type_;
|
||||
txfm_param.tx_size = tx_size_;
|
||||
txfm_param.lossless = 0;
|
||||
txfm_param.bd = bit_depth_;
|
||||
txfm_param.is_hbd = 1;
|
||||
txfm_param.tx_set_type = EXT_TX_SET_ALL16;
|
||||
|
||||
for (int cnt = 0; cnt < randTimes; ++cnt) {
|
||||
for (int r = 0; r < BLK_WIDTH; ++r) {
|
||||
for (int c = 0; c < BLK_WIDTH; ++c) {
|
||||
input[r * cols + c] = (rnd.Rand16() & mask) - (rnd.Rand16() & mask);
|
||||
output[r * stride + c] = rnd.Rand16() & mask;
|
||||
|
||||
ref_output[r * stride + c] = output[r * stride + c];
|
||||
}
|
||||
}
|
||||
fwd_func_(input, inv_input, stride, tx_type_, bit_depth_);
|
||||
|
||||
// produce eob input by setting high freq coeffs to zero
|
||||
const int eob = AOMMIN(cnt + 1, eobmax);
|
||||
for (int i = eob; i < eobmax; i++) {
|
||||
inv_input[scan[i]] = 0;
|
||||
}
|
||||
txfm_param.eob = eob;
|
||||
aom_usec_timer ref_timer, test_timer;
|
||||
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
av1_highbd_inv_txfm_add_c(inv_input, CONVERT_TO_BYTEPTR(ref_output),
|
||||
stride, &txfm_param);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int elapsed_time_c =
|
||||
static_cast<int>(aom_usec_timer_elapsed(&ref_timer));
|
||||
|
||||
aom_usec_timer_start(&test_timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
target_func_(inv_input, CONVERT_TO_BYTEPTR(output), stride, &txfm_param);
|
||||
}
|
||||
aom_usec_timer_mark(&test_timer);
|
||||
const int elapsed_time_simd =
|
||||
static_cast<int>(aom_usec_timer_elapsed(&test_timer));
|
||||
if (run_times > 10) {
|
||||
printf(
|
||||
"txfm_size[%d] \t txfm_type[%d] \t c_time=%d \t simd_time=%d \t "
|
||||
"gain=%d \n",
|
||||
tx_size_, tx_type_, elapsed_time_c, elapsed_time_simd,
|
||||
(elapsed_time_c / elapsed_time_simd));
|
||||
} else {
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
ASSERT_EQ(ref_output[r * stride + c], output[r * stride + c])
|
||||
<< "[" << r << "," << c << "] " << cnt
|
||||
<< " tx_size: " << static_cast<int>(tx_size_)
|
||||
<< " tx_type: " << tx_type_ << " eob " << eob;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdInvTxfm2d, match) {
|
||||
int bitdepth_ar[2] = { 10, 12 };
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
int bd = bitdepth_ar[k];
|
||||
for (int j = 0; j < (int)(TX_SIZES_ALL); ++j) {
|
||||
for (int i = 0; i < (int)TX_TYPES; ++i) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(j),
|
||||
static_cast<TX_TYPE>(i))) {
|
||||
RunAV1InvTxfm2dTest(static_cast<TX_TYPE>(i), static_cast<TX_SIZE>(j),
|
||||
1, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdInvTxfm2d, DISABLED_Speed) {
|
||||
int bitdepth_ar[2] = { 10, 12 };
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
int bd = bitdepth_ar[k];
|
||||
for (int j = 0; j < (int)(TX_SIZES_ALL); ++j) {
|
||||
for (int i = 0; i < (int)TX_TYPES; ++i) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(j),
|
||||
static_cast<TX_TYPE>(i))) {
|
||||
RunAV1InvTxfm2dTest(static_cast<TX_TYPE>(i), static_cast<TX_SIZE>(j),
|
||||
1000000, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1HighbdInvTxfm2d,
|
||||
::testing::Values(av1_highbd_inv_txfm_add_sse4_1));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdInvTxfm2d,
|
||||
::testing::Values(av1_highbd_inv_txfm_add_avx2));
|
||||
#endif
|
||||
} // namespace
|
||||
362
media/libaom/src/test/av1_horz_only_frame_superres_test.cc
Normal file
362
media/libaom/src/test/av1_horz_only_frame_superres_test.cc
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/convolve.h"
|
||||
#include "av1/common/resize.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
const int kTestIters = 10;
|
||||
const int kPerfIters = 1000;
|
||||
|
||||
const int kVPad = 32;
|
||||
const int kHPad = 32;
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
template <typename Pixel>
|
||||
class TestImage {
|
||||
public:
|
||||
TestImage(int w_src, int h, int superres_denom, int x0, int bd)
|
||||
: w_src_(w_src), h_(h), superres_denom_(superres_denom), x0_(x0),
|
||||
bd_(bd) {
|
||||
assert(bd < 16);
|
||||
assert(bd <= 8 * static_cast<int>(sizeof(Pixel)));
|
||||
assert(9 <= superres_denom && superres_denom <= 16);
|
||||
assert(SCALE_NUMERATOR == 8);
|
||||
assert(0 <= x0_ && x0_ <= RS_SCALE_SUBPEL_MASK);
|
||||
|
||||
w_dst_ = w_src_;
|
||||
av1_calculate_unscaled_superres_size(&w_dst_, NULL, superres_denom);
|
||||
|
||||
src_stride_ = ALIGN_POWER_OF_TWO(w_src_ + 2 * kHPad, 4);
|
||||
dst_stride_ = ALIGN_POWER_OF_TWO(w_dst_ + 2 * kHPad, 4);
|
||||
|
||||
// Allocate image data
|
||||
src_data_.resize(2 * src_block_size());
|
||||
dst_data_.resize(2 * dst_block_size());
|
||||
}
|
||||
|
||||
void Initialize(ACMRandom *rnd);
|
||||
void Check() const;
|
||||
|
||||
int src_stride() const { return src_stride_; }
|
||||
int dst_stride() const { return dst_stride_; }
|
||||
|
||||
int src_block_size() const { return (h_ + 2 * kVPad) * src_stride(); }
|
||||
int dst_block_size() const { return (h_ + 2 * kVPad) * dst_stride(); }
|
||||
|
||||
int src_width() const { return w_src_; }
|
||||
int dst_width() const { return w_dst_; }
|
||||
int height() const { return h_; }
|
||||
int x0() const { return x0_; }
|
||||
|
||||
const Pixel *GetSrcData(bool ref, bool borders) const {
|
||||
const Pixel *block = &src_data_[ref ? 0 : src_block_size()];
|
||||
return borders ? block : block + kHPad + src_stride_ * kVPad;
|
||||
}
|
||||
|
||||
Pixel *GetDstData(bool ref, bool borders) {
|
||||
Pixel *block = &dst_data_[ref ? 0 : dst_block_size()];
|
||||
return borders ? block : block + kHPad + dst_stride_ * kVPad;
|
||||
}
|
||||
|
||||
private:
|
||||
int w_src_, w_dst_, h_, superres_denom_, x0_, bd_;
|
||||
int src_stride_, dst_stride_;
|
||||
|
||||
std::vector<Pixel> src_data_;
|
||||
std::vector<Pixel> dst_data_;
|
||||
};
|
||||
|
||||
template <typename Pixel>
|
||||
void FillEdge(ACMRandom *rnd, int num_pixels, int bd, bool trash, Pixel *data) {
|
||||
if (!trash) {
|
||||
memset(data, 0, sizeof(*data) * num_pixels);
|
||||
return;
|
||||
}
|
||||
const Pixel mask = (1 << bd) - 1;
|
||||
for (int i = 0; i < num_pixels; ++i) data[i] = rnd->Rand16() & mask;
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
void PrepBuffers(ACMRandom *rnd, int w, int h, int stride, int bd,
|
||||
bool trash_edges, Pixel *data) {
|
||||
assert(rnd);
|
||||
const Pixel mask = (1 << bd) - 1;
|
||||
|
||||
// Fill in the first buffer with random data
|
||||
// Top border
|
||||
FillEdge(rnd, stride * kVPad, bd, trash_edges, data);
|
||||
for (int r = 0; r < h; ++r) {
|
||||
Pixel *row_data = data + (kVPad + r) * stride;
|
||||
// Left border, contents, right border
|
||||
FillEdge(rnd, kHPad, bd, trash_edges, row_data);
|
||||
for (int c = 0; c < w; ++c) row_data[kHPad + c] = rnd->Rand16() & mask;
|
||||
FillEdge(rnd, kHPad, bd, trash_edges, row_data + kHPad + w);
|
||||
}
|
||||
// Bottom border
|
||||
FillEdge(rnd, stride * kVPad, bd, trash_edges, data + stride * (kVPad + h));
|
||||
|
||||
const int bpp = sizeof(*data);
|
||||
const int block_elts = stride * (h + 2 * kVPad);
|
||||
const int block_size = bpp * block_elts;
|
||||
|
||||
// Now copy that to the second buffer
|
||||
memcpy(data + block_elts, data, block_size);
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
void TestImage<Pixel>::Initialize(ACMRandom *rnd) {
|
||||
PrepBuffers(rnd, w_src_, h_, src_stride_, bd_, false, &src_data_[0]);
|
||||
PrepBuffers(rnd, w_dst_, h_, dst_stride_, bd_, true, &dst_data_[0]);
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
void TestImage<Pixel>::Check() const {
|
||||
const int num_pixels = dst_block_size();
|
||||
const Pixel *ref_dst = &dst_data_[0];
|
||||
const Pixel *tst_dst = &dst_data_[num_pixels];
|
||||
|
||||
// If memcmp returns 0, there's nothing to do.
|
||||
if (0 == memcmp(ref_dst, tst_dst, sizeof(*ref_dst) * num_pixels)) return;
|
||||
|
||||
// Otherwise, iterate through the buffer looking for differences, *ignoring
|
||||
// the edges*
|
||||
const int stride = dst_stride_;
|
||||
for (int r = kVPad; r < h_ + kVPad; ++r) {
|
||||
for (int c = kVPad; c < w_dst_ + kHPad; ++c) {
|
||||
const int32_t ref_value = ref_dst[r * stride + c];
|
||||
const int32_t tst_value = tst_dst[r * stride + c];
|
||||
|
||||
EXPECT_EQ(tst_value, ref_value)
|
||||
<< "Error at row: " << (r - kVPad) << ", col: " << (c - kHPad)
|
||||
<< ", superres_denom: " << superres_denom_ << ", height: " << h_
|
||||
<< ", src_width: " << w_src_ << ", dst_width: " << w_dst_
|
||||
<< ", x0: " << x0_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Pixel>
|
||||
class ConvolveHorizRSTestBase : public ::testing::Test {
|
||||
public:
|
||||
ConvolveHorizRSTestBase() : image_(NULL) {}
|
||||
virtual ~ConvolveHorizRSTestBase() {}
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
// Implemented by subclasses (SetUp depends on the parameters passed
|
||||
// in and RunOne depends on the function to be tested. These can't
|
||||
// be templated for low/high bit depths because they have different
|
||||
// numbers of parameters)
|
||||
virtual void SetUp() = 0;
|
||||
virtual void RunOne(bool ref) = 0;
|
||||
|
||||
protected:
|
||||
void SetBitDepth(int bd) { bd_ = bd; }
|
||||
|
||||
void CorrectnessTest() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int i = 0; i < kTestIters; ++i) {
|
||||
for (int superres_denom = 9; superres_denom <= 16; superres_denom++) {
|
||||
// Get a random height between 512 and 767
|
||||
int height = rnd.Rand8() + 512;
|
||||
|
||||
// Get a random src width between 128 and 383
|
||||
int width_src = rnd.Rand8() + 128;
|
||||
|
||||
// x0 is normally calculated by get_upscale_convolve_x0 in
|
||||
// av1/common/resize.c. However, this test should work for
|
||||
// any value of x0 between 0 and RS_SCALE_SUBPEL_MASK
|
||||
// (inclusive), so we choose one at random.
|
||||
int x0 = rnd.Rand16() % (RS_SCALE_SUBPEL_MASK + 1);
|
||||
|
||||
image_ =
|
||||
new TestImage<Pixel>(width_src, height, superres_denom, x0, bd_);
|
||||
|
||||
Prep(&rnd);
|
||||
RunOne(true);
|
||||
RunOne(false);
|
||||
image_->Check();
|
||||
|
||||
delete image_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedTest() {
|
||||
// Pick some specific parameters to test
|
||||
int height = 767;
|
||||
int width_src = 129;
|
||||
int superres_denom = 13;
|
||||
int x0 = RS_SCALE_SUBPEL_MASK >> 1;
|
||||
|
||||
image_ = new TestImage<Pixel>(width_src, height, superres_denom, x0, bd_);
|
||||
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
Prep(&rnd);
|
||||
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int i = 0; i < kPerfIters; ++i) RunOne(true);
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer tst_timer;
|
||||
aom_usec_timer_start(&tst_timer);
|
||||
for (int i = 0; i < kPerfIters; ++i) RunOne(false);
|
||||
aom_usec_timer_mark(&tst_timer);
|
||||
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
|
||||
|
||||
std::cout << "[ ] C time = " << ref_time / 1000
|
||||
<< " ms, SIMD time = " << tst_time / 1000 << " ms\n";
|
||||
|
||||
EXPECT_GT(ref_time, tst_time)
|
||||
<< "Error: ConvolveHorizRSTest (Speed Test), SIMD slower than C.\n"
|
||||
<< "C time: " << ref_time << " us\n"
|
||||
<< "SIMD time: " << tst_time << " us\n";
|
||||
}
|
||||
|
||||
void Prep(ACMRandom *rnd) {
|
||||
assert(rnd);
|
||||
image_->Initialize(rnd);
|
||||
}
|
||||
|
||||
int bd_;
|
||||
TestImage<Pixel> *image_;
|
||||
};
|
||||
|
||||
typedef void (*LowBDConvolveHorizRsFunc)(const uint8_t *src, int src_stride,
|
||||
uint8_t *dst, int dst_stride, int w,
|
||||
int h, const int16_t *x_filters,
|
||||
const int x0_qn, const int x_step_qn);
|
||||
|
||||
// Test parameter list:
|
||||
// <tst_fun_>
|
||||
typedef tuple<LowBDConvolveHorizRsFunc> LowBDParams;
|
||||
|
||||
class LowBDConvolveHorizRSTest
|
||||
: public ConvolveHorizRSTestBase<uint8_t>,
|
||||
public ::testing::WithParamInterface<LowBDParams> {
|
||||
public:
|
||||
virtual ~LowBDConvolveHorizRSTest() {}
|
||||
|
||||
void SetUp() {
|
||||
tst_fun_ = GET_PARAM(0);
|
||||
const int bd = 8;
|
||||
SetBitDepth(bd);
|
||||
}
|
||||
|
||||
void RunOne(bool ref) {
|
||||
const uint8_t *src = image_->GetSrcData(ref, false);
|
||||
uint8_t *dst = image_->GetDstData(ref, false);
|
||||
const int src_stride = image_->src_stride();
|
||||
const int dst_stride = image_->dst_stride();
|
||||
const int width_src = image_->src_width();
|
||||
const int width_dst = image_->dst_width();
|
||||
const int height = image_->height();
|
||||
const int x0_qn = image_->x0();
|
||||
|
||||
const int32_t x_step_qn =
|
||||
av1_get_upscale_convolve_step(width_src, width_dst);
|
||||
|
||||
if (ref) {
|
||||
av1_convolve_horiz_rs_c(src, src_stride, dst, dst_stride, width_dst,
|
||||
height, &av1_resize_filter_normative[0][0], x0_qn,
|
||||
x_step_qn);
|
||||
} else {
|
||||
tst_fun_(src, src_stride, dst, dst_stride, width_dst, height,
|
||||
&av1_resize_filter_normative[0][0], x0_qn, x_step_qn);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
LowBDConvolveHorizRsFunc tst_fun_;
|
||||
};
|
||||
|
||||
TEST_P(LowBDConvolveHorizRSTest, Correctness) { CorrectnessTest(); }
|
||||
TEST_P(LowBDConvolveHorizRSTest, DISABLED_Speed) { SpeedTest(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, LowBDConvolveHorizRSTest,
|
||||
::testing::Values(av1_convolve_horiz_rs_sse4_1));
|
||||
|
||||
typedef void (*HighBDConvolveHorizRsFunc)(const uint16_t *src, int src_stride,
|
||||
uint16_t *dst, int dst_stride, int w,
|
||||
int h, const int16_t *x_filters,
|
||||
const int x0_qn, const int x_step_qn,
|
||||
int bd);
|
||||
|
||||
// Test parameter list:
|
||||
// <tst_fun_, bd_>
|
||||
typedef tuple<HighBDConvolveHorizRsFunc, int> HighBDParams;
|
||||
|
||||
class HighBDConvolveHorizRSTest
|
||||
: public ConvolveHorizRSTestBase<uint16_t>,
|
||||
public ::testing::WithParamInterface<HighBDParams> {
|
||||
public:
|
||||
virtual ~HighBDConvolveHorizRSTest() {}
|
||||
|
||||
void SetUp() {
|
||||
tst_fun_ = GET_PARAM(0);
|
||||
const int bd = GET_PARAM(1);
|
||||
SetBitDepth(bd);
|
||||
}
|
||||
|
||||
void RunOne(bool ref) {
|
||||
const uint16_t *src = image_->GetSrcData(ref, false);
|
||||
uint16_t *dst = image_->GetDstData(ref, false);
|
||||
const int src_stride = image_->src_stride();
|
||||
const int dst_stride = image_->dst_stride();
|
||||
const int width_src = image_->src_width();
|
||||
const int width_dst = image_->dst_width();
|
||||
const int height = image_->height();
|
||||
const int x0_qn = image_->x0();
|
||||
|
||||
const int32_t x_step_qn =
|
||||
av1_get_upscale_convolve_step(width_src, width_dst);
|
||||
|
||||
if (ref) {
|
||||
av1_highbd_convolve_horiz_rs_c(
|
||||
src, src_stride, dst, dst_stride, width_dst, height,
|
||||
&av1_resize_filter_normative[0][0], x0_qn, x_step_qn, bd_);
|
||||
} else {
|
||||
tst_fun_(src, src_stride, dst, dst_stride, width_dst, height,
|
||||
&av1_resize_filter_normative[0][0], x0_qn, x_step_qn, bd_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HighBDConvolveHorizRsFunc tst_fun_;
|
||||
};
|
||||
|
||||
const int kBDs[] = { 8, 10, 12 };
|
||||
|
||||
TEST_P(HighBDConvolveHorizRSTest, Correctness) { CorrectnessTest(); }
|
||||
TEST_P(HighBDConvolveHorizRSTest, DISABLED_Speed) { SpeedTest(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, HighBDConvolveHorizRSTest,
|
||||
::testing::Combine(::testing::Values(av1_highbd_convolve_horiz_rs_sse4_1),
|
||||
::testing::ValuesIn(kBDs)));
|
||||
|
||||
} // namespace
|
||||
157
media/libaom/src/test/av1_inv_txfm1d_test.cc
Normal file
157
media/libaom/src/test/av1_inv_txfm1d_test.cc
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "test/av1_txfm_test.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/av1_inv_txfm1d.h"
|
||||
#include "av1/encoder/av1_fwd_txfm1d.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::input_base;
|
||||
|
||||
namespace {
|
||||
const int txfm_type_num = 2;
|
||||
const int txfm_size_ls[] = { 4, 8, 16, 32, 64 };
|
||||
|
||||
const TxfmFunc fwd_txfm_func_ls[][txfm_type_num] = {
|
||||
{ av1_fdct4_new, av1_fadst4_new },
|
||||
{ av1_fdct8_new, av1_fadst8_new },
|
||||
{ av1_fdct16_new, av1_fadst16_new },
|
||||
{ av1_fdct32_new, NULL },
|
||||
{ av1_fdct64_new, NULL },
|
||||
};
|
||||
|
||||
const TxfmFunc inv_txfm_func_ls[][txfm_type_num] = {
|
||||
{ av1_idct4_new, av1_iadst4_new },
|
||||
{ av1_idct8_new, av1_iadst8_new },
|
||||
{ av1_idct16_new, av1_iadst16_new },
|
||||
{ av1_idct32_new, NULL },
|
||||
{ av1_idct64_new, NULL },
|
||||
};
|
||||
|
||||
// the maximum stage number of fwd/inv 1d dct/adst txfm is 12
|
||||
const int8_t cos_bit = 13;
|
||||
const int8_t range_bit[12] = { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 };
|
||||
|
||||
void reference_idct_1d_int(const int32_t *in, int32_t *out, int size) {
|
||||
double input[64];
|
||||
for (int i = 0; i < size; ++i) input[i] = in[i];
|
||||
|
||||
double output[64];
|
||||
libaom_test::reference_idct_1d(input, output, size);
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ASSERT_GE(output[i], INT32_MIN);
|
||||
ASSERT_LE(output[i], INT32_MAX);
|
||||
out[i] = static_cast<int32_t>(round(output[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void random_matrix(int32_t *dst, int len, ACMRandom *rnd) {
|
||||
const int bits = 16;
|
||||
const int maxVal = (1 << (bits - 1)) - 1;
|
||||
const int minVal = -(1 << (bits - 1));
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (rnd->Rand8() % 10)
|
||||
dst[i] = minVal + rnd->Rand16() % (1 << bits);
|
||||
else
|
||||
dst[i] = rnd->Rand8() % 2 ? minVal : maxVal;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(av1_inv_txfm1d, InvAccuracyCheck) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
const int count_test_block = 20000;
|
||||
const int max_error[] = { 6, 10, 19, 31, 40 };
|
||||
ASSERT_EQ(NELEMENTS(max_error), TX_SIZES);
|
||||
ASSERT_EQ(NELEMENTS(inv_txfm_func_ls), TX_SIZES);
|
||||
for (int k = 0; k < count_test_block; ++k) {
|
||||
// choose a random transform to test
|
||||
const TX_SIZE tx_size = static_cast<TX_SIZE>(rnd.Rand8() % TX_SIZES);
|
||||
const int tx_size_pix = txfm_size_ls[tx_size];
|
||||
const TxfmFunc inv_txfm_func = inv_txfm_func_ls[tx_size][0];
|
||||
|
||||
int32_t input[64];
|
||||
random_matrix(input, tx_size_pix, &rnd);
|
||||
|
||||
// 64x64 transform assumes last 32 values are zero.
|
||||
memset(input + 32, 0, 32 * sizeof(input[0]));
|
||||
|
||||
int32_t ref_output[64];
|
||||
reference_idct_1d_int(input, ref_output, tx_size_pix);
|
||||
|
||||
int32_t output[64];
|
||||
inv_txfm_func(input, output, cos_bit, range_bit);
|
||||
|
||||
for (int i = 0; i < tx_size_pix; ++i) {
|
||||
EXPECT_LE(abs(output[i] - ref_output[i]), max_error[tx_size])
|
||||
<< "tx_size = " << tx_size << ", i = " << i
|
||||
<< ", output[i] = " << output[i]
|
||||
<< ", ref_output[i] = " << ref_output[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE int get_max_bit(int x) {
|
||||
int max_bit = -1;
|
||||
while (x) {
|
||||
x = x >> 1;
|
||||
max_bit++;
|
||||
}
|
||||
return max_bit;
|
||||
}
|
||||
|
||||
TEST(av1_inv_txfm1d, get_max_bit) {
|
||||
int max_bit = get_max_bit(8);
|
||||
EXPECT_EQ(max_bit, 3);
|
||||
}
|
||||
|
||||
TEST(av1_inv_txfm1d, round_trip) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int si = 0; si < NELEMENTS(fwd_txfm_func_ls); ++si) {
|
||||
int txfm_size = txfm_size_ls[si];
|
||||
|
||||
for (int ti = 0; ti < txfm_type_num; ++ti) {
|
||||
TxfmFunc fwd_txfm_func = fwd_txfm_func_ls[si][ti];
|
||||
TxfmFunc inv_txfm_func = inv_txfm_func_ls[si][ti];
|
||||
int max_error = 2;
|
||||
|
||||
if (!fwd_txfm_func) continue;
|
||||
|
||||
const int count_test_block = 5000;
|
||||
for (int ci = 0; ci < count_test_block; ++ci) {
|
||||
int32_t input[64];
|
||||
int32_t output[64];
|
||||
int32_t round_trip_output[64];
|
||||
|
||||
ASSERT_LE(txfm_size, NELEMENTS(input));
|
||||
|
||||
for (int ni = 0; ni < txfm_size; ++ni) {
|
||||
input[ni] = rnd.Rand16() % input_base - rnd.Rand16() % input_base;
|
||||
}
|
||||
|
||||
fwd_txfm_func(input, output, cos_bit, range_bit);
|
||||
inv_txfm_func(output, round_trip_output, cos_bit, range_bit);
|
||||
|
||||
for (int ni = 0; ni < txfm_size; ++ni) {
|
||||
int node_err =
|
||||
abs(input[ni] - round_shift(round_trip_output[ni],
|
||||
get_max_bit(txfm_size) - 1));
|
||||
EXPECT_LE(node_err, max_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
378
media/libaom/src/test/av1_inv_txfm2d_test.cc
Normal file
378
media/libaom/src/test/av1_inv_txfm2d_test.cc
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/av1_inv_txfm1d_cfg.h"
|
||||
#include "av1/common/scan.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/av1_txfm_test.h"
|
||||
#include "test/util.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::InvTxfm2dFunc;
|
||||
using libaom_test::LbdInvTxfm2dFunc;
|
||||
using libaom_test::bd;
|
||||
using libaom_test::compute_avg_abs_error;
|
||||
using libaom_test::input_base;
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::Range;
|
||||
using ::testing::Values;
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
|
||||
// AV1InvTxfm2dParam argument list:
|
||||
// tx_type_, tx_size_, max_error_, max_avg_error_
|
||||
typedef ::testing::tuple<TX_TYPE, TX_SIZE, int, double> AV1InvTxfm2dParam;
|
||||
|
||||
class AV1InvTxfm2d : public ::testing::TestWithParam<AV1InvTxfm2dParam> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
tx_type_ = GET_PARAM(0);
|
||||
tx_size_ = GET_PARAM(1);
|
||||
max_error_ = GET_PARAM(2);
|
||||
max_avg_error_ = GET_PARAM(3);
|
||||
}
|
||||
|
||||
void RunRoundtripCheck() {
|
||||
int tx_w = tx_size_wide[tx_size_];
|
||||
int tx_h = tx_size_high[tx_size_];
|
||||
int txfm2d_size = tx_w * tx_h;
|
||||
const FwdTxfm2dFunc fwd_txfm_func = libaom_test::fwd_txfm_func_ls[tx_size_];
|
||||
const InvTxfm2dFunc inv_txfm_func = libaom_test::inv_txfm_func_ls[tx_size_];
|
||||
double avg_abs_error = 0;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
|
||||
const int count = 500;
|
||||
|
||||
for (int ci = 0; ci < count; ci++) {
|
||||
DECLARE_ALIGNED(16, int16_t, input[64 * 64]) = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(input));
|
||||
|
||||
for (int ni = 0; ni < txfm2d_size; ++ni) {
|
||||
if (ci == 0) {
|
||||
int extreme_input = input_base - 1;
|
||||
input[ni] = extreme_input; // extreme case
|
||||
} else {
|
||||
input[ni] = rnd.Rand16() % input_base;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_ALIGNED(16, uint16_t, expected[64 * 64]) = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(expected));
|
||||
if (TxfmUsesApproximation()) {
|
||||
// Compare reference forward HT + inverse HT vs forward HT + inverse HT.
|
||||
double ref_input[64 * 64];
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(ref_input));
|
||||
for (int ni = 0; ni < txfm2d_size; ++ni) {
|
||||
ref_input[ni] = input[ni];
|
||||
}
|
||||
double ref_coeffs[64 * 64] = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(ref_coeffs));
|
||||
ASSERT_EQ(tx_type_, DCT_DCT);
|
||||
libaom_test::reference_hybrid_2d(ref_input, ref_coeffs, tx_type_,
|
||||
tx_size_);
|
||||
DECLARE_ALIGNED(16, int32_t, ref_coeffs_int[64 * 64]) = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(ref_coeffs_int));
|
||||
for (int ni = 0; ni < txfm2d_size; ++ni) {
|
||||
ref_coeffs_int[ni] = (int32_t)round(ref_coeffs[ni]);
|
||||
}
|
||||
inv_txfm_func(ref_coeffs_int, expected, tx_w, tx_type_, bd);
|
||||
} else {
|
||||
// Compare original input vs forward HT + inverse HT.
|
||||
for (int ni = 0; ni < txfm2d_size; ++ni) {
|
||||
expected[ni] = input[ni];
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_ALIGNED(16, int32_t, coeffs[64 * 64]) = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(coeffs));
|
||||
fwd_txfm_func(input, coeffs, tx_w, tx_type_, bd);
|
||||
|
||||
DECLARE_ALIGNED(16, uint16_t, actual[64 * 64]) = { 0 };
|
||||
ASSERT_LE(txfm2d_size, NELEMENTS(actual));
|
||||
inv_txfm_func(coeffs, actual, tx_w, tx_type_, bd);
|
||||
|
||||
double actual_max_error = 0;
|
||||
for (int ni = 0; ni < txfm2d_size; ++ni) {
|
||||
const double this_error = abs(expected[ni] - actual[ni]);
|
||||
actual_max_error = AOMMAX(actual_max_error, this_error);
|
||||
}
|
||||
EXPECT_GE(max_error_, actual_max_error)
|
||||
<< " tx_w: " << tx_w << " tx_h " << tx_h << " tx_type: " << tx_type_;
|
||||
if (actual_max_error > max_error_) { // exit early.
|
||||
break;
|
||||
}
|
||||
avg_abs_error += compute_avg_abs_error<uint16_t, uint16_t>(
|
||||
expected, actual, txfm2d_size);
|
||||
}
|
||||
|
||||
avg_abs_error /= count;
|
||||
EXPECT_GE(max_avg_error_, avg_abs_error)
|
||||
<< " tx_w: " << tx_w << " tx_h " << tx_h << " tx_type: " << tx_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool TxfmUsesApproximation() {
|
||||
if (tx_size_wide[tx_size_] == 64 || tx_size_high[tx_size_] == 64) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int max_error_;
|
||||
double max_avg_error_;
|
||||
TX_TYPE tx_type_;
|
||||
TX_SIZE tx_size_;
|
||||
};
|
||||
|
||||
static int max_error_ls[TX_SIZES_ALL] = {
|
||||
2, // 4x4 transform
|
||||
2, // 8x8 transform
|
||||
2, // 16x16 transform
|
||||
4, // 32x32 transform
|
||||
3, // 64x64 transform
|
||||
2, // 4x8 transform
|
||||
2, // 8x4 transform
|
||||
2, // 8x16 transform
|
||||
2, // 16x8 transform
|
||||
3, // 16x32 transform
|
||||
3, // 32x16 transform
|
||||
5, // 32x64 transform
|
||||
5, // 64x32 transform
|
||||
2, // 4x16 transform
|
||||
2, // 16x4 transform
|
||||
2, // 8x32 transform
|
||||
2, // 32x8 transform
|
||||
3, // 16x64 transform
|
||||
3, // 64x16 transform
|
||||
};
|
||||
|
||||
static double avg_error_ls[TX_SIZES_ALL] = {
|
||||
0.002, // 4x4 transform
|
||||
0.05, // 8x8 transform
|
||||
0.07, // 16x16 transform
|
||||
0.4, // 32x32 transform
|
||||
0.3, // 64x64 transform
|
||||
0.02, // 4x8 transform
|
||||
0.02, // 8x4 transform
|
||||
0.04, // 8x16 transform
|
||||
0.07, // 16x8 transform
|
||||
0.4, // 16x32 transform
|
||||
0.5, // 32x16 transform
|
||||
0.38, // 32x64 transform
|
||||
0.39, // 64x32 transform
|
||||
0.2, // 4x16 transform
|
||||
0.2, // 16x4 transform
|
||||
0.2, // 8x32 transform
|
||||
0.2, // 32x8 transform
|
||||
0.38, // 16x64 transform
|
||||
0.38, // 64x16 transform
|
||||
};
|
||||
|
||||
vector<AV1InvTxfm2dParam> GetInvTxfm2dParamList() {
|
||||
vector<AV1InvTxfm2dParam> param_list;
|
||||
for (int s = 0; s < TX_SIZES; ++s) {
|
||||
const int max_error = max_error_ls[s];
|
||||
const double avg_error = avg_error_ls[s];
|
||||
for (int t = 0; t < TX_TYPES; ++t) {
|
||||
const TX_TYPE tx_type = static_cast<TX_TYPE>(t);
|
||||
const TX_SIZE tx_size = static_cast<TX_SIZE>(s);
|
||||
if (libaom_test::IsTxSizeTypeValid(tx_size, tx_type)) {
|
||||
param_list.push_back(
|
||||
AV1InvTxfm2dParam(tx_type, tx_size, max_error, avg_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
return param_list;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, AV1InvTxfm2d,
|
||||
::testing::ValuesIn(GetInvTxfm2dParamList()));
|
||||
|
||||
TEST_P(AV1InvTxfm2d, RunRoundtripCheck) { RunRoundtripCheck(); }
|
||||
|
||||
TEST(AV1InvTxfm2d, CfgTest) {
|
||||
for (int bd_idx = 0; bd_idx < BD_NUM; ++bd_idx) {
|
||||
int bd = libaom_test::bd_arr[bd_idx];
|
||||
int8_t low_range = libaom_test::low_range_arr[bd_idx];
|
||||
int8_t high_range = libaom_test::high_range_arr[bd_idx];
|
||||
for (int tx_size = 0; tx_size < TX_SIZES_ALL; ++tx_size) {
|
||||
for (int tx_type = 0; tx_type < TX_TYPES; ++tx_type) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(tx_size),
|
||||
static_cast<TX_TYPE>(tx_type)) ==
|
||||
false) {
|
||||
continue;
|
||||
}
|
||||
TXFM_2D_FLIP_CFG cfg;
|
||||
av1_get_inv_txfm_cfg(static_cast<TX_TYPE>(tx_type),
|
||||
static_cast<TX_SIZE>(tx_size), &cfg);
|
||||
int8_t stage_range_col[MAX_TXFM_STAGE_NUM];
|
||||
int8_t stage_range_row[MAX_TXFM_STAGE_NUM];
|
||||
av1_gen_inv_stage_range(stage_range_col, stage_range_row, &cfg,
|
||||
(TX_SIZE)tx_size, bd);
|
||||
libaom_test::txfm_stage_range_check(stage_range_col, cfg.stage_num_col,
|
||||
cfg.cos_bit_col, low_range,
|
||||
high_range);
|
||||
libaom_test::txfm_stage_range_check(stage_range_row, cfg.stage_num_row,
|
||||
cfg.cos_bit_row, low_range,
|
||||
high_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef ::testing::tuple<const LbdInvTxfm2dFunc> AV1LbdInvTxfm2dParam;
|
||||
class AV1LbdInvTxfm2d : public ::testing::TestWithParam<AV1LbdInvTxfm2dParam> {
|
||||
public:
|
||||
virtual void SetUp() { target_func_ = GET_PARAM(0); }
|
||||
void RunAV1InvTxfm2dTest(TX_TYPE tx_type, TX_SIZE tx_size, int run_times);
|
||||
|
||||
private:
|
||||
LbdInvTxfm2dFunc target_func_;
|
||||
};
|
||||
|
||||
void AV1LbdInvTxfm2d::RunAV1InvTxfm2dTest(TX_TYPE tx_type, TX_SIZE tx_size,
|
||||
int run_times) {
|
||||
FwdTxfm2dFunc fwd_func_ = libaom_test::fwd_txfm_func_ls[tx_size];
|
||||
InvTxfm2dFunc ref_func_ = libaom_test::inv_txfm_func_ls[tx_size];
|
||||
if (fwd_func_ == NULL || ref_func_ == NULL || target_func_ == NULL) {
|
||||
return;
|
||||
}
|
||||
const int bd = 8;
|
||||
const int BLK_WIDTH = 64;
|
||||
const int BLK_SIZE = BLK_WIDTH * BLK_WIDTH;
|
||||
DECLARE_ALIGNED(16, int16_t, input[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(32, int32_t, inv_input[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(16, uint8_t, output[BLK_SIZE]) = { 0 };
|
||||
DECLARE_ALIGNED(16, uint16_t, ref_output[BLK_SIZE]) = { 0 };
|
||||
int stride = BLK_WIDTH;
|
||||
int rows = tx_size_high[tx_size];
|
||||
int cols = tx_size_wide[tx_size];
|
||||
const int rows_nonezero = AOMMIN(32, rows);
|
||||
const int cols_nonezero = AOMMIN(32, cols);
|
||||
run_times /= (rows * cols);
|
||||
run_times = AOMMAX(1, run_times);
|
||||
const SCAN_ORDER *scan_order = get_default_scan(tx_size, tx_type);
|
||||
const int16_t *scan = scan_order->scan;
|
||||
const int16_t eobmax = rows_nonezero * cols_nonezero;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
int randTimes = run_times == 1 ? (eobmax + 500) : 1;
|
||||
for (int cnt = 0; cnt < randTimes; ++cnt) {
|
||||
const int16_t max_in = (1 << (bd)) - 1;
|
||||
for (int r = 0; r < BLK_WIDTH; ++r) {
|
||||
for (int c = 0; c < BLK_WIDTH; ++c) {
|
||||
input[r * cols + c] = (cnt == 0) ? max_in : rnd.Rand8Extremes();
|
||||
output[r * stride + c] = (cnt == 0) ? 128 : rnd.Rand8();
|
||||
ref_output[r * stride + c] = output[r * stride + c];
|
||||
}
|
||||
}
|
||||
fwd_func_(input, inv_input, stride, tx_type, bd);
|
||||
|
||||
// produce eob input by setting high freq coeffs to zero
|
||||
const int eob = AOMMIN(cnt + 1, eobmax);
|
||||
for (int i = eob; i < eobmax; i++) {
|
||||
inv_input[scan[i]] = 0;
|
||||
}
|
||||
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
ref_func_(inv_input, ref_output, stride, tx_type, bd);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
target_func_(inv_input, output, stride, tx_type, tx_size, eob);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 10) {
|
||||
printf("txfm[%d] %3dx%-3d:%7.2f/%7.2fns", tx_type, cols, rows, time1,
|
||||
time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
for (int c = 0; c < cols; ++c) {
|
||||
uint8_t ref_value = static_cast<uint8_t>(ref_output[r * stride + c]);
|
||||
ASSERT_EQ(ref_value, output[r * stride + c])
|
||||
<< "[" << r << "," << c << "] " << cnt
|
||||
<< " tx_size: " << static_cast<int>(tx_size)
|
||||
<< " tx_type: " << tx_type << " eob " << eob;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AV1LbdInvTxfm2d, match) {
|
||||
for (int j = 0; j < (int)(TX_SIZES_ALL); ++j) {
|
||||
for (int i = 0; i < (int)TX_TYPES; ++i) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(j),
|
||||
static_cast<TX_TYPE>(i))) {
|
||||
RunAV1InvTxfm2dTest(static_cast<TX_TYPE>(i), static_cast<TX_SIZE>(j),
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(AV1LbdInvTxfm2d, DISABLED_Speed) {
|
||||
for (int j = 0; j < (int)(TX_SIZES_ALL); ++j) {
|
||||
for (int i = 0; i < (int)TX_TYPES; ++i) {
|
||||
if (libaom_test::IsTxSizeTypeValid(static_cast<TX_SIZE>(j),
|
||||
static_cast<TX_TYPE>(i))) {
|
||||
RunAV1InvTxfm2dTest(static_cast<TX_TYPE>(i), static_cast<TX_SIZE>(j),
|
||||
10000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSSE3
|
||||
#if defined(_MSC_VER) || defined(__SSSE3__)
|
||||
#include "av1/common/x86/av1_inv_txfm_ssse3.h"
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, AV1LbdInvTxfm2d,
|
||||
::testing::Values(av1_lowbd_inv_txfm2d_add_ssse3));
|
||||
#endif // _MSC_VER || __SSSE3__
|
||||
#endif // HAVE_SSSE3
|
||||
|
||||
#if HAVE_AVX2
|
||||
extern "C" void av1_lowbd_inv_txfm2d_add_avx2(const int32_t *input,
|
||||
uint8_t *output, int stride,
|
||||
TX_TYPE tx_type, TX_SIZE tx_size,
|
||||
int eob);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1LbdInvTxfm2d,
|
||||
::testing::Values(av1_lowbd_inv_txfm2d_add_avx2));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
#if HAVE_NEON
|
||||
|
||||
extern "C" void av1_lowbd_inv_txfm2d_add_neon(const int32_t *input,
|
||||
uint8_t *output, int stride,
|
||||
TX_TYPE tx_type, TX_SIZE tx_size,
|
||||
int eob);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, AV1LbdInvTxfm2d,
|
||||
::testing::Values(av1_lowbd_inv_txfm2d_add_neon));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
} // namespace
|
||||
239
media/libaom/src/test/av1_quantize_test.cc
Normal file
239
media/libaom/src/test/av1_quantize_test.cc
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "av1/common/scan.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef void (*QuantizeFpFunc)(
|
||||
const tran_low_t *coeff_ptr, intptr_t count, const int16_t *zbin_ptr,
|
||||
const int16_t *round_ptr, const int16_t *quant_ptr,
|
||||
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
|
||||
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
|
||||
const int16_t *scan, const int16_t *iscan, int log_scale);
|
||||
|
||||
struct QuantizeFuncParams {
|
||||
QuantizeFuncParams(QuantizeFpFunc qF = NULL, QuantizeFpFunc qRefF = NULL,
|
||||
int count = 16)
|
||||
: qFunc(qF), qFuncRef(qRefF), coeffCount(count) {}
|
||||
QuantizeFpFunc qFunc;
|
||||
QuantizeFpFunc qFuncRef;
|
||||
int coeffCount;
|
||||
};
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
const int numTests = 1000;
|
||||
const int maxSize = 1024;
|
||||
const int roundFactorRange = 127;
|
||||
const int dequantRange = 32768;
|
||||
const int coeffRange = (1 << 20) - 1;
|
||||
|
||||
class AV1QuantizeTest : public ::testing::TestWithParam<QuantizeFuncParams> {
|
||||
public:
|
||||
void RunQuantizeTest() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, tran_low_t, coeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, int16_t, zbin_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, round_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, quant_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, quant_shift_ptr[8]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, qcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, ref_qcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, ref_dqcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, int16_t, dequant_ptr[8]);
|
||||
uint16_t eob;
|
||||
uint16_t ref_eob;
|
||||
int err_count_total = 0;
|
||||
int first_failure = -1;
|
||||
int count = params_.coeffCount;
|
||||
const TX_SIZE txSize = getTxSize(count);
|
||||
int log_scale = (txSize == TX_32X32);
|
||||
QuantizeFpFunc quanFunc = params_.qFunc;
|
||||
QuantizeFpFunc quanFuncRef = params_.qFuncRef;
|
||||
|
||||
const SCAN_ORDER scanOrder = av1_default_scan_orders[txSize];
|
||||
for (int i = 0; i < numTests; i++) {
|
||||
int err_count = 0;
|
||||
ref_eob = eob = -1;
|
||||
for (int j = 0; j < count; j++) {
|
||||
coeff_ptr[j] = rnd(coeffRange);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
zbin_ptr[j] = rnd.Rand16();
|
||||
quant_shift_ptr[j] = rnd.Rand16();
|
||||
// int16_t positive
|
||||
dequant_ptr[j] = abs(rnd(dequantRange));
|
||||
quant_ptr[j] = (1 << 16) / dequant_ptr[j];
|
||||
round_ptr[j] = (abs(rnd(roundFactorRange)) * dequant_ptr[j]) >> 7;
|
||||
}
|
||||
for (int j = 2; j < 8; ++j) {
|
||||
zbin_ptr[j] = zbin_ptr[1];
|
||||
quant_shift_ptr[j] = quant_shift_ptr[1];
|
||||
dequant_ptr[j] = dequant_ptr[1];
|
||||
quant_ptr[j] = quant_ptr[1];
|
||||
round_ptr[j] = round_ptr[1];
|
||||
}
|
||||
quanFuncRef(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr,
|
||||
quant_shift_ptr, ref_qcoeff_ptr, ref_dqcoeff_ptr, dequant_ptr,
|
||||
&ref_eob, scanOrder.scan, scanOrder.iscan, log_scale);
|
||||
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
quanFunc(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr,
|
||||
quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr, &eob,
|
||||
scanOrder.scan, scanOrder.iscan, log_scale));
|
||||
|
||||
for (int j = 0; j < count; ++j) {
|
||||
err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) |
|
||||
(ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]);
|
||||
ASSERT_EQ(ref_qcoeff_ptr[j], qcoeff_ptr[j])
|
||||
<< "qcoeff error: i = " << i << " j = " << j << "\n";
|
||||
EXPECT_EQ(ref_dqcoeff_ptr[j], dqcoeff_ptr[j])
|
||||
<< "dqcoeff error: i = " << i << " j = " << j << "\n";
|
||||
}
|
||||
EXPECT_EQ(ref_eob, eob) << "eob error: "
|
||||
<< "i = " << i << "\n";
|
||||
err_count += (ref_eob != eob);
|
||||
if (err_count && !err_count_total) {
|
||||
first_failure = i;
|
||||
}
|
||||
err_count_total += err_count;
|
||||
}
|
||||
EXPECT_EQ(0, err_count_total)
|
||||
<< "Error: Quantization Test, C output doesn't match SSE2 output. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
void RunEobTest() {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, tran_low_t, coeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, int16_t, zbin_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, round_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, quant_ptr[8]);
|
||||
DECLARE_ALIGNED(16, int16_t, quant_shift_ptr[8]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, qcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, ref_qcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, ref_dqcoeff_ptr[maxSize]);
|
||||
DECLARE_ALIGNED(16, int16_t, dequant_ptr[8]);
|
||||
uint16_t eob;
|
||||
uint16_t ref_eob;
|
||||
int count = params_.coeffCount;
|
||||
const TX_SIZE txSize = getTxSize(count);
|
||||
int log_scale = (txSize == TX_32X32);
|
||||
QuantizeFpFunc quanFunc = params_.qFunc;
|
||||
QuantizeFpFunc quanFuncRef = params_.qFuncRef;
|
||||
const SCAN_ORDER scanOrder = av1_default_scan_orders[txSize];
|
||||
|
||||
for (int i = 0; i < numTests; i++) {
|
||||
ref_eob = eob = -1;
|
||||
for (int j = 0; j < count; j++) {
|
||||
coeff_ptr[j] = 0;
|
||||
}
|
||||
|
||||
coeff_ptr[rnd(count)] = rnd(coeffRange);
|
||||
coeff_ptr[rnd(count)] = rnd(coeffRange);
|
||||
coeff_ptr[rnd(count)] = rnd(coeffRange);
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
zbin_ptr[j] = rnd.Rand16();
|
||||
quant_shift_ptr[j] = rnd.Rand16();
|
||||
// int16_t positive
|
||||
dequant_ptr[j] = abs(rnd(dequantRange));
|
||||
quant_ptr[j] = (1 << 16) / dequant_ptr[j];
|
||||
round_ptr[j] = (abs(rnd(roundFactorRange)) * dequant_ptr[j]) >> 7;
|
||||
}
|
||||
for (int j = 2; j < 8; ++j) {
|
||||
zbin_ptr[j] = zbin_ptr[1];
|
||||
quant_shift_ptr[j] = quant_shift_ptr[1];
|
||||
dequant_ptr[j] = dequant_ptr[1];
|
||||
quant_ptr[j] = quant_ptr[1];
|
||||
round_ptr[j] = round_ptr[1];
|
||||
}
|
||||
|
||||
quanFuncRef(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr,
|
||||
quant_shift_ptr, ref_qcoeff_ptr, ref_dqcoeff_ptr, dequant_ptr,
|
||||
&ref_eob, scanOrder.scan, scanOrder.iscan, log_scale);
|
||||
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
quanFunc(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr,
|
||||
quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr, &eob,
|
||||
scanOrder.scan, scanOrder.iscan, log_scale));
|
||||
EXPECT_EQ(ref_eob, eob) << "eob error: "
|
||||
<< "i = " << i << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetUp() { params_ = GetParam(); }
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
virtual ~AV1QuantizeTest() {}
|
||||
|
||||
private:
|
||||
TX_SIZE getTxSize(int count) {
|
||||
switch (count) {
|
||||
case 16: return TX_4X4;
|
||||
case 64: return TX_8X8;
|
||||
case 256: return TX_16X16;
|
||||
case 1024: return TX_32X32;
|
||||
default: return TX_4X4;
|
||||
}
|
||||
}
|
||||
|
||||
QuantizeFuncParams params_;
|
||||
};
|
||||
|
||||
TEST_P(AV1QuantizeTest, BitExactCheck) { RunQuantizeTest(); }
|
||||
TEST_P(AV1QuantizeTest, EobVerify) { RunEobTest(); }
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
const QuantizeFuncParams qfps[4] = {
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c,
|
||||
16),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c,
|
||||
64),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c,
|
||||
256),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c,
|
||||
1024),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1QuantizeTest, ::testing::ValuesIn(qfps));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
#if HAVE_AVX2
|
||||
const QuantizeFuncParams qfps_avx2[4] = {
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c,
|
||||
16),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c,
|
||||
64),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c,
|
||||
256),
|
||||
QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c,
|
||||
1024),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1QuantizeTest, ::testing::ValuesIn(qfps_avx2));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
} // namespace
|
||||
129
media/libaom/src/test/av1_round_shift_array_test.cc
Normal file
129
media/libaom/src/test/av1_round_shift_array_test.cc
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace AV1CompRoundShift {
|
||||
|
||||
typedef void (*comp_round_shift_array_func)(int32_t *arr, int size, int bit);
|
||||
|
||||
#if HAVE_SSE4_1 || HAVE_NEON
|
||||
const int kValidBitCheck[] = {
|
||||
-4, -3, -2, -1, 0, 1, 2, 3, 4,
|
||||
};
|
||||
#endif // HAVE_SSE4_1 || HAVE_NEON
|
||||
|
||||
typedef ::testing::tuple<comp_round_shift_array_func, BLOCK_SIZE, int>
|
||||
CompRoundShiftParam;
|
||||
|
||||
class AV1CompRoundShiftTest
|
||||
: public ::testing::TestWithParam<CompRoundShiftParam> {
|
||||
public:
|
||||
~AV1CompRoundShiftTest();
|
||||
|
||||
void SetUp() { rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed()); }
|
||||
void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(comp_round_shift_array_func test_impl, BLOCK_SIZE bsize,
|
||||
int bit);
|
||||
void RunSpeedTest(comp_round_shift_array_func test_impl, BLOCK_SIZE bsize,
|
||||
int bit);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
AV1CompRoundShiftTest::~AV1CompRoundShiftTest() { ; }
|
||||
|
||||
void AV1CompRoundShiftTest::RunCheckOutput(
|
||||
comp_round_shift_array_func test_impl, BLOCK_SIZE bsize, int bit) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
const int blk_wd = 64;
|
||||
DECLARE_ALIGNED(32, int32_t, pred_[blk_wd]);
|
||||
DECLARE_ALIGNED(32, int32_t, ref_buffer_[blk_wd]);
|
||||
for (int i = 0; i < (blk_wd); ++i) {
|
||||
ref_buffer_[i] = pred_[i] = rnd_.Rand31() / 16;
|
||||
}
|
||||
av1_round_shift_array_c(ref_buffer_, w, bit);
|
||||
test_impl(pred_, w, bit);
|
||||
for (int x = 0; x < w; ++x) {
|
||||
ASSERT_EQ(ref_buffer_[x], pred_[x]) << w << "x" << h << "mismatch @"
|
||||
<< "(" << x << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void AV1CompRoundShiftTest::RunSpeedTest(comp_round_shift_array_func test_impl,
|
||||
BLOCK_SIZE bsize, int bit) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
const int blk_wd = 64;
|
||||
DECLARE_ALIGNED(32, int32_t, ref_buffer_[blk_wd]);
|
||||
for (int i = 0; i < (blk_wd); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand31();
|
||||
}
|
||||
|
||||
const int num_loops = 1000000000 / (w + h);
|
||||
comp_round_shift_array_func funcs[2] = { av1_round_shift_array_c, test_impl };
|
||||
double elapsed_time[2] = { 0 };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
comp_round_shift_array_func func = funcs[i];
|
||||
for (int j = 0; j < num_loops; ++j) {
|
||||
func(ref_buffer_, w, bit);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
elapsed_time[i] = 1000.0 * time / num_loops;
|
||||
}
|
||||
printf("av1_round_shift_array %3dx%-3d: bit : %d %7.2f/%7.2fns", w, h, bit,
|
||||
elapsed_time[0], elapsed_time[1]);
|
||||
printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
|
||||
}
|
||||
|
||||
TEST_P(AV1CompRoundShiftTest, CheckOutput) {
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), GET_PARAM(2));
|
||||
}
|
||||
|
||||
TEST_P(AV1CompRoundShiftTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0), GET_PARAM(1), GET_PARAM(2));
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, AV1CompRoundShiftTest,
|
||||
::testing::Combine(::testing::Values(&av1_round_shift_array_sse4_1),
|
||||
::testing::ValuesIn(txsize_to_bsize),
|
||||
::testing::ValuesIn(kValidBitCheck)));
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, AV1CompRoundShiftTest,
|
||||
::testing::Combine(::testing::Values(&av1_round_shift_array_neon),
|
||||
::testing::ValuesIn(txsize_to_bsize),
|
||||
::testing::ValuesIn(kValidBitCheck)));
|
||||
#endif
|
||||
|
||||
}; // namespace AV1CompRoundShift
|
||||
371
media/libaom/src/test/av1_txfm_test.cc
Normal file
371
media/libaom/src/test/av1_txfm_test.cc
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "test/av1_txfm_test.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
int get_txfm1d_size(TX_SIZE tx_size) { return tx_size_wide[tx_size]; }
|
||||
|
||||
void get_txfm1d_type(TX_TYPE txfm2d_type, TYPE_TXFM *type0, TYPE_TXFM *type1) {
|
||||
switch (txfm2d_type) {
|
||||
case DCT_DCT:
|
||||
*type0 = TYPE_DCT;
|
||||
*type1 = TYPE_DCT;
|
||||
break;
|
||||
case ADST_DCT:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_DCT;
|
||||
break;
|
||||
case DCT_ADST:
|
||||
*type0 = TYPE_DCT;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case ADST_ADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case FLIPADST_DCT:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_DCT;
|
||||
break;
|
||||
case DCT_FLIPADST:
|
||||
*type0 = TYPE_DCT;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case FLIPADST_FLIPADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case ADST_FLIPADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case FLIPADST_ADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case IDTX:
|
||||
*type0 = TYPE_IDTX;
|
||||
*type1 = TYPE_IDTX;
|
||||
break;
|
||||
case H_DCT:
|
||||
*type0 = TYPE_IDTX;
|
||||
*type1 = TYPE_DCT;
|
||||
break;
|
||||
case V_DCT:
|
||||
*type0 = TYPE_DCT;
|
||||
*type1 = TYPE_IDTX;
|
||||
break;
|
||||
case H_ADST:
|
||||
*type0 = TYPE_IDTX;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case V_ADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_IDTX;
|
||||
break;
|
||||
case H_FLIPADST:
|
||||
*type0 = TYPE_IDTX;
|
||||
*type1 = TYPE_ADST;
|
||||
break;
|
||||
case V_FLIPADST:
|
||||
*type0 = TYPE_ADST;
|
||||
*type1 = TYPE_IDTX;
|
||||
break;
|
||||
default:
|
||||
*type0 = TYPE_DCT;
|
||||
*type1 = TYPE_DCT;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double Sqrt2 = pow(2, 0.5);
|
||||
double invSqrt2 = 1 / pow(2, 0.5);
|
||||
|
||||
double dct_matrix(double n, double k, int size) {
|
||||
return cos(M_PI * (2 * n + 1) * k / (2 * size));
|
||||
}
|
||||
|
||||
void reference_dct_1d(const double *in, double *out, int size) {
|
||||
for (int k = 0; k < size; ++k) {
|
||||
out[k] = 0;
|
||||
for (int n = 0; n < size; ++n) {
|
||||
out[k] += in[n] * dct_matrix(n, k, size);
|
||||
}
|
||||
if (k == 0) out[k] = out[k] * invSqrt2;
|
||||
}
|
||||
}
|
||||
|
||||
void reference_idct_1d(const double *in, double *out, int size) {
|
||||
for (int k = 0; k < size; ++k) {
|
||||
out[k] = 0;
|
||||
for (int n = 0; n < size; ++n) {
|
||||
if (n == 0)
|
||||
out[k] += invSqrt2 * in[n] * dct_matrix(k, n, size);
|
||||
else
|
||||
out[k] += in[n] * dct_matrix(k, n, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(any): Copied from the old 'fadst4' (same as the new 'av1_fadst4_new'
|
||||
// function). Should be replaced by a proper reference function that takes
|
||||
// 'double' input & output.
|
||||
static void fadst4_new(const tran_low_t *input, tran_low_t *output) {
|
||||
tran_high_t x0, x1, x2, x3;
|
||||
tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;
|
||||
|
||||
x0 = input[0];
|
||||
x1 = input[1];
|
||||
x2 = input[2];
|
||||
x3 = input[3];
|
||||
|
||||
if (!(x0 | x1 | x2 | x3)) {
|
||||
output[0] = output[1] = output[2] = output[3] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s0 = sinpi_1_9 * x0;
|
||||
s1 = sinpi_4_9 * x0;
|
||||
s2 = sinpi_2_9 * x1;
|
||||
s3 = sinpi_1_9 * x1;
|
||||
s4 = sinpi_3_9 * x2;
|
||||
s5 = sinpi_4_9 * x3;
|
||||
s6 = sinpi_2_9 * x3;
|
||||
s7 = x0 + x1 - x3;
|
||||
|
||||
x0 = s0 + s2 + s5;
|
||||
x1 = sinpi_3_9 * s7;
|
||||
x2 = s1 - s3 + s6;
|
||||
x3 = s4;
|
||||
|
||||
s0 = x0 + x3;
|
||||
s1 = x1;
|
||||
s2 = x2 - x3;
|
||||
s3 = x2 - x0 + x3;
|
||||
|
||||
// 1-D transform scaling factor is sqrt(2).
|
||||
output[0] = (tran_low_t)fdct_round_shift(s0);
|
||||
output[1] = (tran_low_t)fdct_round_shift(s1);
|
||||
output[2] = (tran_low_t)fdct_round_shift(s2);
|
||||
output[3] = (tran_low_t)fdct_round_shift(s3);
|
||||
}
|
||||
|
||||
void reference_adst_1d(const double *in, double *out, int size) {
|
||||
if (size == 4) { // Special case.
|
||||
tran_low_t int_input[4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int_input[i] = static_cast<tran_low_t>(round(in[i]));
|
||||
}
|
||||
tran_low_t int_output[4];
|
||||
fadst4_new(int_input, int_output);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
out[i] = int_output[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int k = 0; k < size; ++k) {
|
||||
out[k] = 0;
|
||||
for (int n = 0; n < size; ++n) {
|
||||
out[k] += in[n] * sin(M_PI * (2 * n + 1) * (2 * k + 1) / (4 * size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reference_idtx_1d(const double *in, double *out, int size) {
|
||||
double scale = 0;
|
||||
if (size == 4)
|
||||
scale = Sqrt2;
|
||||
else if (size == 8)
|
||||
scale = 2;
|
||||
else if (size == 16)
|
||||
scale = 2 * Sqrt2;
|
||||
else if (size == 32)
|
||||
scale = 4;
|
||||
else if (size == 64)
|
||||
scale = 4 * Sqrt2;
|
||||
for (int k = 0; k < size; ++k) {
|
||||
out[k] = in[k] * scale;
|
||||
}
|
||||
}
|
||||
|
||||
void reference_hybrid_1d(double *in, double *out, int size, int type) {
|
||||
if (type == TYPE_DCT)
|
||||
reference_dct_1d(in, out, size);
|
||||
else if (type == TYPE_ADST)
|
||||
reference_adst_1d(in, out, size);
|
||||
else
|
||||
reference_idtx_1d(in, out, size);
|
||||
}
|
||||
|
||||
double get_amplification_factor(TX_TYPE tx_type, TX_SIZE tx_size) {
|
||||
TXFM_2D_FLIP_CFG fwd_txfm_flip_cfg;
|
||||
av1_get_fwd_txfm_cfg(tx_type, tx_size, &fwd_txfm_flip_cfg);
|
||||
const int tx_width = tx_size_wide[fwd_txfm_flip_cfg.tx_size];
|
||||
const int tx_height = tx_size_high[fwd_txfm_flip_cfg.tx_size];
|
||||
const int8_t *shift = fwd_txfm_flip_cfg.shift;
|
||||
const int amplify_bit = shift[0] + shift[1] + shift[2];
|
||||
double amplify_factor =
|
||||
amplify_bit >= 0 ? (1 << amplify_bit) : (1.0 / (1 << -amplify_bit));
|
||||
|
||||
// For rectangular transforms, we need to multiply by an extra factor.
|
||||
const int rect_type = get_rect_tx_log_ratio(tx_width, tx_height);
|
||||
if (abs(rect_type) == 1) {
|
||||
amplify_factor *= pow(2, 0.5);
|
||||
}
|
||||
return amplify_factor;
|
||||
}
|
||||
|
||||
void reference_hybrid_2d(double *in, double *out, TX_TYPE tx_type,
|
||||
TX_SIZE tx_size) {
|
||||
// Get transform type and size of each dimension.
|
||||
TYPE_TXFM type0;
|
||||
TYPE_TXFM type1;
|
||||
get_txfm1d_type(tx_type, &type0, &type1);
|
||||
const int tx_width = tx_size_wide[tx_size];
|
||||
const int tx_height = tx_size_high[tx_size];
|
||||
|
||||
double *const temp_in = new double[AOMMAX(tx_width, tx_height)];
|
||||
double *const temp_out = new double[AOMMAX(tx_width, tx_height)];
|
||||
double *const out_interm = new double[tx_width * tx_height];
|
||||
const int stride = tx_width;
|
||||
|
||||
// Transform columns.
|
||||
for (int c = 0; c < tx_width; ++c) {
|
||||
for (int r = 0; r < tx_height; ++r) {
|
||||
temp_in[r] = in[r * stride + c];
|
||||
}
|
||||
reference_hybrid_1d(temp_in, temp_out, tx_height, type0);
|
||||
for (int r = 0; r < tx_height; ++r) {
|
||||
out_interm[r * stride + c] = temp_out[r];
|
||||
}
|
||||
}
|
||||
|
||||
// Transform rows.
|
||||
for (int r = 0; r < tx_height; ++r) {
|
||||
reference_hybrid_1d(out_interm + r * stride, out + r * stride, tx_width,
|
||||
type1);
|
||||
}
|
||||
|
||||
delete[] temp_in;
|
||||
delete[] temp_out;
|
||||
delete[] out_interm;
|
||||
|
||||
// These transforms use an approximate 2D DCT transform, by only keeping the
|
||||
// top-left quarter of the coefficients, and repacking them in the first
|
||||
// quarter indices.
|
||||
// TODO(urvang): Refactor this code.
|
||||
if (tx_width == 64 && tx_height == 64) { // tx_size == TX_64X64
|
||||
// Zero out top-right 32x32 area.
|
||||
for (int row = 0; row < 32; ++row) {
|
||||
memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
|
||||
}
|
||||
// Zero out the bottom 64x32 area.
|
||||
memset(out + 32 * 64, 0, 32 * 64 * sizeof(*out));
|
||||
// Re-pack non-zero coeffs in the first 32x32 indices.
|
||||
for (int row = 1; row < 32; ++row) {
|
||||
memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
|
||||
}
|
||||
} else if (tx_width == 32 && tx_height == 64) { // tx_size == TX_32X64
|
||||
// Zero out the bottom 32x32 area.
|
||||
memset(out + 32 * 32, 0, 32 * 32 * sizeof(*out));
|
||||
// Note: no repacking needed here.
|
||||
} else if (tx_width == 64 && tx_height == 32) { // tx_size == TX_64X32
|
||||
// Zero out right 32x32 area.
|
||||
for (int row = 0; row < 32; ++row) {
|
||||
memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
|
||||
}
|
||||
// Re-pack non-zero coeffs in the first 32x32 indices.
|
||||
for (int row = 1; row < 32; ++row) {
|
||||
memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
|
||||
}
|
||||
} else if (tx_width == 16 && tx_height == 64) { // tx_size == TX_16X64
|
||||
// Zero out the bottom 16x32 area.
|
||||
memset(out + 16 * 32, 0, 16 * 32 * sizeof(*out));
|
||||
// Note: no repacking needed here.
|
||||
} else if (tx_width == 64 && tx_height == 16) { // tx_size == TX_64X16
|
||||
// Zero out right 32x16 area.
|
||||
for (int row = 0; row < 16; ++row) {
|
||||
memset(out + row * 64 + 32, 0, 32 * sizeof(*out));
|
||||
}
|
||||
// Re-pack non-zero coeffs in the first 32x16 indices.
|
||||
for (int row = 1; row < 16; ++row) {
|
||||
memcpy(out + row * 32, out + row * 64, 32 * sizeof(*out));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply appropriate scale.
|
||||
const double amplify_factor = get_amplification_factor(tx_type, tx_size);
|
||||
for (int c = 0; c < tx_width; ++c) {
|
||||
for (int r = 0; r < tx_height; ++r) {
|
||||
out[r * stride + c] *= amplify_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void fliplr(Type *dest, int width, int height, int stride) {
|
||||
for (int r = 0; r < height; ++r) {
|
||||
for (int c = 0; c < width / 2; ++c) {
|
||||
const Type tmp = dest[r * stride + c];
|
||||
dest[r * stride + c] = dest[r * stride + width - 1 - c];
|
||||
dest[r * stride + width - 1 - c] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void flipud(Type *dest, int width, int height, int stride) {
|
||||
for (int c = 0; c < width; ++c) {
|
||||
for (int r = 0; r < height / 2; ++r) {
|
||||
const Type tmp = dest[r * stride + c];
|
||||
dest[r * stride + c] = dest[(height - 1 - r) * stride + c];
|
||||
dest[(height - 1 - r) * stride + c] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void fliplrud(Type *dest, int width, int height, int stride) {
|
||||
for (int r = 0; r < height / 2; ++r) {
|
||||
for (int c = 0; c < width; ++c) {
|
||||
const Type tmp = dest[r * stride + c];
|
||||
dest[r * stride + c] = dest[(height - 1 - r) * stride + width - 1 - c];
|
||||
dest[(height - 1 - r) * stride + width - 1 - c] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void fliplr<double>(double *dest, int width, int height, int stride);
|
||||
template void flipud<double>(double *dest, int width, int height, int stride);
|
||||
template void fliplrud<double>(double *dest, int width, int height, int stride);
|
||||
|
||||
int bd_arr[BD_NUM] = { 8, 10, 12 };
|
||||
|
||||
int8_t low_range_arr[BD_NUM] = { 18, 32, 32 };
|
||||
int8_t high_range_arr[BD_NUM] = { 32, 32, 32 };
|
||||
|
||||
void txfm_stage_range_check(const int8_t *stage_range, int stage_num,
|
||||
int8_t cos_bit, int low_range, int high_range) {
|
||||
for (int i = 0; i < stage_num; ++i) {
|
||||
EXPECT_LE(stage_range[i], low_range);
|
||||
ASSERT_LE(stage_range[i] + cos_bit, high_range) << "stage = " << i;
|
||||
}
|
||||
for (int i = 0; i < stage_num - 1; ++i) {
|
||||
// make sure there is no overflow while doing half_btf()
|
||||
ASSERT_LE(stage_range[i + 1] + cos_bit, high_range) << "stage = " << i;
|
||||
}
|
||||
}
|
||||
} // namespace libaom_test
|
||||
135
media/libaom/src/test/av1_txfm_test.h
Normal file
135
media/libaom/src/test/av1_txfm_test.h
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_AV1_TXFM_TEST_H_
|
||||
#define AOM_TEST_AV1_TXFM_TEST_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "av1/common/av1_txfm.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
namespace libaom_test {
|
||||
typedef enum {
|
||||
TYPE_DCT = 0,
|
||||
TYPE_ADST,
|
||||
TYPE_IDTX,
|
||||
TYPE_IDCT,
|
||||
TYPE_IADST,
|
||||
TYPE_LAST
|
||||
} TYPE_TXFM;
|
||||
|
||||
int get_txfm1d_size(TX_SIZE tx_size);
|
||||
|
||||
void get_txfm1d_type(TX_TYPE txfm2d_type, TYPE_TXFM *type0, TYPE_TXFM *type1);
|
||||
|
||||
void reference_dct_1d(const double *in, double *out, int size);
|
||||
void reference_idct_1d(const double *in, double *out, int size);
|
||||
|
||||
void reference_adst_1d(const double *in, double *out, int size);
|
||||
|
||||
void reference_hybrid_1d(double *in, double *out, int size, int type);
|
||||
|
||||
double get_amplification_factor(TX_TYPE tx_type, TX_SIZE tx_size);
|
||||
|
||||
void reference_hybrid_2d(double *in, double *out, TX_TYPE tx_type,
|
||||
TX_SIZE tx_size);
|
||||
template <typename Type1, typename Type2>
|
||||
static double compute_avg_abs_error(const Type1 *a, const Type2 *b,
|
||||
const int size) {
|
||||
double error = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
error += fabs(static_cast<double>(a[i]) - static_cast<double>(b[i]));
|
||||
}
|
||||
error = error / size;
|
||||
return error;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
void fliplr(Type *dest, int width, int height, int stride);
|
||||
|
||||
template <typename Type>
|
||||
void flipud(Type *dest, int width, int height, int stride);
|
||||
|
||||
template <typename Type>
|
||||
void fliplrud(Type *dest, int width, int height, int stride);
|
||||
|
||||
typedef void (*TxfmFunc)(const int32_t *in, int32_t *out, const int8_t cos_bit,
|
||||
const int8_t *range_bit);
|
||||
|
||||
typedef void (*InvTxfm2dFunc)(const int32_t *, uint16_t *, int, TX_TYPE, int);
|
||||
typedef void (*LbdInvTxfm2dFunc)(const int32_t *, uint8_t *, int, TX_TYPE,
|
||||
TX_SIZE, int);
|
||||
|
||||
static const int bd = 10;
|
||||
static const int input_base = (1 << bd);
|
||||
|
||||
static INLINE bool IsTxSizeTypeValid(TX_SIZE tx_size, TX_TYPE tx_type) {
|
||||
const TX_SIZE tx_size_sqr_up = txsize_sqr_up_map[tx_size];
|
||||
TxSetType tx_set_type;
|
||||
if (tx_size_sqr_up > TX_32X32) {
|
||||
tx_set_type = EXT_TX_SET_DCTONLY;
|
||||
} else if (tx_size_sqr_up == TX_32X32) {
|
||||
tx_set_type = EXT_TX_SET_DCT_IDTX;
|
||||
} else {
|
||||
tx_set_type = EXT_TX_SET_ALL16;
|
||||
}
|
||||
return av1_ext_tx_used[tx_set_type][tx_type] != 0;
|
||||
}
|
||||
|
||||
#if CONFIG_AV1_ENCODER
|
||||
|
||||
static const FwdTxfm2dFunc fwd_txfm_func_ls[TX_SIZES_ALL] = {
|
||||
av1_fwd_txfm2d_4x4_c, av1_fwd_txfm2d_8x8_c, av1_fwd_txfm2d_16x16_c,
|
||||
av1_fwd_txfm2d_32x32_c, av1_fwd_txfm2d_64x64_c, av1_fwd_txfm2d_4x8_c,
|
||||
av1_fwd_txfm2d_8x4_c, av1_fwd_txfm2d_8x16_c, av1_fwd_txfm2d_16x8_c,
|
||||
av1_fwd_txfm2d_16x32_c, av1_fwd_txfm2d_32x16_c, av1_fwd_txfm2d_32x64_c,
|
||||
av1_fwd_txfm2d_64x32_c, av1_fwd_txfm2d_4x16_c, av1_fwd_txfm2d_16x4_c,
|
||||
av1_fwd_txfm2d_8x32_c, av1_fwd_txfm2d_32x8_c, av1_fwd_txfm2d_16x64_c,
|
||||
av1_fwd_txfm2d_64x16_c,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const InvTxfm2dFunc inv_txfm_func_ls[TX_SIZES_ALL] = {
|
||||
av1_inv_txfm2d_add_4x4_c, av1_inv_txfm2d_add_8x8_c,
|
||||
av1_inv_txfm2d_add_16x16_c, av1_inv_txfm2d_add_32x32_c,
|
||||
av1_inv_txfm2d_add_64x64_c, av1_inv_txfm2d_add_4x8_c,
|
||||
av1_inv_txfm2d_add_8x4_c, av1_inv_txfm2d_add_8x16_c,
|
||||
av1_inv_txfm2d_add_16x8_c, av1_inv_txfm2d_add_16x32_c,
|
||||
av1_inv_txfm2d_add_32x16_c, av1_inv_txfm2d_add_32x64_c,
|
||||
av1_inv_txfm2d_add_64x32_c, av1_inv_txfm2d_add_4x16_c,
|
||||
av1_inv_txfm2d_add_16x4_c, av1_inv_txfm2d_add_8x32_c,
|
||||
av1_inv_txfm2d_add_32x8_c, av1_inv_txfm2d_add_16x64_c,
|
||||
av1_inv_txfm2d_add_64x16_c,
|
||||
};
|
||||
|
||||
#define BD_NUM 3
|
||||
|
||||
extern int bd_arr[];
|
||||
extern int8_t low_range_arr[];
|
||||
extern int8_t high_range_arr[];
|
||||
|
||||
void txfm_stage_range_check(const int8_t *stage_range, int stage_num,
|
||||
const int8_t cos_bit, int low_range,
|
||||
int high_range);
|
||||
} // namespace libaom_test
|
||||
#endif // AOM_TEST_AV1_TXFM_TEST_H_
|
||||
390
media/libaom/src/test/av1_wedge_utils_test.cc
Normal file
390
media/libaom/src/test/av1_wedge_utils_test.cc
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/function_equivalence_test.h"
|
||||
#include "test/register_state_check.h"
|
||||
|
||||
#define WEDGE_WEIGHT_BITS 6
|
||||
#define MAX_MASK_VALUE (1 << (WEDGE_WEIGHT_BITS))
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::FunctionEquivalenceTest;
|
||||
|
||||
namespace {
|
||||
|
||||
static const int16_t kInt13Max = (1 << 12) - 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// av1_wedge_sse_from_residuals - functionality
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class WedgeUtilsSSEFuncTest : public testing::Test {
|
||||
protected:
|
||||
WedgeUtilsSSEFuncTest() : rng_(ACMRandom::DeterministicSeed()) {}
|
||||
|
||||
static const int kIterations = 1000;
|
||||
|
||||
ACMRandom rng_;
|
||||
};
|
||||
|
||||
static void equiv_blend_residuals(int16_t *r, const int16_t *r0,
|
||||
const int16_t *r1, const uint8_t *m, int N) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
const int32_t m0 = m[i];
|
||||
const int32_t m1 = MAX_MASK_VALUE - m0;
|
||||
const int16_t R = m0 * r0[i] + m1 * r1[i];
|
||||
// Note that this rounding is designed to match the result
|
||||
// you would get when actually blending the 2 predictors and computing
|
||||
// the residuals.
|
||||
r[i] = ROUND_POWER_OF_TWO(R - 1, WEDGE_WEIGHT_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t equiv_sse_from_residuals(const int16_t *r0, const int16_t *r1,
|
||||
const uint8_t *m, int N) {
|
||||
uint64_t acc = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
const int32_t m0 = m[i];
|
||||
const int32_t m1 = MAX_MASK_VALUE - m0;
|
||||
const int16_t R = m0 * r0[i] + m1 * r1[i];
|
||||
const int32_t r = ROUND_POWER_OF_TWO(R - 1, WEDGE_WEIGHT_BITS);
|
||||
acc += r * r;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
TEST_F(WedgeUtilsSSEFuncTest, ResidualBlendingEquiv) {
|
||||
DECLARE_ALIGNED(32, uint8_t, s[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, p0[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, p1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, p[MAX_SB_SQUARE]);
|
||||
|
||||
DECLARE_ALIGNED(32, int16_t, r0[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r_ref[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r_tst[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
s[i] = rng_.Rand8();
|
||||
m[i] = rng_(MAX_MASK_VALUE + 1);
|
||||
}
|
||||
|
||||
const int w = 1 << (rng_(MAX_SB_SIZE_LOG2 + 1 - 3) + 3);
|
||||
const int h = 1 << (rng_(MAX_SB_SIZE_LOG2 + 1 - 3) + 3);
|
||||
const int N = w * h;
|
||||
|
||||
for (int j = 0; j < N; j++) {
|
||||
p0[j] = clamp(s[j] + rng_(33) - 16, 0, UINT8_MAX);
|
||||
p1[j] = clamp(s[j] + rng_(33) - 16, 0, UINT8_MAX);
|
||||
}
|
||||
|
||||
aom_blend_a64_mask(p, w, p0, w, p1, w, m, w, w, h, 0, 0);
|
||||
|
||||
aom_subtract_block(h, w, r0, w, s, w, p0, w);
|
||||
aom_subtract_block(h, w, r1, w, s, w, p1, w);
|
||||
|
||||
aom_subtract_block(h, w, r_ref, w, s, w, p, w);
|
||||
equiv_blend_residuals(r_tst, r0, r1, m, N);
|
||||
|
||||
for (int i = 0; i < N; ++i) ASSERT_EQ(r_ref[i], r_tst[i]);
|
||||
|
||||
uint64_t ref_sse = aom_sum_squares_i16(r_ref, N);
|
||||
uint64_t tst_sse = equiv_sse_from_residuals(r0, r1, m, N);
|
||||
|
||||
ASSERT_EQ(ref_sse, tst_sse);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t sse_from_residuals(const int16_t *r0, const int16_t *r1,
|
||||
const uint8_t *m, int N) {
|
||||
uint64_t acc = 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
const int32_t m0 = m[i];
|
||||
const int32_t m1 = MAX_MASK_VALUE - m0;
|
||||
const int32_t r = m0 * r0[i] + m1 * r1[i];
|
||||
acc += r * r;
|
||||
}
|
||||
return ROUND_POWER_OF_TWO(acc, 2 * WEDGE_WEIGHT_BITS);
|
||||
}
|
||||
|
||||
TEST_F(WedgeUtilsSSEFuncTest, ResidualBlendingMethod) {
|
||||
DECLARE_ALIGNED(32, int16_t, r0[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, d[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r1[i] = rng_(2 * INT8_MAX - 2 * INT8_MIN + 1) + 2 * INT8_MIN;
|
||||
d[i] = rng_(2 * INT8_MAX - 2 * INT8_MIN + 1) + 2 * INT8_MIN;
|
||||
m[i] = rng_(MAX_MASK_VALUE + 1);
|
||||
}
|
||||
|
||||
const int N = 64 * (rng_(MAX_SB_SQUARE / 64) + 1);
|
||||
|
||||
for (int i = 0; i < N; i++) r0[i] = r1[i] + d[i];
|
||||
|
||||
const uint64_t ref_res = sse_from_residuals(r0, r1, m, N);
|
||||
const uint64_t tst_res = av1_wedge_sse_from_residuals(r1, d, m, N);
|
||||
|
||||
ASSERT_EQ(ref_res, tst_res);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// av1_wedge_sse_from_residuals - optimizations
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef uint64_t (*FSSE)(const int16_t *r1, const int16_t *d, const uint8_t *m,
|
||||
int N);
|
||||
typedef libaom_test::FuncParam<FSSE> TestFuncsFSSE;
|
||||
|
||||
class WedgeUtilsSSEOptTest : public FunctionEquivalenceTest<FSSE> {
|
||||
protected:
|
||||
static const int kIterations = 10000;
|
||||
};
|
||||
|
||||
TEST_P(WedgeUtilsSSEOptTest, RandomValues) {
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, d[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r1[i] = rng_(2 * kInt13Max + 1) - kInt13Max;
|
||||
d[i] = rng_(2 * kInt13Max + 1) - kInt13Max;
|
||||
m[i] = rng_(MAX_MASK_VALUE + 1);
|
||||
}
|
||||
|
||||
const int N = 64 * (rng_(MAX_SB_SQUARE / 64) + 1);
|
||||
|
||||
const uint64_t ref_res = params_.ref_func(r1, d, m, N);
|
||||
uint64_t tst_res;
|
||||
ASM_REGISTER_STATE_CHECK(tst_res = params_.tst_func(r1, d, m, N));
|
||||
|
||||
ASSERT_EQ(ref_res, tst_res);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(WedgeUtilsSSEOptTest, ExtremeValues) {
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, d[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
if (rng_(2)) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) r1[i] = kInt13Max;
|
||||
} else {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) r1[i] = -kInt13Max;
|
||||
}
|
||||
|
||||
if (rng_(2)) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) d[i] = kInt13Max;
|
||||
} else {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) d[i] = -kInt13Max;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) m[i] = MAX_MASK_VALUE;
|
||||
|
||||
const int N = 64 * (rng_(MAX_SB_SQUARE / 64) + 1);
|
||||
|
||||
const uint64_t ref_res = params_.ref_func(r1, d, m, N);
|
||||
uint64_t tst_res;
|
||||
ASM_REGISTER_STATE_CHECK(tst_res = params_.tst_func(r1, d, m, N));
|
||||
|
||||
ASSERT_EQ(ref_res, tst_res);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// av1_wedge_sign_from_residuals
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef int (*FSign)(const int16_t *ds, const uint8_t *m, int N, int64_t limit);
|
||||
typedef libaom_test::FuncParam<FSign> TestFuncsFSign;
|
||||
|
||||
class WedgeUtilsSignOptTest : public FunctionEquivalenceTest<FSign> {
|
||||
protected:
|
||||
static const int kIterations = 10000;
|
||||
static const int kMaxSize = 8196; // Size limited by SIMD implementation.
|
||||
};
|
||||
|
||||
TEST_P(WedgeUtilsSignOptTest, RandomValues) {
|
||||
DECLARE_ALIGNED(32, int16_t, r0[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, ds[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r0[i] = rng_(2 * kInt13Max + 1) - kInt13Max;
|
||||
r1[i] = rng_(2 * kInt13Max + 1) - kInt13Max;
|
||||
m[i] = rng_(MAX_MASK_VALUE + 1);
|
||||
}
|
||||
|
||||
const int maxN = AOMMIN(kMaxSize, MAX_SB_SQUARE);
|
||||
const int N = 64 * (rng_(maxN / 64 - 1) + 1);
|
||||
|
||||
int64_t limit;
|
||||
limit = (int64_t)aom_sum_squares_i16(r0, N);
|
||||
limit -= (int64_t)aom_sum_squares_i16(r1, N);
|
||||
limit *= (1 << WEDGE_WEIGHT_BITS) / 2;
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
ds[i] = clamp(r0[i] * r0[i] - r1[i] * r1[i], INT16_MIN, INT16_MAX);
|
||||
|
||||
const int ref_res = params_.ref_func(ds, m, N, limit);
|
||||
int tst_res;
|
||||
ASM_REGISTER_STATE_CHECK(tst_res = params_.tst_func(ds, m, N, limit));
|
||||
|
||||
ASSERT_EQ(ref_res, tst_res);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(WedgeUtilsSignOptTest, ExtremeValues) {
|
||||
DECLARE_ALIGNED(32, int16_t, r0[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, r1[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, ds[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, uint8_t, m[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
switch (rng_(4)) {
|
||||
case 0:
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r0[i] = 0;
|
||||
r1[i] = kInt13Max;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r0[i] = kInt13Max;
|
||||
r1[i] = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r0[i] = 0;
|
||||
r1[i] = -kInt13Max;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
r0[i] = -kInt13Max;
|
||||
r1[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) m[i] = MAX_MASK_VALUE;
|
||||
|
||||
const int maxN = AOMMIN(kMaxSize, MAX_SB_SQUARE);
|
||||
const int N = 64 * (rng_(maxN / 64 - 1) + 1);
|
||||
|
||||
int64_t limit;
|
||||
limit = (int64_t)aom_sum_squares_i16(r0, N);
|
||||
limit -= (int64_t)aom_sum_squares_i16(r1, N);
|
||||
limit *= (1 << WEDGE_WEIGHT_BITS) / 2;
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
ds[i] = clamp(r0[i] * r0[i] - r1[i] * r1[i], INT16_MIN, INT16_MAX);
|
||||
|
||||
const int ref_res = params_.ref_func(ds, m, N, limit);
|
||||
int tst_res;
|
||||
ASM_REGISTER_STATE_CHECK(tst_res = params_.tst_func(ds, m, N, limit));
|
||||
|
||||
ASSERT_EQ(ref_res, tst_res);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// av1_wedge_compute_delta_squares
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FDS)(int16_t *d, const int16_t *a, const int16_t *b, int N);
|
||||
typedef libaom_test::FuncParam<FDS> TestFuncsFDS;
|
||||
|
||||
class WedgeUtilsDeltaSquaresOptTest : public FunctionEquivalenceTest<FDS> {
|
||||
protected:
|
||||
static const int kIterations = 10000;
|
||||
};
|
||||
|
||||
TEST_P(WedgeUtilsDeltaSquaresOptTest, RandomValues) {
|
||||
DECLARE_ALIGNED(32, int16_t, a[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, b[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, d_ref[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(32, int16_t, d_tst[MAX_SB_SQUARE]);
|
||||
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
a[i] = rng_.Rand16();
|
||||
b[i] = rng_(2 * INT16_MAX + 1) - INT16_MAX;
|
||||
}
|
||||
|
||||
const int N = 64 * (rng_(MAX_SB_SQUARE / 64) + 1);
|
||||
|
||||
memset(&d_ref, INT16_MAX, sizeof(d_ref));
|
||||
memset(&d_tst, INT16_MAX, sizeof(d_tst));
|
||||
|
||||
params_.ref_func(d_ref, a, b, N);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(d_tst, a, b, N));
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) ASSERT_EQ(d_ref[i], d_tst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, WedgeUtilsSSEOptTest,
|
||||
::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_c,
|
||||
av1_wedge_sse_from_residuals_sse2)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, WedgeUtilsSignOptTest,
|
||||
::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_c,
|
||||
av1_wedge_sign_from_residuals_sse2)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, WedgeUtilsDeltaSquaresOptTest,
|
||||
::testing::Values(TestFuncsFDS(av1_wedge_compute_delta_squares_c,
|
||||
av1_wedge_compute_delta_squares_sse2)));
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, WedgeUtilsSSEOptTest,
|
||||
::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_sse2,
|
||||
av1_wedge_sse_from_residuals_avx2)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, WedgeUtilsSignOptTest,
|
||||
::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_sse2,
|
||||
av1_wedge_sign_from_residuals_avx2)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, WedgeUtilsDeltaSquaresOptTest,
|
||||
::testing::Values(TestFuncsFDS(av1_wedge_compute_delta_squares_sse2,
|
||||
av1_wedge_compute_delta_squares_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
} // namespace
|
||||
103
media/libaom/src/test/best_encode.sh
Normal file
103
media/libaom/src/test/best_encode.sh
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
#
|
||||
# This source code is subject to the terms of the BSD 2 Clause License and
|
||||
# the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
# was not distributed with this source code in the LICENSE file, you can
|
||||
# obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
# Media Patent License 1.0 was not distributed with this source code in the
|
||||
# PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
#
|
||||
# Author: jimbankoski@google.com (Jim Bankoski)
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Encodes a file using best known settings (slow!)"
|
||||
echo " Usage: be [FILE] [BITRATE]"
|
||||
echo " Example: be akiyo_cif.y4m 200"
|
||||
exit
|
||||
fi
|
||||
|
||||
f=$1 # file is first parameter
|
||||
b=$2 # bitrate is second parameter
|
||||
|
||||
if [[ -e $f.fpf ]]; then
|
||||
# First-pass file found, do second pass only
|
||||
aomenc \
|
||||
$f \
|
||||
-o $f-$b.av1.webm \
|
||||
-p 2 \
|
||||
--pass=2 \
|
||||
--fpf=$f.fpf \
|
||||
--best \
|
||||
--cpu-used=0 \
|
||||
--target-bitrate=$b \
|
||||
--auto-alt-ref=1 \
|
||||
-v \
|
||||
--minsection-pct=0 \
|
||||
--maxsection-pct=800 \
|
||||
--lag-in-frames=25 \
|
||||
--kf-min-dist=0 \
|
||||
--kf-max-dist=99999 \
|
||||
--static-thresh=0 \
|
||||
--min-q=0 \
|
||||
--max-q=63 \
|
||||
--drop-frame=0 \
|
||||
--bias-pct=50 \
|
||||
--minsection-pct=0 \
|
||||
--maxsection-pct=800 \
|
||||
--psnr \
|
||||
--arnr-maxframes=7 \
|
||||
--arnr-strength=3 \
|
||||
--arnr-type=3
|
||||
else
|
||||
# No first-pass file found, do 2-pass encode
|
||||
aomenc \
|
||||
$f \
|
||||
-o $f-$b.av1.webm \
|
||||
-p 2 \
|
||||
--pass=1 \
|
||||
--fpf=$f.fpf \
|
||||
--best \
|
||||
--cpu-used=0 \
|
||||
--target-bitrate=$b \
|
||||
--auto-alt-ref=1 \
|
||||
-v \
|
||||
--minsection-pct=0 \
|
||||
--maxsection-pct=800 \
|
||||
--lag-in-frames=25 \
|
||||
--kf-min-dist=0 \
|
||||
--kf-max-dist=99999 \
|
||||
--static-thresh=0 \
|
||||
--min-q=0 \
|
||||
--max-q=63 \
|
||||
--drop-frame=0
|
||||
|
||||
aomenc \
|
||||
$f \
|
||||
-o $f-$b.av1.webm \
|
||||
-p 2 \
|
||||
--pass=2 \
|
||||
--fpf=$f.fpf \
|
||||
--best \
|
||||
--cpu-used=0 \
|
||||
--target-bitrate=$b \
|
||||
--auto-alt-ref=1 \
|
||||
-v \
|
||||
--minsection-pct=0 \
|
||||
--maxsection-pct=800 \
|
||||
--lag-in-frames=25 \
|
||||
--kf-min-dist=0 \
|
||||
--kf-max-dist=99999 \
|
||||
--static-thresh=0 \
|
||||
--min-q=0 \
|
||||
--max-q=63 \
|
||||
--drop-frame=0 \
|
||||
--bias-pct=50 \
|
||||
--minsection-pct=0 \
|
||||
--maxsection-pct=800 \
|
||||
--psnr \
|
||||
--arnr-maxframes=7 \
|
||||
--arnr-strength=3 \
|
||||
--arnr-type=3
|
||||
fi
|
||||
83
media/libaom/src/test/binary_codes_test.cc
Normal file
83
media/libaom/src/test/binary_codes_test.cc
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/bitreader.h"
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
#include "aom_dsp/binary_codes_reader.h"
|
||||
#include "aom_dsp/binary_codes_writer.h"
|
||||
|
||||
#define ACCT_STR __func__
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for Finite subexponential code with reference
|
||||
TEST(AV1, TestPrimitiveRefsubexpfin) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
const int kBufferSize = 65536;
|
||||
aom_writer bw;
|
||||
uint8_t bw_buffer[kBufferSize];
|
||||
const uint16_t kRanges = 8;
|
||||
const uint16_t kSubexpParams = 6;
|
||||
const uint16_t kReferences = 8;
|
||||
const uint16_t kValues = 16;
|
||||
uint16_t enc_values[kRanges][kSubexpParams][kReferences][kValues][4];
|
||||
const uint16_t range_vals[kRanges] = { 1, 13, 64, 120, 230, 420, 1100, 8000 };
|
||||
aom_start_encode(&bw, bw_buffer);
|
||||
for (int n = 0; n < kRanges; ++n) {
|
||||
const uint16_t range = range_vals[n];
|
||||
for (int k = 0; k < kSubexpParams; ++k) {
|
||||
for (int r = 0; r < kReferences; ++r) {
|
||||
const uint16_t ref = rnd(range);
|
||||
for (int v = 0; v < kValues; ++v) {
|
||||
const uint16_t value = rnd(range);
|
||||
enc_values[n][k][r][v][0] = range;
|
||||
enc_values[n][k][r][v][1] = k;
|
||||
enc_values[n][k][r][v][2] = ref;
|
||||
enc_values[n][k][r][v][3] = value;
|
||||
aom_write_primitive_refsubexpfin(&bw, range, k, ref, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aom_stop_encode(&bw);
|
||||
aom_reader br;
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
GTEST_ASSERT_GE(aom_reader_tell(&br), 0u);
|
||||
GTEST_ASSERT_LE(aom_reader_tell(&br), 1u);
|
||||
for (int n = 0; n < kRanges; ++n) {
|
||||
for (int k = 0; k < kSubexpParams; ++k) {
|
||||
for (int r = 0; r < kReferences; ++r) {
|
||||
for (int v = 0; v < kValues; ++v) {
|
||||
const uint16_t range = enc_values[n][k][r][v][0];
|
||||
assert(k == enc_values[n][k][r][v][1]);
|
||||
const uint16_t ref = enc_values[n][k][r][v][2];
|
||||
const uint16_t value =
|
||||
aom_read_primitive_refsubexpfin(&br, range, k, ref, ACCT_STR);
|
||||
GTEST_ASSERT_EQ(value, enc_values[n][k][r][v][3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(debargha): Adds tests for other primitives
|
||||
} // namespace
|
||||
339
media/libaom/src/test/blend_a64_mask_1d_test.cc
Normal file
339
media/libaom/src/test/blend_a64_mask_1d_test.cc
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/function_equivalence_test.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
#include "aom_dsp/blend.h"
|
||||
|
||||
using libaom_test::FunctionEquivalenceTest;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename F, typename T>
|
||||
class BlendA64Mask1DTest : public FunctionEquivalenceTest<F> {
|
||||
public:
|
||||
static const int kIterations = 10000;
|
||||
static const int kMaxWidth = MAX_SB_SIZE * 5; // * 5 to cover longer strides
|
||||
static const int kMaxHeight = MAX_SB_SIZE;
|
||||
static const int kBufSize = kMaxWidth * kMaxHeight;
|
||||
static const int kMaxMaskWidth = 2 * MAX_SB_SIZE;
|
||||
static const int kMaxMaskSize = kMaxMaskWidth;
|
||||
|
||||
virtual ~BlendA64Mask1DTest() {}
|
||||
|
||||
virtual void Execute(const T *p_src0, const T *p_src1) = 0;
|
||||
|
||||
void Common() {
|
||||
w_ = 2 << this->rng_(MAX_SB_SIZE_LOG2);
|
||||
h_ = 2 << this->rng_(MAX_SB_SIZE_LOG2);
|
||||
|
||||
dst_offset_ = this->rng_(33);
|
||||
dst_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
src0_offset_ = this->rng_(33);
|
||||
src0_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
src1_offset_ = this->rng_(33);
|
||||
src1_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
T *p_src0;
|
||||
T *p_src1;
|
||||
|
||||
switch (this->rng_(3)) {
|
||||
case 0: // Separate sources
|
||||
p_src0 = src0_;
|
||||
p_src1 = src1_;
|
||||
break;
|
||||
case 1: // src0 == dst
|
||||
p_src0 = dst_tst_;
|
||||
src0_stride_ = dst_stride_;
|
||||
src0_offset_ = dst_offset_;
|
||||
p_src1 = src1_;
|
||||
break;
|
||||
case 2: // src1 == dst
|
||||
p_src0 = src0_;
|
||||
p_src1 = dst_tst_;
|
||||
src1_stride_ = dst_stride_;
|
||||
src1_offset_ = dst_offset_;
|
||||
break;
|
||||
default: FAIL();
|
||||
}
|
||||
|
||||
Execute(p_src0, p_src1);
|
||||
|
||||
for (int r = 0; r < h_; ++r) {
|
||||
for (int c = 0; c < w_; ++c) {
|
||||
ASSERT_EQ(dst_ref_[dst_offset_ + r * dst_stride_ + c],
|
||||
dst_tst_[dst_offset_ + r * dst_stride_ + c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
T dst_ref_[kBufSize];
|
||||
T dst_tst_[kBufSize];
|
||||
uint32_t dst_stride_;
|
||||
uint32_t dst_offset_;
|
||||
|
||||
T src0_[kBufSize];
|
||||
uint32_t src0_stride_;
|
||||
uint32_t src0_offset_;
|
||||
|
||||
T src1_[kBufSize];
|
||||
uint32_t src1_stride_;
|
||||
uint32_t src1_offset_;
|
||||
|
||||
uint8_t mask_[kMaxMaskSize];
|
||||
|
||||
int w_;
|
||||
int h_;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 8 bit version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*F8B)(uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1,
|
||||
uint32_t src1_stride, const uint8_t *mask, int w, int h);
|
||||
typedef libaom_test::FuncParam<F8B> TestFuncs;
|
||||
|
||||
class BlendA64Mask1DTest8B : public BlendA64Mask1DTest<F8B, uint8_t> {
|
||||
protected:
|
||||
void Execute(const uint8_t *p_src0, const uint8_t *p_src1) {
|
||||
params_.ref_func(dst_ref_ + dst_offset_, dst_stride_, p_src0 + src0_offset_,
|
||||
src0_stride_, p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
w_, h_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(
|
||||
dst_tst_ + dst_offset_, dst_stride_, p_src0 + src0_offset_,
|
||||
src0_stride_, p_src1 + src1_offset_, src1_stride_, mask_, w_, h_));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BlendA64Mask1DTest8B, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_.Rand8();
|
||||
dst_tst_[i] = rng_.Rand8();
|
||||
|
||||
src0_[i] = rng_.Rand8();
|
||||
src1_[i] = rng_.Rand8();
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BlendA64Mask1DTest8B, ExtremeValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(2) + 254;
|
||||
dst_tst_[i] = rng_(2) + 254;
|
||||
src0_[i] = rng_(2) + 254;
|
||||
src1_[i] = rng_(2) + 254;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(2) + AOM_BLEND_A64_MAX_ALPHA - 1;
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_a64_hmask_ref(uint8_t *dst, uint32_t dst_stride,
|
||||
const uint8_t *src0, uint32_t src0_stride,
|
||||
const uint8_t *src1, uint32_t src1_stride,
|
||||
const uint8_t *mask, int w, int h) {
|
||||
uint8_t mask2d[BlendA64Mask1DTest8B::kMaxMaskSize]
|
||||
[BlendA64Mask1DTest8B::kMaxMaskSize];
|
||||
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int col = 0; col < w; ++col) mask2d[row][col] = mask[col];
|
||||
|
||||
aom_blend_a64_mask_c(dst, dst_stride, src0, src0_stride, src1, src1_stride,
|
||||
&mask2d[0][0], BlendA64Mask1DTest8B::kMaxMaskSize, w, h,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
static void blend_a64_vmask_ref(uint8_t *dst, uint32_t dst_stride,
|
||||
const uint8_t *src0, uint32_t src0_stride,
|
||||
const uint8_t *src1, uint32_t src1_stride,
|
||||
const uint8_t *mask, int w, int h) {
|
||||
uint8_t mask2d[BlendA64Mask1DTest8B::kMaxMaskSize]
|
||||
[BlendA64Mask1DTest8B::kMaxMaskSize];
|
||||
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int col = 0; col < w; ++col) mask2d[row][col] = mask[row];
|
||||
|
||||
aom_blend_a64_mask_c(dst, dst_stride, src0, src0_stride, src1, src1_stride,
|
||||
&mask2d[0][0], BlendA64Mask1DTest8B::kMaxMaskSize, w, h,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, BlendA64Mask1DTest8B,
|
||||
::testing::Values(TestFuncs(blend_a64_hmask_ref, aom_blend_a64_hmask_c),
|
||||
TestFuncs(blend_a64_vmask_ref, aom_blend_a64_vmask_c)));
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, BlendA64Mask1DTest8B,
|
||||
::testing::Values(
|
||||
TestFuncs(blend_a64_hmask_ref, aom_blend_a64_hmask_sse4_1),
|
||||
TestFuncs(blend_a64_vmask_ref, aom_blend_a64_vmask_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(NEON, BlendA64Mask1DTest8B,
|
||||
::testing::Values(TestFuncs(blend_a64_hmask_ref,
|
||||
aom_blend_a64_hmask_neon),
|
||||
TestFuncs(blend_a64_vmask_ref,
|
||||
aom_blend_a64_vmask_neon)));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// High bit-depth version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FHBD)(uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1,
|
||||
uint32_t src1_stride, const uint8_t *mask, int w, int h,
|
||||
int bd);
|
||||
typedef libaom_test::FuncParam<FHBD> TestFuncsHBD;
|
||||
|
||||
class BlendA64Mask1DTestHBD : public BlendA64Mask1DTest<FHBD, uint16_t> {
|
||||
protected:
|
||||
void Execute(const uint16_t *p_src0, const uint16_t *p_src1) {
|
||||
params_.ref_func(CONVERT_TO_BYTEPTR(dst_ref_ + dst_offset_), dst_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
|
||||
mask_, w_, h_, bit_depth_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(
|
||||
CONVERT_TO_BYTEPTR(dst_tst_ + dst_offset_), dst_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_, mask_, w_, h_,
|
||||
bit_depth_));
|
||||
}
|
||||
|
||||
int bit_depth_;
|
||||
};
|
||||
|
||||
TEST_P(BlendA64Mask1DTestHBD, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
|
||||
const int hi = 1 << bit_depth_;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(hi);
|
||||
dst_tst_[i] = rng_(hi);
|
||||
src0_[i] = rng_(hi);
|
||||
src1_[i] = rng_(hi);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BlendA64Mask1DTestHBD, ExtremeValues) {
|
||||
for (int iter = 0; iter < 1000 && !HasFatalFailure(); ++iter) {
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
|
||||
const int hi = 1 << bit_depth_;
|
||||
const int lo = hi - 2;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(hi - lo) + lo;
|
||||
dst_tst_[i] = rng_(hi - lo) + lo;
|
||||
src0_[i] = rng_(hi - lo) + lo;
|
||||
src1_[i] = rng_(hi - lo) + lo;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(2) + AOM_BLEND_A64_MAX_ALPHA - 1;
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
static void highbd_blend_a64_hmask_ref(
|
||||
uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1, uint32_t src1_stride,
|
||||
const uint8_t *mask, int w, int h, int bd) {
|
||||
uint8_t mask2d[BlendA64Mask1DTestHBD::kMaxMaskSize]
|
||||
[BlendA64Mask1DTestHBD::kMaxMaskSize];
|
||||
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int col = 0; col < w; ++col) mask2d[row][col] = mask[col];
|
||||
|
||||
aom_highbd_blend_a64_mask_c(
|
||||
dst, dst_stride, src0, src0_stride, src1, src1_stride, &mask2d[0][0],
|
||||
BlendA64Mask1DTestHBD::kMaxMaskSize, w, h, 0, 0, bd);
|
||||
}
|
||||
|
||||
static void highbd_blend_a64_vmask_ref(
|
||||
uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1, uint32_t src1_stride,
|
||||
const uint8_t *mask, int w, int h, int bd) {
|
||||
uint8_t mask2d[BlendA64Mask1DTestHBD::kMaxMaskSize]
|
||||
[BlendA64Mask1DTestHBD::kMaxMaskSize];
|
||||
|
||||
for (int row = 0; row < h; ++row)
|
||||
for (int col = 0; col < w; ++col) mask2d[row][col] = mask[row];
|
||||
|
||||
aom_highbd_blend_a64_mask_c(
|
||||
dst, dst_stride, src0, src0_stride, src1, src1_stride, &mask2d[0][0],
|
||||
BlendA64Mask1DTestHBD::kMaxMaskSize, w, h, 0, 0, bd);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, BlendA64Mask1DTestHBD,
|
||||
::testing::Values(TestFuncsHBD(highbd_blend_a64_hmask_ref,
|
||||
aom_highbd_blend_a64_hmask_c),
|
||||
TestFuncsHBD(highbd_blend_a64_vmask_ref,
|
||||
aom_highbd_blend_a64_vmask_c)));
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, BlendA64Mask1DTestHBD,
|
||||
::testing::Values(TestFuncsHBD(highbd_blend_a64_hmask_ref,
|
||||
aom_highbd_blend_a64_hmask_sse4_1),
|
||||
TestFuncsHBD(highbd_blend_a64_vmask_ref,
|
||||
aom_highbd_blend_a64_vmask_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
} // namespace
|
||||
583
media/libaom/src/test/blend_a64_mask_test.cc
Normal file
583
media/libaom/src/test/blend_a64_mask_test.cc
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/function_equivalence_test.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
#include "aom_dsp/blend.h"
|
||||
|
||||
using libaom_test::FunctionEquivalenceTest;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename BlendA64Func, typename SrcPixel, typename DstPixel>
|
||||
class BlendA64MaskTest : public FunctionEquivalenceTest<BlendA64Func> {
|
||||
protected:
|
||||
static const int kIterations = 10000;
|
||||
static const int kMaxWidth = MAX_SB_SIZE * 5; // * 5 to cover longer strides
|
||||
static const int kMaxHeight = MAX_SB_SIZE;
|
||||
static const int kBufSize = kMaxWidth * kMaxHeight;
|
||||
static const int kMaxMaskWidth = 2 * MAX_SB_SIZE;
|
||||
static const int kMaxMaskSize = kMaxMaskWidth * kMaxMaskWidth;
|
||||
|
||||
virtual ~BlendA64MaskTest() {}
|
||||
|
||||
virtual void Execute(const SrcPixel *p_src0, const SrcPixel *p_src1,
|
||||
int run_times) = 0;
|
||||
|
||||
template <typename Pixel>
|
||||
void GetSources(Pixel **src0, Pixel **src1, Pixel * /*dst*/, int run_times) {
|
||||
if (run_times > 1) {
|
||||
*src0 = src0_;
|
||||
*src1 = src1_;
|
||||
return;
|
||||
}
|
||||
switch (this->rng_(3)) {
|
||||
case 0: // Separate sources
|
||||
*src0 = src0_;
|
||||
*src1 = src1_;
|
||||
break;
|
||||
case 1: // src0 == dst
|
||||
*src0 = dst_tst_;
|
||||
src0_stride_ = dst_stride_;
|
||||
src0_offset_ = dst_offset_;
|
||||
*src1 = src1_;
|
||||
break;
|
||||
case 2: // src1 == dst
|
||||
*src0 = src0_;
|
||||
*src1 = dst_tst_;
|
||||
src1_stride_ = dst_stride_;
|
||||
src1_offset_ = dst_offset_;
|
||||
break;
|
||||
default: FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
void GetSources(uint16_t **src0, uint16_t **src1, uint8_t * /*dst*/,
|
||||
int /*run_times*/) {
|
||||
*src0 = src0_;
|
||||
*src1 = src1_;
|
||||
}
|
||||
|
||||
uint8_t Rand1() { return this->rng_.Rand8() & 1; }
|
||||
|
||||
void RunOneTest(int block_size, int subx, int suby, int run_times) {
|
||||
w_ = block_size_wide[block_size];
|
||||
h_ = block_size_high[block_size];
|
||||
run_times = run_times > 1 ? run_times / w_ : 1;
|
||||
subx_ = subx;
|
||||
suby_ = suby;
|
||||
|
||||
dst_offset_ = this->rng_(33);
|
||||
dst_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
src0_offset_ = this->rng_(33);
|
||||
src0_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
src1_offset_ = this->rng_(33);
|
||||
src1_stride_ = this->rng_(kMaxWidth + 1 - w_) + w_;
|
||||
|
||||
mask_stride_ =
|
||||
this->rng_(kMaxWidth + 1 - w_ * (subx_ ? 2 : 1)) + w_ * (subx_ ? 2 : 1);
|
||||
|
||||
SrcPixel *p_src0;
|
||||
SrcPixel *p_src1;
|
||||
|
||||
p_src0 = src0_;
|
||||
p_src1 = src1_;
|
||||
|
||||
GetSources(&p_src0, &p_src1, &dst_ref_[0], run_times);
|
||||
|
||||
Execute(p_src0, p_src1, run_times);
|
||||
|
||||
for (int r = 0; r < h_; ++r) {
|
||||
for (int c = 0; c < w_; ++c) {
|
||||
ASSERT_EQ(dst_ref_[dst_offset_ + r * dst_stride_ + c],
|
||||
dst_tst_[dst_offset_ + r * dst_stride_ + c])
|
||||
<< w_ << "x" << h_ << " subx " << subx_ << " suby " << suby_
|
||||
<< " r: " << r << " c: " << c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunTest(int block_size, int run_times) {
|
||||
subx_ = Rand1();
|
||||
suby_ = Rand1();
|
||||
RunOneTest(block_size, subx_, suby_, run_times);
|
||||
}
|
||||
|
||||
DstPixel dst_ref_[kBufSize];
|
||||
DstPixel dst_tst_[kBufSize];
|
||||
uint32_t dst_stride_;
|
||||
uint32_t dst_offset_;
|
||||
|
||||
SrcPixel src0_[kBufSize];
|
||||
uint32_t src0_stride_;
|
||||
uint32_t src0_offset_;
|
||||
|
||||
SrcPixel src1_[kBufSize];
|
||||
uint32_t src1_stride_;
|
||||
uint32_t src1_offset_;
|
||||
|
||||
uint8_t mask_[kMaxMaskSize];
|
||||
size_t mask_stride_;
|
||||
|
||||
int w_;
|
||||
int h_;
|
||||
|
||||
int suby_;
|
||||
int subx_;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 8 bit version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*F8B)(uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1,
|
||||
uint32_t src1_stride, const uint8_t *mask,
|
||||
uint32_t mask_stride, int w, int h, int subx, int suby);
|
||||
typedef libaom_test::FuncParam<F8B> TestFuncs;
|
||||
|
||||
class BlendA64MaskTest8B : public BlendA64MaskTest<F8B, uint8_t, uint8_t> {
|
||||
protected:
|
||||
void Execute(const uint8_t *p_src0, const uint8_t *p_src1, int run_times) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.ref_func(dst_ref_ + dst_offset_, dst_stride_,
|
||||
p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.tst_func(dst_tst_ + dst_offset_, dst_stride_,
|
||||
p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 1) {
|
||||
printf("%3dx%-3d subx %d suby %d :%7.2f/%7.2fns", w_, h_, subx_, suby_,
|
||||
time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BlendA64MaskTest8B, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_.Rand8();
|
||||
dst_tst_[i] = rng_.Rand8();
|
||||
|
||||
src0_[i] = rng_.Rand8();
|
||||
src1_[i] = rng_.Rand8();
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BlendA64MaskTest8B, ExtremeValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(2) + 254;
|
||||
dst_tst_[i] = rng_(2) + 254;
|
||||
src0_[i] = rng_(2) + 254;
|
||||
src1_[i] = rng_(2) + 254;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(2) + AOM_BLEND_A64_MAX_ALPHA - 1;
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
TEST_P(BlendA64MaskTest8B, DISABLED_Speed) {
|
||||
const int kRunTimes = 10000000;
|
||||
for (int bsize = 0; bsize < BLOCK_SIZES_ALL; ++bsize) {
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_.Rand8();
|
||||
dst_tst_[i] = rng_.Rand8();
|
||||
|
||||
src0_[i] = rng_.Rand8();
|
||||
src1_[i] = rng_.Rand8();
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
RunOneTest(bsize, 1, 1, kRunTimes);
|
||||
RunOneTest(bsize, 1, 0, kRunTimes);
|
||||
RunOneTest(bsize, 0, 1, kRunTimes);
|
||||
RunOneTest(bsize, 0, 0, kRunTimes);
|
||||
}
|
||||
}
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, BlendA64MaskTest8B,
|
||||
::testing::Values(TestFuncs(
|
||||
aom_blend_a64_mask_c, aom_blend_a64_mask_sse4_1)));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, BlendA64MaskTest8B,
|
||||
::testing::Values(TestFuncs(aom_blend_a64_mask_sse4_1,
|
||||
aom_blend_a64_mask_avx2)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 8 bit _d16 version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*F8B_D16)(uint8_t *dst, uint32_t dst_stride, const uint16_t *src0,
|
||||
uint32_t src0_stride, const uint16_t *src1,
|
||||
uint32_t src1_stride, const uint8_t *mask,
|
||||
uint32_t mask_stride, int w, int h, int subx, int suby,
|
||||
ConvolveParams *conv_params);
|
||||
typedef libaom_test::FuncParam<F8B_D16> TestFuncs_d16;
|
||||
|
||||
class BlendA64MaskTest8B_d16
|
||||
: public BlendA64MaskTest<F8B_D16, uint16_t, uint8_t> {
|
||||
protected:
|
||||
// max number of bits used by the source
|
||||
static const int kSrcMaxBitsMask = 0x3fff;
|
||||
|
||||
void Execute(const uint16_t *p_src0, const uint16_t *p_src1, int run_times) {
|
||||
ConvolveParams conv_params;
|
||||
conv_params.round_0 = ROUND0_BITS;
|
||||
conv_params.round_1 = COMPOUND_ROUND1_BITS;
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.ref_func(dst_ref_ + dst_offset_, dst_stride_,
|
||||
p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_, &conv_params);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.tst_func(dst_tst_ + dst_offset_, dst_stride_,
|
||||
p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_, &conv_params);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 1) {
|
||||
printf("%3dx%-3d subx %d suby %d :%7.2f/%7.2fns", w_, h_, subx_, suby_,
|
||||
time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BlendA64MaskTest8B_d16, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_.Rand8();
|
||||
dst_tst_[i] = rng_.Rand8();
|
||||
|
||||
src0_[i] = rng_.Rand16() & kSrcMaxBitsMask;
|
||||
src1_[i] = rng_.Rand16() & kSrcMaxBitsMask;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BlendA64MaskTest8B_d16, ExtremeValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = 255;
|
||||
dst_tst_[i] = 255;
|
||||
|
||||
src0_[i] = kSrcMaxBitsMask;
|
||||
src1_[i] = kSrcMaxBitsMask;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = AOM_BLEND_A64_MAX_ALPHA - 1;
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, BlendA64MaskTest8B_d16,
|
||||
::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c,
|
||||
aom_lowbd_blend_a64_d16_mask_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, BlendA64MaskTest8B_d16,
|
||||
::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c,
|
||||
aom_lowbd_blend_a64_d16_mask_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, BlendA64MaskTest8B_d16,
|
||||
::testing::Values(TestFuncs_d16(aom_lowbd_blend_a64_d16_mask_c,
|
||||
aom_lowbd_blend_a64_d16_mask_neon)));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// High bit-depth version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FHBD)(uint8_t *dst, uint32_t dst_stride, const uint8_t *src0,
|
||||
uint32_t src0_stride, const uint8_t *src1,
|
||||
uint32_t src1_stride, const uint8_t *mask,
|
||||
uint32_t mask_stride, int w, int h, int subx, int suby,
|
||||
int bd);
|
||||
typedef libaom_test::FuncParam<FHBD> TestFuncsHBD;
|
||||
|
||||
class BlendA64MaskTestHBD : public BlendA64MaskTest<FHBD, uint16_t, uint16_t> {
|
||||
protected:
|
||||
void Execute(const uint16_t *p_src0, const uint16_t *p_src1, int run_times) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.ref_func(CONVERT_TO_BYTEPTR(dst_ref_ + dst_offset_), dst_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
|
||||
mask_, kMaxMaskWidth, w_, h_, subx_, suby_, bit_depth_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.tst_func(CONVERT_TO_BYTEPTR(dst_tst_ + dst_offset_), dst_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src0 + src0_offset_), src0_stride_,
|
||||
CONVERT_TO_BYTEPTR(p_src1 + src1_offset_), src1_stride_,
|
||||
mask_, kMaxMaskWidth, w_, h_, subx_, suby_, bit_depth_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 1) {
|
||||
printf("%3dx%-3d subx %d suby %d :%7.2f/%7.2fns", w_, h_, subx_, suby_,
|
||||
time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
}
|
||||
|
||||
int bit_depth_;
|
||||
};
|
||||
|
||||
TEST_P(BlendA64MaskTestHBD, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
|
||||
const int hi = 1 << bit_depth_;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(hi);
|
||||
dst_tst_[i] = rng_(hi);
|
||||
src0_[i] = rng_(hi);
|
||||
src1_[i] = rng_(hi);
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(BlendA64MaskTestHBD, ExtremeValues) {
|
||||
for (int iter = 0; iter < 1000 && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
|
||||
const int hi = 1 << bit_depth_;
|
||||
const int lo = hi - 2;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_(hi - lo) + lo;
|
||||
dst_tst_[i] = rng_(hi - lo) + lo;
|
||||
src0_[i] = rng_(hi - lo) + lo;
|
||||
src1_[i] = rng_(hi - lo) + lo;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(2) + AOM_BLEND_A64_MAX_ALPHA - 1;
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, BlendA64MaskTestHBD,
|
||||
::testing::Values(TestFuncsHBD(aom_highbd_blend_a64_mask_c,
|
||||
aom_highbd_blend_a64_mask_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// HBD _d16 version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FHBD_D16)(uint8_t *dst, uint32_t dst_stride,
|
||||
const CONV_BUF_TYPE *src0, uint32_t src0_stride,
|
||||
const CONV_BUF_TYPE *src1, uint32_t src1_stride,
|
||||
const uint8_t *mask, uint32_t mask_stride, int w,
|
||||
int h, int subx, int suby, ConvolveParams *conv_params,
|
||||
const int bd);
|
||||
typedef libaom_test::FuncParam<FHBD_D16> TestFuncsHBD_d16;
|
||||
|
||||
class BlendA64MaskTestHBD_d16
|
||||
: public BlendA64MaskTest<FHBD_D16, uint16_t, uint16_t> {
|
||||
protected:
|
||||
// max number of bits used by the source
|
||||
static const int kSrcMaxBitsMask = (1 << 14) - 1;
|
||||
static const int kSrcMaxBitsMaskHBD = (1 << 16) - 1;
|
||||
|
||||
void Execute(const uint16_t *p_src0, const uint16_t *p_src1, int run_times) {
|
||||
ConvolveParams conv_params;
|
||||
conv_params.round_0 = (bit_depth_ == 12) ? ROUND0_BITS + 2 : ROUND0_BITS;
|
||||
conv_params.round_1 = COMPOUND_ROUND1_BITS;
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.ref_func(CONVERT_TO_BYTEPTR(dst_ref_ + dst_offset_), dst_stride_,
|
||||
p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_, &conv_params,
|
||||
bit_depth_);
|
||||
}
|
||||
if (params_.tst_func) {
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
params_.tst_func(CONVERT_TO_BYTEPTR(dst_tst_ + dst_offset_),
|
||||
dst_stride_, p_src0 + src0_offset_, src0_stride_,
|
||||
p_src1 + src1_offset_, src1_stride_, mask_,
|
||||
kMaxMaskWidth, w_, h_, subx_, suby_, &conv_params,
|
||||
bit_depth_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 1) {
|
||||
printf("%3dx%-3d subx %d suby %d :%7.2f/%7.2fns", w_, h_, subx_, suby_,
|
||||
time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bit_depth_;
|
||||
int src_max_bits_mask_;
|
||||
};
|
||||
|
||||
TEST_P(BlendA64MaskTestHBD_d16, RandomValues) {
|
||||
if (params_.tst_func == NULL) return;
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
int bsize = rng_.Rand8() % BLOCK_SIZES_ALL;
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
src_max_bits_mask_ =
|
||||
(bit_depth_ == 8) ? kSrcMaxBitsMask : kSrcMaxBitsMaskHBD;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = rng_.Rand8();
|
||||
dst_tst_[i] = rng_.Rand8();
|
||||
|
||||
src0_[i] = rng_.Rand16() & src_max_bits_mask_;
|
||||
src1_[i] = rng_.Rand16() & src_max_bits_mask_;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i)
|
||||
mask_[i] = rng_(AOM_BLEND_A64_MAX_ALPHA + 1);
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
// TODO (Scott LaVarnway), fix this test
|
||||
TEST_P(BlendA64MaskTestHBD_d16, DISABLED_SaturatedValues) {
|
||||
for (int bsize = 0; bsize < BLOCK_SIZES_ALL; ++bsize) {
|
||||
for (bit_depth_ = 8; bit_depth_ <= 12; bit_depth_ += 2) {
|
||||
src_max_bits_mask_ =
|
||||
(bit_depth_ == 8) ? kSrcMaxBitsMask : kSrcMaxBitsMaskHBD;
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
dst_ref_[i] = 0;
|
||||
dst_tst_[i] = (1 << bit_depth_) - 1;
|
||||
|
||||
src0_[i] = src_max_bits_mask_;
|
||||
src1_[i] = src_max_bits_mask_;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kMaxMaskSize; ++i) mask_[i] = AOM_BLEND_A64_MAX_ALPHA;
|
||||
|
||||
RunTest(bsize, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, BlendA64MaskTestHBD_d16,
|
||||
::testing::Values(TestFuncsHBD_d16(aom_highbd_blend_a64_d16_mask_c, NULL)));
|
||||
|
||||
// TODO(slavarnway): Enable the following in the avx2 commit. (56501)
|
||||
#if 0
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, BlendA64MaskTestHBD,
|
||||
::testing::Values(TestFuncsHBD(aom_highbd_blend_a64_mask_c,
|
||||
aom_highbd_blend_a64_mask_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
#endif
|
||||
} // namespace
|
||||
122
media/libaom/src/test/blockd_test.cc
Normal file
122
media/libaom/src/test/blockd_test.cc
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
// Verify the optimized implementation of get_partition_subsize() produces the
|
||||
// same results as the Partition_Subsize lookup table in the spec.
|
||||
TEST(BlockdTest, GetPartitionSubsize) {
|
||||
// The Partition_Subsize table in the spec (Section 9.3. Conversion tables).
|
||||
/* clang-format off */
|
||||
static const BLOCK_SIZE kPartitionSubsize[10][BLOCK_SIZES_ALL] = {
|
||||
{
|
||||
BLOCK_4X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X128,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_128X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X128,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X4,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_32X8,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_64X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}, {
|
||||
BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_4X16,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_8X32,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_16X64,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID,
|
||||
BLOCK_INVALID, BLOCK_INVALID, BLOCK_INVALID
|
||||
}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
for (int partition = 0; partition < 10; partition++) {
|
||||
for (int bsize = BLOCK_4X4; bsize < BLOCK_SIZES_ALL; bsize++) {
|
||||
EXPECT_EQ(kPartitionSubsize[partition][bsize],
|
||||
get_partition_subsize(static_cast<BLOCK_SIZE>(bsize),
|
||||
static_cast<PARTITION_TYPE>(partition)));
|
||||
}
|
||||
}
|
||||
}
|
||||
173
media/libaom/src/test/boolcoder_test.cc
Normal file
173
media/libaom/src/test/boolcoder_test.cc
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/bitreader.h"
|
||||
#include "aom_dsp/bitwriter.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
const int num_tests = 10;
|
||||
} // namespace
|
||||
|
||||
TEST(AV1, TestBitIO) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int n = 0; n < num_tests; ++n) {
|
||||
for (int method = 0; method <= 7; ++method) { // we generate various proba
|
||||
const int kBitsToTest = 1000;
|
||||
uint8_t probas[kBitsToTest];
|
||||
|
||||
for (int i = 0; i < kBitsToTest; ++i) {
|
||||
const int parity = i & 1;
|
||||
/* clang-format off */
|
||||
probas[i] =
|
||||
(method == 0) ? 0 : (method == 1) ? 255 :
|
||||
(method == 2) ? 128 :
|
||||
(method == 3) ? rnd.Rand8() :
|
||||
(method == 4) ? (parity ? 0 : 255) :
|
||||
// alternate between low and high proba:
|
||||
(method == 5) ? (parity ? rnd(128) : 255 - rnd(128)) :
|
||||
(method == 6) ?
|
||||
(parity ? rnd(64) : 255 - rnd(64)) :
|
||||
(parity ? rnd(32) : 255 - rnd(32));
|
||||
/* clang-format on */
|
||||
}
|
||||
for (int bit_method = 0; bit_method <= 3; ++bit_method) {
|
||||
const int random_seed = 6432;
|
||||
const int kBufferSize = 10000;
|
||||
ACMRandom bit_rnd(random_seed);
|
||||
aom_writer bw;
|
||||
uint8_t bw_buffer[kBufferSize];
|
||||
aom_start_encode(&bw, bw_buffer);
|
||||
|
||||
int bit = (bit_method == 0) ? 0 : (bit_method == 1) ? 1 : 0;
|
||||
for (int i = 0; i < kBitsToTest; ++i) {
|
||||
if (bit_method == 2) {
|
||||
bit = (i & 1);
|
||||
} else if (bit_method == 3) {
|
||||
bit = bit_rnd(2);
|
||||
}
|
||||
aom_write(&bw, bit, static_cast<int>(probas[i]));
|
||||
}
|
||||
|
||||
aom_stop_encode(&bw);
|
||||
|
||||
aom_reader br;
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
bit_rnd.Reset(random_seed);
|
||||
for (int i = 0; i < kBitsToTest; ++i) {
|
||||
if (bit_method == 2) {
|
||||
bit = (i & 1);
|
||||
} else if (bit_method == 3) {
|
||||
bit = bit_rnd(2);
|
||||
}
|
||||
GTEST_ASSERT_EQ(aom_read(&br, probas[i], NULL), bit)
|
||||
<< "pos: " << i << " / " << kBitsToTest
|
||||
<< " bit_method: " << bit_method << " method: " << method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define FRAC_DIFF_TOTAL_ERROR 0.18
|
||||
|
||||
TEST(AV1, TestTell) {
|
||||
const int kBufferSize = 10000;
|
||||
aom_writer bw;
|
||||
uint8_t bw_buffer[kBufferSize];
|
||||
const int kSymbols = 1024;
|
||||
// Coders are noisier at low probabilities, so we start at p = 4.
|
||||
for (int p = 4; p < 256; p++) {
|
||||
double probability = p / 256.;
|
||||
aom_start_encode(&bw, bw_buffer);
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_write(&bw, 0, p);
|
||||
}
|
||||
aom_stop_encode(&bw);
|
||||
aom_reader br;
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
uint32_t last_tell = aom_reader_tell(&br);
|
||||
uint32_t last_tell_frac = aom_reader_tell_frac(&br);
|
||||
double frac_diff_total = 0;
|
||||
GTEST_ASSERT_GE(aom_reader_tell(&br), 0u);
|
||||
GTEST_ASSERT_LE(aom_reader_tell(&br), 1u);
|
||||
ASSERT_FALSE(aom_reader_has_overflowed(&br));
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_read(&br, p, NULL);
|
||||
uint32_t tell = aom_reader_tell(&br);
|
||||
uint32_t tell_frac = aom_reader_tell_frac(&br);
|
||||
GTEST_ASSERT_GE(tell, last_tell)
|
||||
<< "tell: " << tell << ", last_tell: " << last_tell;
|
||||
GTEST_ASSERT_GE(tell_frac, last_tell_frac)
|
||||
<< "tell_frac: " << tell_frac
|
||||
<< ", last_tell_frac: " << last_tell_frac;
|
||||
// Frac tell should round up to tell.
|
||||
GTEST_ASSERT_EQ(tell, (tell_frac + 7) >> 3);
|
||||
last_tell = tell;
|
||||
frac_diff_total +=
|
||||
fabs(((tell_frac - last_tell_frac) / 8.0) + log2(probability));
|
||||
last_tell_frac = tell_frac;
|
||||
}
|
||||
const uint32_t expected = (uint32_t)(-kSymbols * log2(probability));
|
||||
// Last tell should be close to the expected value.
|
||||
GTEST_ASSERT_LE(last_tell, expected + 20) << " last_tell: " << last_tell;
|
||||
// The average frac_diff error should be pretty small.
|
||||
GTEST_ASSERT_LE(frac_diff_total / kSymbols, FRAC_DIFF_TOTAL_ERROR)
|
||||
<< " frac_diff_total: " << frac_diff_total;
|
||||
ASSERT_FALSE(aom_reader_has_overflowed(&br));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AV1, TestHasOverflowed) {
|
||||
const int kBufferSize = 10000;
|
||||
aom_writer bw;
|
||||
uint8_t bw_buffer[kBufferSize];
|
||||
const int kSymbols = 1024;
|
||||
// Coders are noisier at low probabilities, so we start at p = 4.
|
||||
for (int p = 4; p < 256; p++) {
|
||||
aom_start_encode(&bw, bw_buffer);
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
aom_write(&bw, 1, p);
|
||||
}
|
||||
aom_stop_encode(&bw);
|
||||
aom_reader br;
|
||||
aom_reader_init(&br, bw_buffer, bw.pos);
|
||||
ASSERT_FALSE(aom_reader_has_overflowed(&br));
|
||||
for (int i = 0; i < kSymbols; i++) {
|
||||
GTEST_ASSERT_EQ(aom_read(&br, p, NULL), 1);
|
||||
ASSERT_FALSE(aom_reader_has_overflowed(&br));
|
||||
}
|
||||
// In the worst case, the encoder uses just a tiny fraction of the last
|
||||
// byte in the buffer. So to guarantee that aom_reader_has_overflowed()
|
||||
// returns true, we have to consume very nearly 8 additional bits of data.
|
||||
// In the worse case, one of the bits in that byte will be 1, and the rest
|
||||
// will be zero. Once we are past that 1 bit, when the probability of
|
||||
// reading zero symbol from aom_read() is high, each additional symbol read
|
||||
// will consume very little additional data (in the case that p == 255,
|
||||
// approximately -log_2(255/256) ~= 0.0056 bits). In that case it would
|
||||
// take around 178 calls to consume more than 8 bits. That is only an upper
|
||||
// bound. In practice we are not guaranteed to hit the worse case and can
|
||||
// get away with 174 calls.
|
||||
for (int i = 0; i < 174; i++) {
|
||||
aom_read(&br, p, NULL);
|
||||
}
|
||||
ASSERT_TRUE(aom_reader_has_overflowed(&br));
|
||||
}
|
||||
}
|
||||
85
media/libaom/src/test/borders_test.cc
Normal file
85
media/libaom/src/test/borders_test.cc
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class BordersTestLarge
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
BordersTestLarge() : EncoderTest(GET_PARAM(0)) {}
|
||||
virtual ~BordersTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(GET_PARAM(1));
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, 1);
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (pkt->data.frame.flags & AOM_FRAME_IS_KEY) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(BordersTestLarge, TestEncodeHighBitrate) {
|
||||
// Validate that this non multiple of 64 wide clip encodes and decodes
|
||||
// without a mismatch when passing in a very low max q. This pushes
|
||||
// the encoder to producing lots of big partitions which will likely
|
||||
// extend into the border and test the border condition.
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 2000;
|
||||
cfg_.rc_max_quantizer = 10;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
|
||||
10);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
TEST_P(BordersTestLarge, TestLowBitrate) {
|
||||
// Validate that this clip encodes and decodes without a mismatch
|
||||
// when passing in a very high min q. This pushes the encoder to producing
|
||||
// lots of small partitions which might will test the other condition.
|
||||
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 200;
|
||||
cfg_.rc_min_quantizer = 40;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
|
||||
10);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(BordersTestLarge,
|
||||
::testing::Values(::libaom_test::kTwoPassGood));
|
||||
} // namespace
|
||||
425
media/libaom/src/test/cdef_test.cc
Normal file
425
media/libaom/src/test/cdef_test.cc
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/cdef_block.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef ::testing::tuple<cdef_filter_block_func, cdef_filter_block_func,
|
||||
BLOCK_SIZE, int, int>
|
||||
cdef_dir_param_t;
|
||||
|
||||
class CDEFBlockTest : public ::testing::TestWithParam<cdef_dir_param_t> {
|
||||
public:
|
||||
virtual ~CDEFBlockTest() {}
|
||||
virtual void SetUp() {
|
||||
cdef = GET_PARAM(0);
|
||||
ref_cdef = GET_PARAM(1);
|
||||
bsize = GET_PARAM(2);
|
||||
boundary = GET_PARAM(3);
|
||||
depth = GET_PARAM(4);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
int bsize;
|
||||
int boundary;
|
||||
int depth;
|
||||
cdef_filter_block_func cdef;
|
||||
cdef_filter_block_func ref_cdef;
|
||||
};
|
||||
|
||||
typedef CDEFBlockTest CDEFSpeedTest;
|
||||
|
||||
void test_cdef(int bsize, int iterations, cdef_filter_block_func cdef,
|
||||
cdef_filter_block_func ref_cdef, int boundary, int depth) {
|
||||
const int size = 8;
|
||||
const int ysize = size + 2 * CDEF_VBORDER;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint16_t, s[ysize * CDEF_BSTRIDE]);
|
||||
DECLARE_ALIGNED(16, static uint16_t, d[size * size]);
|
||||
DECLARE_ALIGNED(16, static uint16_t, ref_d[size * size]);
|
||||
memset(ref_d, 0, sizeof(ref_d));
|
||||
memset(d, 0, sizeof(d));
|
||||
|
||||
int error = 0, pristrength = 0, secstrength, dir;
|
||||
int pridamping, secdamping, bits, level, count,
|
||||
errdepth = 0, errpristrength = 0, errsecstrength = 0, errboundary = 0,
|
||||
errpridamping = 0, errsecdamping = 0;
|
||||
unsigned int pos = 0;
|
||||
|
||||
const unsigned int max_pos = size * size >> static_cast<int>(depth == 8);
|
||||
for (pridamping = 3 + depth - 8; pridamping < 7 - 3 * !!boundary + depth - 8;
|
||||
pridamping++) {
|
||||
for (secdamping = 3 + depth - 8;
|
||||
secdamping < 7 - 3 * !!boundary + depth - 8; secdamping++) {
|
||||
for (count = 0; count < iterations; count++) {
|
||||
for (level = 0; level < (1 << depth) && !error;
|
||||
level += (2 + 6 * !!boundary) << (depth - 8)) {
|
||||
for (bits = 1; bits <= depth && !error; bits += 1 + 3 * !!boundary) {
|
||||
for (unsigned int i = 0; i < sizeof(s) / sizeof(*s); i++)
|
||||
s[i] = clamp((rnd.Rand16() & ((1 << bits) - 1)) + level, 0,
|
||||
(1 << depth) - 1);
|
||||
if (boundary) {
|
||||
if (boundary & 1) { // Left
|
||||
for (int i = 0; i < ysize; i++)
|
||||
for (int j = 0; j < CDEF_HBORDER; j++)
|
||||
s[i * CDEF_BSTRIDE + j] = CDEF_VERY_LARGE;
|
||||
}
|
||||
if (boundary & 2) { // Right
|
||||
for (int i = 0; i < ysize; i++)
|
||||
for (int j = CDEF_HBORDER + size; j < CDEF_BSTRIDE; j++)
|
||||
s[i * CDEF_BSTRIDE + j] = CDEF_VERY_LARGE;
|
||||
}
|
||||
if (boundary & 4) { // Above
|
||||
for (int i = 0; i < CDEF_VBORDER; i++)
|
||||
for (int j = 0; j < CDEF_BSTRIDE; j++)
|
||||
s[i * CDEF_BSTRIDE + j] = CDEF_VERY_LARGE;
|
||||
}
|
||||
if (boundary & 8) { // Below
|
||||
for (int i = CDEF_VBORDER + size; i < ysize; i++)
|
||||
for (int j = 0; j < CDEF_BSTRIDE; j++)
|
||||
s[i * CDEF_BSTRIDE + j] = CDEF_VERY_LARGE;
|
||||
}
|
||||
}
|
||||
for (dir = 0; dir < 8; dir++) {
|
||||
for (pristrength = 0; pristrength <= 19 << (depth - 8) && !error;
|
||||
pristrength += (1 + 4 * !!boundary) << (depth - 8)) {
|
||||
if (pristrength == 16) pristrength = 19;
|
||||
for (secstrength = 0; secstrength <= 4 << (depth - 8) && !error;
|
||||
secstrength += 1 << (depth - 8)) {
|
||||
if (secstrength == 3 << (depth - 8)) continue;
|
||||
ref_cdef(depth == 8 ? (uint8_t *)ref_d : 0, ref_d, size,
|
||||
s + CDEF_HBORDER + CDEF_VBORDER * CDEF_BSTRIDE,
|
||||
pristrength, secstrength, dir, pridamping,
|
||||
secdamping, bsize, (1 << depth) - 1, depth - 8);
|
||||
// If cdef and ref_cdef are the same, we're just testing
|
||||
// speed
|
||||
if (cdef != ref_cdef)
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
cdef(depth == 8 ? (uint8_t *)d : 0, d, size,
|
||||
s + CDEF_HBORDER + CDEF_VBORDER * CDEF_BSTRIDE,
|
||||
pristrength, secstrength, dir, pridamping,
|
||||
secdamping, bsize, (1 << depth) - 1, depth - 8));
|
||||
if (ref_cdef != cdef) {
|
||||
for (pos = 0; pos < max_pos && !error; pos++) {
|
||||
error = ref_d[pos] != d[pos];
|
||||
errdepth = depth;
|
||||
errpristrength = pristrength;
|
||||
errsecstrength = secstrength;
|
||||
errboundary = boundary;
|
||||
errpridamping = pridamping;
|
||||
errsecdamping = secdamping;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos--;
|
||||
EXPECT_EQ(0, error) << "Error: CDEFBlockTest, SIMD and C mismatch."
|
||||
<< std::endl
|
||||
<< "First error at " << pos % size << "," << pos / size
|
||||
<< " (" << (int16_t)ref_d[pos] << " : " << (int16_t)d[pos]
|
||||
<< ") " << std::endl
|
||||
<< "pristrength: " << errpristrength << std::endl
|
||||
<< "pridamping: " << errpridamping << std::endl
|
||||
<< "secstrength: " << errsecstrength << std::endl
|
||||
<< "secdamping: " << errsecdamping << std::endl
|
||||
<< "depth: " << errdepth << std::endl
|
||||
<< "size: " << bsize << std::endl
|
||||
<< "boundary: " << errboundary << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void test_cdef_speed(int bsize, int iterations, cdef_filter_block_func cdef,
|
||||
cdef_filter_block_func ref_cdef, int boundary, int depth) {
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
test_cdef(bsize, iterations, ref_cdef, ref_cdef, boundary, depth);
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
test_cdef(bsize, iterations, cdef, cdef, boundary, depth);
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
|
||||
EXPECT_GT(ref_elapsed_time, elapsed_time)
|
||||
<< "Error: CDEFSpeedTest, SIMD slower than C." << std::endl
|
||||
<< "C time: " << ref_elapsed_time << " us" << std::endl
|
||||
<< "SIMD time: " << elapsed_time << " us" << std::endl;
|
||||
}
|
||||
|
||||
typedef int (*find_dir_t)(const uint16_t *img, int stride, int32_t *var,
|
||||
int coeff_shift);
|
||||
|
||||
typedef ::testing::tuple<find_dir_t, find_dir_t> find_dir_param_t;
|
||||
|
||||
class CDEFFindDirTest : public ::testing::TestWithParam<find_dir_param_t> {
|
||||
public:
|
||||
virtual ~CDEFFindDirTest() {}
|
||||
virtual void SetUp() {
|
||||
finddir = GET_PARAM(0);
|
||||
ref_finddir = GET_PARAM(1);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
find_dir_t finddir;
|
||||
find_dir_t ref_finddir;
|
||||
};
|
||||
|
||||
typedef CDEFFindDirTest CDEFFindDirSpeedTest;
|
||||
|
||||
void test_finddir(int (*finddir)(const uint16_t *img, int stride, int32_t *var,
|
||||
int coeff_shift),
|
||||
int (*ref_finddir)(const uint16_t *img, int stride,
|
||||
int32_t *var, int coeff_shift)) {
|
||||
const int size = 8;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint16_t, s[size * size]);
|
||||
|
||||
int error = 0;
|
||||
int depth, bits, level, count, errdepth = 0;
|
||||
int ref_res = 0, res = 0;
|
||||
int32_t ref_var = 0, var = 0;
|
||||
|
||||
for (depth = 8; depth <= 12 && !error; depth += 2) {
|
||||
for (count = 0; count < 512 && !error; count++) {
|
||||
for (level = 0; level < (1 << depth) && !error;
|
||||
level += 1 << (depth - 8)) {
|
||||
for (bits = 1; bits <= depth && !error; bits++) {
|
||||
for (unsigned int i = 0; i < sizeof(s) / sizeof(*s); i++)
|
||||
s[i] = clamp((rnd.Rand16() & ((1 << bits) - 1)) + level, 0,
|
||||
(1 << depth) - 1);
|
||||
for (int c = 0; c < 1 + 9 * (finddir == ref_finddir); c++)
|
||||
ref_res = ref_finddir(s, size, &ref_var, depth - 8);
|
||||
if (finddir != ref_finddir)
|
||||
ASM_REGISTER_STATE_CHECK(res = finddir(s, size, &var, depth - 8));
|
||||
if (ref_finddir != finddir) {
|
||||
if (res != ref_res || var != ref_var) error = 1;
|
||||
errdepth = depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, error) << "Error: CDEFFindDirTest, SIMD and C mismatch."
|
||||
<< std::endl
|
||||
<< "return: " << res << " : " << ref_res << std::endl
|
||||
<< "var: " << var << " : " << ref_var << std::endl
|
||||
<< "depth: " << errdepth << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void test_finddir_speed(int (*finddir)(const uint16_t *img, int stride,
|
||||
int32_t *var, int coeff_shift),
|
||||
int (*ref_finddir)(const uint16_t *img, int stride,
|
||||
int32_t *var, int coeff_shift)) {
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
test_finddir(ref_finddir, ref_finddir);
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
test_finddir(finddir, finddir);
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
|
||||
EXPECT_GT(ref_elapsed_time, elapsed_time)
|
||||
<< "Error: CDEFFindDirSpeedTest, SIMD slower than C." << std::endl
|
||||
<< "C time: " << ref_elapsed_time << " us" << std::endl
|
||||
<< "SIMD time: " << elapsed_time << " us" << std::endl;
|
||||
}
|
||||
|
||||
TEST_P(CDEFBlockTest, TestSIMDNoMismatch) {
|
||||
test_cdef(bsize, 1, cdef, ref_cdef, boundary, depth);
|
||||
}
|
||||
|
||||
TEST_P(CDEFSpeedTest, DISABLED_TestSpeed) {
|
||||
test_cdef_speed(bsize, 4, cdef, ref_cdef, boundary, depth);
|
||||
}
|
||||
|
||||
TEST_P(CDEFFindDirTest, TestSIMDNoMismatch) {
|
||||
test_finddir(finddir, ref_finddir);
|
||||
}
|
||||
|
||||
TEST_P(CDEFFindDirSpeedTest, DISABLED_TestSpeed) {
|
||||
test_finddir_speed(finddir, ref_finddir);
|
||||
}
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
// VS compiling for 32 bit targets does not support vector types in
|
||||
// structs as arguments, which makes the v256 type of the intrinsics
|
||||
// hard to support, so optimizations for this target are disabled.
|
||||
#if defined(_WIN64) || !defined(_MSC_VER) || defined(__clang__)
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, CDEFBlockTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_sse2),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, CDEFFindDirTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_sse2,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, CDEFBlockTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_ssse3),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CDEFFindDirTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_ssse3,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, CDEFBlockTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_sse4_1),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, CDEFFindDirTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_sse4_1,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, CDEFBlockTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_avx2),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CDEFFindDirTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_avx2,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, CDEFBlockTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_neon),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CDEFFindDirTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_neon,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
// Test speed for all supported architectures
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, CDEFSpeedTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_sse2),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, CDEFFindDirSpeedTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_sse2,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, CDEFSpeedTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_ssse3),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CDEFFindDirSpeedTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_ssse3,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, CDEFSpeedTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_sse4_1),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, CDEFFindDirSpeedTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_sse4_1,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, CDEFSpeedTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_avx2),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CDEFFindDirSpeedTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_avx2,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
NEON, CDEFSpeedTest,
|
||||
::testing::Combine(::testing::Values(&cdef_filter_block_neon),
|
||||
::testing::Values(&cdef_filter_block_c),
|
||||
::testing::Values(BLOCK_4X4, BLOCK_4X8, BLOCK_8X4,
|
||||
BLOCK_8X8),
|
||||
::testing::Range(0, 16), ::testing::Range(8, 13, 2)));
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CDEFFindDirSpeedTest,
|
||||
::testing::Values(make_tuple(&cdef_find_dir_neon,
|
||||
&cdef_find_dir_c)));
|
||||
#endif
|
||||
|
||||
#endif // defined(_WIN64) || !defined(_MSC_VER)
|
||||
} // namespace
|
||||
567
media/libaom/src/test/cfl_test.cc
Normal file
567
media/libaom/src/test/cfl_test.cc
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "test/util.h"
|
||||
#include "test/acm_random.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
#define NUM_ITERATIONS (100)
|
||||
#define NUM_ITERATIONS_SPEED (INT16_MAX)
|
||||
|
||||
#define ALL_CFL_TX_SIZES(function) \
|
||||
make_tuple(TX_4X4, &function), make_tuple(TX_4X8, &function), \
|
||||
make_tuple(TX_4X16, &function), make_tuple(TX_8X4, &function), \
|
||||
make_tuple(TX_8X8, &function), make_tuple(TX_8X16, &function), \
|
||||
make_tuple(TX_8X32, &function), make_tuple(TX_16X4, &function), \
|
||||
make_tuple(TX_16X8, &function), make_tuple(TX_16X16, &function), \
|
||||
make_tuple(TX_16X32, &function), make_tuple(TX_32X8, &function), \
|
||||
make_tuple(TX_32X16, &function), make_tuple(TX_32X32, &function)
|
||||
|
||||
#define ALL_CFL_TX_SIZES_SUBSAMPLE(fun420, fun422, fun444) \
|
||||
make_tuple(TX_4X4, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_4X8, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_4X16, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_8X4, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_8X8, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_8X16, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_8X32, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_16X4, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_16X8, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_16X16, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_16X32, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_32X8, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_32X16, &fun420, &fun422, &fun444), \
|
||||
make_tuple(TX_32X32, &fun420, &fun422, &fun444)
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename A>
|
||||
static void assert_eq(const A *a, const A *b, int width, int height) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
ASSERT_EQ(a[j * CFL_BUF_LINE + i], b[j * CFL_BUF_LINE + i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void assertFaster(int ref_elapsed_time, int elapsed_time) {
|
||||
EXPECT_GT(ref_elapsed_time, elapsed_time)
|
||||
<< "Error: CFLSubtractSpeedTest, SIMD slower than C." << std::endl
|
||||
<< "C time: " << ref_elapsed_time << " us" << std::endl
|
||||
<< "SIMD time: " << elapsed_time << " us" << std::endl;
|
||||
}
|
||||
|
||||
static void printSpeed(int ref_elapsed_time, int elapsed_time, int width,
|
||||
int height) {
|
||||
std::cout.precision(2);
|
||||
std::cout << "[ ] " << width << "x" << height
|
||||
<< ": C time = " << ref_elapsed_time
|
||||
<< " us, SIMD time = " << elapsed_time << " us"
|
||||
<< " (~" << ref_elapsed_time / (double)elapsed_time << "x) "
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
class CFLTest {
|
||||
public:
|
||||
virtual ~CFLTest() {}
|
||||
void init(TX_SIZE tx) {
|
||||
tx_size = tx;
|
||||
width = tx_size_wide[tx_size];
|
||||
height = tx_size_high[tx_size];
|
||||
rnd(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
protected:
|
||||
TX_SIZE tx_size;
|
||||
int width;
|
||||
int height;
|
||||
ACMRandom rnd;
|
||||
};
|
||||
|
||||
template <typename I>
|
||||
class CFLTestWithData : public CFLTest {
|
||||
public:
|
||||
virtual ~CFLTestWithData() {}
|
||||
|
||||
protected:
|
||||
I data[CFL_BUF_SQUARE];
|
||||
I data_ref[CFL_BUF_SQUARE];
|
||||
void randData(I (ACMRandom::*random)()) {
|
||||
for (int j = 0; j < this->height; j++) {
|
||||
for (int i = 0; i < this->width; i++) {
|
||||
const I d = (this->rnd.*random)();
|
||||
data[j * CFL_BUF_LINE + i] = d;
|
||||
data_ref[j * CFL_BUF_LINE + i] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename I>
|
||||
class CFLTestWithAlignedData : public CFLTest {
|
||||
public:
|
||||
CFLTestWithAlignedData() {
|
||||
chroma_pels_ref =
|
||||
reinterpret_cast<I *>(aom_memalign(32, sizeof(I) * CFL_BUF_SQUARE));
|
||||
chroma_pels =
|
||||
reinterpret_cast<I *>(aom_memalign(32, sizeof(I) * CFL_BUF_SQUARE));
|
||||
sub_luma_pels_ref = reinterpret_cast<int16_t *>(
|
||||
aom_memalign(32, sizeof(int16_t) * CFL_BUF_SQUARE));
|
||||
sub_luma_pels = reinterpret_cast<int16_t *>(
|
||||
aom_memalign(32, sizeof(int16_t) * CFL_BUF_SQUARE));
|
||||
memset(chroma_pels_ref, 0, sizeof(I) * CFL_BUF_SQUARE);
|
||||
memset(chroma_pels, 0, sizeof(I) * CFL_BUF_SQUARE);
|
||||
memset(sub_luma_pels_ref, 0, sizeof(int16_t) * CFL_BUF_SQUARE);
|
||||
memset(sub_luma_pels, 0, sizeof(int16_t) * CFL_BUF_SQUARE);
|
||||
}
|
||||
~CFLTestWithAlignedData() {
|
||||
aom_free(chroma_pels_ref);
|
||||
aom_free(sub_luma_pels_ref);
|
||||
aom_free(chroma_pels);
|
||||
aom_free(sub_luma_pels);
|
||||
}
|
||||
|
||||
protected:
|
||||
I *chroma_pels_ref;
|
||||
I *chroma_pels;
|
||||
int16_t *sub_luma_pels_ref;
|
||||
int16_t *sub_luma_pels;
|
||||
int alpha_q3;
|
||||
I dc;
|
||||
void randData(int bd) {
|
||||
alpha_q3 = this->rnd(33) - 16;
|
||||
dc = this->rnd(1 << bd);
|
||||
for (int j = 0; j < this->height; j++) {
|
||||
for (int i = 0; i < this->width; i++) {
|
||||
chroma_pels[j * CFL_BUF_LINE + i] = dc;
|
||||
chroma_pels_ref[j * CFL_BUF_LINE + i] = dc;
|
||||
sub_luma_pels_ref[j * CFL_BUF_LINE + i] =
|
||||
sub_luma_pels[j * CFL_BUF_LINE + i] = this->rnd(1 << (bd + 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef cfl_subtract_average_fn (*sub_avg_fn)(TX_SIZE tx_size);
|
||||
typedef ::testing::tuple<TX_SIZE, sub_avg_fn> sub_avg_param;
|
||||
class CFLSubAvgTest : public ::testing::TestWithParam<sub_avg_param>,
|
||||
public CFLTestWithData<int16_t> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
CFLTest::init(::testing::get<0>(this->GetParam()));
|
||||
sub_avg = ::testing::get<1>(this->GetParam())(tx_size);
|
||||
sub_avg_ref = get_subtract_average_fn_c(tx_size);
|
||||
}
|
||||
virtual ~CFLSubAvgTest() {}
|
||||
|
||||
protected:
|
||||
cfl_subtract_average_fn sub_avg;
|
||||
cfl_subtract_average_fn sub_avg_ref;
|
||||
};
|
||||
|
||||
TEST_P(CFLSubAvgTest, SubAvgTest) {
|
||||
for (int it = 0; it < NUM_ITERATIONS; it++) {
|
||||
randData(&ACMRandom::Rand15Signed);
|
||||
sub_avg((uint16_t *)data, data);
|
||||
sub_avg_ref((uint16_t *)data_ref, data_ref);
|
||||
assert_eq<int16_t>(data, data_ref, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(CFLSubAvgTest, DISABLED_SubAvgSpeedTest) {
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
randData(&ACMRandom::Rand15Signed);
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
sub_avg_ref((uint16_t *)data_ref, data_ref);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
sub_avg((uint16_t *)data, data);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
printSpeed(ref_elapsed_time, elapsed_time, width, height);
|
||||
assertFaster(ref_elapsed_time, elapsed_time);
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename I>
|
||||
class CFLSubsampleTest : public ::testing::TestWithParam<S>,
|
||||
public CFLTestWithData<I> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
CFLTest::init(::testing::get<0>(this->GetParam()));
|
||||
fun_420 = ::testing::get<1>(this->GetParam())(this->tx_size);
|
||||
fun_422 = ::testing::get<2>(this->GetParam())(this->tx_size);
|
||||
fun_444 = ::testing::get<3>(this->GetParam())(this->tx_size);
|
||||
}
|
||||
|
||||
protected:
|
||||
T fun_420;
|
||||
T fun_422;
|
||||
T fun_444;
|
||||
T fun_420_ref;
|
||||
T fun_422_ref;
|
||||
T fun_444_ref;
|
||||
|
||||
void subsampleTest(T fun, T fun_ref, int sub_width, int sub_height,
|
||||
I (ACMRandom::*random)()) {
|
||||
uint16_t sub_luma_pels[CFL_BUF_SQUARE];
|
||||
uint16_t sub_luma_pels_ref[CFL_BUF_SQUARE];
|
||||
|
||||
for (int it = 0; it < NUM_ITERATIONS; it++) {
|
||||
CFLTestWithData<I>::randData(random);
|
||||
fun(this->data, CFL_BUF_LINE, sub_luma_pels);
|
||||
fun_ref(this->data_ref, CFL_BUF_LINE, sub_luma_pels_ref);
|
||||
assert_eq<uint16_t>(sub_luma_pels, sub_luma_pels_ref, sub_width,
|
||||
sub_height);
|
||||
}
|
||||
}
|
||||
|
||||
void subsampleSpeedTest(T fun, T fun_ref, I (ACMRandom::*random)()) {
|
||||
uint16_t sub_luma_pels[CFL_BUF_SQUARE];
|
||||
uint16_t sub_luma_pels_ref[CFL_BUF_SQUARE];
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
|
||||
CFLTestWithData<I>::randData(random);
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
fun_ref(this->data_ref, CFL_BUF_LINE, sub_luma_pels);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
fun(this->data, CFL_BUF_LINE, sub_luma_pels_ref);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
printSpeed(ref_elapsed_time, elapsed_time, this->width, this->height);
|
||||
assertFaster(ref_elapsed_time, elapsed_time);
|
||||
}
|
||||
};
|
||||
|
||||
typedef cfl_subsample_lbd_fn (*get_subsample_lbd_fn)(TX_SIZE tx_size);
|
||||
typedef ::testing::tuple<TX_SIZE, get_subsample_lbd_fn, get_subsample_lbd_fn,
|
||||
get_subsample_lbd_fn>
|
||||
subsample_lbd_param;
|
||||
class CFLSubsampleLBDTest
|
||||
: public CFLSubsampleTest<subsample_lbd_param, cfl_subsample_lbd_fn,
|
||||
uint8_t> {
|
||||
public:
|
||||
virtual ~CFLSubsampleLBDTest() {}
|
||||
virtual void SetUp() {
|
||||
CFLSubsampleTest::SetUp();
|
||||
fun_420_ref = cfl_get_luma_subsampling_420_lbd_c(tx_size);
|
||||
fun_422_ref = cfl_get_luma_subsampling_422_lbd_c(tx_size);
|
||||
fun_444_ref = cfl_get_luma_subsampling_444_lbd_c(tx_size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, SubsampleLBD420Test) {
|
||||
subsampleTest(fun_420, fun_420_ref, width >> 1, height >> 1,
|
||||
&ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, DISABLED_SubsampleLBD420SpeedTest) {
|
||||
subsampleSpeedTest(fun_420, fun_420_ref, &ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, SubsampleLBD422Test) {
|
||||
subsampleTest(fun_422, fun_422_ref, width >> 1, height, &ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, DISABLED_SubsampleLBD422SpeedTest) {
|
||||
subsampleSpeedTest(fun_422, fun_422_ref, &ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, SubsampleLBD444Test) {
|
||||
subsampleTest(fun_444, fun_444_ref, width, height, &ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleLBDTest, DISABLED_SubsampleLBD444SpeedTest) {
|
||||
subsampleSpeedTest(fun_444, fun_444_ref, &ACMRandom::Rand8);
|
||||
}
|
||||
|
||||
typedef cfl_subsample_hbd_fn (*get_subsample_hbd_fn)(TX_SIZE tx_size);
|
||||
typedef ::testing::tuple<TX_SIZE, get_subsample_hbd_fn, get_subsample_hbd_fn,
|
||||
get_subsample_hbd_fn>
|
||||
subsample_hbd_param;
|
||||
class CFLSubsampleHBDTest
|
||||
: public CFLSubsampleTest<subsample_hbd_param, cfl_subsample_hbd_fn,
|
||||
uint16_t> {
|
||||
public:
|
||||
virtual ~CFLSubsampleHBDTest() {}
|
||||
virtual void SetUp() {
|
||||
CFLSubsampleTest::SetUp();
|
||||
fun_420_ref = cfl_get_luma_subsampling_420_hbd_c(tx_size);
|
||||
fun_422_ref = cfl_get_luma_subsampling_422_hbd_c(tx_size);
|
||||
fun_444_ref = cfl_get_luma_subsampling_444_hbd_c(tx_size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, SubsampleHBD420Test) {
|
||||
subsampleTest(fun_420, fun_420_ref, width >> 1, height >> 1,
|
||||
&ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, DISABLED_SubsampleHBD420SpeedTest) {
|
||||
subsampleSpeedTest(fun_420, fun_420_ref, &ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, SubsampleHBD422Test) {
|
||||
subsampleTest(fun_422, fun_422_ref, width >> 1, height, &ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, DISABLED_SubsampleHBD422SpeedTest) {
|
||||
subsampleSpeedTest(fun_422, fun_422_ref, &ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, SubsampleHBD444Test) {
|
||||
subsampleTest(fun_444, fun_444_ref, width, height, &ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
TEST_P(CFLSubsampleHBDTest, DISABLED_SubsampleHBD444SpeedTest) {
|
||||
subsampleSpeedTest(fun_444, fun_444_ref, &ACMRandom::Rand12);
|
||||
}
|
||||
|
||||
typedef cfl_predict_lbd_fn (*get_predict_fn)(TX_SIZE tx_size);
|
||||
typedef ::testing::tuple<TX_SIZE, get_predict_fn> predict_param;
|
||||
class CFLPredictTest : public ::testing::TestWithParam<predict_param>,
|
||||
public CFLTestWithAlignedData<uint8_t> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
CFLTest::init(::testing::get<0>(this->GetParam()));
|
||||
predict = ::testing::get<1>(this->GetParam())(tx_size);
|
||||
predict_ref = get_predict_lbd_fn_c(tx_size);
|
||||
}
|
||||
virtual ~CFLPredictTest() {}
|
||||
|
||||
protected:
|
||||
cfl_predict_lbd_fn predict;
|
||||
cfl_predict_lbd_fn predict_ref;
|
||||
};
|
||||
|
||||
TEST_P(CFLPredictTest, PredictTest) {
|
||||
for (int it = 0; it < NUM_ITERATIONS; it++) {
|
||||
randData(8);
|
||||
predict(sub_luma_pels, chroma_pels, CFL_BUF_LINE, alpha_q3);
|
||||
predict_ref(sub_luma_pels_ref, chroma_pels_ref, CFL_BUF_LINE, alpha_q3);
|
||||
assert_eq<uint8_t>(chroma_pels, chroma_pels_ref, width, height);
|
||||
}
|
||||
}
|
||||
TEST_P(CFLPredictTest, DISABLED_PredictSpeedTest) {
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
randData(8);
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
predict_ref(sub_luma_pels_ref, chroma_pels_ref, CFL_BUF_LINE, alpha_q3);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
predict(sub_luma_pels, chroma_pels, CFL_BUF_LINE, alpha_q3);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
printSpeed(ref_elapsed_time, elapsed_time, width, height);
|
||||
assertFaster(ref_elapsed_time, elapsed_time);
|
||||
}
|
||||
|
||||
typedef cfl_predict_hbd_fn (*get_predict_fn_hbd)(TX_SIZE tx_size);
|
||||
typedef ::testing::tuple<TX_SIZE, get_predict_fn_hbd> predict_param_hbd;
|
||||
class CFLPredictHBDTest : public ::testing::TestWithParam<predict_param_hbd>,
|
||||
public CFLTestWithAlignedData<uint16_t> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
CFLTest::init(::testing::get<0>(this->GetParam()));
|
||||
predict = ::testing::get<1>(this->GetParam())(tx_size);
|
||||
predict_ref = get_predict_hbd_fn_c(tx_size);
|
||||
}
|
||||
virtual ~CFLPredictHBDTest() {}
|
||||
|
||||
protected:
|
||||
cfl_predict_hbd_fn predict;
|
||||
cfl_predict_hbd_fn predict_ref;
|
||||
};
|
||||
|
||||
TEST_P(CFLPredictHBDTest, PredictHBDTest) {
|
||||
int bd = 12;
|
||||
for (int it = 0; it < NUM_ITERATIONS; it++) {
|
||||
randData(bd);
|
||||
predict(sub_luma_pels, chroma_pels, CFL_BUF_LINE, alpha_q3, bd);
|
||||
predict_ref(sub_luma_pels_ref, chroma_pels_ref, CFL_BUF_LINE, alpha_q3, bd);
|
||||
assert_eq<uint16_t>(chroma_pels, chroma_pels_ref, width, height);
|
||||
}
|
||||
}
|
||||
TEST_P(CFLPredictHBDTest, DISABLED_PredictHBDSpeedTest) {
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer timer;
|
||||
const int bd = 12;
|
||||
randData(bd);
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
predict_ref(sub_luma_pels_ref, chroma_pels_ref, CFL_BUF_LINE, alpha_q3, bd);
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
int ref_elapsed_time = (int)aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int k = 0; k < NUM_ITERATIONS_SPEED; k++) {
|
||||
predict(sub_luma_pels, chroma_pels, CFL_BUF_LINE, alpha_q3, bd);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
int elapsed_time = (int)aom_usec_timer_elapsed(&timer);
|
||||
printSpeed(ref_elapsed_time, elapsed_time, width, height);
|
||||
assertFaster(ref_elapsed_time, elapsed_time);
|
||||
}
|
||||
|
||||
#if HAVE_SSE2
|
||||
const sub_avg_param sub_avg_sizes_sse2[] = { ALL_CFL_TX_SIZES(
|
||||
get_subtract_average_fn_sse2) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, CFLSubAvgTest,
|
||||
::testing::ValuesIn(sub_avg_sizes_sse2));
|
||||
|
||||
#endif
|
||||
|
||||
#if HAVE_SSSE3
|
||||
const subsample_lbd_param subsample_lbd_sizes_ssse3[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_lbd_ssse3,
|
||||
cfl_get_luma_subsampling_422_lbd_ssse3,
|
||||
cfl_get_luma_subsampling_444_lbd_ssse3)
|
||||
};
|
||||
|
||||
const subsample_hbd_param subsample_hbd_sizes_ssse3[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_hbd_ssse3,
|
||||
cfl_get_luma_subsampling_422_hbd_ssse3,
|
||||
cfl_get_luma_subsampling_444_hbd_ssse3)
|
||||
};
|
||||
|
||||
const predict_param predict_sizes_ssse3[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_lbd_fn_ssse3) };
|
||||
|
||||
const predict_param_hbd predict_sizes_hbd_ssse3[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_hbd_fn_ssse3) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CFLSubsampleLBDTest,
|
||||
::testing::ValuesIn(subsample_lbd_sizes_ssse3));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CFLSubsampleHBDTest,
|
||||
::testing::ValuesIn(subsample_hbd_sizes_ssse3));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CFLPredictTest,
|
||||
::testing::ValuesIn(predict_sizes_ssse3));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, CFLPredictHBDTest,
|
||||
::testing::ValuesIn(predict_sizes_hbd_ssse3));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
const sub_avg_param sub_avg_sizes_avx2[] = { ALL_CFL_TX_SIZES(
|
||||
get_subtract_average_fn_avx2) };
|
||||
|
||||
const subsample_lbd_param subsample_lbd_sizes_avx2[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_lbd_avx2,
|
||||
cfl_get_luma_subsampling_422_lbd_avx2,
|
||||
cfl_get_luma_subsampling_444_lbd_avx2)
|
||||
};
|
||||
|
||||
const subsample_hbd_param subsample_hbd_sizes_avx2[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_hbd_avx2,
|
||||
cfl_get_luma_subsampling_422_hbd_avx2,
|
||||
cfl_get_luma_subsampling_444_hbd_avx2)
|
||||
};
|
||||
|
||||
const predict_param predict_sizes_avx2[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_lbd_fn_avx2) };
|
||||
|
||||
const predict_param_hbd predict_sizes_hbd_avx2[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_hbd_fn_avx2) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CFLSubAvgTest,
|
||||
::testing::ValuesIn(sub_avg_sizes_avx2));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CFLSubsampleLBDTest,
|
||||
::testing::ValuesIn(subsample_lbd_sizes_avx2));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CFLSubsampleHBDTest,
|
||||
::testing::ValuesIn(subsample_hbd_sizes_avx2));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CFLPredictTest,
|
||||
::testing::ValuesIn(predict_sizes_avx2));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, CFLPredictHBDTest,
|
||||
::testing::ValuesIn(predict_sizes_hbd_avx2));
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON
|
||||
|
||||
const sub_avg_param sub_avg_sizes_neon[] = { ALL_CFL_TX_SIZES(
|
||||
get_subtract_average_fn_neon) };
|
||||
|
||||
const subsample_lbd_param subsample_lbd_sizes_neon[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_lbd_neon,
|
||||
cfl_get_luma_subsampling_422_lbd_neon,
|
||||
cfl_get_luma_subsampling_444_lbd_neon)
|
||||
};
|
||||
|
||||
const subsample_hbd_param subsample_hbd_sizes_neon[] = {
|
||||
ALL_CFL_TX_SIZES_SUBSAMPLE(cfl_get_luma_subsampling_420_hbd_neon,
|
||||
cfl_get_luma_subsampling_422_hbd_neon,
|
||||
cfl_get_luma_subsampling_444_hbd_neon)
|
||||
};
|
||||
|
||||
const predict_param predict_sizes_neon[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_lbd_fn_neon) };
|
||||
|
||||
const predict_param_hbd predict_sizes_hbd_neon[] = { ALL_CFL_TX_SIZES(
|
||||
get_predict_hbd_fn_neon) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CFLSubAvgTest,
|
||||
::testing::ValuesIn(sub_avg_sizes_neon));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CFLSubsampleLBDTest,
|
||||
::testing::ValuesIn(subsample_lbd_sizes_neon));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CFLSubsampleHBDTest,
|
||||
::testing::ValuesIn(subsample_hbd_sizes_neon));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CFLPredictTest,
|
||||
::testing::ValuesIn(predict_sizes_neon));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, CFLPredictHBDTest,
|
||||
::testing::ValuesIn(predict_sizes_hbd_neon));
|
||||
#endif
|
||||
|
||||
#if HAVE_VSX
|
||||
const sub_avg_param sub_avg_sizes_vsx[] = { ALL_CFL_TX_SIZES(
|
||||
get_subtract_average_fn_vsx) };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(VSX, CFLSubAvgTest,
|
||||
::testing::ValuesIn(sub_avg_sizes_vsx));
|
||||
#endif
|
||||
} // namespace
|
||||
31
media/libaom/src/test/clear_system_state.h
Normal file
31
media/libaom/src/test/clear_system_state.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AOM_TEST_CLEAR_SYSTEM_STATE_H_
|
||||
#define AOM_TEST_CLEAR_SYSTEM_STATE_H_
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#if ARCH_X86 || ARCH_X86_64
|
||||
#include "aom_ports/x86.h"
|
||||
#endif
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
// Reset system to a known state. This function should be used for all non-API
|
||||
// test cases.
|
||||
inline void ClearSystemState() {
|
||||
#if ARCH_X86 || ARCH_X86_64
|
||||
aom_reset_mmx_state();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace libaom_test
|
||||
#endif // AOM_TEST_CLEAR_SYSTEM_STATE_H_
|
||||
170
media/libaom/src/test/codec_factory.h
Normal file
170
media/libaom/src/test/codec_factory.h
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AOM_TEST_CODEC_FACTORY_H_
|
||||
#define AOM_TEST_CODEC_FACTORY_H_
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "aom/aom_decoder.h"
|
||||
#include "aom/aom_encoder.h"
|
||||
#if CONFIG_AV1_ENCODER
|
||||
#include "aom/aomcx.h"
|
||||
#endif
|
||||
#if CONFIG_AV1_DECODER
|
||||
#include "aom/aomdx.h"
|
||||
#endif
|
||||
|
||||
#include "test/decode_test_driver.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
namespace libaom_test {
|
||||
|
||||
const int kCodecFactoryParam = 0;
|
||||
|
||||
class CodecFactory {
|
||||
public:
|
||||
CodecFactory() {}
|
||||
|
||||
virtual ~CodecFactory() {}
|
||||
|
||||
virtual Decoder *CreateDecoder(aom_codec_dec_cfg_t cfg) const = 0;
|
||||
|
||||
virtual Decoder *CreateDecoder(aom_codec_dec_cfg_t cfg,
|
||||
const aom_codec_flags_t flags) const = 0;
|
||||
|
||||
virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg,
|
||||
const unsigned long init_flags,
|
||||
TwopassStatsStore *stats) const = 0;
|
||||
|
||||
virtual aom_codec_err_t DefaultEncoderConfig(aom_codec_enc_cfg_t *cfg,
|
||||
int usage) const = 0;
|
||||
};
|
||||
|
||||
/* Provide CodecTestWith<n>Params classes for a variable number of parameters
|
||||
* to avoid having to include a pointer to the CodecFactory in every test
|
||||
* definition.
|
||||
*/
|
||||
template <class T1>
|
||||
class CodecTestWithParam
|
||||
: public ::testing::TestWithParam<
|
||||
::testing::tuple<const libaom_test::CodecFactory *, T1> > {};
|
||||
|
||||
template <class T1, class T2>
|
||||
class CodecTestWith2Params
|
||||
: public ::testing::TestWithParam<
|
||||
::testing::tuple<const libaom_test::CodecFactory *, T1, T2> > {};
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
class CodecTestWith3Params
|
||||
: public ::testing::TestWithParam<
|
||||
::testing::tuple<const libaom_test::CodecFactory *, T1, T2, T3> > {};
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
class CodecTestWith4Params
|
||||
: public ::testing::TestWithParam< ::testing::tuple<
|
||||
const libaom_test::CodecFactory *, T1, T2, T3, T4> > {};
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
class CodecTestWith5Params
|
||||
: public ::testing::TestWithParam< ::testing::tuple<
|
||||
const libaom_test::CodecFactory *, T1, T2, T3, T4, T5> > {};
|
||||
|
||||
/*
|
||||
* AV1 Codec Definitions
|
||||
*/
|
||||
class AV1Decoder : public Decoder {
|
||||
public:
|
||||
explicit AV1Decoder(aom_codec_dec_cfg_t cfg) : Decoder(cfg) {}
|
||||
|
||||
AV1Decoder(aom_codec_dec_cfg_t cfg, const aom_codec_flags_t flag)
|
||||
: Decoder(cfg, flag) {}
|
||||
|
||||
protected:
|
||||
virtual aom_codec_iface_t *CodecInterface() const {
|
||||
#if CONFIG_AV1_DECODER
|
||||
return aom_codec_av1_dx();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class AV1Encoder : public Encoder {
|
||||
public:
|
||||
AV1Encoder(aom_codec_enc_cfg_t cfg, const uint32_t init_flags,
|
||||
TwopassStatsStore *stats)
|
||||
: Encoder(cfg, init_flags, stats) {}
|
||||
|
||||
protected:
|
||||
virtual aom_codec_iface_t *CodecInterface() const {
|
||||
#if CONFIG_AV1_ENCODER
|
||||
return aom_codec_av1_cx();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class AV1CodecFactory : public CodecFactory {
|
||||
public:
|
||||
AV1CodecFactory() : CodecFactory() {}
|
||||
|
||||
virtual Decoder *CreateDecoder(aom_codec_dec_cfg_t cfg) const {
|
||||
return CreateDecoder(cfg, 0);
|
||||
}
|
||||
|
||||
virtual Decoder *CreateDecoder(aom_codec_dec_cfg_t cfg,
|
||||
const aom_codec_flags_t flags) const {
|
||||
#if CONFIG_AV1_DECODER
|
||||
return new AV1Decoder(cfg, flags);
|
||||
#else
|
||||
(void)cfg;
|
||||
(void)flags;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual Encoder *CreateEncoder(aom_codec_enc_cfg_t cfg,
|
||||
const unsigned long init_flags,
|
||||
TwopassStatsStore *stats) const {
|
||||
#if CONFIG_AV1_ENCODER
|
||||
return new AV1Encoder(cfg, init_flags, stats);
|
||||
#else
|
||||
(void)cfg;
|
||||
(void)init_flags;
|
||||
(void)stats;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual aom_codec_err_t DefaultEncoderConfig(aom_codec_enc_cfg_t *cfg,
|
||||
int usage) const {
|
||||
#if CONFIG_AV1_ENCODER
|
||||
return aom_codec_enc_config_default(aom_codec_av1_cx(), cfg, usage);
|
||||
#else
|
||||
(void)cfg;
|
||||
(void)usage;
|
||||
return AOM_CODEC_INCAPABLE;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
const libaom_test::AV1CodecFactory kAV1;
|
||||
|
||||
#define AV1_INSTANTIATE_TEST_CASE(test, ...) \
|
||||
INSTANTIATE_TEST_CASE_P( \
|
||||
AV1, test, \
|
||||
::testing::Combine( \
|
||||
::testing::Values(static_cast<const libaom_test::CodecFactory *>( \
|
||||
&libaom_test::kAV1)), \
|
||||
__VA_ARGS__))
|
||||
|
||||
} // namespace libaom_test
|
||||
#endif // AOM_TEST_CODEC_FACTORY_H_
|
||||
205
media/libaom/src/test/coding_path_sync.cc
Normal file
205
media/libaom/src/test/coding_path_sync.cc
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "aom_ports/mem.h" // ROUND_POWER_OF_TWO
|
||||
#include "aom/aomcx.h"
|
||||
#include "aom/aomdx.h"
|
||||
#include "aom/aom_encoder.h"
|
||||
#include "aom/aom_decoder.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
namespace {
|
||||
|
||||
class CompressedSource {
|
||||
public:
|
||||
explicit CompressedSource(int seed) : rnd_(seed), frame_count_(0) {
|
||||
aom_codec_iface_t *algo = aom_codec_av1_cx();
|
||||
|
||||
aom_codec_enc_cfg_t cfg;
|
||||
aom_codec_enc_config_default(algo, &cfg, 0);
|
||||
|
||||
// force the quantizer, to reduce the sensitivity on encoding choices.
|
||||
// e.g, we don't want this test to break when the rate control is modified.
|
||||
{
|
||||
const int max_q = cfg.rc_max_quantizer;
|
||||
const int min_q = cfg.rc_min_quantizer;
|
||||
const int q = rnd_.PseudoUniform(max_q - min_q + 1) + min_q;
|
||||
|
||||
cfg.rc_end_usage = AOM_Q;
|
||||
cfg.rc_max_quantizer = q;
|
||||
cfg.rc_min_quantizer = q;
|
||||
}
|
||||
|
||||
// choose the picture size
|
||||
{
|
||||
width_ = rnd_.PseudoUniform(kWidth - 8) + 8;
|
||||
height_ = rnd_.PseudoUniform(kHeight - 8) + 8;
|
||||
}
|
||||
|
||||
// choose the chroma subsampling
|
||||
{
|
||||
const aom_img_fmt_t fmts[] = {
|
||||
AOM_IMG_FMT_I420,
|
||||
AOM_IMG_FMT_I422,
|
||||
AOM_IMG_FMT_I444,
|
||||
};
|
||||
|
||||
format_ = fmts[rnd_.PseudoUniform(NELEMENTS(fmts))];
|
||||
}
|
||||
|
||||
cfg.g_w = width_;
|
||||
cfg.g_h = height_;
|
||||
cfg.g_lag_in_frames = 0;
|
||||
if (format_ == AOM_IMG_FMT_I420)
|
||||
cfg.g_profile = 0;
|
||||
else if (format_ == AOM_IMG_FMT_I444)
|
||||
cfg.g_profile = 1;
|
||||
else if (format_ == AOM_IMG_FMT_I422)
|
||||
cfg.g_profile = 2;
|
||||
|
||||
aom_codec_enc_init(&enc_, algo, &cfg, 0);
|
||||
}
|
||||
|
||||
~CompressedSource() { aom_codec_destroy(&enc_); }
|
||||
|
||||
const aom_codec_cx_pkt_t *ReadFrame() {
|
||||
uint8_t buf[kWidth * kHeight * 3] = { 0 };
|
||||
|
||||
// render regular pattern
|
||||
const int period = rnd_.Rand8() % 32 + 1;
|
||||
const int phase = rnd_.Rand8() % period;
|
||||
|
||||
const int val_a = rnd_.Rand8();
|
||||
const int val_b = rnd_.Rand8();
|
||||
|
||||
for (int i = 0; i < (int)sizeof buf; ++i)
|
||||
buf[i] = (i + phase) % period < period / 2 ? val_a : val_b;
|
||||
|
||||
aom_image_t img;
|
||||
aom_img_wrap(&img, format_, width_, height_, 0, buf);
|
||||
aom_codec_encode(&enc_, &img, frame_count_++, 1, 0);
|
||||
|
||||
aom_codec_iter_t iter = NULL;
|
||||
|
||||
const aom_codec_cx_pkt_t *pkt = NULL;
|
||||
|
||||
do {
|
||||
pkt = aom_codec_get_cx_data(&enc_, &iter);
|
||||
} while (pkt && pkt->kind != AOM_CODEC_CX_FRAME_PKT);
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kWidth = 128;
|
||||
static const int kHeight = 128;
|
||||
|
||||
ACMRandom rnd_;
|
||||
aom_img_fmt_t format_;
|
||||
aom_codec_ctx_t enc_;
|
||||
int frame_count_;
|
||||
int width_, height_;
|
||||
};
|
||||
|
||||
// lowers an aom_image_t to a easily comparable/printable form
|
||||
std::vector<int16_t> Serialize(const aom_image_t *img) {
|
||||
std::vector<int16_t> bytes;
|
||||
bytes.reserve(img->d_w * img->d_h * 3);
|
||||
for (int plane = 0; plane < 3; ++plane) {
|
||||
const int w = aom_img_plane_width(img, plane);
|
||||
const int h = aom_img_plane_height(img, plane);
|
||||
|
||||
for (int r = 0; r < h; ++r) {
|
||||
for (int c = 0; c < w; ++c) {
|
||||
unsigned char *row = img->planes[plane] + r * img->stride[plane];
|
||||
if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH)
|
||||
bytes.push_back(row[c * 2]);
|
||||
else
|
||||
bytes.push_back(row[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
class Decoder {
|
||||
public:
|
||||
explicit Decoder(int allowLowbitdepth) {
|
||||
aom_codec_iface_t *algo = aom_codec_av1_dx();
|
||||
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.allow_lowbitdepth = allowLowbitdepth;
|
||||
|
||||
aom_codec_dec_init(&dec_, algo, &cfg, 0);
|
||||
}
|
||||
|
||||
~Decoder() { aom_codec_destroy(&dec_); }
|
||||
|
||||
std::vector<int16_t> decode(const aom_codec_cx_pkt_t *pkt) {
|
||||
aom_codec_decode(&dec_, static_cast<uint8_t *>(pkt->data.frame.buf),
|
||||
pkt->data.frame.sz, NULL);
|
||||
|
||||
aom_codec_iter_t iter = NULL;
|
||||
return Serialize(aom_codec_get_frame(&dec_, &iter));
|
||||
}
|
||||
|
||||
private:
|
||||
aom_codec_ctx_t dec_;
|
||||
};
|
||||
|
||||
// Try to reveal a mismatch between LBD and HBD coding paths.
|
||||
TEST(CodingPathSync, SearchForHbdLbdMismatch) {
|
||||
const int count_tests = 10;
|
||||
for (int i = 0; i < count_tests; ++i) {
|
||||
Decoder dec_hbd(0);
|
||||
Decoder dec_lbd(1);
|
||||
|
||||
CompressedSource enc(i);
|
||||
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
const aom_codec_cx_pkt_t *frame = enc.ReadFrame();
|
||||
|
||||
std::vector<int16_t> lbd_yuv = dec_lbd.decode(frame);
|
||||
std::vector<int16_t> hbd_yuv = dec_hbd.decode(frame);
|
||||
|
||||
ASSERT_EQ(lbd_yuv, hbd_yuv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CodingPathSyncLarge, SearchForHbdLbdMismatchLarge) {
|
||||
const int count_tests = 100;
|
||||
const int seed = 1234;
|
||||
for (int i = 0; i < count_tests; ++i) {
|
||||
Decoder dec_hbd(0);
|
||||
Decoder dec_lbd(1);
|
||||
|
||||
CompressedSource enc(seed + i);
|
||||
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
const aom_codec_cx_pkt_t *frame = enc.ReadFrame();
|
||||
|
||||
std::vector<int16_t> lbd_yuv = dec_lbd.decode(frame);
|
||||
std::vector<int16_t> hbd_yuv = dec_hbd.decode(frame);
|
||||
|
||||
ASSERT_EQ(lbd_yuv, hbd_yuv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
72
media/libaom/src/test/comp_avg_pred_test.cc
Normal file
72
media/libaom/src/test/comp_avg_pred_test.cc
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "test/comp_avg_pred_test.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::AV1JNTCOMPAVG::AV1HighBDJNTCOMPAVGTest;
|
||||
using libaom_test::AV1JNTCOMPAVG::AV1HighBDJNTCOMPAVGUPSAMPLEDTest;
|
||||
using libaom_test::AV1JNTCOMPAVG::AV1JNTCOMPAVGTest;
|
||||
using libaom_test::AV1JNTCOMPAVG::AV1JNTCOMPAVGUPSAMPLEDTest;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST_P(AV1JNTCOMPAVGTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); }
|
||||
|
||||
TEST_P(AV1JNTCOMPAVGTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); }
|
||||
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, AV1JNTCOMPAVGTest,
|
||||
libaom_test::AV1JNTCOMPAVG::BuildParams(aom_jnt_comp_avg_pred_ssse3));
|
||||
#endif
|
||||
|
||||
TEST_P(AV1JNTCOMPAVGUPSAMPLEDTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0));
|
||||
}
|
||||
|
||||
TEST_P(AV1JNTCOMPAVGUPSAMPLEDTest, CheckOutput) {
|
||||
RunCheckOutput(GET_PARAM(0));
|
||||
}
|
||||
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, AV1JNTCOMPAVGUPSAMPLEDTest,
|
||||
libaom_test::AV1JNTCOMPAVG::BuildParams(
|
||||
aom_jnt_comp_avg_upsampled_pred_ssse3));
|
||||
#endif
|
||||
|
||||
TEST_P(AV1HighBDJNTCOMPAVGTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(1)); }
|
||||
|
||||
TEST_P(AV1HighBDJNTCOMPAVGTest, CheckOutput) { RunCheckOutput(GET_PARAM(1)); }
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, AV1HighBDJNTCOMPAVGTest,
|
||||
libaom_test::AV1JNTCOMPAVG::BuildParams(
|
||||
aom_highbd_jnt_comp_avg_pred_sse2, 1));
|
||||
#endif
|
||||
|
||||
TEST_P(AV1HighBDJNTCOMPAVGUPSAMPLEDTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(1));
|
||||
}
|
||||
|
||||
TEST_P(AV1HighBDJNTCOMPAVGUPSAMPLEDTest, CheckOutput) {
|
||||
RunCheckOutput(GET_PARAM(1));
|
||||
}
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, AV1HighBDJNTCOMPAVGUPSAMPLEDTest,
|
||||
libaom_test::AV1JNTCOMPAVG::BuildParams(
|
||||
aom_highbd_jnt_comp_avg_upsampled_pred_sse2));
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
555
media/libaom/src/test/comp_avg_pred_test.h
Normal file
555
media/libaom/src/test/comp_avg_pred_test.h
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_COMP_AVG_PRED_TEST_H_
|
||||
#define AOM_TEST_COMP_AVG_PRED_TEST_H_
|
||||
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "av1/common/common_data.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
|
||||
namespace libaom_test {
|
||||
const int kMaxSize = 128 + 32; // padding
|
||||
|
||||
namespace AV1JNTCOMPAVG {
|
||||
|
||||
typedef void (*jntcompavg_func)(uint8_t *comp_pred, const uint8_t *pred,
|
||||
int width, int height, const uint8_t *ref,
|
||||
int ref_stride,
|
||||
const JNT_COMP_PARAMS *jcp_param);
|
||||
|
||||
typedef void (*jntcompavgupsampled_func)(
|
||||
MACROBLOCKD *xd, const struct AV1Common *const cm, int mi_row, int mi_col,
|
||||
const MV *const mv, uint8_t *comp_pred, const uint8_t *pred, int width,
|
||||
int height, int subpel_x_q3, int subpel_y_q3, const uint8_t *ref,
|
||||
int ref_stride, const JNT_COMP_PARAMS *jcp_param, int subpel_search);
|
||||
|
||||
typedef void (*highbdjntcompavgupsampled_func)(
|
||||
MACROBLOCKD *xd, const struct AV1Common *const cm, int mi_row, int mi_col,
|
||||
const MV *const mv, uint8_t *comp_pred8, const uint8_t *pred8, int width,
|
||||
int height, int subpel_x_q3, int subpel_y_q3, const uint8_t *ref8,
|
||||
int ref_stride, int bd, const JNT_COMP_PARAMS *jcp_param,
|
||||
int subpel_search);
|
||||
|
||||
typedef ::testing::tuple<jntcompavg_func, BLOCK_SIZE> JNTCOMPAVGParam;
|
||||
|
||||
typedef ::testing::tuple<jntcompavgupsampled_func, BLOCK_SIZE>
|
||||
JNTCOMPAVGUPSAMPLEDParam;
|
||||
|
||||
typedef ::testing::tuple<int, jntcompavg_func, BLOCK_SIZE>
|
||||
HighbdJNTCOMPAVGParam;
|
||||
|
||||
typedef ::testing::tuple<int, highbdjntcompavgupsampled_func, BLOCK_SIZE>
|
||||
HighbdJNTCOMPAVGUPSAMPLEDParam;
|
||||
|
||||
::testing::internal::ParamGenerator<JNTCOMPAVGParam> BuildParams(
|
||||
jntcompavg_func filter) {
|
||||
return ::testing::Combine(::testing::Values(filter),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
::testing::internal::ParamGenerator<JNTCOMPAVGUPSAMPLEDParam> BuildParams(
|
||||
jntcompavgupsampled_func filter) {
|
||||
return ::testing::Combine(::testing::Values(filter),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
::testing::internal::ParamGenerator<HighbdJNTCOMPAVGParam> BuildParams(
|
||||
jntcompavg_func filter, int is_hbd) {
|
||||
(void)is_hbd;
|
||||
return ::testing::Combine(::testing::Range(8, 13, 2),
|
||||
::testing::Values(filter),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
::testing::internal::ParamGenerator<HighbdJNTCOMPAVGUPSAMPLEDParam> BuildParams(
|
||||
highbdjntcompavgupsampled_func filter) {
|
||||
return ::testing::Combine(::testing::Range(8, 13, 2),
|
||||
::testing::Values(filter),
|
||||
::testing::Range(BLOCK_4X4, BLOCK_SIZES_ALL));
|
||||
}
|
||||
|
||||
class AV1JNTCOMPAVGTest : public ::testing::TestWithParam<JNTCOMPAVGParam> {
|
||||
public:
|
||||
~AV1JNTCOMPAVGTest() {}
|
||||
void SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
|
||||
void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(jntcompavg_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(1);
|
||||
|
||||
uint8_t pred8[kMaxSize * kMaxSize];
|
||||
uint8_t ref8[kMaxSize * kMaxSize];
|
||||
uint8_t output[kMaxSize * kMaxSize];
|
||||
uint8_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand8();
|
||||
ref8[i * w + j] = rnd_.Rand8();
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
for (int ii = 0; ii < 2; ii++) {
|
||||
for (int jj = 0; jj < 4; jj++) {
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
|
||||
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - in_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - in_w - 7);
|
||||
aom_jnt_comp_avg_pred_c(output, pred8 + offset_r * w + offset_c, in_w,
|
||||
in_h, ref8 + offset_r * w + offset_c, in_w,
|
||||
&jnt_comp_params);
|
||||
test_impl(output2, pred8 + offset_r * w + offset_c, in_w, in_h,
|
||||
ref8 + offset_r * w + offset_c, in_w, &jnt_comp_params);
|
||||
|
||||
for (int i = 0; i < in_h; ++i) {
|
||||
for (int j = 0; j < in_w; ++j) {
|
||||
int idx = i * in_w + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for AV1JNTCOMPAVGTest\n"
|
||||
<< in_w << "x" << in_h << " Pixel mismatch at index " << idx
|
||||
<< " = (" << i << ", " << j << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RunSpeedTest(jntcompavg_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(1);
|
||||
|
||||
uint8_t pred8[kMaxSize * kMaxSize];
|
||||
uint8_t ref8[kMaxSize * kMaxSize];
|
||||
uint8_t output[kMaxSize * kMaxSize];
|
||||
uint8_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand8();
|
||||
ref8[i * w + j] = rnd_.Rand8();
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[0][0][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[0][0][1];
|
||||
|
||||
const int num_loops = 1000000000 / (in_w + in_h);
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
aom_jnt_comp_avg_pred_c(output, pred8, in_w, in_h, ref8, in_w,
|
||||
&jnt_comp_params);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("jntcompavg c_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time / num_loops);
|
||||
|
||||
aom_usec_timer timer1;
|
||||
aom_usec_timer_start(&timer1);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(output2, pred8, in_w, in_h, ref8, in_w, &jnt_comp_params);
|
||||
|
||||
aom_usec_timer_mark(&timer1);
|
||||
const int elapsed_time1 = static_cast<int>(aom_usec_timer_elapsed(&timer1));
|
||||
printf("jntcompavg test_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time1 / num_loops);
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
}; // class AV1JNTCOMPAVGTest
|
||||
|
||||
class AV1JNTCOMPAVGUPSAMPLEDTest
|
||||
: public ::testing::TestWithParam<JNTCOMPAVGUPSAMPLEDParam> {
|
||||
public:
|
||||
~AV1JNTCOMPAVGUPSAMPLEDTest() {}
|
||||
void SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
|
||||
void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(jntcompavgupsampled_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(1);
|
||||
|
||||
uint8_t pred8[kMaxSize * kMaxSize];
|
||||
uint8_t ref8[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(16, uint8_t, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, output2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand8();
|
||||
ref8[i * w + j] = rnd_.Rand8();
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
int sub_x_q3, sub_y_q3;
|
||||
int subpel_search;
|
||||
for (subpel_search = 1; subpel_search <= 2; ++subpel_search) {
|
||||
for (sub_x_q3 = 0; sub_x_q3 < 8; ++sub_x_q3) {
|
||||
for (sub_y_q3 = 0; sub_y_q3 < 8; ++sub_y_q3) {
|
||||
for (int ii = 0; ii < 2; ii++) {
|
||||
for (int jj = 0; jj < 4; jj++) {
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
|
||||
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - in_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - in_w - 7);
|
||||
|
||||
aom_jnt_comp_avg_upsampled_pred_c(
|
||||
NULL, NULL, 0, 0, NULL, output,
|
||||
pred8 + offset_r * w + offset_c, in_w, in_h, sub_x_q3,
|
||||
sub_y_q3, ref8 + offset_r * w + offset_c, in_w,
|
||||
&jnt_comp_params, subpel_search);
|
||||
test_impl(NULL, NULL, 0, 0, NULL, output2,
|
||||
pred8 + offset_r * w + offset_c, in_w, in_h, sub_x_q3,
|
||||
sub_y_q3, ref8 + offset_r * w + offset_c, in_w,
|
||||
&jnt_comp_params, subpel_search);
|
||||
|
||||
for (int i = 0; i < in_h; ++i) {
|
||||
for (int j = 0; j < in_w; ++j) {
|
||||
int idx = i * in_w + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for "
|
||||
"AV1JNTCOMPAVGUPSAMPLEDTest\n"
|
||||
<< in_w << "x" << in_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << sub_y_q3 << ", "
|
||||
<< sub_x_q3 << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RunSpeedTest(jntcompavgupsampled_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(1);
|
||||
|
||||
uint8_t pred8[kMaxSize * kMaxSize];
|
||||
uint8_t ref8[kMaxSize * kMaxSize];
|
||||
DECLARE_ALIGNED(16, uint8_t, output[MAX_SB_SQUARE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, output2[MAX_SB_SQUARE]);
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand8();
|
||||
ref8[i * w + j] = rnd_.Rand8();
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[0][0][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[0][0][1];
|
||||
|
||||
int sub_x_q3 = 0;
|
||||
int sub_y_q3 = 0;
|
||||
|
||||
const int num_loops = 1000000000 / (in_w + in_h);
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
int subpel_search = 2; // set to 1 to test 4-tap filter.
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
aom_jnt_comp_avg_upsampled_pred_c(NULL, NULL, 0, 0, NULL, output, pred8,
|
||||
in_w, in_h, sub_x_q3, sub_y_q3, ref8,
|
||||
in_w, &jnt_comp_params, subpel_search);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("jntcompavgupsampled c_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time / num_loops);
|
||||
|
||||
aom_usec_timer timer1;
|
||||
aom_usec_timer_start(&timer1);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(NULL, NULL, 0, 0, NULL, output2, pred8, in_w, in_h, sub_x_q3,
|
||||
sub_y_q3, ref8, in_w, &jnt_comp_params, subpel_search);
|
||||
|
||||
aom_usec_timer_mark(&timer1);
|
||||
const int elapsed_time1 = static_cast<int>(aom_usec_timer_elapsed(&timer1));
|
||||
printf("jntcompavgupsampled test_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time1 / num_loops);
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
}; // class AV1JNTCOMPAVGUPSAMPLEDTest
|
||||
|
||||
class AV1HighBDJNTCOMPAVGTest
|
||||
: public ::testing::TestWithParam<HighbdJNTCOMPAVGParam> {
|
||||
public:
|
||||
~AV1HighBDJNTCOMPAVGTest() {}
|
||||
void SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
|
||||
|
||||
void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(jntcompavg_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(2);
|
||||
const int bd = GET_PARAM(0);
|
||||
uint16_t pred8[kMaxSize * kMaxSize];
|
||||
uint16_t ref8[kMaxSize * kMaxSize];
|
||||
uint16_t output[kMaxSize * kMaxSize];
|
||||
uint16_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
ref8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
for (int ii = 0; ii < 2; ii++) {
|
||||
for (int jj = 0; jj < 4; jj++) {
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
|
||||
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - in_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - in_w - 7);
|
||||
aom_highbd_jnt_comp_avg_pred_c(
|
||||
CONVERT_TO_BYTEPTR(output),
|
||||
CONVERT_TO_BYTEPTR(pred8) + offset_r * w + offset_c, in_w, in_h,
|
||||
CONVERT_TO_BYTEPTR(ref8) + offset_r * w + offset_c, in_w,
|
||||
&jnt_comp_params);
|
||||
test_impl(CONVERT_TO_BYTEPTR(output2),
|
||||
CONVERT_TO_BYTEPTR(pred8) + offset_r * w + offset_c, in_w,
|
||||
in_h, CONVERT_TO_BYTEPTR(ref8) + offset_r * w + offset_c,
|
||||
in_w, &jnt_comp_params);
|
||||
|
||||
for (int i = 0; i < in_h; ++i) {
|
||||
for (int j = 0; j < in_w; ++j) {
|
||||
int idx = i * in_w + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for AV1HighBDJNTCOMPAVGTest\n"
|
||||
<< in_w << "x" << in_h << " Pixel mismatch at index " << idx
|
||||
<< " = (" << i << ", " << j << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RunSpeedTest(jntcompavg_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(2);
|
||||
const int bd = GET_PARAM(0);
|
||||
uint16_t pred8[kMaxSize * kMaxSize];
|
||||
uint16_t ref8[kMaxSize * kMaxSize];
|
||||
uint16_t output[kMaxSize * kMaxSize];
|
||||
uint16_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
ref8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[0][0][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[0][0][1];
|
||||
|
||||
const int num_loops = 1000000000 / (in_w + in_h);
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
aom_highbd_jnt_comp_avg_pred_c(
|
||||
CONVERT_TO_BYTEPTR(output), CONVERT_TO_BYTEPTR(pred8), in_w, in_h,
|
||||
CONVERT_TO_BYTEPTR(ref8), in_w, &jnt_comp_params);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("highbdjntcompavg c_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time / num_loops);
|
||||
|
||||
aom_usec_timer timer1;
|
||||
aom_usec_timer_start(&timer1);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(CONVERT_TO_BYTEPTR(output2), CONVERT_TO_BYTEPTR(pred8), in_w,
|
||||
in_h, CONVERT_TO_BYTEPTR(ref8), in_w, &jnt_comp_params);
|
||||
|
||||
aom_usec_timer_mark(&timer1);
|
||||
const int elapsed_time1 = static_cast<int>(aom_usec_timer_elapsed(&timer1));
|
||||
printf("highbdjntcompavg test_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time1 / num_loops);
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
}; // class AV1HighBDJNTCOMPAVGTest
|
||||
|
||||
class AV1HighBDJNTCOMPAVGUPSAMPLEDTest
|
||||
: public ::testing::TestWithParam<HighbdJNTCOMPAVGUPSAMPLEDParam> {
|
||||
public:
|
||||
~AV1HighBDJNTCOMPAVGUPSAMPLEDTest() {}
|
||||
void SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
|
||||
void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbdjntcompavgupsampled_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(2);
|
||||
const int bd = GET_PARAM(0);
|
||||
uint16_t pred8[kMaxSize * kMaxSize];
|
||||
uint16_t ref8[kMaxSize * kMaxSize];
|
||||
uint16_t output[kMaxSize * kMaxSize];
|
||||
uint16_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
ref8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
int sub_x_q3, sub_y_q3;
|
||||
int subpel_search;
|
||||
for (subpel_search = 1; subpel_search <= 2; ++subpel_search) {
|
||||
for (sub_x_q3 = 0; sub_x_q3 < 8; ++sub_x_q3) {
|
||||
for (sub_y_q3 = 0; sub_y_q3 < 8; ++sub_y_q3) {
|
||||
for (int ii = 0; ii < 2; ii++) {
|
||||
for (int jj = 0; jj < 4; jj++) {
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[ii][jj][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[ii][jj][1];
|
||||
|
||||
const int offset_r = 3 + rnd_.PseudoUniform(h - in_h - 7);
|
||||
const int offset_c = 3 + rnd_.PseudoUniform(w - in_w - 7);
|
||||
|
||||
aom_highbd_jnt_comp_avg_upsampled_pred_c(
|
||||
NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(output),
|
||||
CONVERT_TO_BYTEPTR(pred8) + offset_r * w + offset_c, in_w,
|
||||
in_h, sub_x_q3, sub_y_q3,
|
||||
CONVERT_TO_BYTEPTR(ref8) + offset_r * w + offset_c, in_w, bd,
|
||||
&jnt_comp_params, subpel_search);
|
||||
test_impl(NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(output2),
|
||||
CONVERT_TO_BYTEPTR(pred8) + offset_r * w + offset_c,
|
||||
in_w, in_h, sub_x_q3, sub_y_q3,
|
||||
CONVERT_TO_BYTEPTR(ref8) + offset_r * w + offset_c,
|
||||
in_w, bd, &jnt_comp_params, subpel_search);
|
||||
|
||||
for (int i = 0; i < in_h; ++i) {
|
||||
for (int j = 0; j < in_w; ++j) {
|
||||
int idx = i * in_w + j;
|
||||
ASSERT_EQ(output[idx], output2[idx])
|
||||
<< "Mismatch at unit tests for "
|
||||
"AV1HighBDJNTCOMPAVGUPSAMPLEDTest\n"
|
||||
<< in_w << "x" << in_h << " Pixel mismatch at index "
|
||||
<< idx << " = (" << i << ", " << j
|
||||
<< "), sub pixel offset = (" << sub_y_q3 << ", "
|
||||
<< sub_x_q3 << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RunSpeedTest(highbdjntcompavgupsampled_func test_impl) {
|
||||
const int w = kMaxSize, h = kMaxSize;
|
||||
const int block_idx = GET_PARAM(2);
|
||||
const int bd = GET_PARAM(0);
|
||||
uint16_t pred8[kMaxSize * kMaxSize];
|
||||
uint16_t ref8[kMaxSize * kMaxSize];
|
||||
uint16_t output[kMaxSize * kMaxSize];
|
||||
uint16_t output2[kMaxSize * kMaxSize];
|
||||
|
||||
for (int i = 0; i < h; ++i)
|
||||
for (int j = 0; j < w; ++j) {
|
||||
pred8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
ref8[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
}
|
||||
const int in_w = block_size_wide[block_idx];
|
||||
const int in_h = block_size_high[block_idx];
|
||||
|
||||
JNT_COMP_PARAMS jnt_comp_params;
|
||||
jnt_comp_params.use_jnt_comp_avg = 1;
|
||||
|
||||
jnt_comp_params.fwd_offset = quant_dist_lookup_table[0][0][0];
|
||||
jnt_comp_params.bck_offset = quant_dist_lookup_table[0][0][1];
|
||||
int sub_x_q3 = 0;
|
||||
int sub_y_q3 = 0;
|
||||
const int num_loops = 1000000000 / (in_w + in_h);
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
int subpel_search = 2; // set to 1 to test 4-tap filter.
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
aom_highbd_jnt_comp_avg_upsampled_pred_c(
|
||||
NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(output),
|
||||
CONVERT_TO_BYTEPTR(pred8), in_w, in_h, sub_x_q3, sub_y_q3,
|
||||
CONVERT_TO_BYTEPTR(ref8), in_w, bd, &jnt_comp_params, subpel_search);
|
||||
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("highbdjntcompavgupsampled c_code %3dx%-3d: %7.2f us\n", in_w, in_h,
|
||||
1000.0 * elapsed_time / num_loops);
|
||||
|
||||
aom_usec_timer timer1;
|
||||
aom_usec_timer_start(&timer1);
|
||||
|
||||
for (int i = 0; i < num_loops; ++i)
|
||||
test_impl(NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(output2),
|
||||
CONVERT_TO_BYTEPTR(pred8), in_w, in_h, sub_x_q3, sub_y_q3,
|
||||
CONVERT_TO_BYTEPTR(ref8), in_w, bd, &jnt_comp_params,
|
||||
subpel_search);
|
||||
|
||||
aom_usec_timer_mark(&timer1);
|
||||
const int elapsed_time1 = static_cast<int>(aom_usec_timer_elapsed(&timer1));
|
||||
printf("highbdjntcompavgupsampled test_code %3dx%-3d: %7.2f us\n", in_w,
|
||||
in_h, 1000.0 * elapsed_time1 / num_loops);
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
}; // class AV1HighBDJNTCOMPAVGUPSAMPLEDTest
|
||||
|
||||
} // namespace AV1JNTCOMPAVG
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_COMP_AVG_PRED_TEST_H_
|
||||
574
media/libaom/src/test/comp_mask_variance_test.cc
Normal file
574
media/libaom/src/test/comp_mask_variance_test.cc
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/variance.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "av1/common/reconinter.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace AV1CompMaskVariance {
|
||||
typedef void (*comp_mask_pred_func)(uint8_t *comp_pred, const uint8_t *pred,
|
||||
int width, int height, const uint8_t *ref,
|
||||
int ref_stride, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask);
|
||||
|
||||
#if HAVE_SSSE3 || HAVE_AV2
|
||||
const BLOCK_SIZE kValidBlockSize[] = {
|
||||
BLOCK_8X8, BLOCK_8X16, BLOCK_8X32, BLOCK_16X8, BLOCK_16X16,
|
||||
BLOCK_16X32, BLOCK_32X8, BLOCK_32X16, BLOCK_32X32,
|
||||
};
|
||||
#endif
|
||||
typedef ::testing::tuple<comp_mask_pred_func, BLOCK_SIZE> CompMaskPredParam;
|
||||
|
||||
class AV1CompMaskVarianceTest
|
||||
: public ::testing::TestWithParam<CompMaskPredParam> {
|
||||
public:
|
||||
~AV1CompMaskVarianceTest();
|
||||
void SetUp();
|
||||
|
||||
void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv);
|
||||
void RunSpeedTest(comp_mask_pred_func test_impl, BLOCK_SIZE bsize);
|
||||
bool CheckResult(int width, int height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const int idx = y * width + x;
|
||||
if (comp_pred1_[idx] != comp_pred2_[idx]) {
|
||||
printf("%dx%d mismatch @%d(%d,%d) ", width, height, idx, y, x);
|
||||
printf("%d != %d ", comp_pred1_[idx], comp_pred2_[idx]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
uint8_t *comp_pred1_;
|
||||
uint8_t *comp_pred2_;
|
||||
uint8_t *pred_;
|
||||
uint8_t *ref_buffer_;
|
||||
uint8_t *ref_;
|
||||
};
|
||||
|
||||
AV1CompMaskVarianceTest::~AV1CompMaskVarianceTest() { ; }
|
||||
|
||||
void AV1CompMaskVarianceTest::SetUp() {
|
||||
rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
|
||||
av1_init_wedge_masks();
|
||||
comp_pred1_ = (uint8_t *)aom_memalign(16, MAX_SB_SQUARE);
|
||||
comp_pred2_ = (uint8_t *)aom_memalign(16, MAX_SB_SQUARE);
|
||||
pred_ = (uint8_t *)aom_memalign(16, MAX_SB_SQUARE);
|
||||
ref_buffer_ = (uint8_t *)aom_memalign(16, MAX_SB_SQUARE + (8 * MAX_SB_SIZE));
|
||||
ref_ = ref_buffer_ + (8 * MAX_SB_SIZE);
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
pred_[i] = rnd_.Rand8();
|
||||
}
|
||||
for (int i = 0; i < MAX_SB_SQUARE + (8 * MAX_SB_SIZE); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand8();
|
||||
}
|
||||
}
|
||||
|
||||
void AV1CompMaskVarianceTest::TearDown() {
|
||||
aom_free(comp_pred1_);
|
||||
aom_free(comp_pred2_);
|
||||
aom_free(pred_);
|
||||
aom_free(ref_buffer_);
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
void AV1CompMaskVarianceTest::RunCheckOutput(comp_mask_pred_func test_impl,
|
||||
BLOCK_SIZE bsize, int inv) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
for (int wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
aom_comp_mask_pred_c(comp_pred1_, pred_, w, h, ref_, MAX_SB_SIZE, mask, w,
|
||||
inv);
|
||||
test_impl(comp_pred2_, pred_, w, h, ref_, MAX_SB_SIZE, mask, w, inv);
|
||||
|
||||
ASSERT_EQ(CheckResult(w, h), true)
|
||||
<< " wedge " << wedge_index << " inv " << inv;
|
||||
}
|
||||
}
|
||||
|
||||
void AV1CompMaskVarianceTest::RunSpeedTest(comp_mask_pred_func test_impl,
|
||||
BLOCK_SIZE bsize) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
int wedge_index = wedge_types / 2;
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
const int num_loops = 1000000000 / (w + h);
|
||||
|
||||
comp_mask_pred_func funcs[2] = { aom_comp_mask_pred_c, test_impl };
|
||||
double elapsed_time[2] = { 0 };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
comp_mask_pred_func func = funcs[i];
|
||||
for (int j = 0; j < num_loops; ++j) {
|
||||
func(comp_pred1_, pred_, w, h, ref_, MAX_SB_SIZE, mask, w, 0);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
elapsed_time[i] = 1000.0 * time / num_loops;
|
||||
}
|
||||
printf("compMask %3dx%-3d: %7.2f/%7.2fns", w, h, elapsed_time[0],
|
||||
elapsed_time[1]);
|
||||
printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
|
||||
}
|
||||
|
||||
TEST_P(AV1CompMaskVarianceTest, CheckOutput) {
|
||||
// inv = 0, 1
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 0);
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
TEST_P(AV1CompMaskVarianceTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0), GET_PARAM(1));
|
||||
}
|
||||
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, AV1CompMaskVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_comp_mask_pred_ssse3),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1CompMaskVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_comp_mask_pred_avx2),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
#endif
|
||||
|
||||
#ifndef aom_comp_mask_pred
|
||||
// can't run this test if aom_comp_mask_pred is defined to aom_comp_mask_pred_c
|
||||
class AV1CompMaskUpVarianceTest : public AV1CompMaskVarianceTest {
|
||||
public:
|
||||
~AV1CompMaskUpVarianceTest();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv);
|
||||
void RunSpeedTest(comp_mask_pred_func test_impl, BLOCK_SIZE bsize,
|
||||
int havSub);
|
||||
};
|
||||
|
||||
AV1CompMaskUpVarianceTest::~AV1CompMaskUpVarianceTest() { ; }
|
||||
|
||||
void AV1CompMaskUpVarianceTest::RunCheckOutput(comp_mask_pred_func test_impl,
|
||||
BLOCK_SIZE bsize, int inv) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
int subpel_search;
|
||||
for (subpel_search = 1; subpel_search <= 2; ++subpel_search) {
|
||||
// loop through subx and suby
|
||||
for (int sub = 0; sub < 8 * 8; ++sub) {
|
||||
int subx = sub & 0x7;
|
||||
int suby = (sub >> 3);
|
||||
for (int wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
|
||||
const uint8_t *mask =
|
||||
av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
// ref
|
||||
aom_comp_mask_upsampled_pred_c(
|
||||
NULL, NULL, 0, 0, NULL, comp_pred1_, pred_, w, h, subx, suby, ref_,
|
||||
MAX_SB_SIZE, mask, w, inv, subpel_search);
|
||||
|
||||
aom_comp_mask_pred = test_impl; // test
|
||||
aom_comp_mask_upsampled_pred(NULL, NULL, 0, 0, NULL, comp_pred2_, pred_,
|
||||
w, h, subx, suby, ref_, MAX_SB_SIZE, mask,
|
||||
w, inv, subpel_search);
|
||||
ASSERT_EQ(CheckResult(w, h), true)
|
||||
<< " wedge " << wedge_index << " inv " << inv << "sub (" << subx
|
||||
<< "," << suby << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AV1CompMaskUpVarianceTest::RunSpeedTest(comp_mask_pred_func test_impl,
|
||||
BLOCK_SIZE bsize, int havSub) {
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
const int subx = havSub ? 3 : 0;
|
||||
const int suby = havSub ? 4 : 0;
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
int wedge_index = wedge_types / 2;
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
const int num_loops = 1000000000 / (w + h);
|
||||
comp_mask_pred_func funcs[2] = { &aom_comp_mask_pred_c, test_impl };
|
||||
double elapsed_time[2] = { 0 };
|
||||
int subpel_search = 2; // set to 1 to test 4-tap filter.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
aom_comp_mask_pred = funcs[i];
|
||||
for (int j = 0; j < num_loops; ++j) {
|
||||
aom_comp_mask_upsampled_pred(NULL, NULL, 0, 0, NULL, comp_pred1_, pred_,
|
||||
w, h, subx, suby, ref_, MAX_SB_SIZE, mask, w,
|
||||
0, subpel_search);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
elapsed_time[i] = 1000.0 * time / num_loops;
|
||||
}
|
||||
printf("CompMaskUp[%d] %3dx%-3d:%7.2f/%7.2fns", havSub, w, h, elapsed_time[0],
|
||||
elapsed_time[1]);
|
||||
printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
|
||||
}
|
||||
|
||||
TEST_P(AV1CompMaskUpVarianceTest, CheckOutput) {
|
||||
// inv mask = 0, 1
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 0);
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
TEST_P(AV1CompMaskUpVarianceTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSSE3, AV1CompMaskUpVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_comp_mask_pred_ssse3),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1CompMaskUpVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_comp_mask_pred_avx2),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
#endif
|
||||
|
||||
#endif // ifndef aom_comp_mask_pred
|
||||
|
||||
typedef void (*highbd_comp_mask_pred_func)(uint8_t *comp_pred8,
|
||||
const uint8_t *pred8, int width,
|
||||
int height, const uint8_t *ref8,
|
||||
int ref_stride, const uint8_t *mask,
|
||||
int mask_stride, int invert_mask);
|
||||
|
||||
typedef ::testing::tuple<highbd_comp_mask_pred_func, BLOCK_SIZE, int>
|
||||
HighbdCompMaskPredParam;
|
||||
|
||||
class AV1HighbdCompMaskVarianceTest
|
||||
: public ::testing::TestWithParam<HighbdCompMaskPredParam> {
|
||||
public:
|
||||
~AV1HighbdCompMaskVarianceTest();
|
||||
void SetUp();
|
||||
|
||||
void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize,
|
||||
int inv);
|
||||
void RunSpeedTest(highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize);
|
||||
bool CheckResult(int width, int height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const int idx = y * width + x;
|
||||
if (comp_pred1_[idx] != comp_pred2_[idx]) {
|
||||
printf("%dx%d mismatch @%d(%d,%d) ", width, height, idx, y, x);
|
||||
printf("%d != %d ", comp_pred1_[idx], comp_pred2_[idx]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
uint16_t *comp_pred1_;
|
||||
uint16_t *comp_pred2_;
|
||||
uint16_t *pred_;
|
||||
uint16_t *ref_buffer_;
|
||||
uint16_t *ref_;
|
||||
};
|
||||
|
||||
AV1HighbdCompMaskVarianceTest::~AV1HighbdCompMaskVarianceTest() { ; }
|
||||
|
||||
void AV1HighbdCompMaskVarianceTest::SetUp() {
|
||||
rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
|
||||
av1_init_wedge_masks();
|
||||
|
||||
comp_pred1_ =
|
||||
(uint16_t *)aom_memalign(16, MAX_SB_SQUARE * sizeof(*comp_pred1_));
|
||||
comp_pred2_ =
|
||||
(uint16_t *)aom_memalign(16, MAX_SB_SQUARE * sizeof(*comp_pred2_));
|
||||
pred_ = (uint16_t *)aom_memalign(16, MAX_SB_SQUARE * sizeof(*pred_));
|
||||
ref_buffer_ = (uint16_t *)aom_memalign(
|
||||
16, (MAX_SB_SQUARE + (8 * MAX_SB_SIZE)) * sizeof(*ref_buffer_));
|
||||
ref_ = ref_buffer_ + (8 * MAX_SB_SIZE);
|
||||
}
|
||||
|
||||
void AV1HighbdCompMaskVarianceTest::TearDown() {
|
||||
aom_free(comp_pred1_);
|
||||
aom_free(comp_pred2_);
|
||||
aom_free(pred_);
|
||||
aom_free(ref_buffer_);
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
void AV1HighbdCompMaskVarianceTest::RunCheckOutput(
|
||||
highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv) {
|
||||
int bd_ = GET_PARAM(2);
|
||||
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
for (int i = 0; i < MAX_SB_SQUARE + (8 * MAX_SB_SIZE); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
|
||||
for (int wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
aom_highbd_comp_mask_pred_c(
|
||||
CONVERT_TO_BYTEPTR(comp_pred1_), CONVERT_TO_BYTEPTR(pred_), w, h,
|
||||
CONVERT_TO_BYTEPTR(ref_), MAX_SB_SIZE, mask, w, inv);
|
||||
|
||||
test_impl(CONVERT_TO_BYTEPTR(comp_pred2_), CONVERT_TO_BYTEPTR(pred_), w, h,
|
||||
CONVERT_TO_BYTEPTR(ref_), MAX_SB_SIZE, mask, w, inv);
|
||||
|
||||
ASSERT_EQ(CheckResult(w, h), true)
|
||||
<< " wedge " << wedge_index << " inv " << inv;
|
||||
}
|
||||
}
|
||||
|
||||
void AV1HighbdCompMaskVarianceTest::RunSpeedTest(
|
||||
highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize) {
|
||||
int bd_ = GET_PARAM(2);
|
||||
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
int wedge_index = wedge_types / 2;
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
for (int i = 0; i < MAX_SB_SQUARE + (8 * MAX_SB_SIZE); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
const int num_loops = 1000000000 / (w + h);
|
||||
|
||||
highbd_comp_mask_pred_func funcs[2] = { aom_highbd_comp_mask_pred_c,
|
||||
test_impl };
|
||||
double elapsed_time[2] = { 0 };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
highbd_comp_mask_pred_func func = funcs[i];
|
||||
for (int j = 0; j < num_loops; ++j) {
|
||||
func(CONVERT_TO_BYTEPTR(comp_pred1_), CONVERT_TO_BYTEPTR(pred_), w, h,
|
||||
CONVERT_TO_BYTEPTR(ref_), MAX_SB_SIZE, mask, w, 0);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
elapsed_time[i] = 1000.0 * time / num_loops;
|
||||
}
|
||||
printf("compMask %3dx%-3d: %7.2f/%7.2fns", w, h, elapsed_time[0],
|
||||
elapsed_time[1]);
|
||||
printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdCompMaskVarianceTest, CheckOutput) {
|
||||
// inv = 0, 1
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 0);
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdCompMaskVarianceTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0), GET_PARAM(1));
|
||||
}
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1HighbdCompMaskVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_avx2),
|
||||
::testing::ValuesIn(kValidBlockSize),
|
||||
::testing::Range(8, 13, 2)));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, AV1HighbdCompMaskVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_sse2),
|
||||
::testing::ValuesIn(kValidBlockSize),
|
||||
::testing::Range(8, 13, 2)));
|
||||
#endif
|
||||
|
||||
#ifndef aom_highbd_comp_mask_pred
|
||||
// can't run this test if aom_highbd_comp_mask_pred is defined to
|
||||
// aom_highbd_comp_mask_pred_c
|
||||
class AV1HighbdCompMaskUpVarianceTest : public AV1HighbdCompMaskVarianceTest {
|
||||
public:
|
||||
~AV1HighbdCompMaskUpVarianceTest();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize,
|
||||
int inv);
|
||||
void RunSpeedTest(highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize,
|
||||
int havSub);
|
||||
};
|
||||
|
||||
AV1HighbdCompMaskUpVarianceTest::~AV1HighbdCompMaskUpVarianceTest() { ; }
|
||||
|
||||
void AV1HighbdCompMaskUpVarianceTest::RunCheckOutput(
|
||||
highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int inv) {
|
||||
int bd_ = GET_PARAM(2);
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
for (int i = 0; i < MAX_SB_SQUARE + (8 * MAX_SB_SIZE); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
|
||||
int subpel_search;
|
||||
for (subpel_search = 1; subpel_search <= 2; ++subpel_search) {
|
||||
// loop through subx and suby
|
||||
for (int sub = 0; sub < 8 * 8; ++sub) {
|
||||
int subx = sub & 0x7;
|
||||
int suby = (sub >> 3);
|
||||
for (int wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
|
||||
const uint8_t *mask =
|
||||
av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
aom_highbd_comp_mask_pred = aom_highbd_comp_mask_pred_c; // ref
|
||||
aom_highbd_comp_mask_upsampled_pred(
|
||||
NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(comp_pred1_),
|
||||
CONVERT_TO_BYTEPTR(pred_), w, h, subx, suby,
|
||||
CONVERT_TO_BYTEPTR(ref_), MAX_SB_SIZE, mask, w, inv, bd_,
|
||||
subpel_search);
|
||||
|
||||
aom_highbd_comp_mask_pred = test_impl; // test
|
||||
aom_highbd_comp_mask_upsampled_pred(
|
||||
NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(comp_pred2_),
|
||||
CONVERT_TO_BYTEPTR(pred_), w, h, subx, suby,
|
||||
CONVERT_TO_BYTEPTR(ref_), MAX_SB_SIZE, mask, w, inv, bd_,
|
||||
subpel_search);
|
||||
ASSERT_EQ(CheckResult(w, h), true)
|
||||
<< " wedge " << wedge_index << " inv " << inv << "sub (" << subx
|
||||
<< "," << suby << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AV1HighbdCompMaskUpVarianceTest::RunSpeedTest(
|
||||
highbd_comp_mask_pred_func test_impl, BLOCK_SIZE bsize, int havSub) {
|
||||
int bd_ = GET_PARAM(2);
|
||||
const int w = block_size_wide[bsize];
|
||||
const int h = block_size_high[bsize];
|
||||
const int subx = havSub ? 3 : 0;
|
||||
const int suby = havSub ? 4 : 0;
|
||||
|
||||
int wedge_types = (1 << get_wedge_bits_lookup(bsize));
|
||||
int wedge_index = wedge_types / 2;
|
||||
const uint8_t *mask = av1_get_contiguous_soft_mask(wedge_index, 1, bsize);
|
||||
|
||||
for (int i = 0; i < MAX_SB_SQUARE; ++i) {
|
||||
pred_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
for (int i = 0; i < MAX_SB_SQUARE + (8 * MAX_SB_SIZE); ++i) {
|
||||
ref_buffer_[i] = rnd_.Rand16() & ((1 << bd_) - 1);
|
||||
}
|
||||
|
||||
const int num_loops = 1000000000 / (w + h);
|
||||
highbd_comp_mask_pred_func funcs[2] = { &aom_highbd_comp_mask_pred_c,
|
||||
test_impl };
|
||||
double elapsed_time[2] = { 0 };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
aom_highbd_comp_mask_pred = funcs[i];
|
||||
int subpel_search = 2; // set to 1 to test 4-tap filter.
|
||||
for (int j = 0; j < num_loops; ++j) {
|
||||
aom_highbd_comp_mask_upsampled_pred(
|
||||
NULL, NULL, 0, 0, NULL, CONVERT_TO_BYTEPTR(comp_pred1_),
|
||||
CONVERT_TO_BYTEPTR(pred_), w, h, subx, suby, CONVERT_TO_BYTEPTR(ref_),
|
||||
MAX_SB_SIZE, mask, w, 0, bd_, subpel_search);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
double time = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
elapsed_time[i] = 1000.0 * time / num_loops;
|
||||
}
|
||||
printf("CompMaskUp[%d] %3dx%-3d:%7.2f/%7.2fns", havSub, w, h, elapsed_time[0],
|
||||
elapsed_time[1]);
|
||||
printf("(%3.2f)\n", elapsed_time[0] / elapsed_time[1]);
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdCompMaskUpVarianceTest, CheckOutput) {
|
||||
// inv mask = 0, 1
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 0);
|
||||
RunCheckOutput(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
TEST_P(AV1HighbdCompMaskUpVarianceTest, DISABLED_Speed) {
|
||||
RunSpeedTest(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, AV1HighbdCompMaskUpVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_avx2),
|
||||
::testing::ValuesIn(kValidBlockSize),
|
||||
::testing::Range(8, 13, 2)));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, AV1HighbdCompMaskUpVarianceTest,
|
||||
::testing::Combine(::testing::Values(&aom_highbd_comp_mask_pred_sse2),
|
||||
::testing::ValuesIn(kValidBlockSize),
|
||||
::testing::Range(8, 13, 2)));
|
||||
#endif
|
||||
|
||||
#endif // ifndef aom_highbd_comp_mask_pred
|
||||
} // namespace AV1CompMaskVariance
|
||||
183
media/libaom/src/test/convolve_round_test.cc
Normal file
183
media/libaom/src/test/convolve_round_test.cc
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
#define CONVOLVE_ROUNDING_PARAM \
|
||||
const int32_t *src, int src_stride, uint8_t *dst, int dst_stride, int w, \
|
||||
int h, int bits
|
||||
|
||||
typedef void (*ConvolveRoundFunc)(CONVOLVE_ROUNDING_PARAM);
|
||||
|
||||
typedef void (*ConvolveRoundFuncHbd)(CONVOLVE_ROUNDING_PARAM, int bd);
|
||||
|
||||
template <ConvolveRoundFuncHbd fn>
|
||||
void highbd_convolve_rounding_8(CONVOLVE_ROUNDING_PARAM) {
|
||||
const int bd = 8;
|
||||
fn(src, src_stride, dst, dst_stride, w, h, bits, bd);
|
||||
}
|
||||
|
||||
template <ConvolveRoundFuncHbd fn>
|
||||
void highbd_convolve_rounding_10(CONVOLVE_ROUNDING_PARAM) {
|
||||
const int bd = 10;
|
||||
fn(src, src_stride, dst, dst_stride, w, h, bits, bd);
|
||||
}
|
||||
|
||||
template <ConvolveRoundFuncHbd fn>
|
||||
void highbd_convolve_rounding_12(CONVOLVE_ROUNDING_PARAM) {
|
||||
const int bd = 12;
|
||||
fn(src, src_stride, dst, dst_stride, w, h, bits, bd);
|
||||
}
|
||||
|
||||
typedef enum { LOWBITDEPTH_TEST, HIGHBITDEPTH_TEST } DataPathType;
|
||||
|
||||
using ::testing::tuple;
|
||||
|
||||
typedef tuple<ConvolveRoundFunc, ConvolveRoundFunc, DataPathType>
|
||||
ConvolveRoundParam;
|
||||
|
||||
const int kTestNum = 5000;
|
||||
|
||||
class ConvolveRoundTest : public ::testing::TestWithParam<ConvolveRoundParam> {
|
||||
protected:
|
||||
ConvolveRoundTest()
|
||||
: func_ref_(GET_PARAM(0)), func_(GET_PARAM(1)), data_path_(GET_PARAM(2)) {
|
||||
}
|
||||
virtual ~ConvolveRoundTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
const size_t block_size = 128 * 128;
|
||||
src_ = reinterpret_cast<int32_t *>(
|
||||
aom_memalign(16, block_size * sizeof(*src_)));
|
||||
dst_ref_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(16, block_size * sizeof(*dst_ref_)));
|
||||
dst_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(16, block_size * sizeof(*dst_)));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
aom_free(src_);
|
||||
aom_free(dst_ref_);
|
||||
aom_free(dst_);
|
||||
}
|
||||
|
||||
void ConvolveRoundingRun() {
|
||||
int test_num = 0;
|
||||
const int src_stride = 128;
|
||||
const int dst_stride = 128;
|
||||
int bits = 13;
|
||||
uint8_t *dst = 0;
|
||||
uint8_t *dst_ref = 0;
|
||||
|
||||
if (data_path_ == LOWBITDEPTH_TEST) {
|
||||
dst = reinterpret_cast<uint8_t *>(dst_);
|
||||
dst_ref = reinterpret_cast<uint8_t *>(dst_ref_);
|
||||
} else if (data_path_ == HIGHBITDEPTH_TEST) {
|
||||
dst = CONVERT_TO_BYTEPTR(dst_);
|
||||
dst_ref = CONVERT_TO_BYTEPTR(dst_ref_);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
while (test_num < kTestNum) {
|
||||
int block_size = test_num % BLOCK_SIZES_ALL;
|
||||
int w = block_size_wide[block_size];
|
||||
int h = block_size_high[block_size];
|
||||
|
||||
if (test_num % 2 == 0)
|
||||
bits -= 1;
|
||||
else
|
||||
bits += 1;
|
||||
|
||||
GenerateBufferWithRandom(src_, src_stride, bits, w, h);
|
||||
|
||||
func_ref_(src_, src_stride, dst_ref, dst_stride, w, h, bits);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
func_(src_, src_stride, dst, dst_stride, w, h, bits));
|
||||
|
||||
if (data_path_ == LOWBITDEPTH_TEST) {
|
||||
for (int r = 0; r < h; ++r) {
|
||||
for (int c = 0; c < w; ++c) {
|
||||
ASSERT_EQ(dst_ref[r * dst_stride + c], dst[r * dst_stride + c])
|
||||
<< "Mismatch at r: " << r << " c: " << c << " w: " << w
|
||||
<< " h: " << h << " test: " << test_num;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int r = 0; r < h; ++r) {
|
||||
for (int c = 0; c < w; ++c) {
|
||||
ASSERT_EQ(dst_ref_[r * dst_stride + c], dst_[r * dst_stride + c])
|
||||
<< "Mismatch at r: " << r << " c: " << c << " w: " << w
|
||||
<< " h: " << h << " test: " << test_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_num++;
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateBufferWithRandom(int32_t *src, int src_stride, int bits, int w,
|
||||
int h) {
|
||||
int32_t number;
|
||||
for (int r = 0; r < h; ++r) {
|
||||
for (int c = 0; c < w; ++c) {
|
||||
number = static_cast<int32_t>(rand_.Rand31());
|
||||
number %= 1 << (bits + 9);
|
||||
src[r * src_stride + c] = number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ACMRandom rand_;
|
||||
int32_t *src_;
|
||||
uint16_t *dst_ref_;
|
||||
uint16_t *dst_;
|
||||
|
||||
ConvolveRoundFunc func_ref_;
|
||||
ConvolveRoundFunc func_;
|
||||
DataPathType data_path_;
|
||||
};
|
||||
|
||||
TEST_P(ConvolveRoundTest, BitExactCheck) { ConvolveRoundingRun(); }
|
||||
|
||||
using ::testing::make_tuple;
|
||||
#if HAVE_AVX2
|
||||
const ConvolveRoundParam kConvRndParamArray[] = {
|
||||
make_tuple(&av1_convolve_rounding_c, &av1_convolve_rounding_avx2,
|
||||
LOWBITDEPTH_TEST),
|
||||
make_tuple(&highbd_convolve_rounding_8<av1_highbd_convolve_rounding_c>,
|
||||
&highbd_convolve_rounding_8<av1_highbd_convolve_rounding_avx2>,
|
||||
HIGHBITDEPTH_TEST),
|
||||
make_tuple(&highbd_convolve_rounding_10<av1_highbd_convolve_rounding_c>,
|
||||
&highbd_convolve_rounding_10<av1_highbd_convolve_rounding_avx2>,
|
||||
HIGHBITDEPTH_TEST),
|
||||
make_tuple(&highbd_convolve_rounding_12<av1_highbd_convolve_rounding_c>,
|
||||
&highbd_convolve_rounding_12<av1_highbd_convolve_rounding_avx2>,
|
||||
HIGHBITDEPTH_TEST)
|
||||
};
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, ConvolveRoundTest,
|
||||
::testing::ValuesIn(kConvRndParamArray));
|
||||
#endif // HAVE_AVX2
|
||||
} // namespace
|
||||
856
media/libaom/src/test/convolve_test.cc
Normal file
856
media/libaom/src/test/convolve_test.cc
Normal file
|
|
@ -0,0 +1,856 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom_dsp/aom_dsp_common.h"
|
||||
#include "aom_dsp/aom_filter.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "av1/common/filter.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static const unsigned int kMaxDimension = MAX_SB_SIZE;
|
||||
|
||||
typedef void (*ConvolveFunc)(const uint8_t *src, ptrdiff_t src_stride,
|
||||
uint8_t *dst, ptrdiff_t dst_stride,
|
||||
const int16_t *filter_x, int filter_x_stride,
|
||||
const int16_t *filter_y, int filter_y_stride,
|
||||
int w, int h);
|
||||
|
||||
struct ConvolveFunctions {
|
||||
ConvolveFunctions(ConvolveFunc copy, ConvolveFunc h8, ConvolveFunc v8, int bd)
|
||||
: copy_(copy), h8_(h8), v8_(v8), use_highbd_(bd) {}
|
||||
|
||||
ConvolveFunc copy_;
|
||||
ConvolveFunc h8_;
|
||||
ConvolveFunc v8_;
|
||||
int use_highbd_; // 0 if high bitdepth not used, else the actual bit depth.
|
||||
};
|
||||
|
||||
typedef ::testing::tuple<int, int, const ConvolveFunctions *> ConvolveParam;
|
||||
|
||||
#define ALL_SIZES_64(convolve_fn) \
|
||||
make_tuple(4, 4, &convolve_fn), make_tuple(8, 4, &convolve_fn), \
|
||||
make_tuple(4, 8, &convolve_fn), make_tuple(8, 8, &convolve_fn), \
|
||||
make_tuple(16, 8, &convolve_fn), make_tuple(8, 16, &convolve_fn), \
|
||||
make_tuple(16, 16, &convolve_fn), make_tuple(32, 16, &convolve_fn), \
|
||||
make_tuple(16, 32, &convolve_fn), make_tuple(32, 32, &convolve_fn), \
|
||||
make_tuple(64, 32, &convolve_fn), make_tuple(32, 64, &convolve_fn), \
|
||||
make_tuple(64, 64, &convolve_fn)
|
||||
|
||||
#define ALL_SIZES(convolve_fn) \
|
||||
make_tuple(128, 64, &convolve_fn), make_tuple(64, 128, &convolve_fn), \
|
||||
make_tuple(128, 128, &convolve_fn), ALL_SIZES_64(convolve_fn)
|
||||
|
||||
// Reference 8-tap subpixel filter, slightly modified to fit into this test.
|
||||
#define AV1_FILTER_WEIGHT 128
|
||||
#define AV1_FILTER_SHIFT 7
|
||||
uint8_t clip_pixel(int x) { return x < 0 ? 0 : x > 255 ? 255 : x; }
|
||||
|
||||
void filter_block2d_8_c(const uint8_t *src_ptr, unsigned int src_stride,
|
||||
const int16_t *HFilter, const int16_t *VFilter,
|
||||
uint8_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width, unsigned int output_height) {
|
||||
// Between passes, we use an intermediate buffer whose height is extended to
|
||||
// have enough horizontally filtered values as input for the vertical pass.
|
||||
// This buffer is allocated to be big enough for the largest block type we
|
||||
// support.
|
||||
const int kInterp_Extend = 4;
|
||||
const unsigned int intermediate_height =
|
||||
(kInterp_Extend - 1) + output_height + kInterp_Extend;
|
||||
unsigned int i, j;
|
||||
|
||||
assert(intermediate_height > 7);
|
||||
|
||||
// Size of intermediate_buffer is max_intermediate_height * filter_max_width,
|
||||
// where max_intermediate_height = (kInterp_Extend - 1) + filter_max_height
|
||||
// + kInterp_Extend
|
||||
// = 3 + 16 + 4
|
||||
// = 23
|
||||
// and filter_max_width = 16
|
||||
//
|
||||
uint8_t intermediate_buffer[(kMaxDimension + 8) * kMaxDimension];
|
||||
const int intermediate_next_stride =
|
||||
1 - static_cast<int>(intermediate_height * output_width);
|
||||
|
||||
// Horizontal pass (src -> transposed intermediate).
|
||||
uint8_t *output_ptr = intermediate_buffer;
|
||||
const int src_next_row_stride = src_stride - output_width;
|
||||
src_ptr -= (kInterp_Extend - 1) * src_stride + (kInterp_Extend - 1);
|
||||
for (i = 0; i < intermediate_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
// Apply filter...
|
||||
const int temp = (src_ptr[0] * HFilter[0]) + (src_ptr[1] * HFilter[1]) +
|
||||
(src_ptr[2] * HFilter[2]) + (src_ptr[3] * HFilter[3]) +
|
||||
(src_ptr[4] * HFilter[4]) + (src_ptr[5] * HFilter[5]) +
|
||||
(src_ptr[6] * HFilter[6]) + (src_ptr[7] * HFilter[7]) +
|
||||
(AV1_FILTER_WEIGHT >> 1); // Rounding
|
||||
|
||||
// Normalize back to 0-255...
|
||||
*output_ptr = clip_pixel(temp >> AV1_FILTER_SHIFT);
|
||||
++src_ptr;
|
||||
output_ptr += intermediate_height;
|
||||
}
|
||||
src_ptr += src_next_row_stride;
|
||||
output_ptr += intermediate_next_stride;
|
||||
}
|
||||
|
||||
// Vertical pass (transposed intermediate -> dst).
|
||||
src_ptr = intermediate_buffer;
|
||||
const int dst_next_row_stride = dst_stride - output_width;
|
||||
for (i = 0; i < output_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
// Apply filter...
|
||||
const int temp = (src_ptr[0] * VFilter[0]) + (src_ptr[1] * VFilter[1]) +
|
||||
(src_ptr[2] * VFilter[2]) + (src_ptr[3] * VFilter[3]) +
|
||||
(src_ptr[4] * VFilter[4]) + (src_ptr[5] * VFilter[5]) +
|
||||
(src_ptr[6] * VFilter[6]) + (src_ptr[7] * VFilter[7]) +
|
||||
(AV1_FILTER_WEIGHT >> 1); // Rounding
|
||||
|
||||
// Normalize back to 0-255...
|
||||
*dst_ptr++ = clip_pixel(temp >> AV1_FILTER_SHIFT);
|
||||
src_ptr += intermediate_height;
|
||||
}
|
||||
src_ptr += intermediate_next_stride;
|
||||
dst_ptr += dst_next_row_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void block2d_average_c(uint8_t *src, unsigned int src_stride,
|
||||
uint8_t *output_ptr, unsigned int output_stride,
|
||||
unsigned int output_width, unsigned int output_height) {
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < output_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
output_ptr[j] = (output_ptr[j] + src[i * src_stride + j] + 1) >> 1;
|
||||
}
|
||||
output_ptr += output_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void filter_average_block2d_8_c(const uint8_t *src_ptr,
|
||||
const unsigned int src_stride,
|
||||
const int16_t *HFilter, const int16_t *VFilter,
|
||||
uint8_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width,
|
||||
unsigned int output_height) {
|
||||
uint8_t tmp[kMaxDimension * kMaxDimension];
|
||||
|
||||
assert(output_width <= kMaxDimension);
|
||||
assert(output_height <= kMaxDimension);
|
||||
filter_block2d_8_c(src_ptr, src_stride, HFilter, VFilter, tmp, kMaxDimension,
|
||||
output_width, output_height);
|
||||
block2d_average_c(tmp, kMaxDimension, dst_ptr, dst_stride, output_width,
|
||||
output_height);
|
||||
}
|
||||
|
||||
void highbd_filter_block2d_8_c(const uint16_t *src_ptr,
|
||||
const unsigned int src_stride,
|
||||
const int16_t *HFilter, const int16_t *VFilter,
|
||||
uint16_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width,
|
||||
unsigned int output_height, int bd) {
|
||||
// Between passes, we use an intermediate buffer whose height is extended to
|
||||
// have enough horizontally filtered values as input for the vertical pass.
|
||||
// This buffer is allocated to be big enough for the largest block type we
|
||||
// support.
|
||||
const int kInterp_Extend = 4;
|
||||
const unsigned int intermediate_height =
|
||||
(kInterp_Extend - 1) + output_height + kInterp_Extend;
|
||||
|
||||
/* Size of intermediate_buffer is max_intermediate_height * filter_max_width,
|
||||
* where max_intermediate_height = (kInterp_Extend - 1) + filter_max_height
|
||||
* + kInterp_Extend
|
||||
* = 3 + 16 + 4
|
||||
* = 23
|
||||
* and filter_max_width = 16
|
||||
*/
|
||||
uint16_t intermediate_buffer[(kMaxDimension + 8) * kMaxDimension] = { 0 };
|
||||
const int intermediate_next_stride =
|
||||
1 - static_cast<int>(intermediate_height * output_width);
|
||||
|
||||
// Horizontal pass (src -> transposed intermediate).
|
||||
{
|
||||
uint16_t *output_ptr = intermediate_buffer;
|
||||
const int src_next_row_stride = src_stride - output_width;
|
||||
unsigned int i, j;
|
||||
src_ptr -= (kInterp_Extend - 1) * src_stride + (kInterp_Extend - 1);
|
||||
for (i = 0; i < intermediate_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
// Apply filter...
|
||||
const int temp = (src_ptr[0] * HFilter[0]) + (src_ptr[1] * HFilter[1]) +
|
||||
(src_ptr[2] * HFilter[2]) + (src_ptr[3] * HFilter[3]) +
|
||||
(src_ptr[4] * HFilter[4]) + (src_ptr[5] * HFilter[5]) +
|
||||
(src_ptr[6] * HFilter[6]) + (src_ptr[7] * HFilter[7]) +
|
||||
(AV1_FILTER_WEIGHT >> 1); // Rounding
|
||||
|
||||
// Normalize back to 0-255...
|
||||
*output_ptr = clip_pixel_highbd(temp >> AV1_FILTER_SHIFT, bd);
|
||||
++src_ptr;
|
||||
output_ptr += intermediate_height;
|
||||
}
|
||||
src_ptr += src_next_row_stride;
|
||||
output_ptr += intermediate_next_stride;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical pass (transposed intermediate -> dst).
|
||||
{
|
||||
const uint16_t *interm_ptr = intermediate_buffer;
|
||||
const int dst_next_row_stride = dst_stride - output_width;
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < output_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
// Apply filter...
|
||||
const int temp =
|
||||
(interm_ptr[0] * VFilter[0]) + (interm_ptr[1] * VFilter[1]) +
|
||||
(interm_ptr[2] * VFilter[2]) + (interm_ptr[3] * VFilter[3]) +
|
||||
(interm_ptr[4] * VFilter[4]) + (interm_ptr[5] * VFilter[5]) +
|
||||
(interm_ptr[6] * VFilter[6]) + (interm_ptr[7] * VFilter[7]) +
|
||||
(AV1_FILTER_WEIGHT >> 1); // Rounding
|
||||
|
||||
// Normalize back to 0-255...
|
||||
*dst_ptr++ = clip_pixel_highbd(temp >> AV1_FILTER_SHIFT, bd);
|
||||
interm_ptr += intermediate_height;
|
||||
}
|
||||
interm_ptr += intermediate_next_stride;
|
||||
dst_ptr += dst_next_row_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void highbd_block2d_average_c(uint16_t *src, unsigned int src_stride,
|
||||
uint16_t *output_ptr, unsigned int output_stride,
|
||||
unsigned int output_width,
|
||||
unsigned int output_height) {
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < output_height; ++i) {
|
||||
for (j = 0; j < output_width; ++j) {
|
||||
output_ptr[j] = (output_ptr[j] + src[i * src_stride + j] + 1) >> 1;
|
||||
}
|
||||
output_ptr += output_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void highbd_filter_average_block2d_8_c(
|
||||
const uint16_t *src_ptr, unsigned int src_stride, const int16_t *HFilter,
|
||||
const int16_t *VFilter, uint16_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width, unsigned int output_height, int bd) {
|
||||
uint16_t tmp[kMaxDimension * kMaxDimension];
|
||||
|
||||
assert(output_width <= kMaxDimension);
|
||||
assert(output_height <= kMaxDimension);
|
||||
highbd_filter_block2d_8_c(src_ptr, src_stride, HFilter, VFilter, tmp,
|
||||
kMaxDimension, output_width, output_height, bd);
|
||||
highbd_block2d_average_c(tmp, kMaxDimension, dst_ptr, dst_stride,
|
||||
output_width, output_height);
|
||||
}
|
||||
|
||||
class ConvolveTest : public ::testing::TestWithParam<ConvolveParam> {
|
||||
public:
|
||||
static void SetUpTestCase() {
|
||||
// Force input_ to be unaligned, output to be 16 byte aligned.
|
||||
input_ = reinterpret_cast<uint8_t *>(
|
||||
aom_memalign(kDataAlignment, kInputBufferSize + 1)) +
|
||||
1;
|
||||
output_ = reinterpret_cast<uint8_t *>(
|
||||
aom_memalign(kDataAlignment, kOutputBufferSize));
|
||||
output_ref_ = reinterpret_cast<uint8_t *>(
|
||||
aom_memalign(kDataAlignment, kOutputBufferSize));
|
||||
input16_ = reinterpret_cast<uint16_t *>(aom_memalign(
|
||||
kDataAlignment, (kInputBufferSize + 1) * sizeof(uint16_t))) +
|
||||
1;
|
||||
output16_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(kDataAlignment, (kOutputBufferSize) * sizeof(uint16_t)));
|
||||
output16_ref_ = reinterpret_cast<uint16_t *>(
|
||||
aom_memalign(kDataAlignment, (kOutputBufferSize) * sizeof(uint16_t)));
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
static void TearDownTestCase() {
|
||||
aom_free(input_ - 1);
|
||||
input_ = NULL;
|
||||
aom_free(output_);
|
||||
output_ = NULL;
|
||||
aom_free(output_ref_);
|
||||
output_ref_ = NULL;
|
||||
aom_free(input16_ - 1);
|
||||
input16_ = NULL;
|
||||
aom_free(output16_);
|
||||
output16_ = NULL;
|
||||
aom_free(output16_ref_);
|
||||
output16_ref_ = NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
static const int kDataAlignment = 16;
|
||||
static const int kOuterBlockSize = 4 * kMaxDimension;
|
||||
static const int kInputStride = kOuterBlockSize;
|
||||
static const int kOutputStride = kOuterBlockSize;
|
||||
static const int kInputBufferSize = kOuterBlockSize * kOuterBlockSize;
|
||||
static const int kOutputBufferSize = kOuterBlockSize * kOuterBlockSize;
|
||||
|
||||
int Width() const { return GET_PARAM(0); }
|
||||
int Height() const { return GET_PARAM(1); }
|
||||
int BorderLeft() const {
|
||||
const int center = (kOuterBlockSize - Width()) / 2;
|
||||
return (center + (kDataAlignment - 1)) & ~(kDataAlignment - 1);
|
||||
}
|
||||
int BorderTop() const { return (kOuterBlockSize - Height()) / 2; }
|
||||
|
||||
bool IsIndexInBorder(int i) {
|
||||
return (i < BorderTop() * kOuterBlockSize ||
|
||||
i >= (BorderTop() + Height()) * kOuterBlockSize ||
|
||||
i % kOuterBlockSize < BorderLeft() ||
|
||||
i % kOuterBlockSize >= (BorderLeft() + Width()));
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
UUT_ = GET_PARAM(2);
|
||||
if (UUT_->use_highbd_ != 0)
|
||||
mask_ = (1 << UUT_->use_highbd_) - 1;
|
||||
else
|
||||
mask_ = 255;
|
||||
/* Set up guard blocks for an inner block centered in the outer block */
|
||||
for (int i = 0; i < kOutputBufferSize; ++i) {
|
||||
if (IsIndexInBorder(i)) {
|
||||
output_[i] = 255;
|
||||
output16_[i] = mask_;
|
||||
} else {
|
||||
output_[i] = 0;
|
||||
output16_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
::libaom_test::ACMRandom prng;
|
||||
for (int i = 0; i < kInputBufferSize; ++i) {
|
||||
if (i & 1) {
|
||||
input_[i] = 255;
|
||||
input16_[i] = mask_;
|
||||
} else {
|
||||
input_[i] = prng.Rand8Extremes();
|
||||
input16_[i] = prng.Rand16() & mask_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetConstantInput(int value) {
|
||||
memset(input_, value, kInputBufferSize);
|
||||
aom_memset16(input16_, value, kInputBufferSize);
|
||||
}
|
||||
|
||||
void CopyOutputToRef() {
|
||||
memcpy(output_ref_, output_, kOutputBufferSize);
|
||||
// Copy 16-bit pixels values. The effective number of bytes is double.
|
||||
memcpy(output16_ref_, output16_, sizeof(output16_[0]) * kOutputBufferSize);
|
||||
}
|
||||
|
||||
void CheckGuardBlocks() {
|
||||
for (int i = 0; i < kOutputBufferSize; ++i) {
|
||||
if (IsIndexInBorder(i)) {
|
||||
EXPECT_EQ(255, output_[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *input() const {
|
||||
const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
return input_ + offset;
|
||||
} else {
|
||||
return CONVERT_TO_BYTEPTR(input16_) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *output() const {
|
||||
const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
return output_ + offset;
|
||||
} else {
|
||||
return CONVERT_TO_BYTEPTR(output16_) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *output_ref() const {
|
||||
const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
return output_ref_ + offset;
|
||||
} else {
|
||||
return CONVERT_TO_BYTEPTR(output16_ref_) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t lookup(uint8_t *list, int index) const {
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
return list[index];
|
||||
} else {
|
||||
return CONVERT_TO_SHORTPTR(list)[index];
|
||||
}
|
||||
}
|
||||
|
||||
void assign_val(uint8_t *list, int index, uint16_t val) const {
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
list[index] = (uint8_t)val;
|
||||
} else {
|
||||
CONVERT_TO_SHORTPTR(list)[index] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void wrapper_filter_average_block2d_8_c(
|
||||
const uint8_t *src_ptr, unsigned int src_stride, const int16_t *HFilter,
|
||||
const int16_t *VFilter, uint8_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width, unsigned int output_height) {
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
filter_average_block2d_8_c(src_ptr, src_stride, HFilter, VFilter, dst_ptr,
|
||||
dst_stride, output_width, output_height);
|
||||
} else {
|
||||
highbd_filter_average_block2d_8_c(
|
||||
CONVERT_TO_SHORTPTR(src_ptr), src_stride, HFilter, VFilter,
|
||||
CONVERT_TO_SHORTPTR(dst_ptr), dst_stride, output_width, output_height,
|
||||
UUT_->use_highbd_);
|
||||
}
|
||||
}
|
||||
|
||||
void wrapper_filter_block2d_8_c(
|
||||
const uint8_t *src_ptr, unsigned int src_stride, const int16_t *HFilter,
|
||||
const int16_t *VFilter, uint8_t *dst_ptr, unsigned int dst_stride,
|
||||
unsigned int output_width, unsigned int output_height) {
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
filter_block2d_8_c(src_ptr, src_stride, HFilter, VFilter, dst_ptr,
|
||||
dst_stride, output_width, output_height);
|
||||
} else {
|
||||
highbd_filter_block2d_8_c(CONVERT_TO_SHORTPTR(src_ptr), src_stride,
|
||||
HFilter, VFilter, CONVERT_TO_SHORTPTR(dst_ptr),
|
||||
dst_stride, output_width, output_height,
|
||||
UUT_->use_highbd_);
|
||||
}
|
||||
}
|
||||
|
||||
const ConvolveFunctions *UUT_;
|
||||
static uint8_t *input_;
|
||||
static uint8_t *output_;
|
||||
static uint8_t *output_ref_;
|
||||
static uint16_t *input16_;
|
||||
static uint16_t *output16_;
|
||||
static uint16_t *output16_ref_;
|
||||
int mask_;
|
||||
};
|
||||
|
||||
uint8_t *ConvolveTest::input_ = NULL;
|
||||
uint8_t *ConvolveTest::output_ = NULL;
|
||||
uint8_t *ConvolveTest::output_ref_ = NULL;
|
||||
uint16_t *ConvolveTest::input16_ = NULL;
|
||||
uint16_t *ConvolveTest::output16_ = NULL;
|
||||
uint16_t *ConvolveTest::output16_ref_ = NULL;
|
||||
|
||||
TEST_P(ConvolveTest, GuardBlocks) { CheckGuardBlocks(); }
|
||||
|
||||
TEST_P(ConvolveTest, Copy) {
|
||||
uint8_t *const in = input();
|
||||
uint8_t *const out = output();
|
||||
|
||||
ASM_REGISTER_STATE_CHECK(UUT_->copy_(in, kInputStride, out, kOutputStride,
|
||||
NULL, 0, NULL, 0, Width(), Height()));
|
||||
|
||||
CheckGuardBlocks();
|
||||
|
||||
for (int y = 0; y < Height(); ++y)
|
||||
for (int x = 0; x < Width(); ++x)
|
||||
ASSERT_EQ(lookup(out, y * kOutputStride + x),
|
||||
lookup(in, y * kInputStride + x))
|
||||
<< "(" << x << "," << y << ")";
|
||||
}
|
||||
|
||||
const int kNumFilterBanks = SWITCHABLE_FILTERS;
|
||||
const int kNumFilters = 16;
|
||||
|
||||
TEST(ConvolveTest, FiltersWontSaturateWhenAddedPairwise) {
|
||||
for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
|
||||
const InterpFilter filter = (InterpFilter)filter_bank;
|
||||
const InterpKernel *filters =
|
||||
(const InterpKernel *)av1_get_interp_filter_kernel(filter);
|
||||
const InterpFilterParams *filter_params =
|
||||
av1_get_interp_filter_params_with_block_size(filter, 8);
|
||||
if (filter_params->taps != SUBPEL_TAPS) continue;
|
||||
for (int i = 0; i < kNumFilters; i++) {
|
||||
const int p0 = filters[i][0] + filters[i][1];
|
||||
const int p1 = filters[i][2] + filters[i][3];
|
||||
const int p2 = filters[i][4] + filters[i][5];
|
||||
const int p3 = filters[i][6] + filters[i][7];
|
||||
EXPECT_LE(p0, 128);
|
||||
EXPECT_LE(p1, 128);
|
||||
EXPECT_LE(p2, 128);
|
||||
EXPECT_LE(p3, 128);
|
||||
EXPECT_LE(p0 + p3, 128);
|
||||
EXPECT_LE(p0 + p3 + p1, 128);
|
||||
EXPECT_LE(p0 + p3 + p1 + p2, 128);
|
||||
EXPECT_EQ(p0 + p1 + p2 + p3, 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int16_t kInvalidFilter[8] = { 0 };
|
||||
|
||||
TEST_P(ConvolveTest, MatchesReferenceSubpixelFilter) {
|
||||
uint8_t *const in = input();
|
||||
uint8_t *const out = output();
|
||||
uint8_t ref8[kOutputStride * kMaxDimension];
|
||||
uint16_t ref16[kOutputStride * kMaxDimension];
|
||||
uint8_t *ref;
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
ref = ref8;
|
||||
} else {
|
||||
ref = CONVERT_TO_BYTEPTR(ref16);
|
||||
}
|
||||
|
||||
for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
|
||||
const InterpFilter filter = (InterpFilter)filter_bank;
|
||||
const InterpKernel *filters =
|
||||
(const InterpKernel *)av1_get_interp_filter_kernel(filter);
|
||||
const InterpFilterParams *filter_params =
|
||||
av1_get_interp_filter_params_with_block_size(filter, 8);
|
||||
if (filter_params->taps != SUBPEL_TAPS) continue;
|
||||
|
||||
for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
|
||||
for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
|
||||
wrapper_filter_block2d_8_c(in, kInputStride, filters[filter_x],
|
||||
filters[filter_y], ref, kOutputStride,
|
||||
Width(), Height());
|
||||
|
||||
if (filter_x && filter_y)
|
||||
continue;
|
||||
else if (filter_y)
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
UUT_->v8_(in, kInputStride, out, kOutputStride, kInvalidFilter,
|
||||
16, filters[filter_y], 16, Width(), Height()));
|
||||
else if (filter_x)
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
UUT_->h8_(in, kInputStride, out, kOutputStride, filters[filter_x],
|
||||
16, kInvalidFilter, 16, Width(), Height()));
|
||||
else
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
UUT_->copy_(in, kInputStride, out, kOutputStride, kInvalidFilter,
|
||||
0, kInvalidFilter, 0, Width(), Height()));
|
||||
|
||||
CheckGuardBlocks();
|
||||
|
||||
for (int y = 0; y < Height(); ++y)
|
||||
for (int x = 0; x < Width(); ++x)
|
||||
ASSERT_EQ(lookup(ref, y * kOutputStride + x),
|
||||
lookup(out, y * kOutputStride + x))
|
||||
<< "mismatch at (" << x << "," << y << "), "
|
||||
<< "filters (" << filter_bank << "," << filter_x << ","
|
||||
<< filter_y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ConvolveTest, FilterExtremes) {
|
||||
uint8_t *const in = input();
|
||||
uint8_t *const out = output();
|
||||
uint8_t ref8[kOutputStride * kMaxDimension];
|
||||
uint16_t ref16[kOutputStride * kMaxDimension];
|
||||
uint8_t *ref;
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
ref = ref8;
|
||||
} else {
|
||||
ref = CONVERT_TO_BYTEPTR(ref16);
|
||||
}
|
||||
|
||||
// Populate ref and out with some random data
|
||||
::libaom_test::ACMRandom prng;
|
||||
for (int y = 0; y < Height(); ++y) {
|
||||
for (int x = 0; x < Width(); ++x) {
|
||||
uint16_t r;
|
||||
if (UUT_->use_highbd_ == 0 || UUT_->use_highbd_ == 8) {
|
||||
r = prng.Rand8Extremes();
|
||||
} else {
|
||||
r = prng.Rand16() & mask_;
|
||||
}
|
||||
assign_val(out, y * kOutputStride + x, r);
|
||||
assign_val(ref, y * kOutputStride + x, r);
|
||||
}
|
||||
}
|
||||
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
int seed_val = 0;
|
||||
while (seed_val < 256) {
|
||||
for (int y = 0; y < 8; ++y) {
|
||||
for (int x = 0; x < 8; ++x) {
|
||||
assign_val(in, y * kOutputStride + x - SUBPEL_TAPS / 2 + 1,
|
||||
((seed_val >> (axis ? y : x)) & 1) * mask_);
|
||||
if (axis) seed_val++;
|
||||
}
|
||||
if (axis)
|
||||
seed_val -= 8;
|
||||
else
|
||||
seed_val++;
|
||||
}
|
||||
if (axis) seed_val += 8;
|
||||
|
||||
for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
|
||||
const InterpFilter filter = (InterpFilter)filter_bank;
|
||||
const InterpKernel *filters =
|
||||
(const InterpKernel *)av1_get_interp_filter_kernel(filter);
|
||||
const InterpFilterParams *filter_params =
|
||||
av1_get_interp_filter_params_with_block_size(filter, 8);
|
||||
if (filter_params->taps != SUBPEL_TAPS) continue;
|
||||
for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
|
||||
for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
|
||||
wrapper_filter_block2d_8_c(in, kInputStride, filters[filter_x],
|
||||
filters[filter_y], ref, kOutputStride,
|
||||
Width(), Height());
|
||||
if (filter_x && filter_y)
|
||||
continue;
|
||||
else if (filter_y)
|
||||
ASM_REGISTER_STATE_CHECK(UUT_->v8_(
|
||||
in, kInputStride, out, kOutputStride, kInvalidFilter, 16,
|
||||
filters[filter_y], 16, Width(), Height()));
|
||||
else if (filter_x)
|
||||
ASM_REGISTER_STATE_CHECK(UUT_->h8_(
|
||||
in, kInputStride, out, kOutputStride, filters[filter_x], 16,
|
||||
kInvalidFilter, 16, Width(), Height()));
|
||||
else
|
||||
ASM_REGISTER_STATE_CHECK(UUT_->copy_(
|
||||
in, kInputStride, out, kOutputStride, kInvalidFilter, 0,
|
||||
kInvalidFilter, 0, Width(), Height()));
|
||||
|
||||
for (int y = 0; y < Height(); ++y)
|
||||
for (int x = 0; x < Width(); ++x)
|
||||
ASSERT_EQ(lookup(ref, y * kOutputStride + x),
|
||||
lookup(out, y * kOutputStride + x))
|
||||
<< "mismatch at (" << x << "," << y << "), "
|
||||
<< "filters (" << filter_bank << "," << filter_x << ","
|
||||
<< filter_y << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ConvolveTest, DISABLED_Copy_Speed) {
|
||||
const uint8_t *const in = input();
|
||||
uint8_t *const out = output();
|
||||
const int kNumTests = 5000000;
|
||||
const int width = Width();
|
||||
const int height = Height();
|
||||
aom_usec_timer timer;
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int n = 0; n < kNumTests; ++n) {
|
||||
UUT_->copy_(in, kInputStride, out, kOutputStride, NULL, 0, NULL, 0, width,
|
||||
height);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("convolve_copy_%dx%d_%d: %d us\n", width, height,
|
||||
UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
|
||||
}
|
||||
|
||||
TEST_P(ConvolveTest, DISABLED_Speed) {
|
||||
uint8_t *const in = input();
|
||||
uint8_t *const out = output();
|
||||
uint8_t ref8[kOutputStride * kMaxDimension];
|
||||
uint16_t ref16[kOutputStride * kMaxDimension];
|
||||
uint8_t *ref;
|
||||
if (UUT_->use_highbd_ == 0) {
|
||||
ref = ref8;
|
||||
} else {
|
||||
ref = CONVERT_TO_BYTEPTR(ref16);
|
||||
}
|
||||
|
||||
// Populate ref and out with some random data
|
||||
::libaom_test::ACMRandom prng;
|
||||
for (int y = 0; y < Height(); ++y) {
|
||||
for (int x = 0; x < Width(); ++x) {
|
||||
uint16_t r;
|
||||
if (UUT_->use_highbd_ == 0 || UUT_->use_highbd_ == 8) {
|
||||
r = prng.Rand8Extremes();
|
||||
} else {
|
||||
r = prng.Rand16() & mask_;
|
||||
}
|
||||
assign_val(out, y * kOutputStride + x, r);
|
||||
assign_val(ref, y * kOutputStride + x, r);
|
||||
}
|
||||
}
|
||||
|
||||
const InterpFilter filter = (InterpFilter)1;
|
||||
const InterpKernel *filters =
|
||||
(const InterpKernel *)av1_get_interp_filter_kernel(filter);
|
||||
wrapper_filter_average_block2d_8_c(in, kInputStride, filters[1], filters[1],
|
||||
out, kOutputStride, Width(), Height());
|
||||
|
||||
aom_usec_timer timer;
|
||||
int tests_num = 1000;
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
while (tests_num > 0) {
|
||||
for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
|
||||
const InterpFilter filter = (InterpFilter)filter_bank;
|
||||
const InterpKernel *filters =
|
||||
(const InterpKernel *)av1_get_interp_filter_kernel(filter);
|
||||
const InterpFilterParams *filter_params =
|
||||
av1_get_interp_filter_params_with_block_size(filter, 8);
|
||||
if (filter_params->taps != SUBPEL_TAPS) continue;
|
||||
|
||||
for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
|
||||
for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
|
||||
if (filter_x && filter_y) continue;
|
||||
if (filter_y)
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
UUT_->v8_(in, kInputStride, out, kOutputStride, kInvalidFilter,
|
||||
16, filters[filter_y], 16, Width(), Height()));
|
||||
else if (filter_x)
|
||||
ASM_REGISTER_STATE_CHECK(UUT_->h8_(
|
||||
in, kInputStride, out, kOutputStride, filters[filter_x], 16,
|
||||
kInvalidFilter, 16, Width(), Height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
tests_num--;
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
|
||||
const int elapsed_time =
|
||||
static_cast<int>(aom_usec_timer_elapsed(&timer) / 1000);
|
||||
printf("%dx%d (bitdepth %d) time: %5d ms\n", Width(), Height(),
|
||||
UUT_->use_highbd_, elapsed_time);
|
||||
}
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
#define WRAP(func, bd) \
|
||||
static void wrap_##func##_##bd( \
|
||||
const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst, \
|
||||
ptrdiff_t dst_stride, const int16_t *filter_x, int filter_x_stride, \
|
||||
const int16_t *filter_y, int filter_y_stride, int w, int h) { \
|
||||
aom_highbd_##func(src, src_stride, dst, dst_stride, filter_x, \
|
||||
filter_x_stride, filter_y, filter_y_stride, w, h, bd); \
|
||||
}
|
||||
#if HAVE_SSE2 && ARCH_X86_64
|
||||
WRAP(convolve_copy_sse2, 8)
|
||||
WRAP(convolve_copy_sse2, 10)
|
||||
WRAP(convolve_copy_sse2, 12)
|
||||
WRAP(convolve8_horiz_sse2, 8)
|
||||
WRAP(convolve8_vert_sse2, 8)
|
||||
WRAP(convolve8_horiz_sse2, 10)
|
||||
WRAP(convolve8_vert_sse2, 10)
|
||||
WRAP(convolve8_horiz_sse2, 12)
|
||||
WRAP(convolve8_vert_sse2, 12)
|
||||
#endif // HAVE_SSE2 && ARCH_X86_64
|
||||
|
||||
WRAP(convolve_copy_c, 8)
|
||||
WRAP(convolve8_horiz_c, 8)
|
||||
WRAP(convolve8_vert_c, 8)
|
||||
WRAP(convolve_copy_c, 10)
|
||||
WRAP(convolve8_horiz_c, 10)
|
||||
WRAP(convolve8_vert_c, 10)
|
||||
WRAP(convolve_copy_c, 12)
|
||||
WRAP(convolve8_horiz_c, 12)
|
||||
WRAP(convolve8_vert_c, 12)
|
||||
|
||||
#if HAVE_AVX2
|
||||
WRAP(convolve_copy_avx2, 8)
|
||||
WRAP(convolve8_horiz_avx2, 8)
|
||||
WRAP(convolve8_vert_avx2, 8)
|
||||
|
||||
WRAP(convolve_copy_avx2, 10)
|
||||
WRAP(convolve8_horiz_avx2, 10)
|
||||
WRAP(convolve8_vert_avx2, 10)
|
||||
|
||||
WRAP(convolve_copy_avx2, 12)
|
||||
WRAP(convolve8_horiz_avx2, 12)
|
||||
WRAP(convolve8_vert_avx2, 12)
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
#undef WRAP
|
||||
|
||||
const ConvolveFunctions convolve8_c(wrap_convolve_copy_c_8,
|
||||
wrap_convolve8_horiz_c_8,
|
||||
wrap_convolve8_vert_c_8, 8);
|
||||
const ConvolveFunctions convolve10_c(wrap_convolve_copy_c_10,
|
||||
wrap_convolve8_horiz_c_10,
|
||||
wrap_convolve8_vert_c_10, 10);
|
||||
const ConvolveFunctions convolve12_c(wrap_convolve_copy_c_12,
|
||||
wrap_convolve8_horiz_c_12,
|
||||
wrap_convolve8_vert_c_12, 12);
|
||||
const ConvolveParam kArrayConvolve_c[] = {
|
||||
ALL_SIZES(convolve8_c), ALL_SIZES(convolve10_c), ALL_SIZES(convolve12_c)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, ConvolveTest, ::testing::ValuesIn(kArrayConvolve_c));
|
||||
|
||||
#if HAVE_SSE2 && ARCH_X86_64
|
||||
const ConvolveFunctions convolve8_sse2(wrap_convolve_copy_sse2_8,
|
||||
wrap_convolve8_horiz_sse2_8,
|
||||
wrap_convolve8_vert_sse2_8, 8);
|
||||
const ConvolveFunctions convolve10_sse2(wrap_convolve_copy_sse2_10,
|
||||
wrap_convolve8_horiz_sse2_10,
|
||||
wrap_convolve8_vert_sse2_10, 10);
|
||||
const ConvolveFunctions convolve12_sse2(wrap_convolve_copy_sse2_12,
|
||||
wrap_convolve8_horiz_sse2_12,
|
||||
wrap_convolve8_vert_sse2_12, 12);
|
||||
const ConvolveParam kArrayConvolve_sse2[] = { ALL_SIZES(convolve8_sse2),
|
||||
ALL_SIZES(convolve10_sse2),
|
||||
ALL_SIZES(convolve12_sse2) };
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, ConvolveTest,
|
||||
::testing::ValuesIn(kArrayConvolve_sse2));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSSE3
|
||||
const ConvolveFunctions convolve8_ssse3(aom_convolve_copy_c,
|
||||
aom_convolve8_horiz_ssse3,
|
||||
aom_convolve8_vert_ssse3, 0);
|
||||
|
||||
const ConvolveParam kArrayConvolve8_ssse3[] = { ALL_SIZES(convolve8_ssse3) };
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, ConvolveTest,
|
||||
::testing::ValuesIn(kArrayConvolve8_ssse3));
|
||||
#endif
|
||||
|
||||
#if HAVE_AVX2
|
||||
const ConvolveFunctions convolve8_avx2(aom_convolve_copy_c,
|
||||
aom_convolve8_horiz_avx2,
|
||||
aom_convolve8_vert_avx2, 0);
|
||||
|
||||
const ConvolveFunctions wrap_convolve8_avx2(wrap_convolve_copy_avx2_8,
|
||||
wrap_convolve8_horiz_avx2_8,
|
||||
wrap_convolve8_vert_avx2_8, 8);
|
||||
const ConvolveFunctions wrap_convolve10_avx2(wrap_convolve_copy_avx2_10,
|
||||
wrap_convolve8_horiz_avx2_10,
|
||||
wrap_convolve8_vert_avx2_10, 10);
|
||||
const ConvolveFunctions wrap_convolve12_avx2(wrap_convolve_copy_avx2_12,
|
||||
wrap_convolve8_horiz_avx2_12,
|
||||
wrap_convolve8_vert_avx2_12, 12);
|
||||
const ConvolveParam kArray_Convolve8_avx2[] = {
|
||||
ALL_SIZES_64(wrap_convolve8_avx2), ALL_SIZES_64(wrap_convolve10_avx2),
|
||||
ALL_SIZES_64(wrap_convolve12_avx2), ALL_SIZES(convolve8_avx2)
|
||||
};
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, ConvolveTest,
|
||||
::testing::ValuesIn(kArray_Convolve8_avx2));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
} // namespace
|
||||
100
media/libaom/src/test/corner_match_test.cc
Normal file
100
media/libaom/src/test/corner_match_test.cc
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
|
||||
#include "av1/encoder/corner_match.h"
|
||||
|
||||
namespace test_libaom {
|
||||
|
||||
namespace AV1CornerMatch {
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
typedef tuple<int> CornerMatchParam;
|
||||
|
||||
class AV1CornerMatchTest : public ::testing::TestWithParam<CornerMatchParam> {
|
||||
public:
|
||||
virtual ~AV1CornerMatchTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput();
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
AV1CornerMatchTest::~AV1CornerMatchTest() {}
|
||||
void AV1CornerMatchTest::SetUp() { rnd_.Reset(ACMRandom::DeterministicSeed()); }
|
||||
void AV1CornerMatchTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1CornerMatchTest::RunCheckOutput() {
|
||||
const int w = 128, h = 128;
|
||||
const int num_iters = 10000;
|
||||
int i, j;
|
||||
|
||||
uint8_t *input1 = new uint8_t[w * h];
|
||||
uint8_t *input2 = new uint8_t[w * h];
|
||||
|
||||
// Test the two extreme cases:
|
||||
// i) Random data, should have correlation close to 0
|
||||
// ii) Linearly related data + noise, should have correlation close to 1
|
||||
int mode = GET_PARAM(0);
|
||||
if (mode == 0) {
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) {
|
||||
input1[i * w + j] = rnd_.Rand8();
|
||||
input2[i * w + j] = rnd_.Rand8();
|
||||
}
|
||||
} else if (mode == 1) {
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) {
|
||||
int v = rnd_.Rand8();
|
||||
input1[i * w + j] = v;
|
||||
input2[i * w + j] = (v / 2) + (rnd_.Rand8() & 15);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
int x1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w - 2 * MATCH_SZ_BY2);
|
||||
int y1 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h - 2 * MATCH_SZ_BY2);
|
||||
int x2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(w - 2 * MATCH_SZ_BY2);
|
||||
int y2 = MATCH_SZ_BY2 + rnd_.PseudoUniform(h - 2 * MATCH_SZ_BY2);
|
||||
|
||||
double res_c =
|
||||
compute_cross_correlation_c(input1, w, x1, y1, input2, w, x2, y2);
|
||||
double res_sse4 =
|
||||
compute_cross_correlation_sse4_1(input1, w, x1, y1, input2, w, x2, y2);
|
||||
|
||||
ASSERT_EQ(res_sse4, res_c);
|
||||
}
|
||||
|
||||
delete[] input1;
|
||||
delete[] input2;
|
||||
}
|
||||
|
||||
TEST_P(AV1CornerMatchTest, CheckOutput) { RunCheckOutput(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, AV1CornerMatchTest,
|
||||
::testing::Values(make_tuple(0), make_tuple(1)));
|
||||
|
||||
} // namespace AV1CornerMatch
|
||||
|
||||
} // namespace test_libaom
|
||||
180
media/libaom/src/test/cpu_speed_test.cc
Normal file
180
media/libaom/src/test/cpu_speed_test.cc
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxPSNR = 100;
|
||||
|
||||
class CpuSpeedTest
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
CpuSpeedTest()
|
||||
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
|
||||
set_cpu_used_(GET_PARAM(2)), min_psnr_(kMaxPSNR),
|
||||
tune_content_(AOM_CONTENT_DEFAULT) {}
|
||||
virtual ~CpuSpeedTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
} else {
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) { min_psnr_ = kMaxPSNR; }
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, tune_content_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (pkt->data.psnr.psnr[0] < min_psnr_) min_psnr_ = pkt->data.psnr.psnr[0];
|
||||
}
|
||||
|
||||
void TestQ0();
|
||||
void TestScreencastQ0();
|
||||
void TestTuneScreen();
|
||||
void TestEncodeHighBitrate();
|
||||
void TestLowBitrate();
|
||||
|
||||
::libaom_test::TestMode encoding_mode_;
|
||||
int set_cpu_used_;
|
||||
double min_psnr_;
|
||||
int tune_content_;
|
||||
};
|
||||
|
||||
void CpuSpeedTest::TestQ0() {
|
||||
// Validate that this non multiple of 64 wide clip encodes and decodes
|
||||
// without a mismatch when passing in a very low max q. This pushes
|
||||
// the encoder to producing lots of big partitions which will likely
|
||||
// extend into the border and test the border condition.
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 400;
|
||||
cfg_.rc_max_quantizer = 0;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
|
||||
10);
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
EXPECT_GE(min_psnr_, kMaxPSNR);
|
||||
}
|
||||
|
||||
void CpuSpeedTest::TestScreencastQ0() {
|
||||
::libaom_test::Y4mVideoSource video("screendata.y4m", 0, 3);
|
||||
cfg_.g_timebase = video.timebase();
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 400;
|
||||
cfg_.rc_max_quantizer = 0;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
EXPECT_GE(min_psnr_, kMaxPSNR);
|
||||
}
|
||||
|
||||
void CpuSpeedTest::TestTuneScreen() {
|
||||
::libaom_test::Y4mVideoSource video("screendata.y4m", 0, 3);
|
||||
cfg_.g_timebase = video.timebase();
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 2000;
|
||||
cfg_.rc_max_quantizer = 63;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
tune_content_ = AOM_CONTENT_SCREEN;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
void CpuSpeedTest::TestEncodeHighBitrate() {
|
||||
// Validate that this non multiple of 64 wide clip encodes and decodes
|
||||
// without a mismatch when passing in a very low max q. This pushes
|
||||
// the encoder to producing lots of big partitions which will likely
|
||||
// extend into the border and test the border condition.
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 12000;
|
||||
cfg_.rc_max_quantizer = 10;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
|
||||
10);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
void CpuSpeedTest::TestLowBitrate() {
|
||||
// Validate that this clip encodes and decodes without a mismatch
|
||||
// when passing in a very high min q. This pushes the encoder to producing
|
||||
// lots of small partitions which might will test the other condition.
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
cfg_.rc_target_bitrate = 200;
|
||||
cfg_.rc_min_quantizer = 40;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_odd.yuv", 208, 144, 30, 1, 0,
|
||||
10);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
TEST_P(CpuSpeedTest, TestQ0) { TestQ0(); }
|
||||
TEST_P(CpuSpeedTest, TestScreencastQ0) { TestScreencastQ0(); }
|
||||
TEST_P(CpuSpeedTest, TestTuneScreen) { TestTuneScreen(); }
|
||||
TEST_P(CpuSpeedTest, TestEncodeHighBitrate) { TestEncodeHighBitrate(); }
|
||||
TEST_P(CpuSpeedTest, TestLowBitrate) { TestLowBitrate(); }
|
||||
|
||||
class CpuSpeedTestLarge : public CpuSpeedTest {};
|
||||
|
||||
TEST_P(CpuSpeedTestLarge, TestQ0) { TestQ0(); }
|
||||
TEST_P(CpuSpeedTestLarge, TestScreencastQ0) { TestScreencastQ0(); }
|
||||
TEST_P(CpuSpeedTestLarge, TestTuneScreen) { TestTuneScreen(); }
|
||||
TEST_P(CpuSpeedTestLarge, TestEncodeHighBitrate) { TestEncodeHighBitrate(); }
|
||||
TEST_P(CpuSpeedTestLarge, TestLowBitrate) { TestLowBitrate(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(CpuSpeedTest,
|
||||
::testing::Values(::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(1, 3));
|
||||
AV1_INSTANTIATE_TEST_CASE(CpuSpeedTestLarge,
|
||||
::testing::Values(::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(0, 1));
|
||||
} // namespace
|
||||
255
media/libaom/src/test/datarate_test.cc
Normal file
255
media/libaom/src/test/datarate_test.cc
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
#include "aom/aom_codec.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class DatarateTestLarge
|
||||
: public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
public:
|
||||
DatarateTestLarge() : EncoderTest(GET_PARAM(0)) {}
|
||||
|
||||
protected:
|
||||
virtual ~DatarateTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(GET_PARAM(1));
|
||||
set_cpu_used_ = GET_PARAM(2);
|
||||
ResetModel();
|
||||
}
|
||||
|
||||
virtual void ResetModel() {
|
||||
last_pts_ = 0;
|
||||
bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
|
||||
frame_number_ = 0;
|
||||
tot_frame_number_ = 0;
|
||||
first_drop_ = 0;
|
||||
num_drops_ = 0;
|
||||
// Denoiser is off by default.
|
||||
denoiser_on_ = 0;
|
||||
bits_total_ = 0;
|
||||
denoiser_offon_test_ = 0;
|
||||
denoiser_offon_period_ = -1;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
|
||||
if (denoiser_offon_test_) {
|
||||
ASSERT_GT(denoiser_offon_period_, 0)
|
||||
<< "denoiser_offon_period_ is not positive.";
|
||||
if ((video->frame() + 1) % denoiser_offon_period_ == 0) {
|
||||
// Flip denoiser_on_ periodically
|
||||
denoiser_on_ ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
encoder->Control(AV1E_SET_NOISE_SENSITIVITY, denoiser_on_);
|
||||
|
||||
const aom_rational_t tb = video->timebase();
|
||||
timebase_ = static_cast<double>(tb.num) / tb.den;
|
||||
duration_ = 0;
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
// Time since last timestamp = duration.
|
||||
aom_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
|
||||
|
||||
if (duration > 1) {
|
||||
// If first drop not set and we have a drop set it to this time.
|
||||
if (!first_drop_) first_drop_ = last_pts_ + 1;
|
||||
// Update the number of frame drops.
|
||||
num_drops_ += static_cast<int>(duration - 1);
|
||||
// Update counter for total number of frames (#frames input to encoder).
|
||||
// Needed for setting the proper layer_id below.
|
||||
tot_frame_number_ += static_cast<int>(duration - 1);
|
||||
}
|
||||
|
||||
// Add to the buffer the bits we'd expect from a constant bitrate server.
|
||||
bits_in_buffer_model_ += static_cast<int64_t>(
|
||||
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
|
||||
|
||||
// Buffer should not go negative.
|
||||
ASSERT_GE(bits_in_buffer_model_, 0)
|
||||
<< "Buffer Underrun at frame " << pkt->data.frame.pts;
|
||||
|
||||
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
|
||||
|
||||
// Update the total encoded bits.
|
||||
bits_total_ += frame_size_in_bits;
|
||||
|
||||
// Update the most recent pts.
|
||||
last_pts_ = pkt->data.frame.pts;
|
||||
++frame_number_;
|
||||
++tot_frame_number_;
|
||||
}
|
||||
|
||||
virtual void EndPassHook(void) {
|
||||
duration_ = (last_pts_ + 1) * timebase_;
|
||||
// Effective file datarate:
|
||||
effective_datarate_ = (bits_total_ / 1000.0) / duration_;
|
||||
}
|
||||
|
||||
aom_codec_pts_t last_pts_;
|
||||
double timebase_;
|
||||
int frame_number_; // Counter for number of non-dropped/encoded frames.
|
||||
int tot_frame_number_; // Counter for total number of input frames.
|
||||
int64_t bits_total_;
|
||||
double duration_;
|
||||
double effective_datarate_;
|
||||
int set_cpu_used_;
|
||||
int64_t bits_in_buffer_model_;
|
||||
aom_codec_pts_t first_drop_;
|
||||
int num_drops_;
|
||||
int denoiser_on_;
|
||||
int denoiser_offon_test_;
|
||||
int denoiser_offon_period_;
|
||||
};
|
||||
|
||||
// Check basic rate targeting for VBR mode.
|
||||
TEST_P(DatarateTestLarge, BasicRateTargetingVBR) {
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 63;
|
||||
cfg_.g_error_resilient = 0;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 140);
|
||||
for (int i = 400; i <= 800; i += 400) {
|
||||
cfg_.rc_target_bitrate = i;
|
||||
ResetModel();
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.75)
|
||||
<< " The datarate for the file is lower than target by too much!";
|
||||
ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.25)
|
||||
<< " The datarate for the file is greater than target by too much!";
|
||||
}
|
||||
}
|
||||
|
||||
// Check basic rate targeting for CBR,
|
||||
TEST_P(DatarateTestLarge, BasicRateTargeting) {
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 500;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_dropframe_thresh = 1;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 63;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 140);
|
||||
for (int i = 150; i < 800; i += 400) {
|
||||
cfg_.rc_target_bitrate = i;
|
||||
ResetModel();
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85)
|
||||
<< " The datarate for the file is lower than target by too much!";
|
||||
ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15)
|
||||
<< " The datarate for the file is greater than target by too much!";
|
||||
}
|
||||
}
|
||||
|
||||
// Check basic rate targeting for CBR.
|
||||
TEST_P(DatarateTestLarge, BasicRateTargeting444) {
|
||||
::libaom_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 140);
|
||||
|
||||
cfg_.g_profile = 1;
|
||||
cfg_.g_timebase = video.timebase();
|
||||
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 500;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_dropframe_thresh = 1;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 63;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
|
||||
for (int i = 250; i < 900; i += 400) {
|
||||
cfg_.rc_target_bitrate = i;
|
||||
ResetModel();
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
|
||||
effective_datarate_ * 0.85)
|
||||
<< " The datarate for the file exceeds the target by too much!";
|
||||
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
|
||||
effective_datarate_ * 1.15)
|
||||
<< " The datarate for the file missed the target!"
|
||||
<< cfg_.rc_target_bitrate << " " << effective_datarate_;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that (1) the first dropped frame gets earlier and earlier
|
||||
// as the drop frame threshold is increased, and (2) that the total number of
|
||||
// frame drops does not decrease as we increase frame drop threshold.
|
||||
// Use a lower qp-max to force some frame drops.
|
||||
TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 500;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_undershoot_pct = 20;
|
||||
cfg_.rc_undershoot_pct = 20;
|
||||
cfg_.rc_dropframe_thresh = 10;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 50;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.rc_target_bitrate = 200;
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.g_error_resilient = 1;
|
||||
// TODO(marpan): Investigate datarate target failures with a smaller keyframe
|
||||
// interval (128).
|
||||
cfg_.kf_max_dist = 9999;
|
||||
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 100);
|
||||
|
||||
const int kDropFrameThreshTestStep = 30;
|
||||
aom_codec_pts_t last_drop = 140;
|
||||
int last_num_drops = 0;
|
||||
for (int i = 40; i < 100; i += kDropFrameThreshTestStep) {
|
||||
cfg_.rc_dropframe_thresh = i;
|
||||
ResetModel();
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85)
|
||||
<< " The datarate for the file is lower than target by too much!";
|
||||
ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15)
|
||||
<< " The datarate for the file is greater than target by too much!";
|
||||
ASSERT_LE(first_drop_, last_drop)
|
||||
<< " The first dropped frame for drop_thresh " << i
|
||||
<< " > first dropped frame for drop_thresh "
|
||||
<< i - kDropFrameThreshTestStep;
|
||||
ASSERT_GE(num_drops_, last_num_drops * 0.85)
|
||||
<< " The number of dropped frames for drop_thresh " << i
|
||||
<< " < number of dropped frames for drop_thresh "
|
||||
<< i - kDropFrameThreshTestStep;
|
||||
last_drop = first_drop_;
|
||||
last_num_drops = num_drops_;
|
||||
}
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(DatarateTestLarge,
|
||||
::testing::Values(::libaom_test::kOnePassGood,
|
||||
::libaom_test::kRealTime),
|
||||
::testing::Values(2, 5));
|
||||
} // namespace
|
||||
55
media/libaom/src/test/decode_api_test.cc
Normal file
55
media/libaom/src/test/decode_api_test.cc
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "test/util.h"
|
||||
#include "aom/aomdx.h"
|
||||
#include "aom/aom_decoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(DecodeAPI, InvalidParams) {
|
||||
static const aom_codec_iface_t *kCodecs[] = {
|
||||
#if CONFIG_AV1_DECODER
|
||||
aom_codec_av1_dx(),
|
||||
#endif
|
||||
};
|
||||
uint8_t buf[1] = { 0 };
|
||||
aom_codec_ctx_t dec;
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_dec_init(NULL, NULL, NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_dec_init(&dec, NULL, NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(NULL, NULL, 0, NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(NULL, buf, 0, NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_decode(NULL, buf, NELEMENTS(buf), NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_decode(NULL, NULL, NELEMENTS(buf), NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_destroy(NULL));
|
||||
EXPECT_TRUE(aom_codec_error(NULL) != NULL);
|
||||
|
||||
for (int i = 0; i < NELEMENTS(kCodecs); ++i) {
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_dec_init(NULL, kCodecs[i], NULL, 0));
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_dec_init(&dec, kCodecs[i], NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_decode(&dec, NULL, NELEMENTS(buf), NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_decode(&dec, buf, 0, NULL));
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&dec));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
185
media/libaom/src/test/decode_multithreaded_test.cc
Normal file
185
media/libaom/src/test/decode_multithreaded_test.cc
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/md5_helper.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static const int kNumMultiThreadDecoders = 3;
|
||||
|
||||
class AV1DecodeMultiThreadedTest
|
||||
: public ::libaom_test::CodecTestWith5Params<int, int, int, int, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AV1DecodeMultiThreadedTest()
|
||||
: EncoderTest(GET_PARAM(0)), md5_single_thread_(), md5_multi_thread_(),
|
||||
n_tile_cols_(GET_PARAM(1)), n_tile_rows_(GET_PARAM(2)),
|
||||
n_tile_groups_(GET_PARAM(3)), set_cpu_used_(GET_PARAM(4)),
|
||||
row_mt_(GET_PARAM(5)) {
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.w = 704;
|
||||
cfg.h = 576;
|
||||
cfg.threads = 1;
|
||||
cfg.allow_lowbitdepth = 1;
|
||||
single_thread_dec_ = codec_->CreateDecoder(cfg, 0);
|
||||
|
||||
// Test cfg.threads == powers of 2.
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
|
||||
cfg.threads <<= 1;
|
||||
multi_thread_dec_[i] = codec_->CreateDecoder(cfg, 0);
|
||||
multi_thread_dec_[i]->Control(AV1D_SET_ROW_MT, row_mt_);
|
||||
}
|
||||
|
||||
if (single_thread_dec_->IsAV1()) {
|
||||
single_thread_dec_->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
single_thread_dec_->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
single_thread_dec_->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
}
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
|
||||
if (multi_thread_dec_[i]->IsAV1()) {
|
||||
multi_thread_dec_[i]->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
multi_thread_dec_[i]->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
multi_thread_dec_[i]->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~AV1DecodeMultiThreadedTest() {
|
||||
delete single_thread_dec_;
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i)
|
||||
delete multi_thread_dec_[i];
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(libaom_test::kTwoPassGood);
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
|
||||
libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, n_tile_cols_);
|
||||
encoder->Control(AV1E_SET_TILE_ROWS, n_tile_rows_);
|
||||
encoder->Control(AV1E_SET_NUM_TG, n_tile_groups_);
|
||||
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMD5(::libaom_test::Decoder *dec, const aom_codec_cx_pkt_t *pkt,
|
||||
::libaom_test::MD5 *md5) {
|
||||
const aom_codec_err_t res = dec->DecodeFrame(
|
||||
reinterpret_cast<uint8_t *>(pkt->data.frame.buf), pkt->data.frame.sz);
|
||||
if (res != AOM_CODEC_OK) {
|
||||
abort_ = true;
|
||||
ASSERT_EQ(AOM_CODEC_OK, res);
|
||||
}
|
||||
const aom_image_t *img = dec->GetDxData().Next();
|
||||
md5->Add(img);
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
UpdateMD5(single_thread_dec_, pkt, &md5_single_thread_);
|
||||
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i)
|
||||
UpdateMD5(multi_thread_dec_[i], pkt, &md5_multi_thread_[i]);
|
||||
}
|
||||
|
||||
void DoTest() {
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = 500;
|
||||
cfg_.g_lag_in_frames = 12;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 704, 576,
|
||||
timebase.den, timebase.num, 0, 5);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
|
||||
const char *md5_single_thread_str = md5_single_thread_.Get();
|
||||
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
|
||||
const char *md5_multi_thread_str = md5_multi_thread_[i].Get();
|
||||
ASSERT_STREQ(md5_single_thread_str, md5_multi_thread_str);
|
||||
}
|
||||
}
|
||||
|
||||
::libaom_test::MD5 md5_single_thread_;
|
||||
::libaom_test::MD5 md5_multi_thread_[kNumMultiThreadDecoders];
|
||||
::libaom_test::Decoder *single_thread_dec_;
|
||||
::libaom_test::Decoder *multi_thread_dec_[kNumMultiThreadDecoders];
|
||||
|
||||
private:
|
||||
int n_tile_cols_;
|
||||
int n_tile_rows_;
|
||||
int n_tile_groups_;
|
||||
int set_cpu_used_;
|
||||
int row_mt_;
|
||||
};
|
||||
|
||||
// run an encode and do the decode both in single thread
|
||||
// and multi thread. Ensure that the MD5 of the output in both cases
|
||||
// is identical. If so, the test passes.
|
||||
TEST_P(AV1DecodeMultiThreadedTest, MD5Match) {
|
||||
cfg_.large_scale_tile = 0;
|
||||
single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i)
|
||||
multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
class AV1DecodeMultiThreadedTestLarge : public AV1DecodeMultiThreadedTest {};
|
||||
|
||||
TEST_P(AV1DecodeMultiThreadedTestLarge, MD5Match) {
|
||||
cfg_.large_scale_tile = 0;
|
||||
single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i)
|
||||
multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
// TODO(ranjit): More tests have to be added using pre-generated MD5.
|
||||
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTest, ::testing::Values(1, 2),
|
||||
::testing::Values(1, 2), ::testing::Values(1),
|
||||
::testing::Values(3), ::testing::Values(0, 1));
|
||||
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTestLarge,
|
||||
::testing::Values(0, 1, 2, 6),
|
||||
::testing::Values(0, 1, 2, 6),
|
||||
::testing::Values(1, 4), ::testing::Values(0),
|
||||
::testing::Values(0, 1));
|
||||
|
||||
class AV1DecodeMultiThreadedLSTestLarge
|
||||
: public AV1DecodeMultiThreadedTestLarge {};
|
||||
|
||||
TEST_P(AV1DecodeMultiThreadedLSTestLarge, MD5Match) {
|
||||
cfg_.large_scale_tile = 1;
|
||||
single_thread_dec_->Control(AV1_SET_TILE_MODE, 1);
|
||||
for (int i = 0; i < kNumMultiThreadDecoders; ++i)
|
||||
multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 1);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedLSTestLarge,
|
||||
::testing::Values(6), ::testing::Values(6),
|
||||
::testing::Values(1), ::testing::Values(0, 3),
|
||||
::testing::Values(0, 1));
|
||||
|
||||
} // namespace
|
||||
246
media/libaom/src/test/decode_perf_test.cc
Normal file
246
media/libaom/src/test/decode_perf_test.cc
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "config/aom_version.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "common/ivfenc.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/decode_test_driver.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/ivf_video_source.h"
|
||||
#include "test/md5_helper.h"
|
||||
#include "test/util.h"
|
||||
#include "test/webm_video_source.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
namespace {
|
||||
|
||||
#define VIDEO_NAME 0
|
||||
#define THREADS 1
|
||||
|
||||
const double kUsecsInSec = 1000000.0;
|
||||
const char kNewEncodeOutputFile[] = "new_encode.ivf";
|
||||
|
||||
/*
|
||||
DecodePerfTest takes a tuple of filename + number of threads to decode with
|
||||
*/
|
||||
typedef ::testing::tuple<const char *, unsigned> DecodePerfParam;
|
||||
|
||||
// TODO(jimbankoski): Add actual test vectors here when available.
|
||||
// const DecodePerfParam kAV1DecodePerfVectors[] = {};
|
||||
|
||||
/*
|
||||
In order to reflect real world performance as much as possible, Perf tests
|
||||
*DO NOT* do any correctness checks. Please run them alongside correctness
|
||||
tests to ensure proper codec integrity. Furthermore, in this test we
|
||||
deliberately limit the amount of system calls we make to avoid OS
|
||||
preemption.
|
||||
|
||||
TODO(joshualitt) create a more detailed perf measurement test to collect
|
||||
power/temp/min max frame decode times/etc
|
||||
*/
|
||||
|
||||
class DecodePerfTest : public ::testing::TestWithParam<DecodePerfParam> {};
|
||||
|
||||
TEST_P(DecodePerfTest, PerfTest) {
|
||||
const char *const video_name = GET_PARAM(VIDEO_NAME);
|
||||
const unsigned threads = GET_PARAM(THREADS);
|
||||
|
||||
libaom_test::WebMVideoSource video(video_name);
|
||||
video.Init();
|
||||
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.threads = threads;
|
||||
cfg.allow_lowbitdepth = 1;
|
||||
libaom_test::AV1Decoder decoder(cfg, 0);
|
||||
|
||||
aom_usec_timer t;
|
||||
aom_usec_timer_start(&t);
|
||||
|
||||
for (video.Begin(); video.cxdata() != NULL; video.Next()) {
|
||||
decoder.DecodeFrame(video.cxdata(), video.frame_size());
|
||||
}
|
||||
|
||||
aom_usec_timer_mark(&t);
|
||||
const double elapsed_secs = double(aom_usec_timer_elapsed(&t)) / kUsecsInSec;
|
||||
const unsigned frames = video.frame_number();
|
||||
const double fps = double(frames) / elapsed_secs;
|
||||
|
||||
printf("{\n");
|
||||
printf("\t\"type\" : \"decode_perf_test\",\n");
|
||||
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
|
||||
printf("\t\"videoName\" : \"%s\",\n", video_name);
|
||||
printf("\t\"threadCount\" : %u,\n", threads);
|
||||
printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
|
||||
printf("\t\"totalFrames\" : %u,\n", frames);
|
||||
printf("\t\"framesPerSecond\" : %f\n", fps);
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
// TODO(jimbankoski): Enabled when we have actual AV1 Decode vectors.
|
||||
// INSTANTIATE_TEST_CASE_P(AV1, DecodePerfTest,
|
||||
// ::testing::ValuesIn(kAV1DecodePerfVectors));
|
||||
|
||||
class AV1NewEncodeDecodePerfTest
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AV1NewEncodeDecodePerfTest()
|
||||
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), speed_(0),
|
||||
outfile_(0), out_frames_(0) {}
|
||||
|
||||
virtual ~AV1NewEncodeDecodePerfTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_min_quantizer = 2;
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_dropframe_thresh = 0;
|
||||
cfg_.rc_undershoot_pct = 50;
|
||||
cfg_.rc_overshoot_pct = 50;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, speed_);
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 2);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {
|
||||
const char *const env = getenv("LIBAOM_TEST_DATA_PATH");
|
||||
const std::string data_path(env ? env : ".");
|
||||
const std::string path_to_source = data_path + "/" + kNewEncodeOutputFile;
|
||||
outfile_ = fopen(path_to_source.c_str(), "wb");
|
||||
ASSERT_TRUE(outfile_ != NULL);
|
||||
}
|
||||
|
||||
virtual void EndPassHook() {
|
||||
if (outfile_ != NULL) {
|
||||
if (!fseek(outfile_, 0, SEEK_SET))
|
||||
ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
|
||||
fclose(outfile_);
|
||||
outfile_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
++out_frames_;
|
||||
|
||||
// Write initial file header if first frame.
|
||||
if (pkt->data.frame.pts == 0)
|
||||
ivf_write_file_header(outfile_, &cfg_, AV1_FOURCC, out_frames_);
|
||||
|
||||
// Write frame header and data.
|
||||
ivf_write_frame_header(outfile_, out_frames_, pkt->data.frame.sz);
|
||||
ASSERT_EQ(fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_),
|
||||
pkt->data.frame.sz);
|
||||
}
|
||||
|
||||
virtual bool DoDecode() const { return false; }
|
||||
|
||||
void set_speed(unsigned int speed) { speed_ = speed; }
|
||||
|
||||
private:
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
uint32_t speed_;
|
||||
FILE *outfile_;
|
||||
uint32_t out_frames_;
|
||||
};
|
||||
|
||||
struct EncodePerfTestVideo {
|
||||
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
|
||||
uint32_t bitrate_, int frames_)
|
||||
: name(name_), width(width_), height(height_), bitrate(bitrate_),
|
||||
frames(frames_) {}
|
||||
const char *name;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bitrate;
|
||||
int frames;
|
||||
};
|
||||
|
||||
const EncodePerfTestVideo kAV1EncodePerfTestVectors[] = {
|
||||
EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
|
||||
};
|
||||
|
||||
TEST_P(AV1NewEncodeDecodePerfTest, PerfTest) {
|
||||
SetUp();
|
||||
|
||||
// TODO(JBB): Make this work by going through the set of given files.
|
||||
const int i = 0;
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = kAV1EncodePerfTestVectors[i].bitrate;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
const char *video_name = kAV1EncodePerfTestVectors[i].name;
|
||||
libaom_test::I420VideoSource video(
|
||||
video_name, kAV1EncodePerfTestVectors[i].width,
|
||||
kAV1EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0,
|
||||
kAV1EncodePerfTestVectors[i].frames);
|
||||
set_speed(2);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
|
||||
const uint32_t threads = 4;
|
||||
|
||||
libaom_test::IVFVideoSource decode_video(kNewEncodeOutputFile);
|
||||
decode_video.Init();
|
||||
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.threads = threads;
|
||||
cfg.allow_lowbitdepth = 1;
|
||||
libaom_test::AV1Decoder decoder(cfg, 0);
|
||||
|
||||
aom_usec_timer t;
|
||||
aom_usec_timer_start(&t);
|
||||
|
||||
for (decode_video.Begin(); decode_video.cxdata() != NULL;
|
||||
decode_video.Next()) {
|
||||
decoder.DecodeFrame(decode_video.cxdata(), decode_video.frame_size());
|
||||
}
|
||||
|
||||
aom_usec_timer_mark(&t);
|
||||
const double elapsed_secs =
|
||||
static_cast<double>(aom_usec_timer_elapsed(&t)) / kUsecsInSec;
|
||||
const unsigned decode_frames = decode_video.frame_number();
|
||||
const double fps = static_cast<double>(decode_frames) / elapsed_secs;
|
||||
|
||||
printf("{\n");
|
||||
printf("\t\"type\" : \"decode_perf_test\",\n");
|
||||
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
|
||||
printf("\t\"videoName\" : \"%s\",\n", kNewEncodeOutputFile);
|
||||
printf("\t\"threadCount\" : %u,\n", threads);
|
||||
printf("\t\"decodeTimeSecs\" : %f,\n", elapsed_secs);
|
||||
printf("\t\"totalFrames\" : %u,\n", decode_frames);
|
||||
printf("\t\"framesPerSecond\" : %f\n", fps);
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AV1NewEncodeDecodePerfTest,
|
||||
::testing::Values(::libaom_test::kTwoPassGood));
|
||||
} // namespace
|
||||
114
media/libaom/src/test/decode_test_driver.cc
Normal file
114
media/libaom/src/test/decode_test_driver.cc
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/decode_test_driver.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
const char kAV1Name[] = "AOMedia Project AV1 Decoder";
|
||||
|
||||
aom_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size,
|
||||
aom_codec_stream_info_t *stream_info) {
|
||||
return aom_codec_peek_stream_info(CodecInterface(), cxdata, size,
|
||||
stream_info);
|
||||
}
|
||||
|
||||
aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size) {
|
||||
return DecodeFrame(cxdata, size, NULL);
|
||||
}
|
||||
|
||||
aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size,
|
||||
void *user_priv) {
|
||||
aom_codec_err_t res_dec;
|
||||
InitOnce();
|
||||
API_REGISTER_STATE_CHECK(
|
||||
res_dec = aom_codec_decode(&decoder_, cxdata, size, user_priv));
|
||||
return res_dec;
|
||||
}
|
||||
|
||||
bool Decoder::IsAV1() const {
|
||||
const char *codec_name = GetDecoderName();
|
||||
return strncmp(kAV1Name, codec_name, sizeof(kAV1Name) - 1) == 0;
|
||||
}
|
||||
|
||||
void DecoderTest::HandlePeekResult(Decoder *const /*decoder*/,
|
||||
CompressedVideoSource * /*video*/,
|
||||
const aom_codec_err_t res_peek) {
|
||||
/* The Av1 implementation of PeekStream returns an error only if the
|
||||
* data passed to it isn't a valid Av1 chunk. */
|
||||
ASSERT_EQ(AOM_CODEC_OK, res_peek)
|
||||
<< "Peek return failed: " << aom_codec_err_to_string(res_peek);
|
||||
}
|
||||
|
||||
void DecoderTest::RunLoop(CompressedVideoSource *video,
|
||||
const aom_codec_dec_cfg_t &dec_cfg) {
|
||||
Decoder *const decoder = codec_->CreateDecoder(dec_cfg, flags_);
|
||||
ASSERT_TRUE(decoder != NULL);
|
||||
bool end_of_file = false;
|
||||
bool peeked_stream = false;
|
||||
|
||||
// Decode frames.
|
||||
for (video->Begin(); !::testing::Test::HasFailure() && !end_of_file;
|
||||
video->Next()) {
|
||||
PreDecodeFrameHook(*video, decoder);
|
||||
|
||||
aom_codec_stream_info_t stream_info;
|
||||
stream_info.is_annexb = 0;
|
||||
|
||||
if (video->cxdata() != NULL) {
|
||||
if (!peeked_stream) {
|
||||
// TODO(yaowu): PeekStream returns error for non-sequence_header_obu,
|
||||
// therefore should only be tried once per sequence, this shall be fixed
|
||||
// once PeekStream is updated to properly operate on other obus.
|
||||
const aom_codec_err_t res_peek = decoder->PeekStream(
|
||||
video->cxdata(), video->frame_size(), &stream_info);
|
||||
HandlePeekResult(decoder, video, res_peek);
|
||||
ASSERT_FALSE(::testing::Test::HasFailure());
|
||||
peeked_stream = true;
|
||||
}
|
||||
|
||||
aom_codec_err_t res_dec =
|
||||
decoder->DecodeFrame(video->cxdata(), video->frame_size());
|
||||
if (!HandleDecodeResult(res_dec, *video, decoder)) break;
|
||||
} else {
|
||||
// Signal end of the file to the decoder.
|
||||
const aom_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
|
||||
end_of_file = true;
|
||||
}
|
||||
|
||||
DxDataIterator dec_iter = decoder->GetDxData();
|
||||
const aom_image_t *img = NULL;
|
||||
|
||||
// Get decompressed data
|
||||
while (!::testing::Test::HasFailure() && (img = dec_iter.Next()))
|
||||
DecompressedFrameHook(*img, video->frame_number());
|
||||
}
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
void DecoderTest::RunLoop(CompressedVideoSource *video) {
|
||||
aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t();
|
||||
RunLoop(video, dec_cfg);
|
||||
}
|
||||
|
||||
void DecoderTest::set_cfg(const aom_codec_dec_cfg_t &dec_cfg) {
|
||||
memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
|
||||
}
|
||||
|
||||
void DecoderTest::set_flags(const aom_codec_flags_t flags) { flags_ = flags; }
|
||||
|
||||
} // namespace libaom_test
|
||||
165
media/libaom/src/test/decode_test_driver.h
Normal file
165
media/libaom/src/test/decode_test_driver.h
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_DECODE_TEST_DRIVER_H_
|
||||
#define AOM_TEST_DECODE_TEST_DRIVER_H_
|
||||
#include <cstring>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "aom/aom_decoder.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
class CodecFactory;
|
||||
class CompressedVideoSource;
|
||||
|
||||
// Provides an object to handle decoding output
|
||||
class DxDataIterator {
|
||||
public:
|
||||
explicit DxDataIterator(aom_codec_ctx_t *decoder)
|
||||
: decoder_(decoder), iter_(NULL) {}
|
||||
|
||||
const aom_image_t *Next() { return aom_codec_get_frame(decoder_, &iter_); }
|
||||
|
||||
private:
|
||||
aom_codec_ctx_t *decoder_;
|
||||
aom_codec_iter_t iter_;
|
||||
};
|
||||
|
||||
// Provides a simplified interface to manage one video decoding.
|
||||
// Similar to Encoder class, the exact services should be added
|
||||
// as more tests are added.
|
||||
class Decoder {
|
||||
public:
|
||||
explicit Decoder(aom_codec_dec_cfg_t cfg)
|
||||
: cfg_(cfg), flags_(0), init_done_(false) {
|
||||
memset(&decoder_, 0, sizeof(decoder_));
|
||||
}
|
||||
|
||||
Decoder(aom_codec_dec_cfg_t cfg, const aom_codec_flags_t flag)
|
||||
: cfg_(cfg), flags_(flag), init_done_(false) {
|
||||
memset(&decoder_, 0, sizeof(decoder_));
|
||||
}
|
||||
|
||||
virtual ~Decoder() { aom_codec_destroy(&decoder_); }
|
||||
|
||||
aom_codec_err_t PeekStream(const uint8_t *cxdata, size_t size,
|
||||
aom_codec_stream_info_t *stream_info);
|
||||
|
||||
aom_codec_err_t DecodeFrame(const uint8_t *cxdata, size_t size);
|
||||
|
||||
aom_codec_err_t DecodeFrame(const uint8_t *cxdata, size_t size,
|
||||
void *user_priv);
|
||||
|
||||
DxDataIterator GetDxData() { return DxDataIterator(&decoder_); }
|
||||
|
||||
void Control(int ctrl_id, int arg) { Control(ctrl_id, arg, AOM_CODEC_OK); }
|
||||
|
||||
void Control(int ctrl_id, const void *arg) {
|
||||
InitOnce();
|
||||
const aom_codec_err_t res = aom_codec_control_(&decoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << DecodeError();
|
||||
}
|
||||
|
||||
void Control(int ctrl_id, int arg, aom_codec_err_t expected_value) {
|
||||
InitOnce();
|
||||
const aom_codec_err_t res = aom_codec_control_(&decoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(expected_value, res) << DecodeError();
|
||||
}
|
||||
|
||||
const char *DecodeError() {
|
||||
const char *detail = aom_codec_error_detail(&decoder_);
|
||||
return detail ? detail : aom_codec_error(&decoder_);
|
||||
}
|
||||
|
||||
// Passes the external frame buffer information to libaom.
|
||||
aom_codec_err_t SetFrameBufferFunctions(
|
||||
aom_get_frame_buffer_cb_fn_t cb_get,
|
||||
aom_release_frame_buffer_cb_fn_t cb_release, void *user_priv) {
|
||||
InitOnce();
|
||||
return aom_codec_set_frame_buffer_functions(&decoder_, cb_get, cb_release,
|
||||
user_priv);
|
||||
}
|
||||
|
||||
const char *GetDecoderName() const {
|
||||
return aom_codec_iface_name(CodecInterface());
|
||||
}
|
||||
|
||||
bool IsAV1() const;
|
||||
|
||||
aom_codec_ctx_t *GetDecoder() { return &decoder_; }
|
||||
|
||||
protected:
|
||||
virtual aom_codec_iface_t *CodecInterface() const = 0;
|
||||
|
||||
void InitOnce() {
|
||||
if (!init_done_) {
|
||||
const aom_codec_err_t res =
|
||||
aom_codec_dec_init(&decoder_, CodecInterface(), &cfg_, flags_);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << DecodeError();
|
||||
init_done_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
aom_codec_ctx_t decoder_;
|
||||
aom_codec_dec_cfg_t cfg_;
|
||||
aom_codec_flags_t flags_;
|
||||
bool init_done_;
|
||||
};
|
||||
|
||||
// Common test functionality for all Decoder tests.
|
||||
class DecoderTest {
|
||||
public:
|
||||
// Main decoding loop
|
||||
virtual void RunLoop(CompressedVideoSource *video);
|
||||
virtual void RunLoop(CompressedVideoSource *video,
|
||||
const aom_codec_dec_cfg_t &dec_cfg);
|
||||
|
||||
virtual void set_cfg(const aom_codec_dec_cfg_t &dec_cfg);
|
||||
virtual void set_flags(const aom_codec_flags_t flags);
|
||||
|
||||
// Hook to be called before decompressing every frame.
|
||||
virtual void PreDecodeFrameHook(const CompressedVideoSource & /*video*/,
|
||||
Decoder * /*decoder*/) {}
|
||||
|
||||
// Hook to be called to handle decode result. Return true to continue.
|
||||
virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
|
||||
const CompressedVideoSource & /*video*/,
|
||||
Decoder *decoder) {
|
||||
EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
|
||||
return AOM_CODEC_OK == res_dec;
|
||||
}
|
||||
|
||||
// Hook to be called on every decompressed frame.
|
||||
virtual void DecompressedFrameHook(const aom_image_t & /*img*/,
|
||||
const unsigned int /*frame_number*/) {}
|
||||
|
||||
// Hook to be called on peek result
|
||||
virtual void HandlePeekResult(Decoder *const decoder,
|
||||
CompressedVideoSource *video,
|
||||
const aom_codec_err_t res_peek);
|
||||
|
||||
protected:
|
||||
explicit DecoderTest(const CodecFactory *codec)
|
||||
: codec_(codec), cfg_(), flags_(0) {}
|
||||
|
||||
virtual ~DecoderTest() {}
|
||||
|
||||
const CodecFactory *codec_;
|
||||
aom_codec_dec_cfg_t cfg_;
|
||||
aom_codec_flags_t flags_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_DECODE_TEST_DRIVER_H_
|
||||
77
media/libaom/src/test/decode_to_md5.sh
Normal file
77
media/libaom/src/test/decode_to_md5.sh
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests the libaom decode_to_md5 example. To add new tests to this
|
||||
## file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to decode_to_md5_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: Make sure input is available:
|
||||
# $AV1_IVF_FILE is required.
|
||||
decode_to_md5_verify_environment() {
|
||||
if [ "$(av1_encode_available)" != "yes" ] && [ ! -e "${AV1_IVF_FILE}" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Runs decode_to_md5 on $1 and captures the md5 sum for the final frame. $2 is
|
||||
# interpreted as codec name and used solely to name the output file. $3 is the
|
||||
# expected md5 sum: It must match that of the final frame.
|
||||
decode_to_md5() {
|
||||
local decoder="$(aom_tool_path decode_to_md5)"
|
||||
local input_file="$1"
|
||||
local codec="$2"
|
||||
local expected_md5="$3"
|
||||
local output_file="${AOM_TEST_OUTPUT_DIR}/decode_to_md5_${codec}"
|
||||
|
||||
if [ ! -x "${decoder}" ]; then
|
||||
elog "${decoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${decoder}" "${input_file}" "${output_file}" \
|
||||
${devnull}
|
||||
|
||||
[ -e "${output_file}" ] || return 1
|
||||
|
||||
local md5_last_frame="$(tail -n1 "${output_file}" | awk '{print $1}')"
|
||||
local actual_md5="$(echo "${md5_last_frame}" | awk '{print $1}')"
|
||||
if [ "${actual_md5}" = "${expected_md5}" ]; then
|
||||
return 0
|
||||
else
|
||||
elog "MD5 mismatch:"
|
||||
elog "Expected: ${expected_md5}"
|
||||
elog "Actual: ${actual_md5}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
DISABLED_decode_to_md5_av1() {
|
||||
# expected MD5 sum for the last frame.
|
||||
local expected_md5="567dd6d4b7a7170edddbf58bbcc3aff1"
|
||||
local file="${AV1_IVF_FILE}"
|
||||
|
||||
# TODO(urvang): Check in the encoded file (like libvpx does) to avoid
|
||||
# encoding every time.
|
||||
if [ "$(av1_decode_available)" = "yes" ]; then
|
||||
if [ ! -e "${AV1_IVF_FILE}" ]; then
|
||||
file="${AOM_TEST_OUTPUT_DIR}/test_encode.ivf"
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf
|
||||
fi
|
||||
decode_to_md5 "${file}" "av1" "${expected_md5}"
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO(tomfinegan): Enable when the bitstream stabilizes.
|
||||
decode_to_md5_tests="DISABLED_decode_to_md5_av1"
|
||||
|
||||
run_tests decode_to_md5_verify_environment "${decode_to_md5_tests}"
|
||||
68
media/libaom/src/test/decode_with_drops.sh
Normal file
68
media/libaom/src/test/decode_with_drops.sh
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests the libaom decode_with_drops example. To add new tests to
|
||||
## this file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to decode_with_drops_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: Make sure input is available:
|
||||
# $AV1_IVF_FILE is required.
|
||||
decode_with_drops_verify_environment() {
|
||||
if [ "$(av1_encode_available)" != "yes" ] && [ ! -e "${AV1_IVF_FILE}" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Runs decode_with_drops on $1, $2 is interpreted as codec name and used solely
|
||||
# to name the output file. $3 is the drop mode, and is passed directly to
|
||||
# decode_with_drops.
|
||||
decode_with_drops() {
|
||||
local decoder="$(aom_tool_path decode_with_drops)"
|
||||
local input_file="$1"
|
||||
local codec="$2"
|
||||
local output_file="${AOM_TEST_OUTPUT_DIR}/decode_with_drops_${codec}"
|
||||
local drop_mode="$3"
|
||||
|
||||
if [ ! -x "${decoder}" ]; then
|
||||
elog "${decoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${decoder}" "${input_file}" "${output_file}" \
|
||||
"${drop_mode}" ${devnull}
|
||||
|
||||
[ -e "${output_file}" ] || return 1
|
||||
}
|
||||
|
||||
|
||||
# Decodes $AV1_IVF_FILE while dropping frames, twice: once in sequence mode,
|
||||
# and once in pattern mode.
|
||||
DISABLED_decode_with_drops_av1() {
|
||||
if [ "$(av1_decode_available)" = "yes" ]; then
|
||||
local file="${AV1_IVF_FILE}"
|
||||
if [ ! -e "${AV1_IVF_FILE}" ]; then
|
||||
file="${AOM_TEST_OUTPUT_DIR}/test_encode.ivf"
|
||||
encode_yuv_raw_input_av1 "${file}" --ivf
|
||||
fi
|
||||
# Drop frames 3 and 4.
|
||||
decode_with_drops "${file}" "av1" "3-4"
|
||||
|
||||
# Test pattern mode: Drop 3 of every 4 frames.
|
||||
decode_with_drops "${file}" "av1" "3/4"
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO(yaowu): Disable this test as trailing_bit check is expected to fail
|
||||
decode_with_drops_tests="DISABLED_decode_with_drops_av1"
|
||||
|
||||
run_tests decode_with_drops_verify_environment "${decode_with_drops_tests}"
|
||||
41
media/libaom/src/test/divu_small_test.cc
Normal file
41
media/libaom/src/test/divu_small_test.cc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "av1/common/odintrin.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
TEST(Daala, TestDIVUuptoMAX) {
|
||||
for (int d = 1; d <= OD_DIVU_DMAX; d++) {
|
||||
for (uint32_t x = 1; x <= 1000000; x++) {
|
||||
GTEST_ASSERT_EQ(x / d, OD_DIVU_SMALL(x, d))
|
||||
<< "x=" << x << " d=" << d << " x/d=" << (x / d)
|
||||
<< " != " << OD_DIVU_SMALL(x, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Daala, TestDIVUrandI31) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int d = 1; d < OD_DIVU_DMAX; d++) {
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
uint32_t x = rnd.Rand31();
|
||||
GTEST_ASSERT_EQ(x / d, OD_DIVU_SMALL(x, d))
|
||||
<< "x=" << x << " d=" << d << " x/d=" << (x / d)
|
||||
<< " != " << OD_DIVU_SMALL(x, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
369
media/libaom/src/test/dr_prediction_test.cc
Normal file
369
media/libaom/src/test/dr_prediction_test.cc
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/pred_common.h"
|
||||
#include "av1/common/reconintra.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kZ1Start = 0;
|
||||
const int kZ2Start = 90;
|
||||
const int kZ3Start = 180;
|
||||
|
||||
const TX_SIZE kTxSize[] = { TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_64X64,
|
||||
TX_4X8, TX_8X4, TX_8X16, TX_16X8, TX_16X32,
|
||||
TX_32X16, TX_32X64, TX_64X32, TX_4X16, TX_16X4,
|
||||
TX_8X32, TX_32X8, TX_16X64, TX_64X16 };
|
||||
|
||||
const char *const kTxSizeStrings[] = {
|
||||
"TX_4X4", "TX_8X8", "TX_16X16", "TX_32X32", "TX_64X64",
|
||||
"TX_4X8", "TX_8X4", "TX_8X16", "TX_16X8", "TX_16X32",
|
||||
"TX_32X16", "TX_32X64", "TX_64X32", "TX_4X16", "TX_16X4",
|
||||
"TX_8X32", "TX_32X8", "TX_16X64", "TX_64X16"
|
||||
};
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
typedef void (*DrPred_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_above, int upsample_left, int dx,
|
||||
int dy, int bd);
|
||||
|
||||
typedef void (*DrPred)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left,
|
||||
int upsample_above, int upsample_left, int dx, int dy,
|
||||
int bd);
|
||||
|
||||
typedef void (*Z1_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left,
|
||||
int upsample_above, int dx, int dy);
|
||||
template <Z1_Lbd fn>
|
||||
void z1_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left, int upsample_above,
|
||||
int /*upsample_left*/, int dx, int dy, int /*bd*/) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy);
|
||||
}
|
||||
|
||||
typedef void (*Z2_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left,
|
||||
int upsample_above, int upsample_left, int dx, int dy);
|
||||
template <Z2_Lbd fn>
|
||||
void z2_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left, int upsample_above,
|
||||
int upsample_left, int dx, int dy, int /*bd*/) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy);
|
||||
}
|
||||
|
||||
typedef void (*Z3_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left,
|
||||
int upsample_left, int dx, int dy);
|
||||
template <Z3_Lbd fn>
|
||||
void z3_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint8_t *above, const uint8_t *left,
|
||||
int /*upsample_above*/, int upsample_left, int dx, int dy,
|
||||
int /*bd*/) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy);
|
||||
}
|
||||
|
||||
typedef void (*Z1_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_above, int dx, int dy, int bd);
|
||||
template <Z1_Hbd fn>
|
||||
void z1_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_above, int /*upsample_left*/, int dx, int dy,
|
||||
int bd) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy, bd);
|
||||
}
|
||||
|
||||
typedef void (*Z2_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_above, int upsample_left, int dx, int dy,
|
||||
int bd);
|
||||
template <Z2_Hbd fn>
|
||||
void z2_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_above, int upsample_left, int dx, int dy,
|
||||
int bd) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy,
|
||||
bd);
|
||||
}
|
||||
|
||||
typedef void (*Z3_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int upsample_left, int dx, int dy, int bd);
|
||||
template <Z3_Hbd fn>
|
||||
void z3_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int /*upsample_above*/, int upsample_left, int dx, int dy,
|
||||
int bd) {
|
||||
fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy, bd);
|
||||
}
|
||||
|
||||
template <typename FuncType>
|
||||
struct DrPredFunc {
|
||||
DrPredFunc(FuncType pred = NULL, FuncType tst = NULL, int bit_depth_value = 0,
|
||||
int start_angle_value = 0)
|
||||
: ref_fn(pred), tst_fn(tst), bit_depth(bit_depth_value),
|
||||
start_angle(start_angle_value) {}
|
||||
|
||||
FuncType ref_fn;
|
||||
FuncType tst_fn;
|
||||
int bit_depth;
|
||||
int start_angle;
|
||||
};
|
||||
|
||||
template <typename Pixel, typename FuncType>
|
||||
class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
|
||||
protected:
|
||||
static const int kMaxNumTests = 100000;
|
||||
static const int kIterations = 10;
|
||||
static const int kDstStride = 64;
|
||||
static const int kDstSize = kDstStride * kDstStride;
|
||||
static const int kOffset = 16;
|
||||
static const int kBufSize = ((2 * MAX_TX_SIZE) << 1) + 16;
|
||||
|
||||
DrPredTest()
|
||||
: enable_upsample_(0), upsample_above_(0), upsample_left_(0), bw_(0),
|
||||
bh_(0), dx_(1), dy_(1), bd_(8), txsize_(TX_4X4) {
|
||||
params_ = this->GetParam();
|
||||
start_angle_ = params_.start_angle;
|
||||
stop_angle_ = start_angle_ + 90;
|
||||
|
||||
dst_ref_ = &dst_ref_data_[0];
|
||||
dst_tst_ = &dst_tst_data_[0];
|
||||
dst_stride_ = kDstStride;
|
||||
above_ = &above_data_[kOffset];
|
||||
left_ = &left_data_[kOffset];
|
||||
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
above_data_[i] = rng_.Rand8();
|
||||
left_data_[i] = rng_.Rand8();
|
||||
}
|
||||
|
||||
for (int i = 0; i < kDstSize; ++i) {
|
||||
dst_ref_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~DrPredTest() {}
|
||||
|
||||
void Predict(bool speedtest, int tx) {
|
||||
const int kNumTests = speedtest ? kMaxNumTests : 1;
|
||||
aom_usec_timer timer;
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int k = 0; k < kNumTests; ++k) {
|
||||
params_.ref_fn(dst_ref_, dst_stride_, bw_, bh_, above_, left_,
|
||||
upsample_above_, upsample_left_, dx_, dy_, bd_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int ref_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
if (params_.tst_fn) {
|
||||
for (int k = 0; k < kNumTests; ++k) {
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_fn(dst_tst_, dst_stride_, bw_, bh_,
|
||||
above_, left_, upsample_above_,
|
||||
upsample_left_, dx_, dy_, bd_));
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const int tst_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
|
||||
OutputTimes(kNumTests, ref_time, tst_time, tx);
|
||||
}
|
||||
|
||||
void RunTest(bool speedtest, int p_angle) {
|
||||
for (int i = 0; i < kBufSize; ++i) {
|
||||
above_data_[i] = left_data_[i] = (1 << bd_) - 1;
|
||||
}
|
||||
|
||||
for (int tx = 0; tx < TX_SIZES_ALL; ++tx) {
|
||||
if (params_.tst_fn == NULL) {
|
||||
for (int i = 0; i < kDstSize; ++i) {
|
||||
dst_tst_[i] = (1 << bd_) - 1;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < kDstSize; ++i) {
|
||||
dst_tst_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bw_ = tx_size_wide[kTxSize[tx]];
|
||||
bh_ = tx_size_high[kTxSize[tx]];
|
||||
|
||||
if (enable_upsample_) {
|
||||
upsample_above_ =
|
||||
av1_use_intra_edge_upsample(bw_, bh_, p_angle - 90, 0);
|
||||
upsample_left_ =
|
||||
av1_use_intra_edge_upsample(bw_, bh_, p_angle - 180, 0);
|
||||
} else {
|
||||
upsample_above_ = upsample_left_ = 0;
|
||||
}
|
||||
|
||||
Predict(speedtest, tx);
|
||||
|
||||
for (int r = 0; r < bh_; ++r) {
|
||||
for (int c = 0; c < bw_; ++c) {
|
||||
ASSERT_EQ(dst_ref_[r * dst_stride_ + c],
|
||||
dst_tst_[r * dst_stride_ + c])
|
||||
<< bw_ << "x" << bh_ << " r: " << r << " c: " << c
|
||||
<< " dx: " << dx_ << " dy: " << dy_
|
||||
<< " upsample_above: " << upsample_above_
|
||||
<< " upsample_left: " << upsample_left_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OutputTimes(int num_tests, int ref_time, int tst_time, int tx) {
|
||||
if (num_tests > 1) {
|
||||
if (params_.tst_fn) {
|
||||
const float x = static_cast<float>(ref_time) / tst_time;
|
||||
printf("\t[%8s] :: ref time %6d, tst time %6d %3.2f\n",
|
||||
kTxSizeStrings[tx], ref_time, tst_time, x);
|
||||
} else {
|
||||
printf("\t[%8s] :: ref time %6d\n", kTxSizeStrings[tx], ref_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pixel dst_ref_data_[kDstSize];
|
||||
Pixel dst_tst_data_[kDstSize];
|
||||
|
||||
Pixel left_data_[kBufSize];
|
||||
Pixel dummy_data_[kBufSize];
|
||||
Pixel above_data_[kBufSize];
|
||||
|
||||
Pixel *dst_ref_;
|
||||
Pixel *dst_tst_;
|
||||
Pixel *above_;
|
||||
Pixel *left_;
|
||||
int dst_stride_;
|
||||
|
||||
int enable_upsample_;
|
||||
int upsample_above_;
|
||||
int upsample_left_;
|
||||
int bw_;
|
||||
int bh_;
|
||||
int dx_;
|
||||
int dy_;
|
||||
int bd_;
|
||||
TX_SIZE txsize_;
|
||||
|
||||
int start_angle_;
|
||||
int stop_angle_;
|
||||
|
||||
ACMRandom rng_;
|
||||
|
||||
DrPredFunc<FuncType> params_;
|
||||
};
|
||||
|
||||
class LowbdDrPredTest : public DrPredTest<uint8_t, DrPred> {};
|
||||
|
||||
TEST_P(LowbdDrPredTest, SaturatedValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
enable_upsample_ = iter & 1;
|
||||
for (int angle = start_angle_; angle < stop_angle_; ++angle) {
|
||||
dx_ = av1_get_dx(angle);
|
||||
dy_ = av1_get_dy(angle);
|
||||
if (dx_ && dy_) RunTest(false, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(LowbdDrPredTest, DISABLED_Speed) {
|
||||
const int angles[] = { 3, 45, 87 };
|
||||
for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int angle = angles[i] + start_angle_;
|
||||
dx_ = av1_get_dx(angle);
|
||||
dy_ = av1_get_dy(angle);
|
||||
printf("enable_upsample: %d angle: %d ~~~~~~~~~~~~~~~\n",
|
||||
enable_upsample_, angle);
|
||||
if (dx_ && dy_) RunTest(true, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, LowbdDrPredTest,
|
||||
::testing::Values(DrPredFunc<DrPred>(&z1_wrapper<av1_dr_prediction_z1_c>,
|
||||
NULL, AOM_BITS_8, kZ1Start),
|
||||
DrPredFunc<DrPred>(&z2_wrapper<av1_dr_prediction_z2_c>,
|
||||
NULL, AOM_BITS_8, kZ2Start),
|
||||
DrPredFunc<DrPred>(&z3_wrapper<av1_dr_prediction_z3_c>,
|
||||
NULL, AOM_BITS_8, kZ3Start)));
|
||||
|
||||
class HighbdDrPredTest : public DrPredTest<uint16_t, DrPred_Hbd> {};
|
||||
|
||||
TEST_P(HighbdDrPredTest, SaturatedValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
enable_upsample_ = iter & 1;
|
||||
for (int angle = start_angle_; angle < stop_angle_; ++angle) {
|
||||
dx_ = av1_get_dx(angle);
|
||||
dy_ = av1_get_dy(angle);
|
||||
if (dx_ && dy_) RunTest(false, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(HighbdDrPredTest, DISABLED_Speed) {
|
||||
const int angles[] = { 3, 45, 87 };
|
||||
for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int angle = angles[i] + start_angle_;
|
||||
dx_ = av1_get_dx(angle);
|
||||
dy_ = av1_get_dy(angle);
|
||||
printf("enable_upsample: %d angle: %d ~~~~~~~~~~~~~~~\n",
|
||||
enable_upsample_, angle);
|
||||
if (dx_ && dy_) RunTest(true, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, HighbdDrPredTest,
|
||||
::testing::Values(
|
||||
DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
|
||||
NULL, AOM_BITS_8, kZ1Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
|
||||
NULL, AOM_BITS_10, kZ1Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
|
||||
NULL, AOM_BITS_12, kZ1Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
|
||||
NULL, AOM_BITS_8, kZ2Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
|
||||
NULL, AOM_BITS_10, kZ2Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
|
||||
NULL, AOM_BITS_12, kZ2Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
|
||||
NULL, AOM_BITS_8, kZ3Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
|
||||
NULL, AOM_BITS_10, kZ3Start),
|
||||
DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
|
||||
NULL, AOM_BITS_12, kZ3Start)));
|
||||
|
||||
} // namespace
|
||||
70
media/libaom/src/test/dump_obu.sh
Normal file
70
media/libaom/src/test/dump_obu.sh
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests the libaom dump_obu tool. To add new tests to this
|
||||
## file, do the following:
|
||||
## 1. Write a shell function (this is your test).
|
||||
## 2. Add the function to dump_obu_tests (on a new line).
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
readonly dump_obu_test_file="${AOM_TEST_OUTPUT_DIR}/av1_obu_test.ivf"
|
||||
|
||||
dump_obu_verify_environment() {
|
||||
if [ ! -e "${YUV_RAW_INPUT}" ]; then
|
||||
elog "The file ${YUV_RAW_INPUT##*/} must exist in LIBAOM_TEST_DATA_PATH."
|
||||
return 1
|
||||
fi
|
||||
if [ "$(dump_obu_available)" = "yes" ]; then
|
||||
if [ -z "$(aom_tool_path dump_obu)" ]; then
|
||||
elog "dump_obu not found in LIBAOM_BIN_PATH, its parent, or child tools/."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
dump_obu_available() {
|
||||
if [ "$(av1_decode_available)" = "yes" ] && \
|
||||
[ "$(av1_encode_available)" = "yes" ]; then
|
||||
echo yes
|
||||
fi
|
||||
}
|
||||
|
||||
aomenc_available() {
|
||||
if [ -x "$(aom_tool_path aomenc)" ]; then
|
||||
echo yes
|
||||
fi
|
||||
}
|
||||
|
||||
encode_test_file() {
|
||||
if [ "$(aomenc_available)" = "yes" ]; then
|
||||
local encoder="$(aom_tool_path aomenc)"
|
||||
|
||||
eval "${encoder}" \
|
||||
$(aomenc_encode_test_fast_params) \
|
||||
$(yuv_raw_input) \
|
||||
--ivf \
|
||||
--output=${dump_obu_test_file} \
|
||||
${devnull}
|
||||
|
||||
if [ ! -e "${dump_obu_test_file}" ]; then
|
||||
elog "dump_obu test input encode failed."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
dump_obu() {
|
||||
encode_test_file
|
||||
eval $(aom_tool_path dump_obu) "${dump_obu_test_file}" ${devnull}
|
||||
}
|
||||
|
||||
dump_obu_tests="dump_obu"
|
||||
|
||||
run_tests dump_obu_verify_environment "${dump_obu_tests}"
|
||||
159
media/libaom/src/test/ec_test.cc
Normal file
159
media/libaom/src/test/ec_test.cc
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "aom_dsp/entenc.h"
|
||||
#include "aom_dsp/entdec.h"
|
||||
|
||||
TEST(EC_TEST, random_ec_test) {
|
||||
od_ec_enc enc;
|
||||
od_ec_dec dec;
|
||||
int sz;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int sym;
|
||||
unsigned int seed;
|
||||
unsigned char *ptr;
|
||||
uint32_t ptr_sz;
|
||||
char *seed_str;
|
||||
ret = 0;
|
||||
seed_str = getenv("EC_TEST_SEED");
|
||||
if (seed_str) {
|
||||
seed = atoi(seed_str);
|
||||
} else {
|
||||
seed = 0xdaa1a;
|
||||
}
|
||||
srand(seed);
|
||||
od_ec_enc_init(&enc, 1);
|
||||
/*Test compatibility between multiple different encode/decode routines.*/
|
||||
for (i = 0; i < 409600; i++) {
|
||||
unsigned *fz;
|
||||
unsigned *fts;
|
||||
unsigned *data;
|
||||
unsigned *tell;
|
||||
unsigned *enc_method;
|
||||
int j;
|
||||
sz = rand() / ((RAND_MAX >> (rand() % 9U)) + 1U);
|
||||
fz = (unsigned *)malloc(sz * sizeof(*fz));
|
||||
fts = (unsigned *)malloc(sz * sizeof(*fts));
|
||||
data = (unsigned *)malloc(sz * sizeof(*data));
|
||||
tell = (unsigned *)malloc((sz + 1) * sizeof(*tell));
|
||||
enc_method = (unsigned *)malloc(sz * sizeof(*enc_method));
|
||||
od_ec_enc_reset(&enc);
|
||||
tell[0] = od_ec_enc_tell_frac(&enc);
|
||||
for (j = 0; j < sz; j++) {
|
||||
data[j] = rand() / ((RAND_MAX >> 1) + 1);
|
||||
|
||||
fts[j] = CDF_PROB_BITS;
|
||||
fz[j] = (rand() % (CDF_PROB_TOP - 2)) >> (CDF_PROB_BITS - fts[j]);
|
||||
fz[j] = OD_MAXI(fz[j], 1);
|
||||
enc_method[j] = 3 + (rand() & 1);
|
||||
switch (enc_method[j]) {
|
||||
case 3: {
|
||||
od_ec_encode_bool_q15(&enc, data[j],
|
||||
OD_ICDF(fz[j] << (CDF_PROB_BITS - fts[j])));
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint16_t cdf[2];
|
||||
cdf[0] = OD_ICDF(fz[j]);
|
||||
cdf[1] = OD_ICDF(1U << fts[j]);
|
||||
od_ec_encode_cdf_q15(&enc, data[j], cdf, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tell[j + 1] = od_ec_enc_tell_frac(&enc);
|
||||
}
|
||||
ptr = od_ec_enc_done(&enc, &ptr_sz);
|
||||
EXPECT_GE(((od_ec_enc_tell(&enc) + 7U) >> 3), ptr_sz)
|
||||
<< "od_ec_enc_tell() lied: "
|
||||
"there's "
|
||||
<< ptr_sz << " bytes instead of " << ((od_ec_enc_tell(&enc) + 7) >> 3)
|
||||
<< " (Random seed: " << seed << ")\n";
|
||||
od_ec_dec_init(&dec, ptr, ptr_sz);
|
||||
EXPECT_EQ(od_ec_dec_tell_frac(&dec), tell[0])
|
||||
<< "od_ec_dec_tell() mismatch between encoder and decoder "
|
||||
"at symbol 0: "
|
||||
<< (unsigned)od_ec_dec_tell_frac(&dec) << " instead of " << tell[0]
|
||||
<< " (Random seed: " << seed << ").\n";
|
||||
for (j = 0; j < sz; j++) {
|
||||
int dec_method;
|
||||
if (CDF_SHIFT == 0) {
|
||||
dec_method = 3 + (rand() & 1);
|
||||
} else {
|
||||
dec_method = enc_method[j];
|
||||
}
|
||||
switch (dec_method) {
|
||||
case 3: {
|
||||
sym = od_ec_decode_bool_q15(
|
||||
&dec, OD_ICDF(fz[j] << (CDF_PROB_BITS - fts[j])));
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint16_t cdf[2];
|
||||
cdf[0] = OD_ICDF(fz[j]);
|
||||
cdf[1] = OD_ICDF(1U << fts[j]);
|
||||
sym = od_ec_decode_cdf_q15(&dec, cdf, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(sym, data[j])
|
||||
<< "Decoded " << sym << " instead of " << data[j]
|
||||
<< " with fz=" << fz[j] << " and ftb=" << fts[j] << "at position "
|
||||
<< j << " of " << sz << " (Random seed: " << seed << ").\n"
|
||||
<< "Encoding method: " << enc_method[j]
|
||||
<< " decoding method: " << dec_method << "\n";
|
||||
EXPECT_EQ(od_ec_dec_tell_frac(&dec), tell[j + 1])
|
||||
<< "od_ec_dec_tell() mismatch between encoder and "
|
||||
"decoder at symbol "
|
||||
<< j + 1 << ": " << (unsigned)od_ec_dec_tell_frac(&dec)
|
||||
<< " instead of " << tell[j + 1] << " (Random seed: " << seed
|
||||
<< ").\n";
|
||||
}
|
||||
free(enc_method);
|
||||
free(tell);
|
||||
free(data);
|
||||
free(fts);
|
||||
free(fz);
|
||||
}
|
||||
od_ec_enc_reset(&enc);
|
||||
if (CDF_SHIFT == 0) {
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(24576));
|
||||
od_ec_enc_patch_initial_bits(&enc, 3, 2);
|
||||
EXPECT_FALSE(enc.error) << "od_ec_enc_patch_initial_bits() failed.\n";
|
||||
od_ec_enc_patch_initial_bits(&enc, 0, 5);
|
||||
EXPECT_TRUE(enc.error)
|
||||
<< "od_ec_enc_patch_initial_bits() didn't fail when it should have.\n";
|
||||
od_ec_enc_reset(&enc);
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(16384));
|
||||
od_ec_encode_bool_q15(&enc, 1, OD_ICDF(32256));
|
||||
od_ec_encode_bool_q15(&enc, 0, OD_ICDF(24576));
|
||||
od_ec_enc_patch_initial_bits(&enc, 0, 2);
|
||||
EXPECT_FALSE(enc.error) << "od_ec_enc_patch_initial_bits() failed.\n";
|
||||
ptr = od_ec_enc_done(&enc, &ptr_sz);
|
||||
EXPECT_EQ(ptr_sz, 2u);
|
||||
EXPECT_EQ(ptr[0], 63)
|
||||
<< "Got " << ptr[0]
|
||||
<< " when expecting 63 for od_ec_enc_patch_initial_bits().\n";
|
||||
}
|
||||
od_ec_enc_clear(&enc);
|
||||
EXPECT_EQ(ret, 0);
|
||||
}
|
||||
73
media/libaom/src/test/encode_api_test.cc
Normal file
73
media/libaom/src/test/encode_api_test.cc
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "test/util.h"
|
||||
#include "aom/aomcx.h"
|
||||
#include "aom/aom_encoder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(EncodeAPI, InvalidParams) {
|
||||
static const aom_codec_iface_t *kCodecs[] = {
|
||||
#if CONFIG_AV1_ENCODER
|
||||
aom_codec_av1_cx(),
|
||||
#endif
|
||||
};
|
||||
uint8_t buf[1] = { 0 };
|
||||
aom_image_t img;
|
||||
aom_codec_ctx_t enc;
|
||||
aom_codec_enc_cfg_t cfg;
|
||||
|
||||
EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, 1, 1, 1, buf));
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(NULL, NULL, NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, NULL, NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_encode(NULL, NULL, 0, 0, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_encode(NULL, &img, 0, 0, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_destroy(NULL));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_enc_config_default(NULL, NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_enc_config_default(NULL, &cfg, 0));
|
||||
EXPECT_TRUE(aom_codec_error(NULL) != NULL);
|
||||
|
||||
for (int i = 0; i < NELEMENTS(kCodecs); ++i) {
|
||||
SCOPED_TRACE(aom_codec_iface_name(kCodecs[i]));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_enc_init(NULL, kCodecs[i], NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_enc_init(&enc, kCodecs[i], NULL, 0));
|
||||
EXPECT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
aom_codec_enc_config_default(kCodecs[i], &cfg, 1));
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(kCodecs[i], &cfg, 0));
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, kCodecs[i], &cfg, 0));
|
||||
|
||||
EXPECT_EQ(NULL, aom_codec_get_global_headers(NULL));
|
||||
|
||||
aom_fixed_buf_t *glob_headers = aom_codec_get_global_headers(&enc);
|
||||
EXPECT_TRUE(glob_headers->buf != NULL);
|
||||
if (glob_headers) {
|
||||
free(glob_headers->buf);
|
||||
free(glob_headers);
|
||||
}
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, NULL, 0, 0, 0));
|
||||
|
||||
EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
188
media/libaom/src/test/encode_perf_test.cc
Normal file
188
media/libaom/src/test/encode_perf_test.cc
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_version.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
#include "aom_ports/aom_timer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxPsnr = 100;
|
||||
const double kUsecsInSec = 1000000.0;
|
||||
|
||||
struct EncodePerfTestVideo {
|
||||
EncodePerfTestVideo(const char *name_, uint32_t width_, uint32_t height_,
|
||||
uint32_t bitrate_, int frames_)
|
||||
: name(name_), width(width_), height(height_), bitrate(bitrate_),
|
||||
frames(frames_) {}
|
||||
const char *name;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bitrate;
|
||||
int frames;
|
||||
};
|
||||
|
||||
const EncodePerfTestVideo kAV1EncodePerfTestVectors[] = {
|
||||
EncodePerfTestVideo("desktop_640_360_30.yuv", 640, 360, 200, 2484),
|
||||
EncodePerfTestVideo("kirland_640_480_30.yuv", 640, 480, 200, 300),
|
||||
EncodePerfTestVideo("macmarcomoving_640_480_30.yuv", 640, 480, 200, 987),
|
||||
EncodePerfTestVideo("macmarcostationary_640_480_30.yuv", 640, 480, 200, 718),
|
||||
EncodePerfTestVideo("niklas_640_480_30.yuv", 640, 480, 200, 471),
|
||||
EncodePerfTestVideo("tacomanarrows_640_480_30.yuv", 640, 480, 200, 300),
|
||||
EncodePerfTestVideo("tacomasmallcameramovement_640_480_30.yuv", 640, 480, 200,
|
||||
300),
|
||||
EncodePerfTestVideo("thaloundeskmtg_640_480_30.yuv", 640, 480, 200, 300),
|
||||
EncodePerfTestVideo("niklas_1280_720_30.yuv", 1280, 720, 600, 470),
|
||||
};
|
||||
|
||||
const int kEncodePerfTestSpeeds[] = { 5, 6, 7, 8 };
|
||||
const int kEncodePerfTestThreads[] = { 1, 2, 4 };
|
||||
|
||||
class AV1EncodePerfTest
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AV1EncodePerfTest()
|
||||
: EncoderTest(GET_PARAM(0)), min_psnr_(kMaxPsnr), nframes_(0),
|
||||
encoding_mode_(GET_PARAM(1)), speed_(0), threads_(1) {}
|
||||
|
||||
virtual ~AV1EncodePerfTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_min_quantizer = 2;
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_dropframe_thresh = 0;
|
||||
cfg_.rc_undershoot_pct = 50;
|
||||
cfg_.rc_overshoot_pct = 50;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.g_error_resilient = 1;
|
||||
cfg_.g_threads = threads_;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) {
|
||||
const int log2_tile_columns = 3;
|
||||
encoder->Control(AOME_SET_CPUUSED, speed_);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, log2_tile_columns);
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {
|
||||
min_psnr_ = kMaxPsnr;
|
||||
nframes_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (pkt->data.psnr.psnr[0] < min_psnr_) {
|
||||
min_psnr_ = pkt->data.psnr.psnr[0];
|
||||
}
|
||||
}
|
||||
|
||||
// for performance reasons don't decode
|
||||
virtual bool DoDecode() { return 0; }
|
||||
|
||||
double min_psnr() const { return min_psnr_; }
|
||||
|
||||
void set_speed(unsigned int speed) { speed_ = speed; }
|
||||
|
||||
void set_threads(unsigned int threads) { threads_ = threads; }
|
||||
|
||||
private:
|
||||
double min_psnr_;
|
||||
unsigned int nframes_;
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
unsigned speed_;
|
||||
unsigned int threads_;
|
||||
};
|
||||
|
||||
TEST_P(AV1EncodePerfTest, PerfTest) {
|
||||
for (size_t i = 0; i < NELEMENTS(kAV1EncodePerfTestVectors); ++i) {
|
||||
for (size_t j = 0; j < NELEMENTS(kEncodePerfTestSpeeds); ++j) {
|
||||
for (size_t k = 0; k < NELEMENTS(kEncodePerfTestThreads); ++k) {
|
||||
if (kAV1EncodePerfTestVectors[i].width < 512 &&
|
||||
kEncodePerfTestThreads[k] > 1)
|
||||
continue;
|
||||
else if (kAV1EncodePerfTestVectors[i].width < 1024 &&
|
||||
kEncodePerfTestThreads[k] > 2)
|
||||
continue;
|
||||
|
||||
set_threads(kEncodePerfTestThreads[k]);
|
||||
SetUp();
|
||||
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = kAV1EncodePerfTestVectors[i].bitrate;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
const unsigned frames = kAV1EncodePerfTestVectors[i].frames;
|
||||
const char *video_name = kAV1EncodePerfTestVectors[i].name;
|
||||
libaom_test::I420VideoSource video(
|
||||
video_name, kAV1EncodePerfTestVectors[i].width,
|
||||
kAV1EncodePerfTestVectors[i].height, timebase.den, timebase.num, 0,
|
||||
kAV1EncodePerfTestVectors[i].frames);
|
||||
set_speed(kEncodePerfTestSpeeds[j]);
|
||||
|
||||
aom_usec_timer t;
|
||||
aom_usec_timer_start(&t);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
|
||||
aom_usec_timer_mark(&t);
|
||||
const double elapsed_secs = aom_usec_timer_elapsed(&t) / kUsecsInSec;
|
||||
const double fps = frames / elapsed_secs;
|
||||
const double minimum_psnr = min_psnr();
|
||||
std::string display_name(video_name);
|
||||
if (kEncodePerfTestThreads[k] > 1) {
|
||||
char thread_count[32];
|
||||
snprintf(thread_count, sizeof(thread_count), "_t-%d",
|
||||
kEncodePerfTestThreads[k]);
|
||||
display_name += thread_count;
|
||||
}
|
||||
|
||||
printf("{\n");
|
||||
printf("\t\"type\" : \"encode_perf_test\",\n");
|
||||
printf("\t\"version\" : \"%s\",\n", VERSION_STRING_NOSP);
|
||||
printf("\t\"videoName\" : \"%s\",\n", display_name.c_str());
|
||||
printf("\t\"encodeTimeSecs\" : %f,\n", elapsed_secs);
|
||||
printf("\t\"totalFrames\" : %u,\n", frames);
|
||||
printf("\t\"framesPerSecond\" : %f,\n", fps);
|
||||
printf("\t\"minPsnr\" : %f,\n", minimum_psnr);
|
||||
printf("\t\"speed\" : %d,\n", kEncodePerfTestSpeeds[j]);
|
||||
printf("\t\"threads\" : %d\n", kEncodePerfTestThreads[k]);
|
||||
printf("}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AV1EncodePerfTest,
|
||||
::testing::Values(::libaom_test::kRealTime));
|
||||
} // namespace
|
||||
288
media/libaom/src/test/encode_test_driver.cc
Normal file
288
media/libaom/src/test/encode_test_driver.cc
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "aom_ports/mem.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/decode_test_driver.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
namespace libaom_test {
|
||||
void Encoder::InitEncoder(VideoSource *video) {
|
||||
aom_codec_err_t res;
|
||||
const aom_image_t *img = video->img();
|
||||
|
||||
if (video->img() && !encoder_.priv) {
|
||||
cfg_.g_w = img->d_w;
|
||||
cfg_.g_h = img->d_h;
|
||||
cfg_.g_timebase = video->timebase();
|
||||
cfg_.rc_twopass_stats_in = stats_->buf();
|
||||
|
||||
res = aom_codec_enc_init(&encoder_, CodecInterface(), &cfg_, init_flags_);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::EncodeFrame(VideoSource *video, const unsigned long frame_flags) {
|
||||
if (video->img())
|
||||
EncodeFrameInternal(*video, frame_flags);
|
||||
else
|
||||
Flush();
|
||||
|
||||
// Handle twopass stats
|
||||
CxDataIterator iter = GetCxData();
|
||||
|
||||
while (const aom_codec_cx_pkt_t *pkt = iter.Next()) {
|
||||
if (pkt->kind != AOM_CODEC_STATS_PKT) continue;
|
||||
|
||||
stats_->Append(*pkt);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::EncodeFrameInternal(const VideoSource &video,
|
||||
const unsigned long frame_flags) {
|
||||
aom_codec_err_t res;
|
||||
const aom_image_t *img = video.img();
|
||||
|
||||
// Handle frame resizing
|
||||
if (cfg_.g_w != img->d_w || cfg_.g_h != img->d_h) {
|
||||
cfg_.g_w = img->d_w;
|
||||
cfg_.g_h = img->d_h;
|
||||
res = aom_codec_enc_config_set(&encoder_, &cfg_);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
// Encode the frame
|
||||
API_REGISTER_STATE_CHECK(res =
|
||||
aom_codec_encode(&encoder_, img, video.pts(),
|
||||
video.duration(), frame_flags));
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
void Encoder::Flush() {
|
||||
const aom_codec_err_t res = aom_codec_encode(&encoder_, NULL, 0, 0, 0);
|
||||
if (!encoder_.priv)
|
||||
ASSERT_EQ(AOM_CODEC_ERROR, res) << EncoderError();
|
||||
else
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
void EncoderTest::InitializeConfig() {
|
||||
const aom_codec_err_t res = codec_->DefaultEncoderConfig(&cfg_, 0);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res);
|
||||
}
|
||||
|
||||
void EncoderTest::SetMode(TestMode mode) {
|
||||
switch (mode) {
|
||||
case kOnePassGood:
|
||||
case kTwoPassGood: break;
|
||||
case kRealTime: cfg_.g_lag_in_frames = 0; break;
|
||||
default: ASSERT_TRUE(false) << "Unexpected mode " << mode;
|
||||
}
|
||||
mode_ = mode;
|
||||
if (mode == kTwoPassGood)
|
||||
passes_ = 2;
|
||||
else
|
||||
passes_ = 1;
|
||||
}
|
||||
|
||||
static bool compare_plane(const uint8_t *const buf1, int stride1,
|
||||
const uint8_t *const buf2, int stride2, int w, int h,
|
||||
int *const mismatch_row, int *const mismatch_col,
|
||||
int *const mismatch_pix1, int *const mismatch_pix2) {
|
||||
int r, c;
|
||||
|
||||
for (r = 0; r < h; ++r) {
|
||||
for (c = 0; c < w; ++c) {
|
||||
const int pix1 = buf1[r * stride1 + c];
|
||||
const int pix2 = buf2[r * stride2 + c];
|
||||
|
||||
if (pix1 != pix2) {
|
||||
if (mismatch_row != NULL) *mismatch_row = r;
|
||||
if (mismatch_col != NULL) *mismatch_col = c;
|
||||
if (mismatch_pix1 != NULL) *mismatch_pix1 = pix1;
|
||||
if (mismatch_pix2 != NULL) *mismatch_pix2 = pix2;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The function should return "true" most of the time, therefore no early
|
||||
// break-out is implemented within the match checking process.
|
||||
static bool compare_img(const aom_image_t *img1, const aom_image_t *img2,
|
||||
int *const mismatch_row, int *const mismatch_col,
|
||||
int *const mismatch_plane, int *const mismatch_pix1,
|
||||
int *const mismatch_pix2) {
|
||||
if (img1->fmt != img2->fmt || img1->cp != img2->cp || img1->tc != img2->tc ||
|
||||
img1->mc != img2->mc || img1->d_w != img2->d_w ||
|
||||
img1->d_h != img2->d_h || img1->monochrome != img2->monochrome) {
|
||||
if (mismatch_row != NULL) *mismatch_row = -1;
|
||||
if (mismatch_col != NULL) *mismatch_col = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int num_planes = img1->monochrome ? 1 : 3;
|
||||
for (int plane = 0; plane < num_planes; plane++) {
|
||||
if (!compare_plane(img1->planes[plane], img1->stride[plane],
|
||||
img2->planes[plane], img2->stride[plane],
|
||||
aom_img_plane_width(img1, plane),
|
||||
aom_img_plane_height(img1, plane), mismatch_row,
|
||||
mismatch_col, mismatch_pix1, mismatch_pix2)) {
|
||||
if (mismatch_plane != NULL) *mismatch_plane = plane;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EncoderTest::MismatchHook(const aom_image_t *img_enc,
|
||||
const aom_image_t *img_dec) {
|
||||
int mismatch_row = 0;
|
||||
int mismatch_col = 0;
|
||||
int mismatch_plane = 0;
|
||||
int mismatch_pix_enc = 0;
|
||||
int mismatch_pix_dec = 0;
|
||||
|
||||
ASSERT_FALSE(compare_img(img_enc, img_dec, &mismatch_row, &mismatch_col,
|
||||
&mismatch_plane, &mismatch_pix_enc,
|
||||
&mismatch_pix_dec));
|
||||
|
||||
GTEST_FAIL() << "Encode/Decode mismatch found:" << std::endl
|
||||
<< " pixel value enc/dec: " << mismatch_pix_enc << "/"
|
||||
<< mismatch_pix_dec << std::endl
|
||||
<< " plane: " << mismatch_plane << std::endl
|
||||
<< " row/col: " << mismatch_row << "/"
|
||||
<< mismatch_col << std::endl;
|
||||
}
|
||||
|
||||
void EncoderTest::RunLoop(VideoSource *video) {
|
||||
aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t();
|
||||
dec_cfg.allow_lowbitdepth = 1;
|
||||
|
||||
stats_.Reset();
|
||||
|
||||
ASSERT_TRUE(passes_ == 1 || passes_ == 2);
|
||||
for (unsigned int pass = 0; pass < passes_; pass++) {
|
||||
last_pts_ = 0;
|
||||
|
||||
if (passes_ == 1)
|
||||
cfg_.g_pass = AOM_RC_ONE_PASS;
|
||||
else if (pass == 0)
|
||||
cfg_.g_pass = AOM_RC_FIRST_PASS;
|
||||
else
|
||||
cfg_.g_pass = AOM_RC_LAST_PASS;
|
||||
|
||||
BeginPassHook(pass);
|
||||
testing::internal::scoped_ptr<Encoder> encoder(
|
||||
codec_->CreateEncoder(cfg_, init_flags_, &stats_));
|
||||
ASSERT_TRUE(encoder.get() != NULL);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(video->Begin());
|
||||
encoder->InitEncoder(video);
|
||||
|
||||
if (mode_ == kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(::testing::Test::HasFatalFailure());
|
||||
|
||||
testing::internal::scoped_ptr<Decoder> decoder(
|
||||
codec_->CreateDecoder(dec_cfg, 0 /* flags */));
|
||||
#if CONFIG_AV1_DECODER
|
||||
if (decoder->IsAV1()) {
|
||||
// Set dec_cfg.tile_row = -1 and dec_cfg.tile_col = -1 so that the whole
|
||||
// frame is decoded.
|
||||
decoder->Control(AV1_SET_TILE_MODE, cfg_.large_scale_tile);
|
||||
decoder->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
decoder->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
decoder->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool again;
|
||||
for (again = true; again; video->Next()) {
|
||||
again = (video->img() != NULL);
|
||||
|
||||
PreEncodeFrameHook(video);
|
||||
PreEncodeFrameHook(video, encoder.get());
|
||||
encoder->EncodeFrame(video, frame_flags_);
|
||||
|
||||
CxDataIterator iter = encoder->GetCxData();
|
||||
|
||||
bool has_cxdata = false;
|
||||
bool has_dxdata = false;
|
||||
while (const aom_codec_cx_pkt_t *pkt = iter.Next()) {
|
||||
pkt = MutateEncoderOutputHook(pkt);
|
||||
again = true;
|
||||
switch (pkt->kind) {
|
||||
case AOM_CODEC_CX_FRAME_PKT:
|
||||
has_cxdata = true;
|
||||
if (decoder.get() != NULL && DoDecode()) {
|
||||
aom_codec_err_t res_dec;
|
||||
if (DoDecodeInvisible()) {
|
||||
res_dec = decoder->DecodeFrame(
|
||||
(const uint8_t *)pkt->data.frame.buf, pkt->data.frame.sz);
|
||||
} else {
|
||||
res_dec = decoder->DecodeFrame(
|
||||
(const uint8_t *)pkt->data.frame.buf +
|
||||
(pkt->data.frame.sz - pkt->data.frame.vis_frame_size),
|
||||
pkt->data.frame.vis_frame_size);
|
||||
}
|
||||
|
||||
if (!HandleDecodeResult(res_dec, decoder.get())) break;
|
||||
|
||||
has_dxdata = true;
|
||||
}
|
||||
ASSERT_GE(pkt->data.frame.pts, last_pts_);
|
||||
last_pts_ = pkt->data.frame.pts;
|
||||
FramePktHook(pkt);
|
||||
break;
|
||||
|
||||
case AOM_CODEC_PSNR_PKT: PSNRPktHook(pkt); break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_dxdata && has_cxdata) {
|
||||
const aom_image_t *img_enc = encoder->GetPreviewFrame();
|
||||
DxDataIterator dec_iter = decoder->GetDxData();
|
||||
const aom_image_t *img_dec = dec_iter.Next();
|
||||
if (img_enc && img_dec) {
|
||||
const bool res =
|
||||
compare_img(img_enc, img_dec, NULL, NULL, NULL, NULL, NULL);
|
||||
if (!res) { // Mismatch
|
||||
MismatchHook(img_enc, img_dec);
|
||||
}
|
||||
}
|
||||
if (img_dec) DecompressedFrameHook(*img_dec, video->pts());
|
||||
}
|
||||
if (!Continue()) break;
|
||||
}
|
||||
|
||||
EndPassHook();
|
||||
|
||||
if (!Continue()) break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace libaom_test
|
||||
249
media/libaom/src/test/encode_test_driver.h
Normal file
249
media/libaom/src/test/encode_test_driver.h
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AOM_TEST_ENCODE_TEST_DRIVER_H_
|
||||
#define AOM_TEST_ENCODE_TEST_DRIVER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#if CONFIG_AV1_ENCODER
|
||||
#include "aom/aomcx.h"
|
||||
#endif
|
||||
#include "aom/aom_encoder.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
class CodecFactory;
|
||||
class VideoSource;
|
||||
|
||||
enum TestMode { kRealTime, kOnePassGood, kTwoPassGood };
|
||||
#define ALL_TEST_MODES \
|
||||
::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood, \
|
||||
::libaom_test::kTwoPassGood)
|
||||
|
||||
#define ONE_PASS_TEST_MODES \
|
||||
::testing::Values(::libaom_test::kRealTime, ::libaom_test::kOnePassGood)
|
||||
|
||||
#define TWO_PASS_TEST_MODES ::testing::Values(::libaom_test::kTwoPassGood)
|
||||
|
||||
#define NONREALTIME_TEST_MODES \
|
||||
::testing::Values(::libaom_test::kOnePassGood, ::libaom_test::kTwoPassGood)
|
||||
|
||||
// Provides an object to handle the libaom get_cx_data() iteration pattern
|
||||
class CxDataIterator {
|
||||
public:
|
||||
explicit CxDataIterator(aom_codec_ctx_t *encoder)
|
||||
: encoder_(encoder), iter_(NULL) {}
|
||||
|
||||
const aom_codec_cx_pkt_t *Next() {
|
||||
return aom_codec_get_cx_data(encoder_, &iter_);
|
||||
}
|
||||
|
||||
private:
|
||||
aom_codec_ctx_t *encoder_;
|
||||
aom_codec_iter_t iter_;
|
||||
};
|
||||
|
||||
// Implements an in-memory store for libaom twopass statistics
|
||||
class TwopassStatsStore {
|
||||
public:
|
||||
void Append(const aom_codec_cx_pkt_t &pkt) {
|
||||
buffer_.append(reinterpret_cast<char *>(pkt.data.twopass_stats.buf),
|
||||
pkt.data.twopass_stats.sz);
|
||||
}
|
||||
|
||||
aom_fixed_buf_t buf() {
|
||||
const aom_fixed_buf_t buf = { &buffer_[0], buffer_.size() };
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Reset() { buffer_.clear(); }
|
||||
|
||||
protected:
|
||||
std::string buffer_;
|
||||
};
|
||||
|
||||
// Provides a simplified interface to manage one video encoding pass, given
|
||||
// a configuration and video source.
|
||||
//
|
||||
// TODO(jkoleszar): The exact services it provides and the appropriate
|
||||
// level of abstraction will be fleshed out as more tests are written.
|
||||
class Encoder {
|
||||
public:
|
||||
Encoder(aom_codec_enc_cfg_t cfg, const uint32_t init_flags,
|
||||
TwopassStatsStore *stats)
|
||||
: cfg_(cfg), init_flags_(init_flags), stats_(stats) {
|
||||
memset(&encoder_, 0, sizeof(encoder_));
|
||||
}
|
||||
|
||||
virtual ~Encoder() { aom_codec_destroy(&encoder_); }
|
||||
|
||||
CxDataIterator GetCxData() { return CxDataIterator(&encoder_); }
|
||||
|
||||
void InitEncoder(VideoSource *video);
|
||||
|
||||
const aom_image_t *GetPreviewFrame() {
|
||||
return aom_codec_get_preview_frame(&encoder_);
|
||||
}
|
||||
// This is a thin wrapper around aom_codec_encode(), so refer to
|
||||
// aom_encoder.h for its semantics.
|
||||
void EncodeFrame(VideoSource *video, const unsigned long frame_flags);
|
||||
|
||||
// Convenience wrapper for EncodeFrame()
|
||||
void EncodeFrame(VideoSource *video) { EncodeFrame(video, 0); }
|
||||
|
||||
void Control(int ctrl_id, int arg) {
|
||||
const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
void Control(int ctrl_id, int *arg) {
|
||||
const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
void Control(int ctrl_id, struct aom_scaling_mode *arg) {
|
||||
const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
|
||||
#if CONFIG_AV1_ENCODER
|
||||
void Control(int ctrl_id, aom_active_map_t *arg) {
|
||||
const aom_codec_err_t res = aom_codec_control_(&encoder_, ctrl_id, arg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Config(const aom_codec_enc_cfg_t *cfg) {
|
||||
const aom_codec_err_t res = aom_codec_enc_config_set(&encoder_, cfg);
|
||||
ASSERT_EQ(AOM_CODEC_OK, res) << EncoderError();
|
||||
cfg_ = *cfg;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual aom_codec_iface_t *CodecInterface() const = 0;
|
||||
|
||||
const char *EncoderError() {
|
||||
const char *detail = aom_codec_error_detail(&encoder_);
|
||||
return detail ? detail : aom_codec_error(&encoder_);
|
||||
}
|
||||
|
||||
// Encode an image
|
||||
void EncodeFrameInternal(const VideoSource &video,
|
||||
const unsigned long frame_flags);
|
||||
|
||||
// Flush the encoder on EOS
|
||||
void Flush();
|
||||
|
||||
aom_codec_ctx_t encoder_;
|
||||
aom_codec_enc_cfg_t cfg_;
|
||||
unsigned long init_flags_;
|
||||
TwopassStatsStore *stats_;
|
||||
};
|
||||
|
||||
// Common test functionality for all Encoder tests.
|
||||
//
|
||||
// This class is a mixin which provides the main loop common to all
|
||||
// encoder tests. It provides hooks which can be overridden by subclasses
|
||||
// to implement each test's specific behavior, while centralizing the bulk
|
||||
// of the boilerplate. Note that it doesn't inherit the gtest testing
|
||||
// classes directly, so that tests can be parameterized differently.
|
||||
class EncoderTest {
|
||||
protected:
|
||||
explicit EncoderTest(const CodecFactory *codec)
|
||||
: codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
|
||||
last_pts_(0), mode_(kRealTime) {
|
||||
// Default to 1 thread.
|
||||
cfg_.g_threads = 1;
|
||||
}
|
||||
|
||||
virtual ~EncoderTest() {}
|
||||
|
||||
// Initialize the cfg_ member with the default configuration.
|
||||
void InitializeConfig();
|
||||
|
||||
// Map the TestMode enum to the passes_ variables.
|
||||
void SetMode(TestMode mode);
|
||||
|
||||
// Set encoder flag.
|
||||
void set_init_flags(unsigned long flag) { // NOLINT(runtime/int)
|
||||
init_flags_ = flag;
|
||||
}
|
||||
|
||||
// Main loop
|
||||
virtual void RunLoop(VideoSource *video);
|
||||
|
||||
// Hook to be called at the beginning of a pass.
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {}
|
||||
|
||||
// Hook to be called at the end of a pass.
|
||||
virtual void EndPassHook() {}
|
||||
|
||||
// Hook to be called before encoding a frame.
|
||||
virtual void PreEncodeFrameHook(VideoSource * /*video*/) {}
|
||||
virtual void PreEncodeFrameHook(VideoSource * /*video*/,
|
||||
Encoder * /*encoder*/) {}
|
||||
|
||||
// Hook to be called on every compressed data packet.
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
|
||||
|
||||
// Hook to be called on every PSNR packet.
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t * /*pkt*/) {}
|
||||
|
||||
// Hook to determine whether the encode loop should continue.
|
||||
virtual bool Continue() const {
|
||||
return !(::testing::Test::HasFatalFailure() || abort_);
|
||||
}
|
||||
|
||||
// Hook to determine whether to decode frame after encoding
|
||||
virtual bool DoDecode() const { return true; }
|
||||
|
||||
// Hook to determine whether to decode invisible frames after encoding
|
||||
virtual bool DoDecodeInvisible() const { return true; }
|
||||
|
||||
// Hook to handle encode/decode mismatch
|
||||
virtual void MismatchHook(const aom_image_t *img1, const aom_image_t *img2);
|
||||
|
||||
// Hook to be called on every decompressed frame.
|
||||
virtual void DecompressedFrameHook(const aom_image_t & /*img*/,
|
||||
aom_codec_pts_t /*pts*/) {}
|
||||
|
||||
// Hook to be called to handle decode result. Return true to continue.
|
||||
virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
|
||||
Decoder *decoder) {
|
||||
EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
|
||||
return AOM_CODEC_OK == res_dec;
|
||||
}
|
||||
|
||||
// Hook that can modify the encoder's output data
|
||||
virtual const aom_codec_cx_pkt_t *MutateEncoderOutputHook(
|
||||
const aom_codec_cx_pkt_t *pkt) {
|
||||
return pkt;
|
||||
}
|
||||
|
||||
const CodecFactory *codec_;
|
||||
bool abort_;
|
||||
aom_codec_enc_cfg_t cfg_;
|
||||
unsigned int passes_;
|
||||
TwopassStatsStore stats_;
|
||||
unsigned long init_flags_;
|
||||
unsigned long frame_flags_;
|
||||
aom_codec_pts_t last_pts_;
|
||||
TestMode mode_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_ENCODE_TEST_DRIVER_H_
|
||||
262
media/libaom/src/test/encodetxb_test.cc
Normal file
262
media/libaom/src/test/encodetxb_test.cc
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "av1/common/idct.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/scan.h"
|
||||
#include "av1/common/txb_common.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
typedef void (*GetNzMapContextsFunc)(const uint8_t *const levels,
|
||||
const int16_t *const scan,
|
||||
const uint16_t eob, const TX_SIZE tx_size,
|
||||
const TX_CLASS tx_class,
|
||||
int8_t *const coeff_contexts);
|
||||
|
||||
class EncodeTxbTest : public ::testing::TestWithParam<GetNzMapContextsFunc> {
|
||||
public:
|
||||
EncodeTxbTest() : get_nz_map_contexts_func_(GetParam()) {}
|
||||
|
||||
virtual ~EncodeTxbTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
coeff_contexts_ref_ = reinterpret_cast<int8_t *>(
|
||||
aom_memalign(16, sizeof(*coeff_contexts_ref_) * MAX_TX_SQUARE));
|
||||
ASSERT_TRUE(coeff_contexts_ref_ != NULL);
|
||||
coeff_contexts_ = reinterpret_cast<int8_t *>(
|
||||
aom_memalign(16, sizeof(*coeff_contexts_) * MAX_TX_SQUARE));
|
||||
ASSERT_TRUE(coeff_contexts_ != NULL);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
aom_free(coeff_contexts_ref_);
|
||||
aom_free(coeff_contexts_);
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
void GetNzMapContextsRun() {
|
||||
const int kNumTests = 10;
|
||||
int result = 0;
|
||||
|
||||
for (int is_inter = 0; is_inter < 2; ++is_inter) {
|
||||
for (int tx_type = DCT_DCT; tx_type < TX_TYPES; ++tx_type) {
|
||||
const TX_CLASS tx_class = tx_type_to_class[tx_type];
|
||||
for (int tx_size = TX_4X4; tx_size < TX_SIZES_ALL; ++tx_size) {
|
||||
const int bwl = get_txb_bwl((TX_SIZE)tx_size);
|
||||
const int width = get_txb_wide((TX_SIZE)tx_size);
|
||||
const int height = get_txb_high((TX_SIZE)tx_size);
|
||||
const int real_width = tx_size_wide[tx_size];
|
||||
const int real_height = tx_size_high[tx_size];
|
||||
const int16_t *const scan = av1_scan_orders[tx_size][tx_type].scan;
|
||||
|
||||
levels_ = set_levels(levels_buf_, width);
|
||||
for (int i = 0; i < kNumTests && !result; ++i) {
|
||||
for (int eob = 1; eob <= width * height && !result; ++eob) {
|
||||
InitDataWithEob(scan, bwl, eob);
|
||||
|
||||
av1_get_nz_map_contexts_c(levels_, scan, eob, (TX_SIZE)tx_size,
|
||||
tx_class, coeff_contexts_ref_);
|
||||
get_nz_map_contexts_func_(levels_, scan, eob, (TX_SIZE)tx_size,
|
||||
tx_class, coeff_contexts_);
|
||||
|
||||
result = Compare(scan, eob);
|
||||
|
||||
EXPECT_EQ(result, 0)
|
||||
<< " tx_class " << tx_class << " width " << real_width
|
||||
<< " height " << real_height << " eob " << eob;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedTestGetNzMapContextsRun() {
|
||||
const int kNumTests = 2000000000;
|
||||
aom_usec_timer timer;
|
||||
|
||||
printf("Note: Only test the largest possible eob case!\n");
|
||||
for (int tx_size = TX_4X4; tx_size < TX_SIZES_ALL; ++tx_size) {
|
||||
const int bwl = get_txb_bwl((TX_SIZE)tx_size);
|
||||
const int width = get_txb_wide((TX_SIZE)tx_size);
|
||||
const int height = get_txb_high((TX_SIZE)tx_size);
|
||||
const int real_width = tx_size_wide[tx_size];
|
||||
const int real_height = tx_size_high[tx_size];
|
||||
const TX_TYPE tx_type = DCT_DCT;
|
||||
const TX_CLASS tx_class = tx_type_to_class[tx_type];
|
||||
const int16_t *const scan = av1_scan_orders[tx_size][tx_type].scan;
|
||||
const int eob = width * height;
|
||||
const int numTests = kNumTests / (width * height);
|
||||
|
||||
levels_ = set_levels(levels_buf_, width);
|
||||
InitDataWithEob(scan, bwl, eob);
|
||||
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < numTests; ++i) {
|
||||
get_nz_map_contexts_func_(levels_, scan, eob, (TX_SIZE)tx_size,
|
||||
tx_class, coeff_contexts_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
|
||||
const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
|
||||
printf("get_nz_map_contexts_%2dx%2d: %7.1f ms\n", real_width, real_height,
|
||||
elapsed_time / 1000.0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void InitDataWithEob(const int16_t *const scan, const int bwl,
|
||||
const int eob) {
|
||||
memset(levels_buf_, 0, sizeof(levels_buf_));
|
||||
memset(coeff_contexts_, 0, sizeof(*coeff_contexts_) * MAX_TX_SQUARE);
|
||||
|
||||
for (int c = 0; c < eob; ++c) {
|
||||
levels_[get_padded_idx(scan[c], bwl)] =
|
||||
static_cast<uint8_t>(clamp(rnd_.Rand8(), 0, INT8_MAX));
|
||||
coeff_contexts_[scan[c]] = rnd_.Rand16() >> 1;
|
||||
}
|
||||
|
||||
memcpy(coeff_contexts_ref_, coeff_contexts_,
|
||||
sizeof(*coeff_contexts_) * MAX_TX_SQUARE);
|
||||
}
|
||||
|
||||
bool Compare(const int16_t *const scan, const int eob) const {
|
||||
bool result = false;
|
||||
if (memcmp(coeff_contexts_, coeff_contexts_ref_,
|
||||
sizeof(*coeff_contexts_ref_) * MAX_TX_SQUARE)) {
|
||||
for (int i = 0; i < eob; i++) {
|
||||
const int pos = scan[i];
|
||||
if (coeff_contexts_ref_[pos] != coeff_contexts_[pos]) {
|
||||
printf("coeff_contexts_[%d] diff:%6d (ref),%6d (opt)\n", pos,
|
||||
coeff_contexts_ref_[pos], coeff_contexts_[pos]);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
GetNzMapContextsFunc get_nz_map_contexts_func_;
|
||||
ACMRandom rnd_;
|
||||
uint8_t levels_buf_[TX_PAD_2D];
|
||||
uint8_t *levels_;
|
||||
int8_t *coeff_contexts_ref_;
|
||||
int8_t *coeff_contexts_;
|
||||
};
|
||||
|
||||
TEST_P(EncodeTxbTest, GetNzMapContexts) { GetNzMapContextsRun(); }
|
||||
|
||||
TEST_P(EncodeTxbTest, DISABLED_SpeedTestGetNzMapContexts) {
|
||||
SpeedTestGetNzMapContextsRun();
|
||||
}
|
||||
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, EncodeTxbTest,
|
||||
::testing::Values(av1_get_nz_map_contexts_sse2));
|
||||
#endif
|
||||
|
||||
typedef void (*av1_txb_init_levels_func)(const tran_low_t *const coeff,
|
||||
const int width, const int height,
|
||||
uint8_t *const levels);
|
||||
|
||||
typedef ::testing::tuple<av1_txb_init_levels_func, int> TxbInitLevelParam;
|
||||
|
||||
class EncodeTxbInitLevelTest
|
||||
: public ::testing::TestWithParam<TxbInitLevelParam> {
|
||||
public:
|
||||
virtual ~EncodeTxbInitLevelTest() {}
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
void RunTest(av1_txb_init_levels_func test_func, int tx_size, int is_speed);
|
||||
};
|
||||
|
||||
void EncodeTxbInitLevelTest::RunTest(av1_txb_init_levels_func test_func,
|
||||
int tx_size, int is_speed) {
|
||||
const int width = get_txb_wide((TX_SIZE)tx_size);
|
||||
const int height = get_txb_high((TX_SIZE)tx_size);
|
||||
tran_low_t coeff[MAX_TX_SQUARE];
|
||||
|
||||
uint8_t levels_buf[2][TX_PAD_2D];
|
||||
uint8_t *const levels0 = set_levels(levels_buf[0], width);
|
||||
uint8_t *const levels1 = set_levels(levels_buf[1], width);
|
||||
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
coeff[i] = rnd.Rand15Signed() + rnd.Rand15Signed();
|
||||
}
|
||||
for (int i = 0; i < TX_PAD_2D; i++) {
|
||||
levels_buf[0][i] = rnd.Rand8();
|
||||
levels_buf[1][i] = rnd.Rand8();
|
||||
}
|
||||
const int run_times = is_speed ? (width * height) * 10000 : 1;
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
av1_txb_init_levels_c(coeff, width, height, levels0);
|
||||
}
|
||||
const double t1 = get_time_mark(&timer);
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int i = 0; i < run_times; ++i) {
|
||||
test_func(coeff, width, height, levels1);
|
||||
}
|
||||
const double t2 = get_time_mark(&timer);
|
||||
if (is_speed) {
|
||||
printf("init %3dx%-3d:%7.2f/%7.2fns", width, height, t1, t2);
|
||||
printf("(%3.2f)\n", t1 / t2);
|
||||
}
|
||||
const int stride = width + TX_PAD_HOR;
|
||||
for (int r = 0; r < height + TX_PAD_VER; ++r) {
|
||||
for (int c = 0; c < stride; ++c) {
|
||||
ASSERT_EQ(levels_buf[0][c + r * stride], levels_buf[1][c + r * stride])
|
||||
<< "[" << r << "," << c << "] " << run_times << width << "x"
|
||||
<< height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(EncodeTxbInitLevelTest, match) {
|
||||
RunTest(GET_PARAM(0), GET_PARAM(1), 0);
|
||||
}
|
||||
|
||||
TEST_P(EncodeTxbInitLevelTest, DISABLED_Speed) {
|
||||
RunTest(GET_PARAM(0), GET_PARAM(1), 1);
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, EncodeTxbInitLevelTest,
|
||||
::testing::Combine(::testing::Values(&av1_txb_init_levels_sse4_1),
|
||||
::testing::Range(0, static_cast<int>(TX_SIZES_ALL), 1)));
|
||||
#endif
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, EncodeTxbInitLevelTest,
|
||||
::testing::Combine(::testing::Values(&av1_txb_init_levels_avx2),
|
||||
::testing::Range(0, static_cast<int>(TX_SIZES_ALL), 1)));
|
||||
#endif
|
||||
} // namespace
|
||||
199
media/libaom/src/test/end_to_end_test.cc
Normal file
199
media/libaom/src/test/end_to_end_test.cc
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
#include "test/yuv_video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const unsigned int kWidth = 160;
|
||||
const unsigned int kHeight = 90;
|
||||
const unsigned int kFramerate = 50;
|
||||
const unsigned int kFrames = 10;
|
||||
const int kBitrate = 500;
|
||||
// List of psnr thresholds for speed settings 0-7 and 5 encoding modes
|
||||
const double kPsnrThreshold[][5] = {
|
||||
// Note:
|
||||
// AV1 HBD average PSNR is slightly lower than AV1.
|
||||
// We make two cases here to enable the testing and
|
||||
// guard picture quality.
|
||||
#if CONFIG_AV1_ENCODER
|
||||
{ 36.0, 37.0, 37.0, 37.0, 37.0 }, { 31.0, 36.0, 36.0, 36.0, 36.0 },
|
||||
{ 31.0, 35.0, 35.0, 35.0, 35.0 }, { 31.0, 34.0, 34.0, 34.0, 34.0 },
|
||||
{ 31.0, 33.0, 33.0, 33.0, 33.0 }, { 31.0, 32.0, 32.0, 32.0, 32.0 },
|
||||
{ 30.0, 31.0, 31.0, 31.0, 31.0 }, { 29.0, 30.0, 30.0, 30.0, 30.0 },
|
||||
#else
|
||||
{ 36.0, 37.0, 37.0, 37.0, 37.0 }, { 35.0, 36.0, 36.0, 36.0, 36.0 },
|
||||
{ 34.0, 35.0, 35.0, 35.0, 35.0 }, { 33.0, 34.0, 34.0, 34.0, 34.0 },
|
||||
{ 32.0, 33.0, 33.0, 33.0, 33.0 }, { 31.0, 32.0, 32.0, 32.0, 32.0 },
|
||||
{ 30.0, 31.0, 31.0, 31.0, 31.0 }, { 29.0, 30.0, 30.0, 30.0, 30.0 },
|
||||
#endif // CONFIG_AV1_ENCODER
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *filename;
|
||||
unsigned int input_bit_depth;
|
||||
aom_img_fmt fmt;
|
||||
aom_bit_depth_t bit_depth;
|
||||
unsigned int profile;
|
||||
} TestVideoParam;
|
||||
|
||||
const TestVideoParam kTestVectors[] = {
|
||||
{ "park_joy_90p_8_420.y4m", 8, AOM_IMG_FMT_I420, AOM_BITS_8, 0 },
|
||||
{ "park_joy_90p_8_422.y4m", 8, AOM_IMG_FMT_I422, AOM_BITS_8, 2 },
|
||||
{ "park_joy_90p_8_444.y4m", 8, AOM_IMG_FMT_I444, AOM_BITS_8, 1 },
|
||||
{ "park_joy_90p_10_420.y4m", 10, AOM_IMG_FMT_I42016, AOM_BITS_10, 0 },
|
||||
{ "park_joy_90p_10_422.y4m", 10, AOM_IMG_FMT_I42216, AOM_BITS_10, 2 },
|
||||
{ "park_joy_90p_10_444.y4m", 10, AOM_IMG_FMT_I44416, AOM_BITS_10, 1 },
|
||||
{ "park_joy_90p_12_420.y4m", 12, AOM_IMG_FMT_I42016, AOM_BITS_12, 2 },
|
||||
{ "park_joy_90p_12_422.y4m", 12, AOM_IMG_FMT_I42216, AOM_BITS_12, 2 },
|
||||
{ "park_joy_90p_12_444.y4m", 12, AOM_IMG_FMT_I44416, AOM_BITS_12, 2 },
|
||||
};
|
||||
|
||||
// Encoding modes tested
|
||||
const libaom_test::TestMode kEncodingModeVectors[] = {
|
||||
::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood,
|
||||
::libaom_test::kRealTime,
|
||||
};
|
||||
|
||||
// Speed settings tested
|
||||
const int kCpuUsedVectors[] = { 1, 2, 3, 5, 6 };
|
||||
|
||||
int is_extension_y4m(const char *filename) {
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if (!dot || dot == filename)
|
||||
return 0;
|
||||
else
|
||||
return !strcmp(dot, ".y4m");
|
||||
}
|
||||
|
||||
class EndToEndTest
|
||||
: public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode,
|
||||
TestVideoParam, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
EndToEndTest()
|
||||
: EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(2)),
|
||||
cpu_used_(GET_PARAM(3)), psnr_(0.0), nframes_(0),
|
||||
encoding_mode_(GET_PARAM(1)) {}
|
||||
|
||||
virtual ~EndToEndTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
cfg_.g_lag_in_frames = 5;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
} else {
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int) {
|
||||
psnr_ = 0.0;
|
||||
nframes_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
psnr_ += pkt->data.psnr.psnr[0];
|
||||
nframes_++;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 4);
|
||||
encoder->Control(AOME_SET_CPUUSED, cpu_used_);
|
||||
// Test screen coding tools at cpu_used = 1 && encoding mode is two-pass.
|
||||
if (cpu_used_ == 1 && encoding_mode_ == ::libaom_test::kTwoPassGood)
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN);
|
||||
else
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double GetAveragePsnr() const {
|
||||
if (nframes_) return psnr_ / nframes_;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double GetPsnrThreshold() {
|
||||
return kPsnrThreshold[cpu_used_][encoding_mode_];
|
||||
}
|
||||
|
||||
void DoTest() {
|
||||
cfg_.rc_target_bitrate = kBitrate;
|
||||
cfg_.g_error_resilient = 0;
|
||||
cfg_.g_profile = test_video_param_.profile;
|
||||
cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
|
||||
cfg_.g_bit_depth = test_video_param_.bit_depth;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH;
|
||||
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video;
|
||||
if (is_extension_y4m(test_video_param_.filename)) {
|
||||
video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0,
|
||||
kFrames));
|
||||
} else {
|
||||
video.reset(new libaom_test::YUVVideoSource(
|
||||
test_video_param_.filename, test_video_param_.fmt, kWidth, kHeight,
|
||||
kFramerate, 1, 0, kFrames));
|
||||
}
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
const double psnr = GetAveragePsnr();
|
||||
EXPECT_GT(psnr, GetPsnrThreshold())
|
||||
<< "cpu used = " << cpu_used_ << ", encoding mode = " << encoding_mode_;
|
||||
}
|
||||
|
||||
TestVideoParam test_video_param_;
|
||||
int cpu_used_;
|
||||
|
||||
private:
|
||||
double psnr_;
|
||||
unsigned int nframes_;
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
};
|
||||
|
||||
class EndToEndTestLarge : public EndToEndTest {};
|
||||
|
||||
TEST_P(EndToEndTestLarge, EndtoEndPSNRTest) { DoTest(); }
|
||||
|
||||
TEST_P(EndToEndTest, EndtoEndPSNRTest) { DoTest(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(EndToEndTestLarge,
|
||||
::testing::ValuesIn(kEncodingModeVectors),
|
||||
::testing::ValuesIn(kTestVectors),
|
||||
::testing::ValuesIn(kCpuUsedVectors));
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(EndToEndTest,
|
||||
::testing::Values(kEncodingModeVectors[0]),
|
||||
::testing::Values(kTestVectors[2]), // 444
|
||||
::testing::Values(kCpuUsedVectors[2]));
|
||||
} // namespace
|
||||
171
media/libaom/src/test/error_block_test.cc
Normal file
171
media/libaom/src/test/error_block_test.cc
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/entropy.h"
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
const int kNumIterations = 1000;
|
||||
|
||||
typedef int64_t (*ErrorBlockFunc)(const tran_low_t *coeff,
|
||||
const tran_low_t *dqcoeff,
|
||||
intptr_t block_size, int64_t *ssz, int bps);
|
||||
|
||||
typedef ::testing::tuple<ErrorBlockFunc, ErrorBlockFunc, aom_bit_depth_t>
|
||||
ErrorBlockParam;
|
||||
|
||||
class ErrorBlockTest : public ::testing::TestWithParam<ErrorBlockParam> {
|
||||
public:
|
||||
virtual ~ErrorBlockTest() {}
|
||||
virtual void SetUp() {
|
||||
error_block_op_ = GET_PARAM(0);
|
||||
ref_error_block_op_ = GET_PARAM(1);
|
||||
bit_depth_ = GET_PARAM(2);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
aom_bit_depth_t bit_depth_;
|
||||
ErrorBlockFunc error_block_op_;
|
||||
ErrorBlockFunc ref_error_block_op_;
|
||||
};
|
||||
|
||||
TEST_P(ErrorBlockTest, OperationCheck) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
|
||||
int err_count_total = 0;
|
||||
int first_failure = -1;
|
||||
intptr_t block_size;
|
||||
int64_t ssz;
|
||||
int64_t ret;
|
||||
int64_t ref_ssz;
|
||||
int64_t ref_ret;
|
||||
const int msb = bit_depth_ + 8 - 1;
|
||||
for (int i = 0; i < kNumIterations; ++i) {
|
||||
int err_count = 0;
|
||||
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
|
||||
for (int j = 0; j < block_size; j++) {
|
||||
// coeff and dqcoeff will always have at least the same sign, and this
|
||||
// can be used for optimization, so generate test input precisely.
|
||||
if (rnd(2)) {
|
||||
// Positive number
|
||||
coeff[j] = rnd(1 << msb);
|
||||
dqcoeff[j] = rnd(1 << msb);
|
||||
} else {
|
||||
// Negative number
|
||||
coeff[j] = -rnd(1 << msb);
|
||||
dqcoeff[j] = -rnd(1 << msb);
|
||||
}
|
||||
}
|
||||
ref_ret =
|
||||
ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
|
||||
err_count += (ref_ret != ret) | (ref_ssz != ssz);
|
||||
if (err_count && !err_count_total) {
|
||||
first_failure = i;
|
||||
}
|
||||
err_count_total += err_count;
|
||||
}
|
||||
EXPECT_EQ(0, err_count_total)
|
||||
<< "Error: Error Block Test, C output doesn't match optimized output. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
TEST_P(ErrorBlockTest, ExtremeValues) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
|
||||
DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
|
||||
int err_count_total = 0;
|
||||
int first_failure = -1;
|
||||
intptr_t block_size;
|
||||
int64_t ssz;
|
||||
int64_t ret;
|
||||
int64_t ref_ssz;
|
||||
int64_t ref_ret;
|
||||
const int msb = bit_depth_ + 8 - 1;
|
||||
int max_val = ((1 << msb) - 1);
|
||||
for (int i = 0; i < kNumIterations; ++i) {
|
||||
int err_count = 0;
|
||||
int k = (i / 9) % 9;
|
||||
|
||||
// Change the maximum coeff value, to test different bit boundaries
|
||||
if (k == 8 && (i % 9) == 0) {
|
||||
max_val >>= 1;
|
||||
}
|
||||
block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
|
||||
for (int j = 0; j < block_size; j++) {
|
||||
if (k < 4) {
|
||||
// Test at positive maximum values
|
||||
coeff[j] = k % 2 ? max_val : 0;
|
||||
dqcoeff[j] = (k >> 1) % 2 ? max_val : 0;
|
||||
} else if (k < 8) {
|
||||
// Test at negative maximum values
|
||||
coeff[j] = k % 2 ? -max_val : 0;
|
||||
dqcoeff[j] = (k >> 1) % 2 ? -max_val : 0;
|
||||
} else {
|
||||
if (rnd(2)) {
|
||||
// Positive number
|
||||
coeff[j] = rnd(1 << 14);
|
||||
dqcoeff[j] = rnd(1 << 14);
|
||||
} else {
|
||||
// Negative number
|
||||
coeff[j] = -rnd(1 << 14);
|
||||
dqcoeff[j] = -rnd(1 << 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
ref_ret =
|
||||
ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
|
||||
err_count += (ref_ret != ret) | (ref_ssz != ssz);
|
||||
if (err_count && !err_count_total) {
|
||||
first_failure = i;
|
||||
}
|
||||
err_count_total += err_count;
|
||||
}
|
||||
EXPECT_EQ(0, err_count_total)
|
||||
<< "Error: Error Block Test, C output doesn't match optimized output. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
#if (HAVE_SSE2 || HAVE_AVX)
|
||||
using ::testing::make_tuple;
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, ErrorBlockTest,
|
||||
::testing::Values(make_tuple(&av1_highbd_block_error_sse2,
|
||||
&av1_highbd_block_error_c, AOM_BITS_10),
|
||||
make_tuple(&av1_highbd_block_error_sse2,
|
||||
&av1_highbd_block_error_c, AOM_BITS_12),
|
||||
make_tuple(&av1_highbd_block_error_sse2,
|
||||
&av1_highbd_block_error_c, AOM_BITS_8)));
|
||||
#endif // HAVE_SSE2
|
||||
} // namespace
|
||||
438
media/libaom/src/test/error_resilience_test.cc
Normal file
438
media/libaom/src/test/error_resilience_test.cc
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxErrorFrames = 12;
|
||||
const int kMaxInvisibleErrorFrames = 12;
|
||||
const int kMaxDroppableFrames = 12;
|
||||
const int kMaxErrorResilientFrames = 12;
|
||||
const int kMaxNoMFMVFrames = 12;
|
||||
const int kMaxPrimRefNoneFrames = 12;
|
||||
const int kMaxSFrames = 12;
|
||||
const int kCpuUsed = 1;
|
||||
|
||||
class ErrorResilienceTestLarge
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
ErrorResilienceTestLarge()
|
||||
: EncoderTest(GET_PARAM(0)), psnr_(0.0), nframes_(0), mismatch_psnr_(0.0),
|
||||
mismatch_nframes_(0), encoding_mode_(GET_PARAM(1)), allow_mismatch_(0) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
virtual ~ErrorResilienceTestLarge() {}
|
||||
|
||||
void Reset() {
|
||||
error_nframes_ = 0;
|
||||
invisible_error_nframes_ = 0;
|
||||
droppable_nframes_ = 0;
|
||||
error_resilient_nframes_ = 0;
|
||||
nomfmv_nframes_ = 0;
|
||||
prim_ref_none_nframes_ = 0;
|
||||
s_nframes_ = 0;
|
||||
}
|
||||
|
||||
void SetupEncoder(int bitrate, int lag) {
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = bitrate;
|
||||
cfg_.kf_mode = AOM_KF_DISABLED;
|
||||
cfg_.g_lag_in_frames = lag;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {
|
||||
psnr_ = 0.0;
|
||||
nframes_ = 0;
|
||||
decoded_nframes_ = 0;
|
||||
mismatch_psnr_ = 0.0;
|
||||
mismatch_nframes_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
psnr_ += pkt->data.psnr.psnr[0];
|
||||
nframes_++;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
|
||||
libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 0) encoder->Control(AOME_SET_CPUUSED, kCpuUsed);
|
||||
frame_flags_ &=
|
||||
~(AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
|
||||
AOM_EFLAG_NO_REF_FRAME_MVS | AOM_EFLAG_ERROR_RESILIENT |
|
||||
AOM_EFLAG_SET_S_FRAME | AOM_EFLAG_SET_PRIMARY_REF_NONE);
|
||||
if (droppable_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < droppable_nframes_; ++i) {
|
||||
if (droppable_frames_[i] == video->frame()) {
|
||||
std::cout << " Encoding droppable frame: "
|
||||
<< droppable_frames_[i] << "\n";
|
||||
frame_flags_ |= (AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
|
||||
AOM_EFLAG_NO_UPD_ARF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error_resilient_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < error_resilient_nframes_; ++i) {
|
||||
if (error_resilient_frames_[i] == video->frame()) {
|
||||
std::cout << " Encoding error_resilient frame: "
|
||||
<< error_resilient_frames_[i] << "\n";
|
||||
frame_flags_ |= AOM_EFLAG_ERROR_RESILIENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nomfmv_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < nomfmv_nframes_; ++i) {
|
||||
if (nomfmv_frames_[i] == video->frame()) {
|
||||
std::cout << " Encoding no mfmv frame: "
|
||||
<< nomfmv_frames_[i] << "\n";
|
||||
frame_flags_ |= AOM_EFLAG_NO_REF_FRAME_MVS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prim_ref_none_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < prim_ref_none_nframes_; ++i) {
|
||||
if (prim_ref_none_frames_[i] == video->frame()) {
|
||||
std::cout << " Encoding no PRIMARY_REF_NONE frame: "
|
||||
<< prim_ref_none_frames_[i] << "\n";
|
||||
frame_flags_ |= AOM_EFLAG_SET_PRIMARY_REF_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encoder->Control(AV1E_SET_S_FRAME_MODE, 0);
|
||||
if (s_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < s_nframes_; ++i) {
|
||||
if (s_frames_[i] == video->frame()) {
|
||||
std::cout << " Encoding S frame: " << s_frames_[i]
|
||||
<< "\n";
|
||||
frame_flags_ |= AOM_EFLAG_SET_S_FRAME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_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 bool DoDecodeInvisible() const {
|
||||
if (invisible_error_nframes_ > 0 &&
|
||||
(cfg_.g_pass == AOM_RC_LAST_PASS || cfg_.g_pass == AOM_RC_ONE_PASS)) {
|
||||
for (unsigned int i = 0; i < invisible_error_nframes_; ++i) {
|
||||
if (invisible_error_frames_[i] == nframes_ - 1) {
|
||||
std::cout << " Skipping decoding all invisible frames in "
|
||||
"frame pkt: "
|
||||
<< invisible_error_frames_[i] << "\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void MismatchHook(const aom_image_t *img1, const aom_image_t *img2) {
|
||||
if (allow_mismatch_) {
|
||||
double mismatch_psnr = compute_psnr(img1, img2);
|
||||
mismatch_psnr_ += mismatch_psnr;
|
||||
++mismatch_nframes_;
|
||||
// std::cout << "Mismatch frame psnr: " << mismatch_psnr << "\n";
|
||||
} else {
|
||||
::libaom_test::EncoderTest::MismatchHook(img1, img2);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DecompressedFrameHook(const aom_image_t &img,
|
||||
aom_codec_pts_t pts) {
|
||||
(void)img;
|
||||
(void)pts;
|
||||
++decoded_nframes_;
|
||||
}
|
||||
|
||||
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 SetInvisibleErrorFrames(int num, unsigned int *list) {
|
||||
if (num > kMaxInvisibleErrorFrames)
|
||||
num = kMaxInvisibleErrorFrames;
|
||||
else if (num < 0)
|
||||
num = 0;
|
||||
invisible_error_nframes_ = num;
|
||||
for (unsigned int i = 0; i < invisible_error_nframes_; ++i)
|
||||
invisible_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];
|
||||
}
|
||||
|
||||
void SetErrorResilientFrames(int num, unsigned int *list) {
|
||||
if (num > kMaxErrorResilientFrames)
|
||||
num = kMaxErrorResilientFrames;
|
||||
else if (num < 0)
|
||||
num = 0;
|
||||
error_resilient_nframes_ = num;
|
||||
for (unsigned int i = 0; i < error_resilient_nframes_; ++i)
|
||||
error_resilient_frames_[i] = list[i];
|
||||
}
|
||||
|
||||
void SetNoMFMVFrames(int num, unsigned int *list) {
|
||||
if (num > kMaxNoMFMVFrames)
|
||||
num = kMaxNoMFMVFrames;
|
||||
else if (num < 0)
|
||||
num = 0;
|
||||
nomfmv_nframes_ = num;
|
||||
for (unsigned int i = 0; i < nomfmv_nframes_; ++i)
|
||||
nomfmv_frames_[i] = list[i];
|
||||
}
|
||||
|
||||
void SetPrimaryRefNoneFrames(int num, unsigned int *list) {
|
||||
if (num > kMaxPrimRefNoneFrames)
|
||||
num = kMaxPrimRefNoneFrames;
|
||||
else if (num < 0)
|
||||
num = 0;
|
||||
prim_ref_none_nframes_ = num;
|
||||
for (unsigned int i = 0; i < prim_ref_none_nframes_; ++i)
|
||||
prim_ref_none_frames_[i] = list[i];
|
||||
}
|
||||
|
||||
void SetSFrames(int num, unsigned int *list) {
|
||||
if (num > kMaxSFrames)
|
||||
num = kMaxSFrames;
|
||||
else if (num < 0)
|
||||
num = 0;
|
||||
s_nframes_ = num;
|
||||
for (unsigned int i = 0; i < s_nframes_; ++i) s_frames_[i] = list[i];
|
||||
}
|
||||
|
||||
unsigned int GetMismatchFrames() { return mismatch_nframes_; }
|
||||
unsigned int GetEncodedFrames() { return nframes_; }
|
||||
unsigned int GetDecodedFrames() { return decoded_nframes_; }
|
||||
|
||||
void SetAllowMismatch(int allow) { allow_mismatch_ = allow; }
|
||||
|
||||
private:
|
||||
double psnr_;
|
||||
unsigned int nframes_;
|
||||
unsigned int decoded_nframes_;
|
||||
unsigned int error_nframes_;
|
||||
unsigned int invisible_error_nframes_;
|
||||
unsigned int droppable_nframes_;
|
||||
unsigned int error_resilient_nframes_;
|
||||
unsigned int nomfmv_nframes_;
|
||||
unsigned int prim_ref_none_nframes_;
|
||||
unsigned int s_nframes_;
|
||||
double mismatch_psnr_;
|
||||
unsigned int mismatch_nframes_;
|
||||
unsigned int error_frames_[kMaxErrorFrames];
|
||||
unsigned int invisible_error_frames_[kMaxInvisibleErrorFrames];
|
||||
unsigned int droppable_frames_[kMaxDroppableFrames];
|
||||
unsigned int error_resilient_frames_[kMaxErrorResilientFrames];
|
||||
unsigned int nomfmv_frames_[kMaxNoMFMVFrames];
|
||||
unsigned int prim_ref_none_frames_[kMaxPrimRefNoneFrames];
|
||||
unsigned int s_frames_[kMaxSFrames];
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
int allow_mismatch_;
|
||||
};
|
||||
|
||||
TEST_P(ErrorResilienceTestLarge, OnVersusOff) {
|
||||
SetupEncoder(2000, 10);
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
cfg_.g_timebase.den, cfg_.g_timebase.num,
|
||||
0, 12);
|
||||
|
||||
// Global error resilient mode OFF.
|
||||
cfg_.g_error_resilient = 0;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
const double psnr_resilience_off = GetAveragePsnr();
|
||||
EXPECT_GT(psnr_resilience_off, 25.0);
|
||||
|
||||
Reset();
|
||||
// Error resilient mode ON for certain frames
|
||||
unsigned int num_error_resilient_frames = 5;
|
||||
unsigned int error_resilient_frame_list[] = { 3, 5, 6, 9, 11 };
|
||||
SetErrorResilientFrames(num_error_resilient_frames,
|
||||
error_resilient_frame_list);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
const double psnr_resilience_on = GetAveragePsnr();
|
||||
EXPECT_GT(psnr_resilience_on, 25.0);
|
||||
|
||||
// Test that turning on error resilient mode hurts by 10% at most.
|
||||
if (psnr_resilience_off > 0.0) {
|
||||
const double psnr_ratio = psnr_resilience_on / psnr_resilience_off;
|
||||
EXPECT_GE(psnr_ratio, 0.9);
|
||||
EXPECT_LE(psnr_ratio, 1.1);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for successful decoding and no encoder/decoder mismatch
|
||||
// if we lose (i.e., drop before decoding) a set of droppable
|
||||
// frames (i.e., frames that don't update any reference buffers).
|
||||
TEST_P(ErrorResilienceTestLarge, DropFramesWithoutRecovery) {
|
||||
SetupEncoder(500, 10);
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
cfg_.g_timebase.den, cfg_.g_timebase.num,
|
||||
0, 20);
|
||||
|
||||
// Set an arbitrary set of error frames same as droppable frames.
|
||||
unsigned int num_droppable_frames = 3;
|
||||
unsigned int droppable_frame_list[] = { 5, 10, 13 };
|
||||
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 << " Encoded frames: " << GetEncodedFrames() << "\n";
|
||||
std::cout << " Decoded frames: " << GetDecodedFrames() << "\n";
|
||||
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n";
|
||||
EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_droppable_frames);
|
||||
}
|
||||
|
||||
// Check for ParseAbility property of an error-resilient frame.
|
||||
// Encode a frame in error-resilient mode (E-frame), and disallow all
|
||||
// subsequent frames from using MFMV. If frames are dropped before the
|
||||
// E frame, all frames starting from the E frame should be parse-able.
|
||||
TEST_P(ErrorResilienceTestLarge, ParseAbilityTest) {
|
||||
SetupEncoder(500, 10);
|
||||
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
cfg_.g_timebase.den, cfg_.g_timebase.num,
|
||||
0, 15);
|
||||
|
||||
SetAllowMismatch(1);
|
||||
|
||||
// Note that an E-frame cannot be forced on a frame that is a
|
||||
// show_existing_frame, or a frame that comes directly after an invisible
|
||||
// frame. Currently, this will cause an assertion failure.
|
||||
// Set an arbitrary error resilient (E) frame
|
||||
unsigned int num_error_resilient_frames = 1;
|
||||
unsigned int error_resilient_frame_list[] = { 8 };
|
||||
SetErrorResilientFrames(num_error_resilient_frames,
|
||||
error_resilient_frame_list);
|
||||
// Ensure that any invisible frames before the E frame are dropped
|
||||
SetInvisibleErrorFrames(num_error_resilient_frames,
|
||||
error_resilient_frame_list);
|
||||
// Set all frames after the error resilient frame to not allow MFMV
|
||||
unsigned int num_post_error_resilient_frames = 6;
|
||||
unsigned int post_error_resilient_frame_list[] = { 9, 10, 11, 12, 13, 14 };
|
||||
SetNoMFMVFrames(num_post_error_resilient_frames,
|
||||
post_error_resilient_frame_list);
|
||||
|
||||
// Set a few frames before the E frame that are lost (not decoded)
|
||||
unsigned int num_error_frames = 5;
|
||||
unsigned int error_frame_list[] = { 3, 4, 5, 6, 7 };
|
||||
SetErrorFrames(num_error_frames, error_frame_list);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::cout << " Encoded frames: " << GetEncodedFrames() << "\n";
|
||||
std::cout << " Decoded frames: " << GetDecodedFrames() << "\n";
|
||||
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n";
|
||||
EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_error_frames);
|
||||
// All frames following the E-frame and the E-frame are expected to have
|
||||
// mismatches, but still be parse-able.
|
||||
EXPECT_LE(GetMismatchFrames(), num_post_error_resilient_frames + 1);
|
||||
}
|
||||
|
||||
// Check for ParseAbility property of an S frame.
|
||||
// Encode an S-frame. If frames are dropped before the S-frame, all frames
|
||||
// starting from the S frame should be parse-able.
|
||||
TEST_P(ErrorResilienceTestLarge, SFrameTest) {
|
||||
SetupEncoder(500, 10);
|
||||
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
cfg_.g_timebase.den, cfg_.g_timebase.num,
|
||||
0, 15);
|
||||
|
||||
SetAllowMismatch(1);
|
||||
|
||||
// Note that an S-frame cannot be forced on a frame that is a
|
||||
// show_existing_frame. This issue still needs to be addressed.
|
||||
// Set an arbitrary S-frame
|
||||
unsigned int num_s_frames = 1;
|
||||
unsigned int s_frame_list[] = { 6 };
|
||||
SetSFrames(num_s_frames, s_frame_list);
|
||||
// Ensure that any invisible frames before the S frame are dropped
|
||||
SetInvisibleErrorFrames(num_s_frames, s_frame_list);
|
||||
|
||||
// Set a few frames before the S frame that are lost (not decoded)
|
||||
unsigned int num_error_frames = 4;
|
||||
unsigned int error_frame_list[] = { 2, 3, 4, 5 };
|
||||
SetErrorFrames(num_error_frames, error_frame_list);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::cout << " Encoded frames: " << GetEncodedFrames() << "\n";
|
||||
std::cout << " Decoded frames: " << GetDecodedFrames() << "\n";
|
||||
std::cout << " Mismatch frames: " << GetMismatchFrames() << "\n";
|
||||
EXPECT_EQ(GetEncodedFrames() - GetDecodedFrames(), num_error_frames);
|
||||
// All frames following the S-frame and the S-frame are expected to have
|
||||
// mismatches, but still be parse-able.
|
||||
EXPECT_LE(GetMismatchFrames(), GetEncodedFrames() - s_frame_list[0]);
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(ErrorResilienceTestLarge, NONREALTIME_TEST_MODES);
|
||||
} // namespace
|
||||
273
media/libaom/src/test/ethread_test.cc
Normal file
273
media/libaom/src/test/ethread_test.cc
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/md5_helper.h"
|
||||
#include "test/util.h"
|
||||
#include "test/yuv_video_source.h"
|
||||
|
||||
namespace {
|
||||
class AVxEncoderThreadTest
|
||||
: public ::libaom_test::CodecTestWith4Params<libaom_test::TestMode, int,
|
||||
int, int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AVxEncoderThreadTest()
|
||||
: EncoderTest(GET_PARAM(0)), encoder_initialized_(false),
|
||||
encoding_mode_(GET_PARAM(1)), set_cpu_used_(GET_PARAM(2)),
|
||||
tile_cols_(GET_PARAM(3)), tile_rows_(GET_PARAM(4)) {
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
cfg.w = 1280;
|
||||
cfg.h = 720;
|
||||
cfg.allow_lowbitdepth = 1;
|
||||
decoder_ = codec_->CreateDecoder(cfg, 0);
|
||||
if (decoder_->IsAV1()) {
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_ROW, -1);
|
||||
decoder_->Control(AV1_SET_DECODE_TILE_COL, -1);
|
||||
}
|
||||
|
||||
size_enc_.clear();
|
||||
md5_dec_.clear();
|
||||
md5_enc_.clear();
|
||||
}
|
||||
virtual ~AVxEncoderThreadTest() { delete decoder_; }
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
cfg_.g_lag_in_frames = 5;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.rc_2pass_vbr_minsection_pct = 5;
|
||||
cfg_.rc_2pass_vbr_maxsection_pct = 2000;
|
||||
} else {
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.g_error_resilient = 1;
|
||||
}
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {
|
||||
encoder_initialized_ = false;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource * /*video*/,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (!encoder_initialized_) {
|
||||
SetTileSize(encoder);
|
||||
encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
|
||||
encoder->Control(AV1E_SET_ROW_MT, row_mt_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 0);
|
||||
} else {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
|
||||
encoder->Control(AV1E_SET_AQ_MODE, 3);
|
||||
}
|
||||
encoder_initialized_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetTileSize(libaom_test::Encoder *encoder) {
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, tile_cols_);
|
||||
encoder->Control(AV1E_SET_TILE_ROWS, tile_rows_);
|
||||
}
|
||||
|
||||
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
size_enc_.push_back(pkt->data.frame.sz);
|
||||
|
||||
::libaom_test::MD5 md5_enc;
|
||||
md5_enc.Add(reinterpret_cast<uint8_t *>(pkt->data.frame.buf),
|
||||
pkt->data.frame.sz);
|
||||
md5_enc_.push_back(md5_enc.Get());
|
||||
|
||||
const aom_codec_err_t res = decoder_->DecodeFrame(
|
||||
reinterpret_cast<uint8_t *>(pkt->data.frame.buf), pkt->data.frame.sz);
|
||||
if (res != AOM_CODEC_OK) {
|
||||
abort_ = true;
|
||||
ASSERT_EQ(AOM_CODEC_OK, res);
|
||||
}
|
||||
const aom_image_t *img = decoder_->GetDxData().Next();
|
||||
|
||||
if (img) {
|
||||
::libaom_test::MD5 md5_res;
|
||||
md5_res.Add(img);
|
||||
md5_dec_.push_back(md5_res.Get());
|
||||
}
|
||||
}
|
||||
|
||||
void DoTest() {
|
||||
::libaom_test::YUVVideoSource video(
|
||||
"niklas_640_480_30.yuv", AOM_IMG_FMT_I420, 640, 480, 30, 1, 15, 21);
|
||||
cfg_.rc_target_bitrate = 1000;
|
||||
|
||||
// Encode using single thread.
|
||||
row_mt_ = 0;
|
||||
cfg_.g_threads = 1;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::vector<size_t> single_thr_size_enc;
|
||||
std::vector<std::string> single_thr_md5_enc;
|
||||
std::vector<std::string> single_thr_md5_dec;
|
||||
single_thr_size_enc = size_enc_;
|
||||
single_thr_md5_enc = md5_enc_;
|
||||
single_thr_md5_dec = md5_dec_;
|
||||
size_enc_.clear();
|
||||
md5_enc_.clear();
|
||||
md5_dec_.clear();
|
||||
|
||||
// Encode using multiple threads.
|
||||
cfg_.g_threads = 4;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::vector<size_t> multi_thr_size_enc;
|
||||
std::vector<std::string> multi_thr_md5_enc;
|
||||
std::vector<std::string> multi_thr_md5_dec;
|
||||
multi_thr_size_enc = size_enc_;
|
||||
multi_thr_md5_enc = md5_enc_;
|
||||
multi_thr_md5_dec = md5_dec_;
|
||||
size_enc_.clear();
|
||||
md5_enc_.clear();
|
||||
md5_dec_.clear();
|
||||
|
||||
// Check that the vectors are equal.
|
||||
ASSERT_EQ(single_thr_size_enc, multi_thr_size_enc);
|
||||
ASSERT_EQ(single_thr_md5_enc, multi_thr_md5_enc);
|
||||
ASSERT_EQ(single_thr_md5_dec, multi_thr_md5_dec);
|
||||
|
||||
// Encode using multiple threads row-mt enabled.
|
||||
row_mt_ = 1;
|
||||
cfg_.g_threads = 2;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::vector<size_t> multi_thr2_row_mt_size_enc;
|
||||
std::vector<std::string> multi_thr2_row_mt_md5_enc;
|
||||
std::vector<std::string> multi_thr2_row_mt_md5_dec;
|
||||
multi_thr2_row_mt_size_enc = size_enc_;
|
||||
multi_thr2_row_mt_md5_enc = md5_enc_;
|
||||
multi_thr2_row_mt_md5_dec = md5_dec_;
|
||||
size_enc_.clear();
|
||||
md5_enc_.clear();
|
||||
md5_dec_.clear();
|
||||
|
||||
// Disable threads=3 test for now to reduce the time so that the nightly
|
||||
// test would not time out.
|
||||
// cfg_.g_threads = 3;
|
||||
// ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
// std::vector<size_t> multi_thr3_row_mt_size_enc;
|
||||
// std::vector<std::string> multi_thr3_row_mt_md5_enc;
|
||||
// std::vector<std::string> multi_thr3_row_mt_md5_dec;
|
||||
// multi_thr3_row_mt_size_enc = size_enc_;
|
||||
// multi_thr3_row_mt_md5_enc = md5_enc_;
|
||||
// multi_thr3_row_mt_md5_dec = md5_dec_;
|
||||
// size_enc_.clear();
|
||||
// md5_enc_.clear();
|
||||
// md5_dec_.clear();
|
||||
// Check that the vectors are equal.
|
||||
// ASSERT_EQ(multi_thr3_row_mt_size_enc, multi_thr2_row_mt_size_enc);
|
||||
// ASSERT_EQ(multi_thr3_row_mt_md5_enc, multi_thr2_row_mt_md5_enc);
|
||||
// ASSERT_EQ(multi_thr3_row_mt_md5_dec, multi_thr2_row_mt_md5_dec);
|
||||
|
||||
cfg_.g_threads = 4;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
std::vector<size_t> multi_thr4_row_mt_size_enc;
|
||||
std::vector<std::string> multi_thr4_row_mt_md5_enc;
|
||||
std::vector<std::string> multi_thr4_row_mt_md5_dec;
|
||||
multi_thr4_row_mt_size_enc = size_enc_;
|
||||
multi_thr4_row_mt_md5_enc = md5_enc_;
|
||||
multi_thr4_row_mt_md5_dec = md5_dec_;
|
||||
size_enc_.clear();
|
||||
md5_enc_.clear();
|
||||
md5_dec_.clear();
|
||||
|
||||
// Check that the vectors are equal.
|
||||
ASSERT_EQ(multi_thr4_row_mt_size_enc, multi_thr2_row_mt_size_enc);
|
||||
ASSERT_EQ(multi_thr4_row_mt_md5_enc, multi_thr2_row_mt_md5_enc);
|
||||
ASSERT_EQ(multi_thr4_row_mt_md5_dec, multi_thr2_row_mt_md5_dec);
|
||||
}
|
||||
|
||||
bool encoder_initialized_;
|
||||
::libaom_test::TestMode encoding_mode_;
|
||||
int set_cpu_used_;
|
||||
int tile_cols_;
|
||||
int tile_rows_;
|
||||
int row_mt_;
|
||||
::libaom_test::Decoder *decoder_;
|
||||
std::vector<size_t> size_enc_;
|
||||
std::vector<std::string> md5_enc_;
|
||||
std::vector<std::string> md5_dec_;
|
||||
};
|
||||
|
||||
TEST_P(AVxEncoderThreadTest, EncoderResultTest) {
|
||||
cfg_.large_scale_tile = 0;
|
||||
decoder_->Control(AV1_SET_TILE_MODE, 0);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
class AVxEncoderThreadTestLarge : public AVxEncoderThreadTest {};
|
||||
|
||||
TEST_P(AVxEncoderThreadTestLarge, EncoderResultTest) {
|
||||
cfg_.large_scale_tile = 0;
|
||||
decoder_->Control(AV1_SET_TILE_MODE, 0);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
// For AV1, only test speed 0 to 3.
|
||||
// Here test cpu_used 2 and 3
|
||||
AV1_INSTANTIATE_TEST_CASE(AVxEncoderThreadTest,
|
||||
::testing::Values(::libaom_test::kTwoPassGood),
|
||||
::testing::Range(2, 4), ::testing::Values(0, 2),
|
||||
::testing::Values(0, 1));
|
||||
|
||||
// Test cpu_used 0 and 1.
|
||||
AV1_INSTANTIATE_TEST_CASE(AVxEncoderThreadTestLarge,
|
||||
::testing::Values(::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(0, 2), ::testing::Values(0, 1, 2, 6),
|
||||
::testing::Values(0, 1, 2, 6));
|
||||
|
||||
class AVxEncoderThreadLSTest : public AVxEncoderThreadTest {
|
||||
virtual void SetTileSize(libaom_test::Encoder *encoder) {
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, tile_cols_);
|
||||
encoder->Control(AV1E_SET_TILE_ROWS, tile_rows_);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(AVxEncoderThreadLSTest, EncoderResultTest) {
|
||||
cfg_.large_scale_tile = 1;
|
||||
decoder_->Control(AV1_SET_TILE_MODE, 1);
|
||||
decoder_->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
class AVxEncoderThreadLSTestLarge : public AVxEncoderThreadLSTest {};
|
||||
|
||||
TEST_P(AVxEncoderThreadLSTestLarge, EncoderResultTest) {
|
||||
cfg_.large_scale_tile = 1;
|
||||
decoder_->Control(AV1_SET_TILE_MODE, 1);
|
||||
decoder_->Control(AV1D_EXT_TILE_DEBUG, 1);
|
||||
DoTest();
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(AVxEncoderThreadLSTestLarge,
|
||||
::testing::Values(::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood),
|
||||
::testing::Range(0, 4), ::testing::Values(0, 6),
|
||||
::testing::Values(0, 6));
|
||||
} // namespace
|
||||
29
media/libaom/src/test/examples.sh
Normal file
29
media/libaom/src/test/examples.sh
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file runs all of the tests for the libaom examples.
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
example_tests=$(ls -r $(dirname $0)/*.sh)
|
||||
|
||||
# List of script names to exclude.
|
||||
exclude_list="best_encode examples run_encodes tools_common"
|
||||
|
||||
# Filter out the scripts in $exclude_list.
|
||||
for word in ${exclude_list}; do
|
||||
example_tests=$(filter_strings "${example_tests}" "${word}" exclude)
|
||||
done
|
||||
|
||||
for test in ${example_tests}; do
|
||||
# Source each test script so that exporting variables can be avoided.
|
||||
AOM_TEST_NAME="$(basename ${test%.*})"
|
||||
. "${test}"
|
||||
done
|
||||
512
media/libaom/src/test/external_frame_buffer_test.cc
Normal file
512
media/libaom/src/test/external_frame_buffer_test.cc
Normal file
|
|
@ -0,0 +1,512 @@
|
|||
/*
|
||||
* Copyright (c) 2014 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>
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/decode_test_driver.h"
|
||||
#include "test/ivf_video_source.h"
|
||||
#include "test/md5_helper.h"
|
||||
#include "test/test_vectors.h"
|
||||
#include "test/util.h"
|
||||
#if CONFIG_WEBM_IO
|
||||
#include "test/webm_video_source.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
const int kVideoNameParam = 1;
|
||||
|
||||
struct ExternalFrameBuffer {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
int in_use;
|
||||
};
|
||||
|
||||
// Class to manipulate a list of external frame buffers.
|
||||
class ExternalFrameBufferList {
|
||||
public:
|
||||
ExternalFrameBufferList()
|
||||
: num_buffers_(0), num_used_buffers_(0), ext_fb_list_(NULL) {}
|
||||
|
||||
virtual ~ExternalFrameBufferList() {
|
||||
for (int i = 0; i < num_buffers_; ++i) {
|
||||
delete[] ext_fb_list_[i].data;
|
||||
}
|
||||
delete[] ext_fb_list_;
|
||||
}
|
||||
|
||||
// Creates the list to hold the external buffers. Returns true on success.
|
||||
bool CreateBufferList(int num_buffers) {
|
||||
if (num_buffers < 0) return false;
|
||||
|
||||
num_buffers_ = num_buffers;
|
||||
ext_fb_list_ = new ExternalFrameBuffer[num_buffers_];
|
||||
EXPECT_TRUE(ext_fb_list_ != NULL);
|
||||
memset(ext_fb_list_, 0, sizeof(ext_fb_list_[0]) * num_buffers_);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Searches the frame buffer list for a free frame buffer. Makes sure
|
||||
// that the frame buffer is at least |min_size| in bytes. Marks that the
|
||||
// frame buffer is in use by libvpx. Finally sets |fb| to point to the
|
||||
// external frame buffer. Returns < 0 on an error.
|
||||
int GetFreeFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
|
||||
EXPECT_TRUE(fb != NULL);
|
||||
const int idx = FindFreeBufferIndex();
|
||||
if (idx == num_buffers_) return -1;
|
||||
|
||||
if (ext_fb_list_[idx].size < min_size) {
|
||||
delete[] ext_fb_list_[idx].data;
|
||||
ext_fb_list_[idx].data = new uint8_t[min_size];
|
||||
memset(ext_fb_list_[idx].data, 0, min_size);
|
||||
ext_fb_list_[idx].size = min_size;
|
||||
}
|
||||
|
||||
SetFrameBuffer(idx, fb);
|
||||
|
||||
num_used_buffers_++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test function that will not allocate any data for the frame buffer.
|
||||
// Returns < 0 on an error.
|
||||
int GetZeroFrameBuffer(size_t min_size, aom_codec_frame_buffer_t *fb) {
|
||||
EXPECT_TRUE(fb != NULL);
|
||||
const int idx = FindFreeBufferIndex();
|
||||
if (idx == num_buffers_) return -1;
|
||||
|
||||
if (ext_fb_list_[idx].size < min_size) {
|
||||
delete[] ext_fb_list_[idx].data;
|
||||
ext_fb_list_[idx].data = NULL;
|
||||
ext_fb_list_[idx].size = min_size;
|
||||
}
|
||||
|
||||
SetFrameBuffer(idx, fb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Marks the external frame buffer that |fb| is pointing to as free.
|
||||
// Returns < 0 on an error.
|
||||
int ReturnFrameBuffer(aom_codec_frame_buffer_t *fb) {
|
||||
if (fb == NULL) {
|
||||
EXPECT_TRUE(fb != NULL);
|
||||
return -1;
|
||||
}
|
||||
ExternalFrameBuffer *const ext_fb =
|
||||
reinterpret_cast<ExternalFrameBuffer *>(fb->priv);
|
||||
if (ext_fb == NULL) {
|
||||
EXPECT_TRUE(ext_fb != NULL);
|
||||
return -1;
|
||||
}
|
||||
EXPECT_EQ(1, ext_fb->in_use);
|
||||
ext_fb->in_use = 0;
|
||||
num_used_buffers_--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Checks that the ximage data is contained within the external frame buffer
|
||||
// private data passed back in the ximage.
|
||||
void CheckXImageFrameBuffer(const aom_image_t *img) {
|
||||
if (img->fb_priv != NULL) {
|
||||
const struct ExternalFrameBuffer *const ext_fb =
|
||||
reinterpret_cast<ExternalFrameBuffer *>(img->fb_priv);
|
||||
|
||||
ASSERT_TRUE(img->planes[0] >= ext_fb->data &&
|
||||
img->planes[0] < (ext_fb->data + ext_fb->size));
|
||||
}
|
||||
}
|
||||
|
||||
int num_used_buffers() const { return num_used_buffers_; }
|
||||
|
||||
private:
|
||||
// Returns the index of the first free frame buffer. Returns |num_buffers_|
|
||||
// if there are no free frame buffers.
|
||||
int FindFreeBufferIndex() {
|
||||
int i;
|
||||
// Find a free frame buffer.
|
||||
for (i = 0; i < num_buffers_; ++i) {
|
||||
if (!ext_fb_list_[i].in_use) break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// Sets |fb| to an external frame buffer. idx is the index into the frame
|
||||
// buffer list.
|
||||
void SetFrameBuffer(int idx, aom_codec_frame_buffer_t *fb) {
|
||||
ASSERT_TRUE(fb != NULL);
|
||||
fb->data = ext_fb_list_[idx].data;
|
||||
fb->size = ext_fb_list_[idx].size;
|
||||
ASSERT_EQ(0, ext_fb_list_[idx].in_use);
|
||||
ext_fb_list_[idx].in_use = 1;
|
||||
fb->priv = &ext_fb_list_[idx];
|
||||
}
|
||||
|
||||
int num_buffers_;
|
||||
int num_used_buffers_;
|
||||
ExternalFrameBuffer *ext_fb_list_;
|
||||
};
|
||||
|
||||
#if CONFIG_WEBM_IO
|
||||
|
||||
// Callback used by libvpx to request the application to return a frame
|
||||
// buffer of at least |min_size| in bytes.
|
||||
int get_aom_frame_buffer(void *user_priv, size_t min_size,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferList *const fb_list =
|
||||
reinterpret_cast<ExternalFrameBufferList *>(user_priv);
|
||||
return fb_list->GetFreeFrameBuffer(min_size, fb);
|
||||
}
|
||||
|
||||
// Callback used by libvpx to tell the application that |fb| is not needed
|
||||
// anymore.
|
||||
int release_aom_frame_buffer(void *user_priv, aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferList *const fb_list =
|
||||
reinterpret_cast<ExternalFrameBufferList *>(user_priv);
|
||||
return fb_list->ReturnFrameBuffer(fb);
|
||||
}
|
||||
|
||||
// Callback will not allocate data for frame buffer.
|
||||
int get_aom_zero_frame_buffer(void *user_priv, size_t min_size,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferList *const fb_list =
|
||||
reinterpret_cast<ExternalFrameBufferList *>(user_priv);
|
||||
return fb_list->GetZeroFrameBuffer(min_size, fb);
|
||||
}
|
||||
|
||||
// Callback will allocate one less byte than |min_size|.
|
||||
int get_aom_one_less_byte_frame_buffer(void *user_priv, size_t min_size,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferList *const fb_list =
|
||||
reinterpret_cast<ExternalFrameBufferList *>(user_priv);
|
||||
return fb_list->GetFreeFrameBuffer(min_size - 1, fb);
|
||||
}
|
||||
|
||||
// Callback will not release the external frame buffer.
|
||||
int do_not_release_aom_frame_buffer(void *user_priv,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
(void)user_priv;
|
||||
(void)fb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // CONFIG_WEBM_IO
|
||||
|
||||
// Class for testing passing in external frame buffers to libaom.
|
||||
class ExternalFrameBufferMD5Test
|
||||
: public ::libaom_test::DecoderTest,
|
||||
public ::libaom_test::CodecTestWithParam<const char *> {
|
||||
protected:
|
||||
ExternalFrameBufferMD5Test()
|
||||
: DecoderTest(GET_PARAM(::libaom_test::kCodecFactoryParam)),
|
||||
md5_file_(NULL), num_buffers_(0) {}
|
||||
|
||||
virtual ~ExternalFrameBufferMD5Test() {
|
||||
if (md5_file_ != NULL) fclose(md5_file_);
|
||||
}
|
||||
|
||||
virtual void PreDecodeFrameHook(
|
||||
const libaom_test::CompressedVideoSource &video,
|
||||
libaom_test::Decoder *decoder) {
|
||||
if (num_buffers_ > 0 && video.frame_number() == 0) {
|
||||
// Have libvpx use frame buffers we create.
|
||||
ASSERT_TRUE(fb_list_.CreateBufferList(num_buffers_));
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
decoder->SetFrameBufferFunctions(GetAV1FrameBuffer,
|
||||
ReleaseAV1FrameBuffer, this));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenMD5File(const std::string &md5_file_name_) {
|
||||
md5_file_ = libaom_test::OpenTestDataFile(md5_file_name_);
|
||||
ASSERT_TRUE(md5_file_ != NULL)
|
||||
<< "Md5 file open failed. Filename: " << md5_file_name_;
|
||||
}
|
||||
|
||||
virtual void DecompressedFrameHook(const aom_image_t &img,
|
||||
const unsigned int frame_number) {
|
||||
ASSERT_TRUE(md5_file_ != NULL);
|
||||
char expected_md5[33];
|
||||
char junk[128];
|
||||
|
||||
// Read correct md5 checksums.
|
||||
const int res = fscanf(md5_file_, "%s %s", expected_md5, junk);
|
||||
ASSERT_NE(EOF, res) << "Read md5 data failed";
|
||||
expected_md5[32] = '\0';
|
||||
|
||||
::libaom_test::MD5 md5_res;
|
||||
md5_res.Add(&img);
|
||||
const char *const actual_md5 = md5_res.Get();
|
||||
|
||||
// Check md5 match.
|
||||
ASSERT_STREQ(expected_md5, actual_md5)
|
||||
<< "Md5 checksums don't match: frame number = " << frame_number;
|
||||
}
|
||||
|
||||
// Callback to get a free external frame buffer. Return value < 0 is an
|
||||
// error.
|
||||
static int GetAV1FrameBuffer(void *user_priv, size_t min_size,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferMD5Test *const md5Test =
|
||||
reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv);
|
||||
return md5Test->fb_list_.GetFreeFrameBuffer(min_size, fb);
|
||||
}
|
||||
|
||||
// Callback to release an external frame buffer. Return value < 0 is an
|
||||
// error.
|
||||
static int ReleaseAV1FrameBuffer(void *user_priv,
|
||||
aom_codec_frame_buffer_t *fb) {
|
||||
ExternalFrameBufferMD5Test *const md5Test =
|
||||
reinterpret_cast<ExternalFrameBufferMD5Test *>(user_priv);
|
||||
return md5Test->fb_list_.ReturnFrameBuffer(fb);
|
||||
}
|
||||
|
||||
void set_num_buffers(int num_buffers) { num_buffers_ = num_buffers; }
|
||||
int num_buffers() const { return num_buffers_; }
|
||||
|
||||
private:
|
||||
FILE *md5_file_;
|
||||
int num_buffers_;
|
||||
ExternalFrameBufferList fb_list_;
|
||||
};
|
||||
|
||||
#if CONFIG_WEBM_IO
|
||||
const char kAV1TestFile[] = "av1-1-b8-01-size-226x226.ivf";
|
||||
const char kAV1NonRefTestFile[] = "av1-1-b8-01-size-226x226.ivf";
|
||||
|
||||
// Class for testing passing in external frame buffers to libvpx.
|
||||
class ExternalFrameBufferTest : public ::testing::Test {
|
||||
protected:
|
||||
ExternalFrameBufferTest() : video_(NULL), decoder_(NULL), num_buffers_(0) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
video_ = new libaom_test::IVFVideoSource(kAV1TestFile);
|
||||
ASSERT_TRUE(video_ != NULL);
|
||||
video_->Init();
|
||||
video_->Begin();
|
||||
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
decoder_ = new libaom_test::AV1Decoder(cfg, 0);
|
||||
ASSERT_TRUE(decoder_ != NULL);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
delete decoder_;
|
||||
decoder_ = NULL;
|
||||
delete video_;
|
||||
video_ = NULL;
|
||||
}
|
||||
|
||||
// Passes the external frame buffer information to libvpx.
|
||||
aom_codec_err_t SetFrameBufferFunctions(
|
||||
int num_buffers, aom_get_frame_buffer_cb_fn_t cb_get,
|
||||
aom_release_frame_buffer_cb_fn_t cb_release) {
|
||||
if (num_buffers > 0) {
|
||||
num_buffers_ = num_buffers;
|
||||
EXPECT_TRUE(fb_list_.CreateBufferList(num_buffers_));
|
||||
}
|
||||
|
||||
return decoder_->SetFrameBufferFunctions(cb_get, cb_release, &fb_list_);
|
||||
}
|
||||
|
||||
aom_codec_err_t DecodeOneFrame() {
|
||||
const aom_codec_err_t res =
|
||||
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
|
||||
CheckDecodedFrames();
|
||||
if (res == AOM_CODEC_OK) video_->Next();
|
||||
return res;
|
||||
}
|
||||
|
||||
aom_codec_err_t DecodeRemainingFrames() {
|
||||
for (; video_->cxdata() != NULL; video_->Next()) {
|
||||
const aom_codec_err_t res =
|
||||
decoder_->DecodeFrame(video_->cxdata(), video_->frame_size());
|
||||
if (res != AOM_CODEC_OK) return res;
|
||||
CheckDecodedFrames();
|
||||
}
|
||||
return AOM_CODEC_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
void CheckDecodedFrames() {
|
||||
libaom_test::DxDataIterator dec_iter = decoder_->GetDxData();
|
||||
const aom_image_t *img = NULL;
|
||||
|
||||
// Get decompressed data
|
||||
while ((img = dec_iter.Next()) != NULL) {
|
||||
fb_list_.CheckXImageFrameBuffer(img);
|
||||
}
|
||||
}
|
||||
|
||||
libaom_test::IVFVideoSource *video_;
|
||||
libaom_test::AV1Decoder *decoder_;
|
||||
int num_buffers_;
|
||||
ExternalFrameBufferList fb_list_;
|
||||
};
|
||||
|
||||
class ExternalFrameBufferNonRefTest : public ExternalFrameBufferTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
video_ = new libaom_test::IVFVideoSource(kAV1NonRefTestFile);
|
||||
ASSERT_TRUE(video_ != NULL);
|
||||
video_->Init();
|
||||
video_->Begin();
|
||||
|
||||
aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
|
||||
decoder_ = new libaom_test::AV1Decoder(cfg, 0);
|
||||
ASSERT_TRUE(decoder_ != NULL);
|
||||
}
|
||||
|
||||
virtual void CheckFrameBufferRelease() {
|
||||
TearDown();
|
||||
ASSERT_EQ(0, fb_list_.num_used_buffers());
|
||||
}
|
||||
};
|
||||
#endif // CONFIG_WEBM_IO
|
||||
|
||||
// This test runs through the set of test vectors, and decodes them.
|
||||
// Libvpx will call into the application to allocate a frame buffer when
|
||||
// needed. The md5 checksums are computed for each frame in the video file.
|
||||
// If md5 checksums match the correct md5 data, then the test is passed.
|
||||
// Otherwise, the test failed.
|
||||
TEST_P(ExternalFrameBufferMD5Test, DISABLED_ExtFBMD5Match) {
|
||||
const std::string filename = GET_PARAM(kVideoNameParam);
|
||||
|
||||
// Number of buffers equals #AOM_MAXIMUM_REF_BUFFERS +
|
||||
// #AOM_MAXIMUM_WORK_BUFFERS + four jitter buffers.
|
||||
const int jitter_buffers = 4;
|
||||
const int num_buffers =
|
||||
AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS + jitter_buffers;
|
||||
set_num_buffers(num_buffers);
|
||||
|
||||
// Open compressed video file.
|
||||
testing::internal::scoped_ptr<libaom_test::CompressedVideoSource> video;
|
||||
if (filename.substr(filename.length() - 3, 3) == "ivf") {
|
||||
video.reset(new libaom_test::IVFVideoSource(filename));
|
||||
} else {
|
||||
#if CONFIG_WEBM_IO
|
||||
video.reset(new libaom_test::WebMVideoSource(filename));
|
||||
#else
|
||||
fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n",
|
||||
filename.c_str());
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
video->Init();
|
||||
|
||||
// Construct md5 file name.
|
||||
const std::string md5_filename = filename + ".md5";
|
||||
OpenMD5File(md5_filename);
|
||||
|
||||
// Decode frame, and check the md5 matching.
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
}
|
||||
|
||||
#if CONFIG_WEBM_IO
|
||||
TEST_F(ExternalFrameBufferTest, MinFrameBuffers) {
|
||||
// Minimum number of external frame buffers for AV1 is
|
||||
// #AOM_MAXIMUM_REF_BUFFERS + #AOM_MAXIMUM_WORK_BUFFERS.
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, EightJitterBuffers) {
|
||||
// Number of buffers equals #AOM_MAXIMUM_REF_BUFFERS +
|
||||
// #AOM_MAXIMUM_WORK_BUFFERS + eight jitter buffers.
|
||||
const int jitter_buffers = 8;
|
||||
const int num_buffers =
|
||||
AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS + jitter_buffers;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, DISABLED_NotEnoughBuffers) {
|
||||
// Minimum number of external frame buffers for AV1 is
|
||||
// #AOM_MAXIMUM_REF_BUFFERS + #AOM_MAXIMUM_WORK_BUFFERS. Most files will
|
||||
// only use 5 frame buffers at one time.
|
||||
const int num_buffers = 2;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
|
||||
// Only run this on long clips. Decoding a very short clip will return
|
||||
// AOM_CODEC_OK even with only 2 buffers.
|
||||
ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, DISABLED_NoRelease) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
do_not_release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
|
||||
ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeRemainingFrames());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, NullRealloc) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_zero_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeOneFrame());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, ReallocOneLessByte) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK, SetFrameBufferFunctions(
|
||||
num_buffers, get_aom_one_less_byte_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_MEM_ERROR, DecodeOneFrame());
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, NullGetFunction) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(
|
||||
AOM_CODEC_INVALID_PARAM,
|
||||
SetFrameBufferFunctions(num_buffers, NULL, release_aom_frame_buffer));
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, NullReleaseFunction) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_INVALID_PARAM,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer, NULL));
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeOneFrame());
|
||||
ASSERT_EQ(AOM_CODEC_ERROR,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
}
|
||||
|
||||
TEST_F(ExternalFrameBufferNonRefTest, ReleaseNonRefFrameBuffer) {
|
||||
const int num_buffers = AOM_MAXIMUM_REF_BUFFERS + AOM_MAXIMUM_WORK_BUFFERS;
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
SetFrameBufferFunctions(num_buffers, get_aom_frame_buffer,
|
||||
release_aom_frame_buffer));
|
||||
ASSERT_EQ(AOM_CODEC_OK, DecodeRemainingFrames());
|
||||
CheckFrameBufferRelease();
|
||||
}
|
||||
#endif // CONFIG_WEBM_IO
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(
|
||||
ExternalFrameBufferMD5Test,
|
||||
::testing::ValuesIn(libaom_test::kAV1TestVectors,
|
||||
libaom_test::kAV1TestVectors +
|
||||
libaom_test::kNumAV1TestVectors));
|
||||
} // namespace
|
||||
256
media/libaom/src/test/fft_test.cc
Normal file
256
media/libaom/src/test/fft_test.cc
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
#include "aom_dsp/fft_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
#include "av1/common/common.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef void (*tform_fun_t)(const float *input, float *temp, float *output);
|
||||
|
||||
// Simple 1D FFT implementation
|
||||
template <typename InputType>
|
||||
void fft(const InputType *data, std::complex<float> *result, int n) {
|
||||
if (n == 1) {
|
||||
result[0] = data[0];
|
||||
return;
|
||||
}
|
||||
std::vector<InputType> temp(n);
|
||||
for (int k = 0; k < n / 2; ++k) {
|
||||
temp[k] = data[2 * k];
|
||||
temp[n / 2 + k] = data[2 * k + 1];
|
||||
}
|
||||
fft(&temp[0], result, n / 2);
|
||||
fft(&temp[n / 2], result + n / 2, n / 2);
|
||||
for (int k = 0; k < n / 2; ++k) {
|
||||
std::complex<float> w = std::complex<float>((float)cos(2. * PI * k / n),
|
||||
(float)-sin(2. * PI * k / n));
|
||||
std::complex<float> a = result[k];
|
||||
std::complex<float> b = result[n / 2 + k];
|
||||
result[k] = a + w * b;
|
||||
result[n / 2 + k] = a - w * b;
|
||||
}
|
||||
}
|
||||
|
||||
void transpose(std::vector<std::complex<float> > *data, int n) {
|
||||
for (int y = 0; y < n; ++y) {
|
||||
for (int x = y + 1; x < n; ++x) {
|
||||
std::swap((*data)[y * n + x], (*data)[x * n + y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple 2D FFT implementation
|
||||
template <class InputType>
|
||||
std::vector<std::complex<float> > fft2d(const InputType *input, int n) {
|
||||
std::vector<std::complex<float> > rowfft(n * n);
|
||||
std::vector<std::complex<float> > result(n * n);
|
||||
for (int y = 0; y < n; ++y) {
|
||||
fft(input + y * n, &rowfft[y * n], n);
|
||||
}
|
||||
transpose(&rowfft, n);
|
||||
for (int y = 0; y < n; ++y) {
|
||||
fft(&rowfft[y * n], &result[y * n], n);
|
||||
}
|
||||
transpose(&result, n);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct FFTTestArg {
|
||||
int n;
|
||||
void (*fft)(const float *input, float *temp, float *output);
|
||||
FFTTestArg(int n_in, tform_fun_t fft_in) : n(n_in), fft(fft_in) {}
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const FFTTestArg &test_arg) {
|
||||
return os << "fft_arg { n:" << test_arg.n << " fft:" << test_arg.fft << " }";
|
||||
}
|
||||
|
||||
class FFT2DTest : public ::testing::TestWithParam<FFTTestArg> {
|
||||
protected:
|
||||
void SetUp() {
|
||||
int n = GetParam().n;
|
||||
input_ = (float *)aom_memalign(32, sizeof(*input_) * n * n);
|
||||
temp_ = (float *)aom_memalign(32, sizeof(*temp_) * n * n);
|
||||
output_ = (float *)aom_memalign(32, sizeof(*output_) * n * n * 2);
|
||||
memset(input_, 0, sizeof(*input_) * n * n);
|
||||
memset(temp_, 0, sizeof(*temp_) * n * n);
|
||||
memset(output_, 0, sizeof(*output_) * n * n * 2);
|
||||
}
|
||||
void TearDown() {
|
||||
aom_free(input_);
|
||||
aom_free(temp_);
|
||||
aom_free(output_);
|
||||
}
|
||||
float *input_;
|
||||
float *temp_;
|
||||
float *output_;
|
||||
};
|
||||
|
||||
TEST_P(FFT2DTest, Correct) {
|
||||
int n = GetParam().n;
|
||||
for (int i = 0; i < n * n; ++i) {
|
||||
input_[i] = 1;
|
||||
std::vector<std::complex<float> > expected = fft2d<float>(&input_[0], n);
|
||||
GetParam().fft(&input_[0], &temp_[0], &output_[0]);
|
||||
for (int y = 0; y < n; ++y) {
|
||||
for (int x = 0; x < (n / 2) + 1; ++x) {
|
||||
EXPECT_NEAR(expected[y * n + x].real(), output_[2 * (y * n + x)], 1e-5);
|
||||
EXPECT_NEAR(expected[y * n + x].imag(), output_[2 * (y * n + x) + 1],
|
||||
1e-5);
|
||||
}
|
||||
}
|
||||
input_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(FFT2DTest, Benchmark) {
|
||||
int n = GetParam().n;
|
||||
float sum = 0;
|
||||
for (int i = 0; i < 1000 * (64 - n); ++i) {
|
||||
input_[i % (n * n)] = 1;
|
||||
GetParam().fft(&input_[0], &temp_[0], &output_[0]);
|
||||
sum += output_[0];
|
||||
input_[i % (n * n)] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(C, FFT2DTest,
|
||||
::testing::Values(FFTTestArg(2, aom_fft2x2_float_c),
|
||||
FFTTestArg(4, aom_fft4x4_float_c),
|
||||
FFTTestArg(8, aom_fft8x8_float_c),
|
||||
FFTTestArg(16, aom_fft16x16_float_c),
|
||||
FFTTestArg(32,
|
||||
aom_fft32x32_float_c)));
|
||||
#if ARCH_X86 || ARCH_X86_64
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, FFT2DTest,
|
||||
::testing::Values(FFTTestArg(4, aom_fft4x4_float_sse2),
|
||||
FFTTestArg(8, aom_fft8x8_float_sse2),
|
||||
FFTTestArg(16, aom_fft16x16_float_sse2),
|
||||
FFTTestArg(32, aom_fft32x32_float_sse2)));
|
||||
#endif // HAVE_SSE2
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, FFT2DTest,
|
||||
::testing::Values(FFTTestArg(8, aom_fft8x8_float_avx2),
|
||||
FFTTestArg(16, aom_fft16x16_float_avx2),
|
||||
FFTTestArg(32, aom_fft32x32_float_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // ARCH_X86 || ARCH_X86_64
|
||||
|
||||
struct IFFTTestArg {
|
||||
int n;
|
||||
tform_fun_t ifft;
|
||||
IFFTTestArg(int n_in, tform_fun_t ifft_in) : n(n_in), ifft(ifft_in) {}
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const IFFTTestArg &test_arg) {
|
||||
return os << "ifft_arg { n:" << test_arg.n << " fft:" << test_arg.ifft
|
||||
<< " }";
|
||||
}
|
||||
|
||||
class IFFT2DTest : public ::testing::TestWithParam<IFFTTestArg> {
|
||||
protected:
|
||||
void SetUp() {
|
||||
int n = GetParam().n;
|
||||
input_ = (float *)aom_memalign(32, sizeof(*input_) * n * n * 2);
|
||||
temp_ = (float *)aom_memalign(32, sizeof(*temp_) * n * n * 2);
|
||||
output_ = (float *)aom_memalign(32, sizeof(*output_) * n * n);
|
||||
memset(input_, 0, sizeof(*input_) * n * n * 2);
|
||||
memset(temp_, 0, sizeof(*temp_) * n * n * 2);
|
||||
memset(output_, 0, sizeof(*output_) * n * n);
|
||||
}
|
||||
void TearDown() {
|
||||
aom_free(input_);
|
||||
aom_free(temp_);
|
||||
aom_free(output_);
|
||||
}
|
||||
float *input_;
|
||||
float *temp_;
|
||||
float *output_;
|
||||
};
|
||||
|
||||
TEST_P(IFFT2DTest, Correctness) {
|
||||
int n = GetParam().n;
|
||||
ASSERT_GE(n, 2);
|
||||
std::vector<float> expected(n * n);
|
||||
std::vector<float> actual(n * n);
|
||||
// Do forward transform then invert to make sure we get back expected
|
||||
for (int y = 0; y < n; ++y) {
|
||||
for (int x = 0; x < n; ++x) {
|
||||
expected[y * n + x] = 1;
|
||||
std::vector<std::complex<float> > input_c = fft2d(&expected[0], n);
|
||||
for (int i = 0; i < n * n; ++i) {
|
||||
input_[2 * i + 0] = input_c[i].real();
|
||||
input_[2 * i + 1] = input_c[i].imag();
|
||||
}
|
||||
GetParam().ifft(&input_[0], &temp_[0], &output_[0]);
|
||||
|
||||
for (int yy = 0; yy < n; ++yy) {
|
||||
for (int xx = 0; xx < n; ++xx) {
|
||||
EXPECT_NEAR(expected[yy * n + xx], output_[yy * n + xx] / (n * n),
|
||||
1e-5);
|
||||
}
|
||||
}
|
||||
expected[y * n + x] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(IFFT2DTest, Benchmark) {
|
||||
int n = GetParam().n;
|
||||
float sum = 0;
|
||||
for (int i = 0; i < 1000 * (64 - n); ++i) {
|
||||
input_[i % (n * n)] = 1;
|
||||
GetParam().ifft(&input_[0], &temp_[0], &output_[0]);
|
||||
sum += output_[0];
|
||||
input_[i % (n * n)] = 0;
|
||||
}
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, IFFT2DTest,
|
||||
::testing::Values(IFFTTestArg(2, aom_ifft2x2_float_c),
|
||||
IFFTTestArg(4, aom_ifft4x4_float_c),
|
||||
IFFTTestArg(8, aom_ifft8x8_float_c),
|
||||
IFFTTestArg(16, aom_ifft16x16_float_c),
|
||||
IFFTTestArg(32, aom_ifft32x32_float_c)));
|
||||
#if ARCH_X86 || ARCH_X86_64
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE2, IFFT2DTest,
|
||||
::testing::Values(IFFTTestArg(4, aom_ifft4x4_float_sse2),
|
||||
IFFTTestArg(8, aom_ifft8x8_float_sse2),
|
||||
IFFTTestArg(16, aom_ifft16x16_float_sse2),
|
||||
IFFTTestArg(32, aom_ifft32x32_float_sse2)));
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AVX2, IFFT2DTest,
|
||||
::testing::Values(IFFTTestArg(8, aom_ifft8x8_float_avx2),
|
||||
IFFTTestArg(16, aom_ifft16x16_float_avx2),
|
||||
IFFTTestArg(32, aom_ifft32x32_float_avx2)));
|
||||
#endif // HAVE_AVX2
|
||||
#endif // ARCH_X86 || ARCH_X86_64
|
||||
|
||||
} // namespace
|
||||
250
media/libaom/src/test/film_grain_table_test.cc
Normal file
250
media/libaom/src/test/film_grain_table_test.cc
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "aom_dsp/grain_table.h"
|
||||
#include "aom/internal/aom_codec_internal.h"
|
||||
#include "av1/encoder/grain_test_vectors.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
void grain_equal(const aom_film_grain_t *expected,
|
||||
const aom_film_grain_t *actual) {
|
||||
EXPECT_EQ(expected->apply_grain, actual->apply_grain);
|
||||
EXPECT_EQ(expected->update_parameters, actual->update_parameters);
|
||||
if (!expected->update_parameters) return;
|
||||
EXPECT_EQ(expected->num_y_points, actual->num_y_points);
|
||||
EXPECT_EQ(expected->num_cb_points, actual->num_cb_points);
|
||||
EXPECT_EQ(expected->num_cr_points, actual->num_cr_points);
|
||||
EXPECT_EQ(0, memcmp(expected->scaling_points_y, actual->scaling_points_y,
|
||||
expected->num_y_points *
|
||||
sizeof(expected->scaling_points_y[0])));
|
||||
EXPECT_EQ(0, memcmp(expected->scaling_points_cb, actual->scaling_points_cb,
|
||||
expected->num_cb_points *
|
||||
sizeof(expected->scaling_points_cb[0])));
|
||||
EXPECT_EQ(0, memcmp(expected->scaling_points_cr, actual->scaling_points_cr,
|
||||
expected->num_cr_points *
|
||||
sizeof(expected->scaling_points_cr[0])));
|
||||
EXPECT_EQ(expected->scaling_shift, actual->scaling_shift);
|
||||
EXPECT_EQ(expected->ar_coeff_lag, actual->ar_coeff_lag);
|
||||
EXPECT_EQ(expected->ar_coeff_shift, actual->ar_coeff_shift);
|
||||
|
||||
const int num_pos_luma =
|
||||
2 * expected->ar_coeff_lag * (expected->ar_coeff_lag + 1);
|
||||
const int num_pos_chroma = num_pos_luma;
|
||||
EXPECT_EQ(0, memcmp(expected->ar_coeffs_y, actual->ar_coeffs_y,
|
||||
sizeof(expected->ar_coeffs_y[0]) * num_pos_luma));
|
||||
if (actual->num_cb_points || actual->chroma_scaling_from_luma) {
|
||||
EXPECT_EQ(0, memcmp(expected->ar_coeffs_cb, actual->ar_coeffs_cb,
|
||||
sizeof(expected->ar_coeffs_cb[0]) * num_pos_chroma));
|
||||
}
|
||||
if (actual->num_cr_points || actual->chroma_scaling_from_luma) {
|
||||
EXPECT_EQ(0, memcmp(expected->ar_coeffs_cr, actual->ar_coeffs_cr,
|
||||
sizeof(expected->ar_coeffs_cr[0]) * num_pos_chroma));
|
||||
}
|
||||
EXPECT_EQ(expected->overlap_flag, actual->overlap_flag);
|
||||
EXPECT_EQ(expected->chroma_scaling_from_luma,
|
||||
actual->chroma_scaling_from_luma);
|
||||
EXPECT_EQ(expected->grain_scale_shift, actual->grain_scale_shift);
|
||||
// EXPECT_EQ(expected->random_seed, actual->random_seed);
|
||||
|
||||
// clip_to_restricted and bit_depth aren't written
|
||||
if (expected->num_cb_points) {
|
||||
EXPECT_EQ(expected->cb_mult, actual->cb_mult);
|
||||
EXPECT_EQ(expected->cb_luma_mult, actual->cb_luma_mult);
|
||||
EXPECT_EQ(expected->cb_offset, actual->cb_offset);
|
||||
}
|
||||
if (expected->num_cr_points) {
|
||||
EXPECT_EQ(expected->cr_mult, actual->cr_mult);
|
||||
EXPECT_EQ(expected->cr_luma_mult, actual->cr_luma_mult);
|
||||
EXPECT_EQ(expected->cr_offset, actual->cr_offset);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FilmGrainTableTest, AddAndLookupSingleSegment) {
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
aom_film_grain_t grain;
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 0, 1000, false, &grain));
|
||||
|
||||
aom_film_grain_table_append(&table, 1000, 2000, film_grain_test_vectors + 0);
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 0, 1000, false, &grain));
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 2000, 3000, false, &grain));
|
||||
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 1000, 2000, false, &grain));
|
||||
|
||||
grain.bit_depth = film_grain_test_vectors[0].bit_depth;
|
||||
EXPECT_EQ(0, memcmp(&grain, film_grain_test_vectors + 0, sizeof(table)));
|
||||
|
||||
// Extend the existing segment
|
||||
aom_film_grain_table_append(&table, 2000, 3000, film_grain_test_vectors + 0);
|
||||
EXPECT_EQ(0, table.head->next);
|
||||
|
||||
// Lookup and remove and check that the entry is no longer there
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 1000, 2000, true, &grain));
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 1000, 2000, false, &grain));
|
||||
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 2000, 3000, true, &grain));
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 2000, 3000, false, &grain));
|
||||
|
||||
EXPECT_EQ(0, table.head);
|
||||
EXPECT_EQ(0, table.tail);
|
||||
aom_film_grain_table_free(&table);
|
||||
}
|
||||
|
||||
TEST(FilmGrainTableTest, SplitSingleSegment) {
|
||||
aom_film_grain_table_t table;
|
||||
aom_film_grain_t grain;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
aom_film_grain_table_append(&table, 0, 1000, film_grain_test_vectors + 0);
|
||||
|
||||
// Test lookup and remove that adjusts start time
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 0, 100, true, &grain));
|
||||
EXPECT_EQ(NULL, table.head->next);
|
||||
EXPECT_EQ(100, table.head->start_time);
|
||||
|
||||
// Test lookup and remove that adjusts end time
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 900, 1000, true, &grain));
|
||||
EXPECT_EQ(NULL, table.head->next);
|
||||
EXPECT_EQ(100, table.head->start_time);
|
||||
EXPECT_EQ(900, table.head->end_time);
|
||||
|
||||
// Test lookup and remove that splits the first entry
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, 400, 600, true, &grain));
|
||||
EXPECT_EQ(100, table.head->start_time);
|
||||
EXPECT_EQ(400, table.head->end_time);
|
||||
|
||||
ASSERT_NE((void *)NULL, table.head->next);
|
||||
EXPECT_EQ(table.tail, table.head->next);
|
||||
EXPECT_EQ(600, table.head->next->start_time);
|
||||
EXPECT_EQ(900, table.head->next->end_time);
|
||||
|
||||
aom_film_grain_table_free(&table);
|
||||
}
|
||||
|
||||
TEST(FilmGrainTableTest, AddAndLookupMultipleSegments) {
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
aom_film_grain_t grain;
|
||||
const int kNumTestVectors =
|
||||
sizeof(film_grain_test_vectors) / sizeof(film_grain_test_vectors[0]);
|
||||
for (int i = 0; i < kNumTestVectors; ++i) {
|
||||
aom_film_grain_table_append(&table, i * 1000, (i + 1) * 1000,
|
||||
film_grain_test_vectors + i);
|
||||
}
|
||||
|
||||
for (int i = kNumTestVectors - 1; i >= 0; --i) {
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, i * 1000, (i + 1) * 1000,
|
||||
true, &grain));
|
||||
grain_equal(film_grain_test_vectors + i, &grain);
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, i * 1000, (i + 1) * 1000,
|
||||
true, &grain));
|
||||
}
|
||||
|
||||
// Verify that all the data has been removed
|
||||
for (int i = 0; i < kNumTestVectors; ++i) {
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, i * 1000, (i + 1) * 1000,
|
||||
true, &grain));
|
||||
}
|
||||
aom_film_grain_table_free(&table);
|
||||
}
|
||||
|
||||
class FilmGrainTableIOTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() { memset(&error_, 0, sizeof(error_)); }
|
||||
struct aom_internal_error_info error_;
|
||||
};
|
||||
|
||||
TEST_F(FilmGrainTableIOTest, ReadMissingFile) {
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
ASSERT_EQ(AOM_CODEC_ERROR, aom_film_grain_table_read(
|
||||
&table, "/path/to/missing/file", &error_));
|
||||
}
|
||||
|
||||
TEST_F(FilmGrainTableIOTest, ReadTruncatedFile) {
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
std::string grain_file;
|
||||
FILE *file = libaom_test::GetTempOutFile(&grain_file);
|
||||
fwrite("deadbeef", 8, 1, file);
|
||||
fclose(file);
|
||||
ASSERT_EQ(AOM_CODEC_ERROR,
|
||||
aom_film_grain_table_read(&table, grain_file.c_str(), &error_));
|
||||
EXPECT_EQ(0, remove(grain_file.c_str()));
|
||||
}
|
||||
|
||||
TEST_F(FilmGrainTableIOTest, RoundTripReadWrite) {
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
aom_film_grain_t expected_grain[16];
|
||||
const int kNumTestVectors =
|
||||
sizeof(film_grain_test_vectors) / sizeof(film_grain_test_vectors[0]);
|
||||
for (int i = 0; i < kNumTestVectors; ++i) {
|
||||
expected_grain[i] = film_grain_test_vectors[i];
|
||||
expected_grain[i].random_seed = i;
|
||||
expected_grain[i].update_parameters = i % 2;
|
||||
expected_grain[i].apply_grain = (i + 1) % 2;
|
||||
expected_grain[i].bit_depth = 0;
|
||||
aom_film_grain_table_append(&table, i * 1000, (i + 1) * 1000,
|
||||
expected_grain + i);
|
||||
}
|
||||
std::string grain_file;
|
||||
fclose(libaom_test::GetTempOutFile(&grain_file));
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
aom_film_grain_table_write(&table, grain_file.c_str(), &error_));
|
||||
aom_film_grain_table_free(&table);
|
||||
|
||||
memset(&table, 0, sizeof(table));
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
aom_film_grain_table_read(&table, grain_file.c_str(), &error_));
|
||||
for (int i = 0; i < kNumTestVectors; ++i) {
|
||||
aom_film_grain_t grain;
|
||||
EXPECT_TRUE(aom_film_grain_table_lookup(&table, i * 1000, (i + 1) * 1000,
|
||||
true, &grain));
|
||||
grain_equal(expected_grain + i, &grain);
|
||||
}
|
||||
aom_film_grain_table_free(&table);
|
||||
EXPECT_EQ(0, remove(grain_file.c_str()));
|
||||
}
|
||||
|
||||
TEST_F(FilmGrainTableIOTest, RoundTripSplit) {
|
||||
std::string grain_file;
|
||||
fclose(libaom_test::GetTempOutFile(&grain_file));
|
||||
|
||||
aom_film_grain_table_t table;
|
||||
memset(&table, 0, sizeof(table));
|
||||
|
||||
aom_film_grain_t grain = film_grain_test_vectors[0];
|
||||
aom_film_grain_table_append(&table, 0, 3000, &grain);
|
||||
ASSERT_TRUE(aom_film_grain_table_lookup(&table, 1000, 2000, true, &grain));
|
||||
ASSERT_TRUE(aom_film_grain_table_lookup(&table, 0, 1000, false, &grain));
|
||||
EXPECT_FALSE(aom_film_grain_table_lookup(&table, 1000, 2000, false, &grain));
|
||||
ASSERT_TRUE(aom_film_grain_table_lookup(&table, 2000, 3000, false, &grain));
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
aom_film_grain_table_write(&table, grain_file.c_str(), &error_));
|
||||
aom_film_grain_table_free(&table);
|
||||
|
||||
memset(&table, 0, sizeof(table));
|
||||
ASSERT_EQ(AOM_CODEC_OK,
|
||||
aom_film_grain_table_read(&table, grain_file.c_str(), &error_));
|
||||
ASSERT_TRUE(aom_film_grain_table_lookup(&table, 0, 1000, false, &grain));
|
||||
ASSERT_FALSE(aom_film_grain_table_lookup(&table, 1000, 2000, false, &grain));
|
||||
ASSERT_TRUE(aom_film_grain_table_lookup(&table, 2000, 3000, false, &grain));
|
||||
aom_film_grain_table_free(&table);
|
||||
|
||||
EXPECT_EQ(0, remove(grain_file.c_str()));
|
||||
}
|
||||
134
media/libaom/src/test/filterintra_test.cc
Normal file
134
media/libaom/src/test/filterintra_test.cc
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
typedef void (*Predictor)(uint8_t *dst, ptrdiff_t stride, TX_SIZE tx_size,
|
||||
const uint8_t *above, const uint8_t *left, int mode);
|
||||
|
||||
// Note:
|
||||
// Test parameter list:
|
||||
// Reference predictor, optimized predictor, prediction mode, tx size
|
||||
//
|
||||
typedef tuple<Predictor, Predictor, int> PredFuncMode;
|
||||
typedef tuple<PredFuncMode, TX_SIZE> PredParams;
|
||||
|
||||
const int MaxTxSize = 32;
|
||||
|
||||
const int MaxTestNum = 100;
|
||||
|
||||
class AV1FilterIntraPredTest : public ::testing::TestWithParam<PredParams> {
|
||||
public:
|
||||
virtual ~AV1FilterIntraPredTest() {}
|
||||
virtual void SetUp() {
|
||||
PredFuncMode funcMode = GET_PARAM(0);
|
||||
predFuncRef_ = ::testing::get<0>(funcMode);
|
||||
predFunc_ = ::testing::get<1>(funcMode);
|
||||
mode_ = ::testing::get<2>(funcMode);
|
||||
txSize_ = GET_PARAM(1);
|
||||
|
||||
alloc_ = new uint8_t[2 * MaxTxSize + 1];
|
||||
predRef_ = new uint8_t[MaxTxSize * MaxTxSize];
|
||||
pred_ = new uint8_t[MaxTxSize * MaxTxSize];
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
delete[] alloc_;
|
||||
delete[] predRef_;
|
||||
delete[] pred_;
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
protected:
|
||||
void RunTest() const {
|
||||
int tstIndex = 0;
|
||||
int stride = tx_size_wide[txSize_];
|
||||
uint8_t *left = alloc_;
|
||||
uint8_t *above = alloc_ + MaxTxSize;
|
||||
while (tstIndex < MaxTestNum) {
|
||||
PrepareBuffer();
|
||||
predFuncRef_(predRef_, stride, txSize_, &above[1], left, mode_);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
predFunc_(pred_, stride, txSize_, &above[1], left, mode_));
|
||||
DiffPred(tstIndex);
|
||||
tstIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void PrepareBuffer() const {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
int i = 0;
|
||||
while (i < (2 * MaxTxSize + 1)) {
|
||||
alloc_[i] = rnd.Rand8();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void DiffPred(int testNum) const {
|
||||
int i = 0;
|
||||
while (i < tx_size_wide[txSize_] * tx_size_high[txSize_]) {
|
||||
EXPECT_EQ(predRef_[i], pred_[i]) << "Error at position: " << i << " "
|
||||
<< "Tx size: " << tx_size_wide[txSize_]
|
||||
<< "x" << tx_size_high[txSize_] << " "
|
||||
<< "Test number: " << testNum;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
Predictor predFunc_;
|
||||
Predictor predFuncRef_;
|
||||
int mode_;
|
||||
TX_SIZE txSize_;
|
||||
uint8_t *alloc_;
|
||||
uint8_t *pred_;
|
||||
uint8_t *predRef_;
|
||||
};
|
||||
|
||||
TEST_P(AV1FilterIntraPredTest, BitExactCheck) { RunTest(); }
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
const PredFuncMode kPredFuncMdArray[] = {
|
||||
make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1,
|
||||
FILTER_DC_PRED),
|
||||
make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1,
|
||||
FILTER_V_PRED),
|
||||
make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1,
|
||||
FILTER_H_PRED),
|
||||
make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1,
|
||||
FILTER_D157_PRED),
|
||||
make_tuple(&av1_filter_intra_predictor_c, &av1_filter_intra_predictor_sse4_1,
|
||||
FILTER_PAETH_PRED),
|
||||
};
|
||||
|
||||
const TX_SIZE kTxSize[] = { TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_4X8,
|
||||
TX_8X4, TX_8X16, TX_16X8, TX_16X32, TX_32X16,
|
||||
TX_4X16, TX_16X4, TX_8X32, TX_32X8 };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, AV1FilterIntraPredTest,
|
||||
::testing::Combine(::testing::ValuesIn(kPredFuncMdArray),
|
||||
::testing::ValuesIn(kTxSize)));
|
||||
} // namespace
|
||||
78
media/libaom/src/test/frame_size_tests.cc
Normal file
78
media/libaom/src/test/frame_size_tests.cc
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class AV1FrameSizeTests : public ::testing::Test,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
AV1FrameSizeTests()
|
||||
: EncoderTest(&::libaom_test::kAV1), expected_res_(AOM_CODEC_OK) {}
|
||||
virtual ~AV1FrameSizeTests() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(::libaom_test::kRealTime);
|
||||
}
|
||||
|
||||
virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
|
||||
libaom_test::Decoder *decoder) {
|
||||
EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
|
||||
return !::testing::Test::HasFailure();
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, 7);
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
|
||||
int expected_res_;
|
||||
};
|
||||
|
||||
#if CONFIG_SIZE_LIMIT
|
||||
TEST_F(AV1FrameSizeTests, TestInvalidSizes) {
|
||||
::libaom_test::RandomVideoSource video;
|
||||
|
||||
video.SetSize(DECODE_WIDTH_LIMIT + 16, DECODE_HEIGHT_LIMIT + 16);
|
||||
video.set_limit(2);
|
||||
expected_res_ = AOM_CODEC_CORRUPT_FRAME;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
|
||||
TEST_F(AV1FrameSizeTests, LargeValidSizes) {
|
||||
::libaom_test::RandomVideoSource video;
|
||||
|
||||
video.SetSize(DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT);
|
||||
video.set_limit(2);
|
||||
expected_res_ = AOM_CODEC_OK;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(AV1FrameSizeTests, OneByOneVideo) {
|
||||
::libaom_test::RandomVideoSource video;
|
||||
|
||||
video.SetSize(1, 1);
|
||||
video.set_limit(2);
|
||||
expected_res_ = AOM_CODEC_OK;
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
}
|
||||
#undef ONE_BY_ONE_VIDEO_NAME
|
||||
} // namespace
|
||||
69
media/libaom/src/test/function_equivalence_test.h
Normal file
69
media/libaom/src/test/function_equivalence_test.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_FUNCTION_EQUIVALENCE_TEST_H_
|
||||
#define AOM_TEST_FUNCTION_EQUIVALENCE_TEST_H_
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/util.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace libaom_test {
|
||||
// Base class for tests that compare 2 implementations of the same function
|
||||
// for equivalence. The template parameter should be pointer to a function
|
||||
// that is being tested.
|
||||
//
|
||||
// The test takes a 3-parameters encapsulating struct 'FuncParam', containing:
|
||||
// - Pointer to reference function
|
||||
// - Pointer to tested function
|
||||
// - Integer bit depth (default to 0).
|
||||
//
|
||||
// These values are then accessible in the tests as member of params_:
|
||||
// params_.ref_func, params_.tst_func, and params_.bit_depth.
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
struct FuncParam {
|
||||
FuncParam(T ref = NULL, T tst = NULL, int bit_depth = 0)
|
||||
: ref_func(ref), tst_func(tst), bit_depth(bit_depth) {}
|
||||
T ref_func;
|
||||
T tst_func;
|
||||
int bit_depth;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::ostream &operator<<(std::ostream &os, const FuncParam<T> &p) {
|
||||
return os << "bit_depth:" << p.bit_depth
|
||||
<< " function:" << reinterpret_cast<const void *>(p.ref_func)
|
||||
<< " function:" << reinterpret_cast<const void *>(p.tst_func);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class FunctionEquivalenceTest : public ::testing::TestWithParam<FuncParam<T> > {
|
||||
public:
|
||||
FunctionEquivalenceTest() : rng_(ACMRandom::DeterministicSeed()) {}
|
||||
|
||||
virtual ~FunctionEquivalenceTest() {}
|
||||
|
||||
virtual void SetUp() { params_ = this->GetParam(); }
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
ACMRandom rng_;
|
||||
FuncParam<T> params_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
#endif // AOM_TEST_FUNCTION_EQUIVALENCE_TEST_H_
|
||||
98
media/libaom/src/test/fwht4x4_test.cc
Normal file
98
media/libaom/src/test/fwht4x4_test.cc
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/transform_test_base.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/entropy.h"
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_ports/mem.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride);
|
||||
typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride);
|
||||
|
||||
using libaom_test::FhtFunc;
|
||||
|
||||
typedef ::testing::tuple<FdctFunc, IdctFunc, TX_TYPE, aom_bit_depth_t, int>
|
||||
Dct4x4Param;
|
||||
|
||||
void fwht4x4_ref(const int16_t *in, tran_low_t *out, int stride,
|
||||
TxfmParam * /*txfm_param*/) {
|
||||
av1_fwht4x4_c(in, out, stride);
|
||||
}
|
||||
|
||||
void iwht4x4_10(const tran_low_t *in, uint8_t *out, int stride) {
|
||||
av1_highbd_iwht4x4_16_add_c(in, out, stride, 10);
|
||||
}
|
||||
|
||||
void iwht4x4_12(const tran_low_t *in, uint8_t *out, int stride) {
|
||||
av1_highbd_iwht4x4_16_add_c(in, out, stride, 12);
|
||||
}
|
||||
|
||||
class Trans4x4WHT : public libaom_test::TransformTestBase,
|
||||
public ::testing::TestWithParam<Dct4x4Param> {
|
||||
public:
|
||||
virtual ~Trans4x4WHT() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
fwd_txfm_ = GET_PARAM(0);
|
||||
inv_txfm_ = GET_PARAM(1);
|
||||
pitch_ = 4;
|
||||
height_ = 4;
|
||||
fwd_txfm_ref = fwht4x4_ref;
|
||||
bit_depth_ = GET_PARAM(3);
|
||||
mask_ = (1 << bit_depth_) - 1;
|
||||
num_coeffs_ = GET_PARAM(4);
|
||||
}
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
void RunFwdTxfm(const int16_t *in, tran_low_t *out, int stride) {
|
||||
fwd_txfm_(in, out, stride);
|
||||
}
|
||||
void RunInvTxfm(const tran_low_t *out, uint8_t *dst, int stride) {
|
||||
inv_txfm_(out, dst, stride);
|
||||
}
|
||||
|
||||
FdctFunc fwd_txfm_;
|
||||
IdctFunc inv_txfm_;
|
||||
};
|
||||
|
||||
TEST_P(Trans4x4WHT, AccuracyCheck) { RunAccuracyCheck(0, 0.00001); }
|
||||
|
||||
TEST_P(Trans4x4WHT, CoeffCheck) { RunCoeffCheck(); }
|
||||
|
||||
TEST_P(Trans4x4WHT, MemCheck) { RunMemCheck(); }
|
||||
|
||||
TEST_P(Trans4x4WHT, InvAccuracyCheck) { RunInvAccuracyCheck(0); }
|
||||
using ::testing::make_tuple;
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, Trans4x4WHT,
|
||||
::testing::Values(make_tuple(&av1_highbd_fwht4x4_c, &iwht4x4_10, DCT_DCT,
|
||||
AOM_BITS_10, 16),
|
||||
make_tuple(&av1_highbd_fwht4x4_c, &iwht4x4_12, DCT_DCT,
|
||||
AOM_BITS_12, 16)));
|
||||
} // namespace
|
||||
1087
media/libaom/src/test/gviz_api.py
Normal file
1087
media/libaom/src/test/gviz_api.py
Normal file
File diff suppressed because it is too large
Load diff
133
media/libaom/src/test/hash_test.cc
Normal file
133
media/libaom/src/test/hash_test.cc
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/encoder/hash.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef uint32_t (*get_crc32c_value_func)(void *calculator, uint8_t *p,
|
||||
int length);
|
||||
|
||||
typedef ::testing::tuple<get_crc32c_value_func, int> HashParam;
|
||||
|
||||
class AV1Crc32cHashTest : public ::testing::TestWithParam<HashParam> {
|
||||
public:
|
||||
~AV1Crc32cHashTest();
|
||||
void SetUp();
|
||||
|
||||
void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(get_crc32c_value_func test_impl);
|
||||
void RunSpeedTest(get_crc32c_value_func test_impl);
|
||||
|
||||
void RunZeroTest(get_crc32c_value_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
CRC32C calc_;
|
||||
uint8_t *buffer_;
|
||||
int bsize_;
|
||||
int length_;
|
||||
};
|
||||
|
||||
AV1Crc32cHashTest::~AV1Crc32cHashTest() { ; }
|
||||
|
||||
void AV1Crc32cHashTest::SetUp() {
|
||||
rnd_.Reset(libaom_test::ACMRandom::DeterministicSeed());
|
||||
av1_crc32c_calculator_init(&calc_);
|
||||
|
||||
bsize_ = GET_PARAM(1);
|
||||
length_ = bsize_ * bsize_ * sizeof(uint16_t);
|
||||
buffer_ = new uint8_t[length_];
|
||||
ASSERT_TRUE(buffer_ != NULL);
|
||||
for (int i = 0; i < length_; ++i) {
|
||||
buffer_[i] = rnd_.Rand8();
|
||||
}
|
||||
}
|
||||
|
||||
void AV1Crc32cHashTest::TearDown() { delete[] buffer_; }
|
||||
|
||||
void AV1Crc32cHashTest::RunCheckOutput(get_crc32c_value_func test_impl) {
|
||||
get_crc32c_value_func ref_impl = av1_get_crc32c_value_c;
|
||||
// for the same buffer crc should be the same
|
||||
uint32_t crc0 = test_impl(&calc_, buffer_, length_);
|
||||
uint32_t crc1 = test_impl(&calc_, buffer_, length_);
|
||||
uint32_t crc2 = ref_impl(&calc_, buffer_, length_);
|
||||
ASSERT_EQ(crc0, crc1);
|
||||
ASSERT_EQ(crc0, crc2); // should equal to software version
|
||||
// modify buffer
|
||||
buffer_[0] += 1;
|
||||
uint32_t crc3 = test_impl(&calc_, buffer_, length_);
|
||||
uint32_t crc4 = ref_impl(&calc_, buffer_, length_);
|
||||
ASSERT_NE(crc0, crc3); // crc shoud not equal to previous one
|
||||
ASSERT_EQ(crc3, crc4);
|
||||
}
|
||||
|
||||
void AV1Crc32cHashTest::RunSpeedTest(get_crc32c_value_func test_impl) {
|
||||
get_crc32c_value_func impls[] = { av1_get_crc32c_value_c, test_impl };
|
||||
const int repeat = 10000000 / (bsize_ + bsize_);
|
||||
|
||||
aom_usec_timer timer;
|
||||
double time[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int j = 0; j < repeat; ++j) {
|
||||
impls[i](&calc_, buffer_, length_);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
time[i] = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
}
|
||||
printf("hash %3dx%-3d:%7.2f/%7.2fus", bsize_, bsize_, time[0], time[1]);
|
||||
printf("(%3.2f)\n", time[0] / time[1]);
|
||||
}
|
||||
|
||||
void AV1Crc32cHashTest::RunZeroTest(get_crc32c_value_func test_impl) {
|
||||
uint8_t buffer0[1024] = { 0 };
|
||||
// for buffer with different size the crc should not be the same
|
||||
const uint32_t crc0 = test_impl(&calc_, buffer0, 32);
|
||||
const uint32_t crc1 = test_impl(&calc_, buffer0, 128);
|
||||
const uint32_t crc2 = test_impl(&calc_, buffer0, 1024);
|
||||
ASSERT_NE(crc0, crc1);
|
||||
ASSERT_NE(crc0, crc2);
|
||||
ASSERT_NE(crc1, crc2);
|
||||
}
|
||||
|
||||
TEST_P(AV1Crc32cHashTest, CheckOutput) { RunCheckOutput(GET_PARAM(0)); }
|
||||
|
||||
TEST_P(AV1Crc32cHashTest, CheckZero) { RunZeroTest(GET_PARAM(0)); }
|
||||
|
||||
TEST_P(AV1Crc32cHashTest, DISABLED_Speed) { RunSpeedTest(GET_PARAM(0)); }
|
||||
|
||||
const int kValidBlockSize[] = { 64, 32, 8, 4 };
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
C, AV1Crc32cHashTest,
|
||||
::testing::Combine(::testing::Values(&av1_get_crc32c_value_c),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
|
||||
#if HAVE_SSE4_2
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_2, AV1Crc32cHashTest,
|
||||
::testing::Combine(::testing::Values(&av1_get_crc32c_value_sse4_2),
|
||||
::testing::ValuesIn(kValidBlockSize)));
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
239
media/libaom/src/test/hbd_metrics_test.cc
Normal file
239
media/libaom/src/test/hbd_metrics_test.cc
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "aom_dsp/psnr.h"
|
||||
#include "aom_dsp/ssim.h"
|
||||
#include "aom_ports/mem.h"
|
||||
#include "aom_ports/msvc.h"
|
||||
#include "aom_scale/yv12config.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest);
|
||||
typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
||||
uint32_t bd);
|
||||
|
||||
double compute_hbd_psnr(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
||||
uint32_t bd) {
|
||||
PSNR_STATS psnr;
|
||||
aom_calc_highbd_psnr(source, dest, &psnr, bd, in_bd);
|
||||
return psnr.psnr[0];
|
||||
}
|
||||
|
||||
double compute_psnr(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest) {
|
||||
PSNR_STATS psnr;
|
||||
aom_calc_psnr(source, dest, &psnr);
|
||||
return psnr.psnr[0];
|
||||
}
|
||||
|
||||
double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
||||
uint32_t bd) {
|
||||
double tempy, tempu, tempv;
|
||||
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
|
||||
}
|
||||
|
||||
double compute_psnrhvs(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest) {
|
||||
double tempy, tempu, tempv;
|
||||
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, 8, 8);
|
||||
}
|
||||
|
||||
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
||||
uint32_t bd) {
|
||||
double tempy, tempu, tempv;
|
||||
return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
|
||||
}
|
||||
|
||||
double compute_fastssim(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest) {
|
||||
double tempy, tempu, tempv;
|
||||
return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, 8, 8);
|
||||
}
|
||||
|
||||
double compute_hbd_aomssim(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
||||
uint32_t bd) {
|
||||
double ssim, weight;
|
||||
ssim = aom_highbd_calc_ssim(source, dest, &weight, bd, in_bd);
|
||||
return 100 * pow(ssim / weight, 8.0);
|
||||
}
|
||||
|
||||
double compute_aomssim(const YV12_BUFFER_CONFIG *source,
|
||||
const YV12_BUFFER_CONFIG *dest) {
|
||||
double ssim, weight;
|
||||
ssim = aom_calc_ssim(source, dest, &weight);
|
||||
return 100 * pow(ssim / weight, 8.0);
|
||||
}
|
||||
|
||||
class HBDMetricsTestBase {
|
||||
public:
|
||||
virtual ~HBDMetricsTestBase() {}
|
||||
|
||||
protected:
|
||||
void RunAccuracyCheck() {
|
||||
const int width = 1920;
|
||||
const int height = 1080;
|
||||
size_t i = 0;
|
||||
const uint8_t kPixFiller = 128;
|
||||
YV12_BUFFER_CONFIG lbd_src, lbd_dst;
|
||||
YV12_BUFFER_CONFIG hbd_src, hbd_dst;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
double lbd_db, hbd_db;
|
||||
|
||||
memset(&lbd_src, 0, sizeof(lbd_src));
|
||||
memset(&lbd_dst, 0, sizeof(lbd_dst));
|
||||
memset(&hbd_src, 0, sizeof(hbd_src));
|
||||
memset(&hbd_dst, 0, sizeof(hbd_dst));
|
||||
|
||||
aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16);
|
||||
aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16);
|
||||
aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16);
|
||||
aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16);
|
||||
|
||||
memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz);
|
||||
while (i < lbd_src.buffer_alloc_sz) {
|
||||
uint16_t spel, dpel;
|
||||
spel = lbd_src.buffer_alloc[i];
|
||||
// Create some distortion for dst buffer.
|
||||
dpel = rnd.Rand8();
|
||||
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
|
||||
((uint16_t *)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8);
|
||||
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
||||
i++;
|
||||
}
|
||||
|
||||
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
||||
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
||||
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
|
||||
|
||||
i = 0;
|
||||
while (i < lbd_src.buffer_alloc_sz) {
|
||||
uint16_t dpel;
|
||||
// Create some small distortion for dst buffer.
|
||||
dpel = 120 + (rnd.Rand8() >> 4);
|
||||
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
|
||||
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
||||
i++;
|
||||
}
|
||||
|
||||
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
||||
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
||||
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
|
||||
|
||||
i = 0;
|
||||
while (i < lbd_src.buffer_alloc_sz) {
|
||||
uint16_t dpel;
|
||||
// Create some small distortion for dst buffer.
|
||||
dpel = 126 + (rnd.Rand8() >> 6);
|
||||
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
|
||||
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
||||
i++;
|
||||
}
|
||||
|
||||
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
||||
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
||||
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
|
||||
|
||||
aom_free_frame_buffer(&lbd_src);
|
||||
aom_free_frame_buffer(&lbd_dst);
|
||||
aom_free_frame_buffer(&hbd_src);
|
||||
aom_free_frame_buffer(&hbd_dst);
|
||||
}
|
||||
|
||||
int input_bit_depth_;
|
||||
int bit_depth_;
|
||||
double threshold_;
|
||||
LBDMetricFunc lbd_metric_;
|
||||
HBDMetricFunc hbd_metric_;
|
||||
};
|
||||
|
||||
typedef ::testing::tuple<LBDMetricFunc, HBDMetricFunc, int, int, double>
|
||||
MetricTestTParam;
|
||||
class HBDMetricsTest : public HBDMetricsTestBase,
|
||||
public ::testing::TestWithParam<MetricTestTParam> {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
lbd_metric_ = GET_PARAM(0);
|
||||
hbd_metric_ = GET_PARAM(1);
|
||||
input_bit_depth_ = GET_PARAM(2);
|
||||
bit_depth_ = GET_PARAM(3);
|
||||
threshold_ = GET_PARAM(4);
|
||||
}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_P(HBDMetricsTest, RunAccuracyCheck) { RunAccuracyCheck(); }
|
||||
|
||||
// Allow small variation due to floating point operations.
|
||||
static const double kSsim_thresh = 0.001;
|
||||
// Allow some additional errors accumulated in floating point operations.
|
||||
static const double kFSsim_thresh = 0.03;
|
||||
// Allow some extra variation due to rounding error accumulated in dct.
|
||||
static const double kPhvs_thresh = 0.3;
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AOMSSIM, HBDMetricsTest,
|
||||
::testing::Values(MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
||||
8, 10, kSsim_thresh),
|
||||
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
||||
10, 10, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
||||
8, 12, kSsim_thresh),
|
||||
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
||||
12, 12, kPhvs_thresh)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FASTSSIM, HBDMetricsTest,
|
||||
::testing::Values(MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
||||
8, 10, kFSsim_thresh),
|
||||
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
||||
10, 10, kFSsim_thresh),
|
||||
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
||||
8, 12, kFSsim_thresh),
|
||||
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
||||
12, 12, kFSsim_thresh)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PSNRHVS, HBDMetricsTest,
|
||||
::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
||||
8, 10, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
||||
10, 10, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
||||
8, 12, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
||||
12, 12, kPhvs_thresh)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PSNR, HBDMetricsTest,
|
||||
::testing::Values(
|
||||
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 10, 10,
|
||||
kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 12, kPhvs_thresh),
|
||||
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 12, 12,
|
||||
kPhvs_thresh)));
|
||||
} // namespace
|
||||
62
media/libaom/src/test/hiprec_convolve_test.cc
Normal file
62
media/libaom/src/test/hiprec_convolve_test.cc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/hiprec_convolve_test_util.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
using libaom_test::ACMRandom;
|
||||
using libaom_test::AV1HighbdHiprecConvolve::AV1HighbdHiprecConvolveTest;
|
||||
using libaom_test::AV1HiprecConvolve::AV1HiprecConvolveTest;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST_P(AV1HiprecConvolveTest, CheckOutput) { RunCheckOutput(GET_PARAM(3)); }
|
||||
TEST_P(AV1HiprecConvolveTest, DISABLED_SpeedTest) {
|
||||
RunSpeedTest(GET_PARAM(3));
|
||||
}
|
||||
#if HAVE_SSE2
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, AV1HiprecConvolveTest,
|
||||
libaom_test::AV1HiprecConvolve::BuildParams(
|
||||
av1_wiener_convolve_add_src_sse2));
|
||||
#endif
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1HiprecConvolveTest,
|
||||
libaom_test::AV1HiprecConvolve::BuildParams(
|
||||
av1_wiener_convolve_add_src_avx2));
|
||||
#endif
|
||||
#if HAVE_NEON
|
||||
INSTANTIATE_TEST_CASE_P(NEON, AV1HiprecConvolveTest,
|
||||
libaom_test::AV1HiprecConvolve::BuildParams(
|
||||
av1_wiener_convolve_add_src_neon));
|
||||
#endif
|
||||
|
||||
#if HAVE_SSSE3 || HAVE_AVX2
|
||||
TEST_P(AV1HighbdHiprecConvolveTest, CheckOutput) {
|
||||
RunCheckOutput(GET_PARAM(4));
|
||||
}
|
||||
TEST_P(AV1HighbdHiprecConvolveTest, DISABLED_SpeedTest) {
|
||||
RunSpeedTest(GET_PARAM(4));
|
||||
}
|
||||
#if HAVE_SSSE3
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, AV1HighbdHiprecConvolveTest,
|
||||
libaom_test::AV1HighbdHiprecConvolve::BuildParams(
|
||||
av1_highbd_wiener_convolve_add_src_ssse3));
|
||||
#endif
|
||||
#if HAVE_AVX2
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, AV1HighbdHiprecConvolveTest,
|
||||
libaom_test::AV1HighbdHiprecConvolve::BuildParams(
|
||||
av1_highbd_wiener_convolve_add_src_avx2));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
331
media/libaom/src/test/hiprec_convolve_test_util.cc
Normal file
331
media/libaom/src/test/hiprec_convolve_test_util.cc
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "test/hiprec_convolve_test_util.h"
|
||||
|
||||
#include "av1/common/restoration.h"
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
// Generate a random pair of filter kernels, using the ranges
|
||||
// of possible values from the loop-restoration experiment
|
||||
static void generate_kernels(ACMRandom *rnd, InterpKernel hkernel,
|
||||
InterpKernel vkernel) {
|
||||
hkernel[0] = hkernel[6] =
|
||||
WIENER_FILT_TAP0_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP0_MAXV + 1 - WIENER_FILT_TAP0_MINV);
|
||||
hkernel[1] = hkernel[5] =
|
||||
WIENER_FILT_TAP1_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP1_MAXV + 1 - WIENER_FILT_TAP1_MINV);
|
||||
hkernel[2] = hkernel[4] =
|
||||
WIENER_FILT_TAP2_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP2_MAXV + 1 - WIENER_FILT_TAP2_MINV);
|
||||
hkernel[3] = -(hkernel[0] + hkernel[1] + hkernel[2]);
|
||||
hkernel[7] = 0;
|
||||
|
||||
vkernel[0] = vkernel[6] =
|
||||
WIENER_FILT_TAP0_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP0_MAXV + 1 - WIENER_FILT_TAP0_MINV);
|
||||
vkernel[1] = vkernel[5] =
|
||||
WIENER_FILT_TAP1_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP1_MAXV + 1 - WIENER_FILT_TAP1_MINV);
|
||||
vkernel[2] = vkernel[4] =
|
||||
WIENER_FILT_TAP2_MINV +
|
||||
rnd->PseudoUniform(WIENER_FILT_TAP2_MAXV + 1 - WIENER_FILT_TAP2_MINV);
|
||||
vkernel[3] = -(vkernel[0] + vkernel[1] + vkernel[2]);
|
||||
vkernel[7] = 0;
|
||||
}
|
||||
|
||||
namespace AV1HiprecConvolve {
|
||||
|
||||
::testing::internal::ParamGenerator<HiprecConvolveParam> BuildParams(
|
||||
hiprec_convolve_func filter) {
|
||||
const HiprecConvolveParam params[] = {
|
||||
make_tuple(8, 8, 50000, filter), make_tuple(8, 4, 50000, filter),
|
||||
make_tuple(64, 24, 1000, filter), make_tuple(64, 64, 1000, filter),
|
||||
make_tuple(64, 56, 1000, filter), make_tuple(32, 8, 10000, filter),
|
||||
make_tuple(32, 28, 10000, filter), make_tuple(32, 32, 10000, filter),
|
||||
make_tuple(16, 34, 10000, filter), make_tuple(32, 34, 10000, filter),
|
||||
make_tuple(64, 34, 1000, filter), make_tuple(8, 17, 10000, filter),
|
||||
make_tuple(16, 17, 10000, filter), make_tuple(32, 17, 10000, filter)
|
||||
};
|
||||
return ::testing::ValuesIn(params);
|
||||
}
|
||||
|
||||
AV1HiprecConvolveTest::~AV1HiprecConvolveTest() {}
|
||||
void AV1HiprecConvolveTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1HiprecConvolveTest::TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
void AV1HiprecConvolveTest::RunCheckOutput(hiprec_convolve_func test_impl) {
|
||||
const int w = 128, h = 128;
|
||||
const int out_w = GET_PARAM(0), out_h = GET_PARAM(1);
|
||||
const int num_iters = GET_PARAM(2);
|
||||
int i, j;
|
||||
const ConvolveParams conv_params = get_conv_params_wiener(8);
|
||||
|
||||
uint8_t *input_ = new uint8_t[h * w];
|
||||
uint8_t *input = input_;
|
||||
|
||||
// The AVX2 convolve functions always write rows with widths that are
|
||||
// multiples of 16. So to avoid a buffer overflow, we may need to pad
|
||||
// rows to a multiple of 16.
|
||||
int output_n = ALIGN_POWER_OF_TWO(out_w, 4) * out_h;
|
||||
uint8_t *output = new uint8_t[output_n];
|
||||
uint8_t *output2 = new uint8_t[output_n];
|
||||
|
||||
// Generate random filter kernels
|
||||
DECLARE_ALIGNED(16, InterpKernel, hkernel);
|
||||
DECLARE_ALIGNED(16, InterpKernel, vkernel);
|
||||
|
||||
generate_kernels(&rnd_, hkernel, vkernel);
|
||||
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
// Choose random locations within the source block
|
||||
int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_wiener_convolve_add_src_c(input + offset_r * w + offset_c, w, output,
|
||||
out_w, hkernel, 16, vkernel, 16, out_w, out_h,
|
||||
&conv_params);
|
||||
test_impl(input + offset_r * w + offset_c, w, output2, out_w, hkernel, 16,
|
||||
vkernel, 16, out_w, out_h, &conv_params);
|
||||
|
||||
for (j = 0; j < out_w * out_h; ++j)
|
||||
ASSERT_EQ(output[j], output2[j])
|
||||
<< "Pixel mismatch at index " << j << " = (" << (j % out_w) << ", "
|
||||
<< (j / out_w) << ") on iteration " << i;
|
||||
}
|
||||
delete[] input_;
|
||||
delete[] output;
|
||||
delete[] output2;
|
||||
}
|
||||
|
||||
void AV1HiprecConvolveTest::RunSpeedTest(hiprec_convolve_func test_impl) {
|
||||
const int w = 128, h = 128;
|
||||
const int out_w = GET_PARAM(0), out_h = GET_PARAM(1);
|
||||
const int num_iters = GET_PARAM(2) / 500;
|
||||
int i, j, k;
|
||||
const ConvolveParams conv_params = get_conv_params_wiener(8);
|
||||
|
||||
uint8_t *input_ = new uint8_t[h * w];
|
||||
uint8_t *input = input_;
|
||||
|
||||
// The AVX2 convolve functions always write rows with widths that are
|
||||
// multiples of 16. So to avoid a buffer overflow, we may need to pad
|
||||
// rows to a multiple of 16.
|
||||
int output_n = ALIGN_POWER_OF_TWO(out_w, 4) * out_h;
|
||||
uint8_t *output = new uint8_t[output_n];
|
||||
uint8_t *output2 = new uint8_t[output_n];
|
||||
|
||||
// Generate random filter kernels
|
||||
DECLARE_ALIGNED(16, InterpKernel, hkernel);
|
||||
DECLARE_ALIGNED(16, InterpKernel, vkernel);
|
||||
|
||||
generate_kernels(&rnd_, hkernel, vkernel);
|
||||
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand8();
|
||||
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
for (j = 3; j < h - out_h - 4; j++) {
|
||||
for (k = 3; k < w - out_w - 4; k++) {
|
||||
av1_wiener_convolve_add_src_c(input + j * w + k, w, output, out_w,
|
||||
hkernel, 16, vkernel, 16, out_w, out_h,
|
||||
&conv_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer tst_timer;
|
||||
aom_usec_timer_start(&tst_timer);
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
for (j = 3; j < h - out_h - 4; j++) {
|
||||
for (k = 3; k < w - out_w - 4; k++) {
|
||||
test_impl(input + j * w + k, w, output2, out_w, hkernel, 16, vkernel,
|
||||
16, out_w, out_h, &conv_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&tst_timer);
|
||||
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
|
||||
|
||||
std::cout << "[ ] C time = " << ref_time / 1000
|
||||
<< " ms, SIMD time = " << tst_time / 1000 << " ms\n";
|
||||
|
||||
EXPECT_GT(ref_time, tst_time)
|
||||
<< "Error: AV1HiprecConvolveTest.SpeedTest, SIMD slower than C.\n"
|
||||
<< "C time: " << ref_time << " us\n"
|
||||
<< "SIMD time: " << tst_time << " us\n";
|
||||
|
||||
delete[] input_;
|
||||
delete[] output;
|
||||
delete[] output2;
|
||||
}
|
||||
} // namespace AV1HiprecConvolve
|
||||
|
||||
namespace AV1HighbdHiprecConvolve {
|
||||
|
||||
::testing::internal::ParamGenerator<HighbdHiprecConvolveParam> BuildParams(
|
||||
highbd_hiprec_convolve_func filter) {
|
||||
const HighbdHiprecConvolveParam params[] = {
|
||||
make_tuple(8, 8, 50000, 8, filter), make_tuple(64, 64, 1000, 8, filter),
|
||||
make_tuple(32, 8, 10000, 8, filter), make_tuple(8, 8, 50000, 10, filter),
|
||||
make_tuple(64, 64, 1000, 10, filter), make_tuple(32, 8, 10000, 10, filter),
|
||||
make_tuple(8, 8, 50000, 12, filter), make_tuple(64, 64, 1000, 12, filter),
|
||||
make_tuple(32, 8, 10000, 12, filter),
|
||||
};
|
||||
return ::testing::ValuesIn(params);
|
||||
}
|
||||
|
||||
AV1HighbdHiprecConvolveTest::~AV1HighbdHiprecConvolveTest() {}
|
||||
void AV1HighbdHiprecConvolveTest::SetUp() {
|
||||
rnd_.Reset(ACMRandom::DeterministicSeed());
|
||||
}
|
||||
|
||||
void AV1HighbdHiprecConvolveTest::TearDown() {
|
||||
libaom_test::ClearSystemState();
|
||||
}
|
||||
|
||||
void AV1HighbdHiprecConvolveTest::RunCheckOutput(
|
||||
highbd_hiprec_convolve_func test_impl) {
|
||||
const int w = 128, h = 128;
|
||||
const int out_w = GET_PARAM(0), out_h = GET_PARAM(1);
|
||||
const int num_iters = GET_PARAM(2);
|
||||
const int bd = GET_PARAM(3);
|
||||
int i, j;
|
||||
const ConvolveParams conv_params = get_conv_params_wiener(bd);
|
||||
|
||||
uint16_t *input = new uint16_t[h * w];
|
||||
|
||||
// The AVX2 convolve functions always write rows with widths that are
|
||||
// multiples of 16. So to avoid a buffer overflow, we may need to pad
|
||||
// rows to a multiple of 16.
|
||||
int output_n = ALIGN_POWER_OF_TWO(out_w, 4) * out_h;
|
||||
uint16_t *output = new uint16_t[output_n];
|
||||
uint16_t *output2 = new uint16_t[output_n];
|
||||
|
||||
// Generate random filter kernels
|
||||
DECLARE_ALIGNED(16, InterpKernel, hkernel);
|
||||
DECLARE_ALIGNED(16, InterpKernel, vkernel);
|
||||
|
||||
generate_kernels(&rnd_, hkernel, vkernel);
|
||||
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
|
||||
uint8_t *input_ptr = CONVERT_TO_BYTEPTR(input);
|
||||
uint8_t *output_ptr = CONVERT_TO_BYTEPTR(output);
|
||||
uint8_t *output2_ptr = CONVERT_TO_BYTEPTR(output2);
|
||||
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
// Choose random locations within the source block
|
||||
int offset_r = 3 + rnd_.PseudoUniform(h - out_h - 7);
|
||||
int offset_c = 3 + rnd_.PseudoUniform(w - out_w - 7);
|
||||
av1_highbd_wiener_convolve_add_src_c(
|
||||
input_ptr + offset_r * w + offset_c, w, output_ptr, out_w, hkernel, 16,
|
||||
vkernel, 16, out_w, out_h, &conv_params, bd);
|
||||
test_impl(input_ptr + offset_r * w + offset_c, w, output2_ptr, out_w,
|
||||
hkernel, 16, vkernel, 16, out_w, out_h, &conv_params, bd);
|
||||
|
||||
for (j = 0; j < out_w * out_h; ++j)
|
||||
ASSERT_EQ(output[j], output2[j])
|
||||
<< "Pixel mismatch at index " << j << " = (" << (j % out_w) << ", "
|
||||
<< (j / out_w) << ") on iteration " << i;
|
||||
}
|
||||
delete[] input;
|
||||
delete[] output;
|
||||
delete[] output2;
|
||||
}
|
||||
|
||||
void AV1HighbdHiprecConvolveTest::RunSpeedTest(
|
||||
highbd_hiprec_convolve_func test_impl) {
|
||||
const int w = 128, h = 128;
|
||||
const int out_w = GET_PARAM(0), out_h = GET_PARAM(1);
|
||||
const int num_iters = GET_PARAM(2) / 500;
|
||||
const int bd = GET_PARAM(3);
|
||||
int i, j, k;
|
||||
const ConvolveParams conv_params = get_conv_params_wiener(bd);
|
||||
|
||||
uint16_t *input = new uint16_t[h * w];
|
||||
|
||||
// The AVX2 convolve functions always write rows with widths that are
|
||||
// multiples of 16. So to avoid a buffer overflow, we may need to pad
|
||||
// rows to a multiple of 16.
|
||||
int output_n = ALIGN_POWER_OF_TWO(out_w, 4) * out_h;
|
||||
uint16_t *output = new uint16_t[output_n];
|
||||
uint16_t *output2 = new uint16_t[output_n];
|
||||
|
||||
// Generate random filter kernels
|
||||
DECLARE_ALIGNED(16, InterpKernel, hkernel);
|
||||
DECLARE_ALIGNED(16, InterpKernel, vkernel);
|
||||
|
||||
generate_kernels(&rnd_, hkernel, vkernel);
|
||||
|
||||
for (i = 0; i < h; ++i)
|
||||
for (j = 0; j < w; ++j) input[i * w + j] = rnd_.Rand16() & ((1 << bd) - 1);
|
||||
|
||||
uint8_t *input_ptr = CONVERT_TO_BYTEPTR(input);
|
||||
uint8_t *output_ptr = CONVERT_TO_BYTEPTR(output);
|
||||
uint8_t *output2_ptr = CONVERT_TO_BYTEPTR(output2);
|
||||
|
||||
aom_usec_timer ref_timer;
|
||||
aom_usec_timer_start(&ref_timer);
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
for (j = 3; j < h - out_h - 4; j++) {
|
||||
for (k = 3; k < w - out_w - 4; k++) {
|
||||
av1_highbd_wiener_convolve_add_src_c(
|
||||
input_ptr + j * w + k, w, output_ptr, out_w, hkernel, 16, vkernel,
|
||||
16, out_w, out_h, &conv_params, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&ref_timer);
|
||||
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
|
||||
|
||||
aom_usec_timer tst_timer;
|
||||
aom_usec_timer_start(&tst_timer);
|
||||
for (i = 0; i < num_iters; ++i) {
|
||||
for (j = 3; j < h - out_h - 4; j++) {
|
||||
for (k = 3; k < w - out_w - 4; k++) {
|
||||
test_impl(input_ptr + j * w + k, w, output2_ptr, out_w, hkernel, 16,
|
||||
vkernel, 16, out_w, out_h, &conv_params, bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&tst_timer);
|
||||
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
|
||||
|
||||
std::cout << "[ ] C time = " << ref_time / 1000
|
||||
<< " ms, SIMD time = " << tst_time / 1000 << " ms\n";
|
||||
|
||||
EXPECT_GT(ref_time, tst_time)
|
||||
<< "Error: AV1HighbdHiprecConvolveTest.SpeedTest, SIMD slower than C.\n"
|
||||
<< "C time: " << ref_time << " us\n"
|
||||
<< "SIMD time: " << tst_time << " us\n";
|
||||
|
||||
delete[] input;
|
||||
delete[] output;
|
||||
delete[] output2;
|
||||
}
|
||||
} // namespace AV1HighbdHiprecConvolve
|
||||
} // namespace libaom_test
|
||||
93
media/libaom/src/test/hiprec_convolve_test_util.h
Normal file
93
media/libaom/src/test/hiprec_convolve_test_util.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_HIPREC_CONVOLVE_TEST_UTIL_H_
|
||||
#define AOM_TEST_HIPREC_CONVOLVE_TEST_UTIL_H_
|
||||
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/util.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "aom_ports/aom_timer.h"
|
||||
#include "av1/common/convolve.h"
|
||||
#include "av1/common/mv.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
namespace AV1HiprecConvolve {
|
||||
|
||||
typedef void (*hiprec_convolve_func)(const uint8_t *src, ptrdiff_t src_stride,
|
||||
uint8_t *dst, ptrdiff_t dst_stride,
|
||||
const int16_t *filter_x, int x_step_q4,
|
||||
const int16_t *filter_y, int y_step_q4,
|
||||
int w, int h,
|
||||
const ConvolveParams *conv_params);
|
||||
|
||||
typedef ::testing::tuple<int, int, int, hiprec_convolve_func>
|
||||
HiprecConvolveParam;
|
||||
|
||||
::testing::internal::ParamGenerator<HiprecConvolveParam> BuildParams(
|
||||
hiprec_convolve_func filter);
|
||||
|
||||
class AV1HiprecConvolveTest
|
||||
: public ::testing::TestWithParam<HiprecConvolveParam> {
|
||||
public:
|
||||
virtual ~AV1HiprecConvolveTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(hiprec_convolve_func test_impl);
|
||||
void RunSpeedTest(hiprec_convolve_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
} // namespace AV1HiprecConvolve
|
||||
|
||||
namespace AV1HighbdHiprecConvolve {
|
||||
typedef void (*highbd_hiprec_convolve_func)(
|
||||
const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,
|
||||
ptrdiff_t dst_stride, const int16_t *filter_x, int x_step_q4,
|
||||
const int16_t *filter_y, int y_step_q4, int w, int h,
|
||||
const ConvolveParams *conv_params, int bps);
|
||||
|
||||
typedef ::testing::tuple<int, int, int, int, highbd_hiprec_convolve_func>
|
||||
HighbdHiprecConvolveParam;
|
||||
|
||||
::testing::internal::ParamGenerator<HighbdHiprecConvolveParam> BuildParams(
|
||||
highbd_hiprec_convolve_func filter);
|
||||
|
||||
class AV1HighbdHiprecConvolveTest
|
||||
: public ::testing::TestWithParam<HighbdHiprecConvolveParam> {
|
||||
public:
|
||||
virtual ~AV1HighbdHiprecConvolveTest();
|
||||
virtual void SetUp();
|
||||
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
void RunCheckOutput(highbd_hiprec_convolve_func test_impl);
|
||||
void RunSpeedTest(highbd_hiprec_convolve_func test_impl);
|
||||
|
||||
libaom_test::ACMRandom rnd_;
|
||||
};
|
||||
|
||||
} // namespace AV1HighbdHiprecConvolve
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_HIPREC_CONVOLVE_TEST_UTIL_H_
|
||||
322
media/libaom/src/test/horz_superres_test.cc
Normal file
322
media/libaom/src/test/horz_superres_test.cc
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "av1/encoder/encoder.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
#include "test/yuv_video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::make_tuple;
|
||||
using ::testing::tuple;
|
||||
|
||||
/* TESTING PARAMETERS */
|
||||
|
||||
#define NUM_TEST_VIDEOS 3
|
||||
|
||||
const int kBitrate = 40;
|
||||
|
||||
// PSNR thresholds found by experiment
|
||||
const double kPSNRThresholds[] = { 26.0, 28.0, 20.0 };
|
||||
|
||||
typedef struct {
|
||||
const char *filename;
|
||||
aom_img_fmt fmt;
|
||||
aom_bit_depth_t bit_depth;
|
||||
unsigned int profile;
|
||||
unsigned int limit;
|
||||
unsigned int screen_content;
|
||||
} TestVideoParam;
|
||||
|
||||
const TestVideoParam kTestVideoVectors[] = {
|
||||
{ "park_joy_90p_8_420.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 5, 0 },
|
||||
{ "park_joy_90p_10_444.y4m", AOM_IMG_FMT_I44416, AOM_BITS_10, 1, 5, 0 },
|
||||
{ "screendata.y4m", AOM_IMG_FMT_I420, AOM_BITS_8, 0, 4, 1 },
|
||||
};
|
||||
|
||||
// Superres modes tested
|
||||
// SUPERRES_QTHRESH is not included, as it has its own test
|
||||
const SUPERRES_MODE kSuperresModesNotQThresh[] = { SUPERRES_FIXED,
|
||||
SUPERRES_RANDOM };
|
||||
|
||||
// Superres denominators and superres kf denominators to be tested
|
||||
typedef tuple<int, int> SuperresDenominatorPair;
|
||||
const SuperresDenominatorPair kSuperresDenominators[] = {
|
||||
make_tuple(16, 9), make_tuple(13, 11), make_tuple(9, 9),
|
||||
make_tuple(13, 13), make_tuple(11, 16), make_tuple(8, 16),
|
||||
make_tuple(16, 8), make_tuple(8, 8), make_tuple(9, 14),
|
||||
};
|
||||
|
||||
// Superres q thresholds and superres kf q thresholds to be tested
|
||||
typedef tuple<int, int> SuperresQThresholdPair;
|
||||
const SuperresQThresholdPair kSuperresQThresholds[] = {
|
||||
make_tuple(63, 63), make_tuple(63, 41), make_tuple(17, 63),
|
||||
make_tuple(41, 11), make_tuple(1, 37), make_tuple(11, 11),
|
||||
make_tuple(1, 1), make_tuple(17, 29), make_tuple(29, 11),
|
||||
};
|
||||
|
||||
/* END (TESTING PARAMETERS) */
|
||||
|
||||
// Test parameter list:
|
||||
// <[needed for EncoderTest], test_video_idx_, superres_mode_,
|
||||
// tuple(superres_denom_, superres_kf_denom_)>
|
||||
typedef tuple<const libaom_test::CodecFactory *, int, SUPERRES_MODE,
|
||||
SuperresDenominatorPair>
|
||||
HorzSuperresTestParam;
|
||||
|
||||
class HorzSuperresEndToEndTest
|
||||
: public ::testing::TestWithParam<HorzSuperresTestParam>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
HorzSuperresEndToEndTest()
|
||||
: EncoderTest(GET_PARAM(0)), test_video_idx_(GET_PARAM(1)),
|
||||
superres_mode_(GET_PARAM(2)), psnr_(0.0), frame_count_(0) {
|
||||
test_video_param_ = kTestVideoVectors[test_video_idx_];
|
||||
|
||||
SuperresDenominatorPair denoms = GET_PARAM(3);
|
||||
superres_denom_ = ::testing::get<0>(denoms);
|
||||
superres_kf_denom_ = ::testing::get<1>(denoms);
|
||||
}
|
||||
|
||||
virtual ~HorzSuperresEndToEndTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(::libaom_test::kTwoPassGood);
|
||||
cfg_.g_lag_in_frames = 5;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.rc_target_bitrate = kBitrate;
|
||||
cfg_.g_error_resilient = 0;
|
||||
cfg_.g_profile = test_video_param_.profile;
|
||||
cfg_.g_input_bit_depth = (unsigned int)test_video_param_.bit_depth;
|
||||
cfg_.g_bit_depth = test_video_param_.bit_depth;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH;
|
||||
|
||||
// Set superres parameters
|
||||
cfg_.rc_superres_mode = superres_mode_;
|
||||
cfg_.rc_superres_denominator = superres_denom_;
|
||||
cfg_.rc_superres_kf_denominator = superres_kf_denom_;
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int) {
|
||||
psnr_ = 0.0;
|
||||
frame_count_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
psnr_ += pkt->data.psnr.psnr[0];
|
||||
frame_count_++;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 4);
|
||||
|
||||
// Set cpu-used = 8 for speed
|
||||
encoder->Control(AOME_SET_CPUUSED, 8);
|
||||
|
||||
// Test screen coding tools
|
||||
if (test_video_param_.screen_content)
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN);
|
||||
else
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT);
|
||||
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
|
||||
double GetAveragePsnr() const {
|
||||
if (frame_count_) return psnr_ / frame_count_;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double GetPsnrThreshold() { return kPSNRThresholds[test_video_idx_]; }
|
||||
|
||||
void DoTest() {
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video;
|
||||
video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0,
|
||||
test_video_param_.limit));
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
const double psnr = GetAveragePsnr();
|
||||
EXPECT_GT(psnr, GetPsnrThreshold())
|
||||
<< "superres_mode_ = " << superres_mode_
|
||||
<< ", superres_denom_ = " << superres_denom_
|
||||
<< ", superres_kf_denom_ = " << superres_kf_denom_;
|
||||
|
||||
EXPECT_EQ(test_video_param_.limit, frame_count_)
|
||||
<< "superres_mode_ = " << superres_mode_
|
||||
<< ", superres_denom_ = " << superres_denom_
|
||||
<< ", superres_kf_denom_ = " << superres_kf_denom_;
|
||||
}
|
||||
|
||||
int test_video_idx_;
|
||||
TestVideoParam test_video_param_;
|
||||
SUPERRES_MODE superres_mode_;
|
||||
int superres_denom_;
|
||||
int superres_kf_denom_;
|
||||
|
||||
private:
|
||||
double psnr_;
|
||||
unsigned int frame_count_;
|
||||
};
|
||||
|
||||
TEST_P(HorzSuperresEndToEndTest, HorzSuperresEndToEndPSNRTest) { DoTest(); }
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(HorzSuperresEndToEndTest,
|
||||
::testing::Range(0, NUM_TEST_VIDEOS),
|
||||
::testing::ValuesIn(kSuperresModesNotQThresh),
|
||||
::testing::ValuesIn(kSuperresDenominators));
|
||||
|
||||
// Test parameter list:
|
||||
// <[needed for EncoderTest], test_video_idx_, tuple(superres_denom_,
|
||||
// superres_kf_denom_), tuple(superres_qthresh_,superres_kf_qthresh_)>
|
||||
typedef tuple<const libaom_test::CodecFactory *, int, SuperresDenominatorPair,
|
||||
SuperresQThresholdPair>
|
||||
HorzSuperresQThreshTestParam;
|
||||
|
||||
class HorzSuperresQThreshEndToEndTest
|
||||
: public ::testing::TestWithParam<HorzSuperresQThreshTestParam>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
HorzSuperresQThreshEndToEndTest()
|
||||
: EncoderTest(GET_PARAM(0)), test_video_idx_(GET_PARAM(1)),
|
||||
superres_mode_(SUPERRES_QTHRESH), psnr_(0.0), frame_count_(0) {
|
||||
test_video_param_ = kTestVideoVectors[test_video_idx_];
|
||||
|
||||
SuperresDenominatorPair denoms = GET_PARAM(2);
|
||||
superres_denom_ = ::testing::get<0>(denoms);
|
||||
superres_kf_denom_ = ::testing::get<1>(denoms);
|
||||
|
||||
SuperresQThresholdPair qthresholds = GET_PARAM(3);
|
||||
superres_qthresh_ = ::testing::get<0>(qthresholds);
|
||||
superres_kf_qthresh_ = ::testing::get<1>(qthresholds);
|
||||
}
|
||||
|
||||
virtual ~HorzSuperresQThreshEndToEndTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(::libaom_test::kTwoPassGood);
|
||||
cfg_.g_lag_in_frames = 5;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
cfg_.rc_target_bitrate = kBitrate;
|
||||
cfg_.g_error_resilient = 0;
|
||||
cfg_.g_profile = test_video_param_.profile;
|
||||
cfg_.g_input_bit_depth = (unsigned int)test_video_param_.bit_depth;
|
||||
cfg_.g_bit_depth = test_video_param_.bit_depth;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
if (cfg_.g_bit_depth > 8) init_flags_ |= AOM_CODEC_USE_HIGHBITDEPTH;
|
||||
|
||||
// Set superres parameters
|
||||
cfg_.rc_superres_mode = superres_mode_;
|
||||
cfg_.rc_superres_denominator = superres_denom_;
|
||||
cfg_.rc_superres_kf_denominator = superres_kf_denom_;
|
||||
cfg_.rc_superres_qthresh = superres_qthresh_;
|
||||
cfg_.rc_superres_kf_qthresh = superres_kf_qthresh_;
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int) {
|
||||
psnr_ = 0.0;
|
||||
frame_count_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
psnr_ += pkt->data.psnr.psnr[0];
|
||||
frame_count_++;
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
|
||||
encoder->Control(AV1E_SET_TILE_COLUMNS, 0);
|
||||
|
||||
// Set cpu-used = 8 for speed
|
||||
encoder->Control(AOME_SET_CPUUSED, 8);
|
||||
|
||||
// Test screen coding tools
|
||||
if (test_video_param_.screen_content)
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN);
|
||||
else
|
||||
encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT);
|
||||
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
|
||||
double GetAveragePsnr() const {
|
||||
if (frame_count_) return psnr_ / frame_count_;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double GetPsnrThreshold() { return kPSNRThresholds[test_video_idx_]; }
|
||||
|
||||
void DoTest() {
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video;
|
||||
video.reset(new libaom_test::Y4mVideoSource(test_video_param_.filename, 0,
|
||||
test_video_param_.limit));
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
const double psnr = GetAveragePsnr();
|
||||
EXPECT_GT(psnr, GetPsnrThreshold())
|
||||
<< "superres_mode_ = " << superres_mode_
|
||||
<< ", superres_denom_ = " << superres_denom_
|
||||
<< ", superres_kf_denom_ = " << superres_kf_denom_
|
||||
<< ", superres_qthresh_ = " << superres_qthresh_
|
||||
<< ", superres_kf_qthresh_ = " << superres_kf_qthresh_;
|
||||
|
||||
EXPECT_EQ(test_video_param_.limit, frame_count_)
|
||||
<< "superres_mode_ = " << superres_mode_
|
||||
<< ", superres_denom_ = " << superres_denom_
|
||||
<< ", superres_kf_denom_ = " << superres_kf_denom_
|
||||
<< ", superres_qthresh_ = " << superres_qthresh_
|
||||
<< ", superres_kf_qthresh_ = " << superres_kf_qthresh_;
|
||||
}
|
||||
|
||||
int test_video_idx_;
|
||||
TestVideoParam test_video_param_;
|
||||
SUPERRES_MODE superres_mode_;
|
||||
int superres_denom_;
|
||||
int superres_kf_denom_;
|
||||
int superres_qthresh_;
|
||||
int superres_kf_qthresh_;
|
||||
|
||||
private:
|
||||
double psnr_;
|
||||
unsigned int frame_count_;
|
||||
};
|
||||
|
||||
TEST_P(HorzSuperresQThreshEndToEndTest, HorzSuperresQThreshEndToEndPSNRTest) {
|
||||
DoTest();
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(HorzSuperresQThreshEndToEndTest,
|
||||
::testing::Range(0, NUM_TEST_VIDEOS),
|
||||
::testing::ValuesIn(kSuperresDenominators),
|
||||
::testing::ValuesIn(kSuperresQThresholds));
|
||||
|
||||
} // namespace
|
||||
34
media/libaom/src/test/i420_video_source.h
Normal file
34
media/libaom/src/test/i420_video_source.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AOM_TEST_I420_VIDEO_SOURCE_H_
|
||||
#define AOM_TEST_I420_VIDEO_SOURCE_H_
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "test/yuv_video_source.h"
|
||||
|
||||
namespace libaom_test {
|
||||
|
||||
// This class extends VideoSource to allow parsing of raw yv12
|
||||
// so that we can do actual file encodes.
|
||||
class I420VideoSource : public YUVVideoSource {
|
||||
public:
|
||||
I420VideoSource(const std::string &file_name, unsigned int width,
|
||||
unsigned int height, int rate_numerator, int rate_denominator,
|
||||
unsigned int start, int limit)
|
||||
: YUVVideoSource(file_name, AOM_IMG_FMT_I420, width, height,
|
||||
rate_numerator, rate_denominator, start, limit) {}
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_I420_VIDEO_SOURCE_H_
|
||||
337
media/libaom/src/test/intra_edge_test.cc
Normal file
337
media/libaom/src/test/intra_edge_test.cc
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/function_equivalence_test.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
#include "config/av1_rtcd.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
#include "av1/common/enums.h"
|
||||
|
||||
using libaom_test::FunctionEquivalenceTest;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename F, typename T>
|
||||
class UpsampleTest : public FunctionEquivalenceTest<F> {
|
||||
protected:
|
||||
static const int kIterations = 1000000;
|
||||
static const int kMinEdge = 4;
|
||||
static const int kMaxEdge = 24;
|
||||
static const int kBufSize = 2 * 64 + 32;
|
||||
static const int kOffset = 16;
|
||||
|
||||
virtual ~UpsampleTest() {}
|
||||
|
||||
virtual void Execute(T *edge_tst) = 0;
|
||||
|
||||
void Common() {
|
||||
edge_ref_ = &edge_ref_data_[kOffset];
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
|
||||
Execute(edge_tst_);
|
||||
|
||||
const int max_idx = (size_ - 1) * 2;
|
||||
for (int r = -2; r <= max_idx; ++r) {
|
||||
ASSERT_EQ(edge_ref_[r], edge_tst_[r]);
|
||||
}
|
||||
}
|
||||
|
||||
T edge_ref_data_[kBufSize];
|
||||
T edge_tst_data_[kBufSize];
|
||||
|
||||
T *edge_ref_;
|
||||
T *edge_tst_;
|
||||
|
||||
int size_;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 8 bit version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*UP8B)(uint8_t *p, int size);
|
||||
typedef libaom_test::FuncParam<UP8B> TestFuncs;
|
||||
|
||||
class UpsampleTest8B : public UpsampleTest<UP8B, uint8_t> {
|
||||
protected:
|
||||
void Execute(uint8_t *edge_tst) {
|
||||
params_.ref_func(edge_ref_, size_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst, size_));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(UpsampleTest8B, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
size_ = 4 * (this->rng_(4) + 1);
|
||||
|
||||
int i, pix = 0;
|
||||
for (i = 0; i < kOffset + size_; ++i) {
|
||||
pix = rng_.Rand8();
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = edge_ref_data_[i];
|
||||
}
|
||||
|
||||
// Extend final sample
|
||||
while (i < kBufSize) {
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = pix;
|
||||
i++;
|
||||
}
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, UpsampleTest8B,
|
||||
::testing::Values(TestFuncs(av1_upsample_intra_edge_c,
|
||||
av1_upsample_intra_edge_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// High bit-depth version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*UPHB)(uint16_t *p, int size, int bd);
|
||||
typedef libaom_test::FuncParam<UPHB> TestFuncsHBD;
|
||||
|
||||
class UpsampleTestHB : public UpsampleTest<UPHB, uint16_t> {
|
||||
protected:
|
||||
void Execute(uint16_t *edge_tst) {
|
||||
params_.ref_func(edge_ref_, size_, bit_depth_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst, size_, bit_depth_));
|
||||
}
|
||||
int bit_depth_;
|
||||
};
|
||||
|
||||
TEST_P(UpsampleTestHB, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
const int hi = 1 << bit_depth_;
|
||||
|
||||
size_ = 4 * (this->rng_(4) + 1);
|
||||
|
||||
int i, pix = 0;
|
||||
for (i = 0; i < kOffset + size_; ++i) {
|
||||
pix = rng_(hi);
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = pix;
|
||||
}
|
||||
|
||||
// Extend final sample
|
||||
while (i < kBufSize) {
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = pix;
|
||||
i++;
|
||||
}
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, UpsampleTestHB,
|
||||
::testing::Values(TestFuncsHBD(av1_upsample_intra_edge_high_c,
|
||||
av1_upsample_intra_edge_high_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
template <typename F, typename T>
|
||||
class FilterEdgeTest : public FunctionEquivalenceTest<F> {
|
||||
protected:
|
||||
static const int kIterations = 1000000;
|
||||
static const int kMaxEdge = 2 * 64;
|
||||
static const int kBufSize = kMaxEdge + 32;
|
||||
static const int kOffset = 15;
|
||||
|
||||
virtual ~FilterEdgeTest() {}
|
||||
|
||||
virtual void Execute(T *edge_tst) = 0;
|
||||
|
||||
void Common() {
|
||||
edge_ref_ = &edge_ref_data_[kOffset];
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
|
||||
Execute(edge_tst_);
|
||||
|
||||
for (int r = 0; r < size_; ++r) {
|
||||
ASSERT_EQ(edge_ref_[r], edge_tst_[r]);
|
||||
}
|
||||
}
|
||||
|
||||
T edge_ref_data_[kBufSize];
|
||||
T edge_tst_data_[kBufSize];
|
||||
|
||||
T *edge_ref_;
|
||||
T *edge_tst_;
|
||||
|
||||
int size_;
|
||||
int strength_;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 8 bit version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FE8B)(uint8_t *p, int size, int strength);
|
||||
typedef libaom_test::FuncParam<FE8B> FilterEdgeTestFuncs;
|
||||
|
||||
class FilterEdgeTest8B : public FilterEdgeTest<FE8B, uint8_t> {
|
||||
protected:
|
||||
void Execute(uint8_t *edge_tst) {
|
||||
params_.ref_func(edge_ref_, size_, strength_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst, size_, strength_));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(FilterEdgeTest8B, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
strength_ = this->rng_(4);
|
||||
size_ = 4 * (this->rng_(128 / 4) + 1) + 1;
|
||||
|
||||
int i, pix = 0;
|
||||
for (i = 0; i < kOffset + size_; ++i) {
|
||||
pix = rng_.Rand8();
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = pix;
|
||||
}
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SSE4_1, FilterEdgeTest8B,
|
||||
::testing::Values(FilterEdgeTestFuncs(av1_filter_intra_edge_c,
|
||||
av1_filter_intra_edge_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// High bit-depth version
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (*FEHB)(uint16_t *p, int size, int strength);
|
||||
typedef libaom_test::FuncParam<FEHB> FilterEdgeTestFuncsHBD;
|
||||
|
||||
class FilterEdgeTestHB : public FilterEdgeTest<FEHB, uint16_t> {
|
||||
protected:
|
||||
void Execute(uint16_t *edge_tst) {
|
||||
params_.ref_func(edge_ref_, size_, strength_);
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst, size_, strength_));
|
||||
}
|
||||
int bit_depth_;
|
||||
};
|
||||
|
||||
TEST_P(FilterEdgeTestHB, RandomValues) {
|
||||
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
|
||||
switch (rng_(3)) {
|
||||
case 0: bit_depth_ = 8; break;
|
||||
case 1: bit_depth_ = 10; break;
|
||||
default: bit_depth_ = 12; break;
|
||||
}
|
||||
const int hi = 1 << bit_depth_;
|
||||
strength_ = this->rng_(4);
|
||||
size_ = 4 * (this->rng_(128 / 4) + 1) + 1;
|
||||
|
||||
int i, pix = 0;
|
||||
for (i = 0; i < kOffset + size_; ++i) {
|
||||
pix = rng_(hi);
|
||||
edge_ref_data_[i] = pix;
|
||||
edge_tst_data_[i] = pix;
|
||||
}
|
||||
|
||||
Common();
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_SSE4_1
|
||||
INSTANTIATE_TEST_CASE_P(SSE4_1, FilterEdgeTestHB,
|
||||
::testing::Values(FilterEdgeTestFuncsHBD(
|
||||
av1_filter_intra_edge_high_c,
|
||||
av1_filter_intra_edge_high_sse4_1)));
|
||||
#endif // HAVE_SSE4_1
|
||||
|
||||
// Speed tests
|
||||
|
||||
TEST_P(UpsampleTest8B, DISABLED_Speed) {
|
||||
const int test_count = 10000000;
|
||||
size_ = kMaxEdge;
|
||||
for (int i = 0; i < kOffset + size_; ++i) {
|
||||
edge_tst_data_[i] = rng_.Rand8();
|
||||
}
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
for (int iter = 0; iter < test_count; ++iter) {
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst_, size_));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(UpsampleTestHB, DISABLED_Speed) {
|
||||
const int test_count = 10000000;
|
||||
size_ = kMaxEdge;
|
||||
bit_depth_ = 12;
|
||||
const int hi = 1 << bit_depth_;
|
||||
for (int i = 0; i < kOffset + size_; ++i) {
|
||||
edge_tst_data_[i] = rng_(hi);
|
||||
}
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
for (int iter = 0; iter < test_count; ++iter) {
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst_, size_, bit_depth_));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(FilterEdgeTest8B, DISABLED_Speed) {
|
||||
const int test_count = 10000000;
|
||||
size_ = kMaxEdge;
|
||||
strength_ = 1;
|
||||
for (int i = 0; i < kOffset + size_; ++i) {
|
||||
edge_tst_data_[i] = rng_.Rand8();
|
||||
}
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
for (int iter = 0; iter < test_count; ++iter) {
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst_, size_, strength_));
|
||||
// iterate over filter strengths (1,2,3)
|
||||
strength_ = (strength_ == 3) ? 1 : strength_ + 1;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(FilterEdgeTestHB, DISABLED_Speed) {
|
||||
const int test_count = 10000000;
|
||||
size_ = kMaxEdge;
|
||||
strength_ = 1;
|
||||
bit_depth_ = 12;
|
||||
const int hi = 1 << bit_depth_;
|
||||
for (int i = 0; i < kOffset + size_; ++i) {
|
||||
edge_tst_data_[i] = rng_(hi);
|
||||
}
|
||||
edge_tst_ = &edge_tst_data_[kOffset];
|
||||
for (int iter = 0; iter < test_count; ++iter) {
|
||||
ASM_REGISTER_STATE_CHECK(params_.tst_func(edge_tst_, size_, strength_));
|
||||
// iterate over filter strengths (1,2,3)
|
||||
strength_ = (strength_ == 3) ? 1 : strength_ + 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
168
media/libaom/src/test/intrabc_test.cc
Normal file
168
media/libaom/src/test/intrabc_test.cc
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/enums.h"
|
||||
#include "av1/common/mv.h"
|
||||
#include "av1/common/mvref_common.h"
|
||||
#include "av1/common/onyxc_int.h"
|
||||
#include "av1/common/tile_common.h"
|
||||
|
||||
namespace {
|
||||
TEST(IntrabcTest, DvValidation) {
|
||||
struct DvTestCase {
|
||||
MV dv;
|
||||
int mi_row_offset;
|
||||
int mi_col_offset;
|
||||
BLOCK_SIZE bsize;
|
||||
bool valid;
|
||||
};
|
||||
const int kSubPelScale = 8;
|
||||
const int kTileMaxMibWidth = 8;
|
||||
const DvTestCase kDvCases[] = {
|
||||
{ { 0, 0 }, 0, 0, BLOCK_128X128, false },
|
||||
{ { 0, 0 }, 0, 0, BLOCK_64X64, false },
|
||||
{ { 0, 0 }, 0, 0, BLOCK_32X32, false },
|
||||
{ { 0, 0 }, 0, 0, BLOCK_16X16, false },
|
||||
{ { 0, 0 }, 0, 0, BLOCK_8X8, false },
|
||||
{ { 0, 0 }, 0, 0, BLOCK_4X4, false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, -MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_16X16,
|
||||
true },
|
||||
{ { 0, -MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_16X16,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, 0 },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_16X16,
|
||||
true },
|
||||
{ { MAX_SB_SIZE * kSubPelScale, 0 },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_16X16,
|
||||
false },
|
||||
{ { 0, MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_16X16,
|
||||
false },
|
||||
{ { -32 * kSubPelScale, -32 * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
true },
|
||||
{ { -32 * kSubPelScale, -32 * kSubPelScale },
|
||||
32 / MI_SIZE,
|
||||
32 / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
false },
|
||||
{ { -32 * kSubPelScale - kSubPelScale / 2, -32 * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
false },
|
||||
{ { -33 * kSubPelScale, -32 * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
true },
|
||||
{ { -32 * kSubPelScale, -32 * kSubPelScale - kSubPelScale / 2 },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
false },
|
||||
{ { -32 * kSubPelScale, -33 * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_32X32,
|
||||
true },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, -MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
true },
|
||||
{ { -(MAX_SB_SIZE + 1) * kSubPelScale, -MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, -(MAX_SB_SIZE + 1) * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -(MAX_SB_SIZE - 1) * kSubPelScale, -MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, -(MAX_SB_SIZE - 1) * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
true },
|
||||
{ { -(MAX_SB_SIZE - 1) * kSubPelScale, -(MAX_SB_SIZE - 1) * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale, MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale,
|
||||
(kTileMaxMibWidth - 2) * MAX_SB_SIZE * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
{ { -MAX_SB_SIZE * kSubPelScale,
|
||||
((kTileMaxMibWidth - 2) * MAX_SB_SIZE + 1) * kSubPelScale },
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
MAX_SB_SIZE / MI_SIZE,
|
||||
BLOCK_LARGEST,
|
||||
false },
|
||||
};
|
||||
|
||||
MACROBLOCKD xd;
|
||||
memset(&xd, 0, sizeof(xd));
|
||||
xd.tile.mi_row_start = 8 * MAX_MIB_SIZE;
|
||||
xd.tile.mi_row_end = 16 * MAX_MIB_SIZE;
|
||||
xd.tile.mi_col_start = 24 * MAX_MIB_SIZE;
|
||||
xd.tile.mi_col_end = xd.tile.mi_col_start + kTileMaxMibWidth * MAX_MIB_SIZE;
|
||||
xd.plane[1].subsampling_x = 1;
|
||||
xd.plane[1].subsampling_y = 1;
|
||||
xd.plane[2].subsampling_x = 1;
|
||||
xd.plane[2].subsampling_y = 1;
|
||||
|
||||
AV1_COMMON cm;
|
||||
memset(&cm, 0, sizeof(cm));
|
||||
|
||||
for (int i = 0; i < static_cast<int>(GTEST_ARRAY_SIZE_(kDvCases)); ++i) {
|
||||
EXPECT_EQ(static_cast<int>(kDvCases[i].valid),
|
||||
av1_is_dv_valid(kDvCases[i].dv, &cm, &xd,
|
||||
xd.tile.mi_row_start + kDvCases[i].mi_row_offset,
|
||||
xd.tile.mi_col_start + kDvCases[i].mi_col_offset,
|
||||
kDvCases[i].bsize, MAX_MIB_SIZE_LOG2))
|
||||
<< "DvCases[" << i << "]";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
266
media/libaom/src/test/intrapred_test.cc
Normal file
266
media/libaom/src/test/intrapred_test.cc
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/blockd.h"
|
||||
#include "av1/common/common.h"
|
||||
#include "av1/common/pred_common.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
const int count_test_block = 100000;
|
||||
|
||||
typedef void (*HighbdIntraPred)(uint16_t *dst, ptrdiff_t stride,
|
||||
const uint16_t *above, const uint16_t *left,
|
||||
int bps);
|
||||
typedef void (*IntraPred)(uint8_t *dst, ptrdiff_t stride, const uint8_t *above,
|
||||
const uint8_t *left);
|
||||
|
||||
} // namespace
|
||||
|
||||
// NOTE: Under gcc version 7.3.0 (Debian 7.3.0-5), if this template is in the
|
||||
// anonymous namespace, then we get a strange compiler warning in
|
||||
// the begin() and end() methods of the ParamGenerator template class in
|
||||
// gtest/internal/gtest-param-util.h:
|
||||
// warning: ‘<anonymous>’ is used uninitialized in this function
|
||||
// As a workaround, put this template outside the anonymous namespace.
|
||||
// See bug aomedia:2003.
|
||||
template <typename FuncType>
|
||||
struct IntraPredFunc {
|
||||
IntraPredFunc(FuncType pred = NULL, FuncType ref = NULL,
|
||||
int block_width_value = 0, int block_height_value = 0,
|
||||
int bit_depth_value = 0)
|
||||
: pred_fn(pred), ref_fn(ref), block_width(block_width_value),
|
||||
block_height(block_height_value), bit_depth(bit_depth_value) {}
|
||||
|
||||
FuncType pred_fn;
|
||||
FuncType ref_fn;
|
||||
int block_width;
|
||||
int block_height;
|
||||
int bit_depth;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename FuncType, typename Pixel>
|
||||
class AV1IntraPredTest
|
||||
: public ::testing::TestWithParam<IntraPredFunc<FuncType> > {
|
||||
public:
|
||||
void RunTest(Pixel *left_col, Pixel *above_data, Pixel *dst, Pixel *ref_dst) {
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
const int block_width = params_.block_width;
|
||||
const int block_height = params_.block_height;
|
||||
above_row_ = above_data + 16;
|
||||
left_col_ = left_col;
|
||||
dst_ = dst;
|
||||
ref_dst_ = ref_dst;
|
||||
int error_count = 0;
|
||||
for (int i = 0; i < count_test_block; ++i) {
|
||||
// Fill edges with random data, try first with saturated values.
|
||||
for (int x = -1; x <= block_width * 2; x++) {
|
||||
if (i == 0) {
|
||||
above_row_[x] = mask_;
|
||||
} else {
|
||||
above_row_[x] = rnd.Rand16() & mask_;
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < block_height; y++) {
|
||||
if (i == 0) {
|
||||
left_col_[y] = mask_;
|
||||
} else {
|
||||
left_col_[y] = rnd.Rand16() & mask_;
|
||||
}
|
||||
}
|
||||
Predict();
|
||||
CheckPrediction(i, &error_count);
|
||||
}
|
||||
ASSERT_EQ(0, error_count);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
params_ = this->GetParam();
|
||||
stride_ = params_.block_width * 3;
|
||||
mask_ = (1 << params_.bit_depth) - 1;
|
||||
}
|
||||
|
||||
virtual void Predict() = 0;
|
||||
|
||||
void CheckPrediction(int test_case_number, int *error_count) const {
|
||||
// For each pixel ensure that the calculated value is the same as reference.
|
||||
const int block_width = params_.block_width;
|
||||
const int block_height = params_.block_height;
|
||||
for (int y = 0; y < block_height; y++) {
|
||||
for (int x = 0; x < block_width; x++) {
|
||||
*error_count += ref_dst_[x + y * stride_] != dst_[x + y * stride_];
|
||||
if (*error_count == 1) {
|
||||
ASSERT_EQ(ref_dst_[x + y * stride_], dst_[x + y * stride_])
|
||||
<< " Failed on Test Case Number " << test_case_number
|
||||
<< " location: x = " << x << " y = " << y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pixel *above_row_;
|
||||
Pixel *left_col_;
|
||||
Pixel *dst_;
|
||||
Pixel *ref_dst_;
|
||||
ptrdiff_t stride_;
|
||||
int mask_;
|
||||
|
||||
IntraPredFunc<FuncType> params_;
|
||||
};
|
||||
|
||||
class HighbdIntraPredTest : public AV1IntraPredTest<HighbdIntraPred, uint16_t> {
|
||||
protected:
|
||||
void Predict() {
|
||||
const int bit_depth = params_.bit_depth;
|
||||
params_.ref_fn(ref_dst_, stride_, above_row_, left_col_, bit_depth);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
params_.pred_fn(dst_, stride_, above_row_, left_col_, bit_depth));
|
||||
}
|
||||
};
|
||||
|
||||
class LowbdIntraPredTest : public AV1IntraPredTest<IntraPred, uint8_t> {
|
||||
protected:
|
||||
void Predict() {
|
||||
params_.ref_fn(ref_dst_, stride_, above_row_, left_col_);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
params_.pred_fn(dst_, stride_, above_row_, left_col_));
|
||||
}
|
||||
};
|
||||
|
||||
// Suppress an unitialized warning. Once there are implementations to test then
|
||||
// this can be restored.
|
||||
TEST_P(HighbdIntraPredTest, Bitexact) {
|
||||
// max block size is 64
|
||||
DECLARE_ALIGNED(16, uint16_t, left_col[2 * 64]);
|
||||
DECLARE_ALIGNED(16, uint16_t, above_data[2 * 64 + 64]);
|
||||
DECLARE_ALIGNED(16, uint16_t, dst[3 * 64 * 64]);
|
||||
DECLARE_ALIGNED(16, uint16_t, ref_dst[3 * 64 * 64]);
|
||||
av1_zero(left_col);
|
||||
av1_zero(above_data);
|
||||
RunTest(left_col, above_data, dst, ref_dst);
|
||||
}
|
||||
|
||||
// Same issue as above but for arm.
|
||||
#if !HAVE_NEON
|
||||
TEST_P(LowbdIntraPredTest, Bitexact) {
|
||||
// max block size is 32
|
||||
DECLARE_ALIGNED(16, uint8_t, left_col[2 * 32]);
|
||||
DECLARE_ALIGNED(16, uint8_t, above_data[2 * 32 + 32]);
|
||||
DECLARE_ALIGNED(16, uint8_t, dst[3 * 32 * 32]);
|
||||
DECLARE_ALIGNED(16, uint8_t, ref_dst[3 * 32 * 32]);
|
||||
av1_zero(left_col);
|
||||
av1_zero(above_data);
|
||||
RunTest(left_col, above_data, dst, ref_dst);
|
||||
}
|
||||
#endif // !HAVE_NEON
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// High Bit Depth Tests
|
||||
#define highbd_entry(type, width, height, opt, bd) \
|
||||
IntraPredFunc<HighbdIntraPred>( \
|
||||
&aom_highbd_##type##_predictor_##width##x##height##_##opt, \
|
||||
&aom_highbd_##type##_predictor_##width##x##height##_c, width, height, \
|
||||
bd)
|
||||
|
||||
#if 0
|
||||
#define highbd_intrapred(type, opt, bd) \
|
||||
highbd_entry(type, 4, 4, opt, bd), highbd_entry(type, 4, 8, opt, bd), \
|
||||
highbd_entry(type, 8, 4, opt, bd), highbd_entry(type, 8, 8, opt, bd), \
|
||||
highbd_entry(type, 8, 16, opt, bd), highbd_entry(type, 16, 8, opt, bd), \
|
||||
highbd_entry(type, 16, 16, opt, bd), \
|
||||
highbd_entry(type, 16, 32, opt, bd), \
|
||||
highbd_entry(type, 32, 16, opt, bd), highbd_entry(type, 32, 32, opt, bd)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Low Bit Depth Tests
|
||||
|
||||
#define lowbd_entry(type, width, height, opt) \
|
||||
IntraPredFunc<IntraPred>(&aom_##type##_predictor_##width##x##height##_##opt, \
|
||||
&aom_##type##_predictor_##width##x##height##_c, \
|
||||
width, height, 8)
|
||||
|
||||
#define lowbd_intrapred(type, opt) \
|
||||
lowbd_entry(type, 4, 4, opt), lowbd_entry(type, 4, 8, opt), \
|
||||
lowbd_entry(type, 8, 4, opt), lowbd_entry(type, 8, 8, opt), \
|
||||
lowbd_entry(type, 8, 16, opt), lowbd_entry(type, 16, 8, opt), \
|
||||
lowbd_entry(type, 16, 16, opt), lowbd_entry(type, 16, 32, opt), \
|
||||
lowbd_entry(type, 32, 16, opt), lowbd_entry(type, 32, 32, opt)
|
||||
|
||||
#if HAVE_SSE2
|
||||
const IntraPredFunc<IntraPred> LowbdIntraPredTestVector[] = {
|
||||
lowbd_intrapred(dc, sse2), lowbd_intrapred(dc_top, sse2),
|
||||
lowbd_intrapred(dc_left, sse2), lowbd_intrapred(dc_128, sse2),
|
||||
lowbd_intrapred(v, sse2), lowbd_intrapred(h, sse2),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, LowbdIntraPredTest,
|
||||
::testing::ValuesIn(LowbdIntraPredTestVector));
|
||||
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_SSSE3
|
||||
const IntraPredFunc<IntraPred> LowbdIntraPredTestVectorSsse3[] = {
|
||||
lowbd_intrapred(paeth, ssse3),
|
||||
lowbd_intrapred(smooth, ssse3),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, LowbdIntraPredTest,
|
||||
::testing::ValuesIn(LowbdIntraPredTestVectorSsse3));
|
||||
|
||||
#endif // HAVE_SSSE3
|
||||
|
||||
#if HAVE_AVX2
|
||||
const IntraPredFunc<IntraPred> LowbdIntraPredTestVectorAvx2[] = {
|
||||
lowbd_entry(dc, 32, 32, avx2), lowbd_entry(dc_top, 32, 32, avx2),
|
||||
lowbd_entry(dc_left, 32, 32, avx2), lowbd_entry(dc_128, 32, 32, avx2),
|
||||
lowbd_entry(v, 32, 32, avx2), lowbd_entry(h, 32, 32, avx2),
|
||||
lowbd_entry(dc, 32, 16, avx2), lowbd_entry(dc_top, 32, 16, avx2),
|
||||
lowbd_entry(dc_left, 32, 16, avx2), lowbd_entry(dc_128, 32, 16, avx2),
|
||||
lowbd_entry(v, 32, 16, avx2), lowbd_entry(paeth, 16, 8, avx2),
|
||||
lowbd_entry(paeth, 16, 16, avx2), lowbd_entry(paeth, 16, 32, avx2),
|
||||
lowbd_entry(paeth, 32, 16, avx2), lowbd_entry(paeth, 32, 32, avx2),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, LowbdIntraPredTest,
|
||||
::testing::ValuesIn(LowbdIntraPredTestVectorAvx2));
|
||||
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
#if HAVE_NEON
|
||||
const IntraPredFunc<HighbdIntraPred> HighbdIntraPredTestVectorNeon[] = {
|
||||
highbd_entry(dc, 4, 4, neon, 8), highbd_entry(dc, 8, 8, neon, 8),
|
||||
highbd_entry(dc, 16, 16, neon, 8), highbd_entry(dc, 32, 32, neon, 8),
|
||||
highbd_entry(dc, 64, 64, neon, 8),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, HighbdIntraPredTest,
|
||||
::testing::ValuesIn(HighbdIntraPredTestVectorNeon));
|
||||
|
||||
#endif // HAVE_NEON
|
||||
} // namespace
|
||||
122
media/libaom/src/test/invalid_file_test.cc
Normal file
122
media/libaom/src/test/invalid_file_test.cc
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/ivf_video_source.h"
|
||||
#include "test/util.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct DecodeParam {
|
||||
int threads;
|
||||
const char *filename;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const DecodeParam &dp) {
|
||||
return os << "threads: " << dp.threads << " file: " << dp.filename;
|
||||
}
|
||||
|
||||
class InvalidFileTest : public ::libaom_test::DecoderTest,
|
||||
public ::libaom_test::CodecTestWithParam<DecodeParam> {
|
||||
protected:
|
||||
InvalidFileTest() : DecoderTest(GET_PARAM(0)), res_file_(NULL) {}
|
||||
|
||||
virtual ~InvalidFileTest() {
|
||||
if (res_file_ != NULL) fclose(res_file_);
|
||||
}
|
||||
|
||||
void OpenResFile(const std::string &res_file_name) {
|
||||
res_file_ = libaom_test::OpenTestDataFile(res_file_name);
|
||||
ASSERT_TRUE(res_file_ != NULL)
|
||||
<< "Result file open failed. Filename: " << res_file_name;
|
||||
}
|
||||
|
||||
virtual bool HandleDecodeResult(
|
||||
const aom_codec_err_t res_dec,
|
||||
const libaom_test::CompressedVideoSource &video,
|
||||
libaom_test::Decoder *decoder) {
|
||||
EXPECT_TRUE(res_file_ != NULL);
|
||||
int expected_res_dec = -1;
|
||||
|
||||
// Read integer result.
|
||||
const int res = fscanf(res_file_, "%d", &expected_res_dec);
|
||||
EXPECT_NE(res, EOF) << "Read result data failed";
|
||||
|
||||
if (expected_res_dec != -1) {
|
||||
// Check results match.
|
||||
const DecodeParam input = GET_PARAM(1);
|
||||
if (input.threads > 1) {
|
||||
// The serial decode check is too strict for tile-threaded decoding as
|
||||
// there is no guarantee on the decode order nor which specific error
|
||||
// will take precedence. Currently a tile-level error is not forwarded
|
||||
// so the frame will simply be marked corrupt.
|
||||
EXPECT_TRUE(res_dec == expected_res_dec ||
|
||||
res_dec == AOM_CODEC_CORRUPT_FRAME)
|
||||
<< "Results don't match: frame number = " << video.frame_number()
|
||||
<< ". (" << decoder->DecodeError()
|
||||
<< "). Expected: " << expected_res_dec << " or "
|
||||
<< AOM_CODEC_CORRUPT_FRAME;
|
||||
} else {
|
||||
EXPECT_EQ(expected_res_dec, res_dec)
|
||||
<< "Results don't match: frame number = " << video.frame_number()
|
||||
<< ". (" << decoder->DecodeError() << ")";
|
||||
}
|
||||
}
|
||||
|
||||
return !HasFailure();
|
||||
}
|
||||
|
||||
virtual void HandlePeekResult(libaom_test::Decoder *const /*decoder*/,
|
||||
libaom_test::CompressedVideoSource * /*video*/,
|
||||
const aom_codec_err_t /*res_peek*/) {}
|
||||
|
||||
void RunTest() {
|
||||
const DecodeParam input = GET_PARAM(1);
|
||||
aom_codec_dec_cfg_t cfg = { 0, 0, 0, CONFIG_LOWBITDEPTH, { 1 } };
|
||||
cfg.threads = input.threads;
|
||||
const std::string filename = input.filename;
|
||||
libaom_test::IVFVideoSource decode_video(filename);
|
||||
decode_video.Init();
|
||||
|
||||
// Construct result file name. The file holds a list of expected integer
|
||||
// results, one for each decoded frame. Any result that doesn't match
|
||||
// the files list will cause a test failure.
|
||||
const std::string res_filename = filename + ".res";
|
||||
OpenResFile(res_filename);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&decode_video, cfg));
|
||||
}
|
||||
|
||||
private:
|
||||
FILE *res_file_;
|
||||
};
|
||||
|
||||
TEST_P(InvalidFileTest, ReturnCode) { RunTest(); }
|
||||
|
||||
const DecodeParam kAV1InvalidFileTests[] = {
|
||||
{ 1, "invalid-bug-1814.ivf" },
|
||||
{ 4, "invalid-oss-fuzz-9463.ivf" },
|
||||
{ 1, "invalid-oss-fuzz-9482.ivf" },
|
||||
{ 1, "invalid-oss-fuzz-9720.ivf" },
|
||||
{ 1, "invalid-oss-fuzz-10061.ivf" },
|
||||
{ 1, "invalid-oss-fuzz-10117-mc-buf-use-highbd.ivf" },
|
||||
{ 1, "invalid-oss-fuzz-10227.ivf" },
|
||||
};
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(InvalidFileTest,
|
||||
::testing::ValuesIn(kAV1InvalidFileTests));
|
||||
|
||||
} // namespace
|
||||
114
media/libaom/src/test/ivf_video_source.h
Normal file
114
media/libaom/src/test/ivf_video_source.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#ifndef AOM_TEST_IVF_VIDEO_SOURCE_H_
|
||||
#define AOM_TEST_IVF_VIDEO_SOURCE_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
#include <string>
|
||||
|
||||
#include "aom_ports/sanitizer.h"
|
||||
#include "test/video_source.h"
|
||||
|
||||
namespace libaom_test {
|
||||
const unsigned int kCodeBufferSize = 256 * 1024 * 1024;
|
||||
const unsigned int kIvfFileHdrSize = 32;
|
||||
const unsigned int kIvfFrameHdrSize = 12;
|
||||
|
||||
static unsigned int MemGetLe32(const uint8_t *mem) {
|
||||
return (mem[3] << 24) | (mem[2] << 16) | (mem[1] << 8) | (mem[0]);
|
||||
}
|
||||
|
||||
// This class extends VideoSource to allow parsing of ivf files,
|
||||
// so that we can do actual file decodes.
|
||||
class IVFVideoSource : public CompressedVideoSource {
|
||||
public:
|
||||
explicit IVFVideoSource(const std::string &file_name)
|
||||
: file_name_(file_name), input_file_(NULL), compressed_frame_buf_(NULL),
|
||||
frame_sz_(0), frame_(0), end_of_file_(false) {}
|
||||
|
||||
virtual ~IVFVideoSource() {
|
||||
delete[] compressed_frame_buf_;
|
||||
|
||||
if (input_file_) fclose(input_file_);
|
||||
}
|
||||
|
||||
virtual void Init() {
|
||||
// Allocate a buffer for read in the compressed video frame.
|
||||
compressed_frame_buf_ = new uint8_t[kCodeBufferSize];
|
||||
ASSERT_TRUE(compressed_frame_buf_ != NULL)
|
||||
<< "Allocate frame buffer failed";
|
||||
ASAN_POISON_MEMORY_REGION(compressed_frame_buf_, kCodeBufferSize);
|
||||
}
|
||||
|
||||
virtual void Begin() {
|
||||
input_file_ = OpenTestDataFile(file_name_);
|
||||
ASSERT_TRUE(input_file_ != NULL)
|
||||
<< "Input file open failed. Filename: " << file_name_;
|
||||
|
||||
// Read file header
|
||||
uint8_t file_hdr[kIvfFileHdrSize];
|
||||
ASSERT_EQ(kIvfFileHdrSize, fread(file_hdr, 1, kIvfFileHdrSize, input_file_))
|
||||
<< "File header read failed.";
|
||||
// Check file header
|
||||
ASSERT_TRUE(file_hdr[0] == 'D' && file_hdr[1] == 'K' &&
|
||||
file_hdr[2] == 'I' && file_hdr[3] == 'F')
|
||||
<< "Input is not an IVF file.";
|
||||
|
||||
FillFrame();
|
||||
}
|
||||
|
||||
virtual void Next() {
|
||||
++frame_;
|
||||
FillFrame();
|
||||
}
|
||||
|
||||
void FillFrame() {
|
||||
ASSERT_TRUE(input_file_ != NULL);
|
||||
uint8_t frame_hdr[kIvfFrameHdrSize];
|
||||
// Check frame header and read a frame from input_file.
|
||||
if (fread(frame_hdr, 1, kIvfFrameHdrSize, input_file_) !=
|
||||
kIvfFrameHdrSize) {
|
||||
end_of_file_ = true;
|
||||
} else {
|
||||
end_of_file_ = false;
|
||||
|
||||
frame_sz_ = MemGetLe32(frame_hdr);
|
||||
ASSERT_LE(frame_sz_, kCodeBufferSize)
|
||||
<< "Frame is too big for allocated code buffer";
|
||||
ASAN_UNPOISON_MEMORY_REGION(compressed_frame_buf_, kCodeBufferSize);
|
||||
ASSERT_EQ(frame_sz_,
|
||||
fread(compressed_frame_buf_, 1, frame_sz_, input_file_))
|
||||
<< "Failed to read complete frame";
|
||||
ASAN_POISON_MEMORY_REGION(compressed_frame_buf_ + frame_sz_,
|
||||
kCodeBufferSize - frame_sz_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual const uint8_t *cxdata() const {
|
||||
return end_of_file_ ? NULL : compressed_frame_buf_;
|
||||
}
|
||||
virtual size_t frame_size() const { return frame_sz_; }
|
||||
virtual unsigned int frame_number() const { return frame_; }
|
||||
|
||||
protected:
|
||||
std::string file_name_;
|
||||
FILE *input_file_;
|
||||
uint8_t *compressed_frame_buf_;
|
||||
size_t frame_sz_;
|
||||
unsigned int frame_;
|
||||
bool end_of_file_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_IVF_VIDEO_SOURCE_H_
|
||||
98
media/libaom/src/test/lightfield_test.sh
Normal file
98
media/libaom/src/test/lightfield_test.sh
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#!/bin/sh
|
||||
## Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
##
|
||||
## This source code is subject to the terms of the BSD 2 Clause License and
|
||||
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
## was not distributed with this source code in the LICENSE file, you can
|
||||
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
## Media Patent License 1.0 was not distributed with this source code in the
|
||||
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
##
|
||||
## This file tests the lightfield example.
|
||||
##
|
||||
. $(dirname $0)/tools_common.sh
|
||||
|
||||
# Environment check: $infile is required.
|
||||
lightfield_test_verify_environment() {
|
||||
local infile="${LIBAOM_TEST_DATA_PATH}/vase10x10.yuv"
|
||||
if [ ! -e "${infile}" ]; then
|
||||
echo "Libaom test data must exist in LIBAOM_TEST_DATA_PATH."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run the lightfield example
|
||||
lightfield_test() {
|
||||
local img_width=1024
|
||||
local img_height=1024
|
||||
local lf_width=10
|
||||
local lf_height=10
|
||||
local lf_blocksize=5
|
||||
local num_references=4
|
||||
local num_tile_lists=2
|
||||
|
||||
# Encode the lightfield.
|
||||
local encoder="${LIBAOM_BIN_PATH}/lightfield_encoder${AOM_TEST_EXE_SUFFIX}"
|
||||
local yuv_file="${LIBAOM_TEST_DATA_PATH}/vase10x10.yuv"
|
||||
local lf_file="${AOM_TEST_OUTPUT_DIR}/vase10x10.ivf"
|
||||
if [ ! -x "${encoder}" ]; then
|
||||
elog "${encoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${encoder}" "${img_width}" "${img_height}" \
|
||||
"${yuv_file}" "${lf_file}" "${lf_width}" \
|
||||
"${lf_height}" "${lf_blocksize}" ${devnull}
|
||||
|
||||
[ -e "${lf_file}" ] || return 1
|
||||
|
||||
# Parse lightfield bitstream to construct and output a new bitstream that can
|
||||
# be decoded by an AV1 decoder.
|
||||
local bs_decoder="${LIBAOM_BIN_PATH}/lightfield_bitstream_parsing${AOM_TEST_EXE_SUFFIX}"
|
||||
local tl_file="${AOM_TEST_OUTPUT_DIR}/vase_tile_list.ivf"
|
||||
if [ ! -x "${bs_decoder}" ]; then
|
||||
elog "${bs_decoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${bs_decoder}" "${lf_file}" "${tl_file}" \
|
||||
"${num_references}" ${devnull}
|
||||
|
||||
[ -e "${tl_file}" ] || return 1
|
||||
|
||||
# Run lightfield tile list decoder
|
||||
local tl_decoder="${LIBAOM_BIN_PATH}/lightfield_tile_list_decoder${AOM_TEST_EXE_SUFFIX}"
|
||||
local tl_outfile="${AOM_TEST_OUTPUT_DIR}/vase_tile_list.yuv"
|
||||
if [ ! -x "${tl_decoder}" ]; then
|
||||
elog "${tl_decoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${tl_decoder}" "${tl_file}" "${tl_outfile}" \
|
||||
"${num_references}" "${num_tile_lists}" ${devnull}
|
||||
|
||||
[ -e "${tl_outfile}" ] || return 1
|
||||
|
||||
# Run reference lightfield decoder
|
||||
local ref_decoder="${LIBAOM_BIN_PATH}/lightfield_decoder${AOM_TEST_EXE_SUFFIX}"
|
||||
local tl_reffile="${AOM_TEST_OUTPUT_DIR}/vase_reference.yuv"
|
||||
if [ ! -x "${ref_decoder}" ]; then
|
||||
elog "${ref_decoder} does not exist or is not executable."
|
||||
return 1
|
||||
fi
|
||||
|
||||
eval "${AOM_TEST_PREFIX}" "${ref_decoder}" "${lf_file}" "${tl_reffile}" \
|
||||
"${num_references}" ${devnull}
|
||||
|
||||
[ -e "${tl_reffile}" ] || return 1
|
||||
|
||||
# Check if tl_outfile and tl_reffile are identical. If not identical, this test fails.
|
||||
diff ${tl_outfile} ${tl_reffile} > /dev/null
|
||||
if [ $? -eq 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
lightfield_test_tests="lightfield_test"
|
||||
|
||||
run_tests lightfield_test_verify_environment "${lightfield_test_tests}"
|
||||
50
media/libaom/src/test/log2_test.cc
Normal file
50
media/libaom/src/test/log2_test.cc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "aom_ports/bitops.h"
|
||||
#include "av1/common/entropymode.h"
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
TEST(Log2Test, GetMsb) {
|
||||
// Test small numbers exhaustively.
|
||||
for (unsigned int n = 1; n < 10000; n++) {
|
||||
EXPECT_EQ(get_msb(n), static_cast<int>(floor(log2(n))));
|
||||
}
|
||||
|
||||
// Test every power of 2 and the two adjacent numbers.
|
||||
for (int exponent = 2; exponent < 32; exponent++) {
|
||||
const unsigned int power_of_2 = 1U << exponent;
|
||||
EXPECT_EQ(get_msb(power_of_2 - 1), exponent - 1);
|
||||
EXPECT_EQ(get_msb(power_of_2), exponent);
|
||||
EXPECT_EQ(get_msb(power_of_2 + 1), exponent);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Log2Test, Av1CeilLog2) {
|
||||
// Test small numbers exhaustively.
|
||||
EXPECT_EQ(av1_ceil_log2(0), 0);
|
||||
for (int n = 1; n < 10000; n++) {
|
||||
EXPECT_EQ(av1_ceil_log2(n), static_cast<int>(ceil(log2(n))));
|
||||
}
|
||||
|
||||
// Test every power of 2 and the two adjacent numbers.
|
||||
for (int exponent = 2; exponent < 31; exponent++) {
|
||||
const int power_of_2 = 1 << exponent;
|
||||
EXPECT_EQ(av1_ceil_log2(power_of_2 - 1), exponent);
|
||||
EXPECT_EQ(av1_ceil_log2(power_of_2), exponent);
|
||||
// The current implementation of av1_ceil_log2 only works up to 2^30.
|
||||
if (exponent < 30) {
|
||||
EXPECT_EQ(av1_ceil_log2(power_of_2 + 1), exponent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
126
media/libaom/src/test/lossless_test.cc
Normal file
126
media/libaom/src/test/lossless_test.cc
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/util.h"
|
||||
#include "test/y4m_video_source.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMaxPsnr = 100;
|
||||
|
||||
class LosslessTestLarge
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
LosslessTestLarge()
|
||||
: EncoderTest(GET_PARAM(0)), psnr_(kMaxPsnr), nframes_(0),
|
||||
encoding_mode_(GET_PARAM(1)) {}
|
||||
|
||||
virtual ~LosslessTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
// Only call Control if quantizer > 0 to verify that using quantizer
|
||||
// alone will activate lossless
|
||||
if (cfg_.rc_max_quantizer > 0 || cfg_.rc_min_quantizer > 0) {
|
||||
encoder->Control(AV1E_SET_LOSSLESS, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void BeginPassHook(unsigned int /*pass*/) {
|
||||
psnr_ = kMaxPsnr;
|
||||
nframes_ = 0;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
if (pkt->data.psnr.psnr[0] < psnr_) psnr_ = pkt->data.psnr.psnr[0];
|
||||
}
|
||||
|
||||
double GetMinPsnr() const { return psnr_; }
|
||||
|
||||
private:
|
||||
double psnr_;
|
||||
unsigned int nframes_;
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
};
|
||||
|
||||
TEST_P(LosslessTestLarge, TestLossLessEncoding) {
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = 2000;
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 0;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
// intentionally changed the dimension for better testing coverage
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
timebase.den, timebase.num, 0, 5);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
const double psnr_lossless = GetMinPsnr();
|
||||
EXPECT_GE(psnr_lossless, kMaxPsnr);
|
||||
}
|
||||
|
||||
TEST_P(LosslessTestLarge, TestLossLessEncoding444) {
|
||||
libaom_test::Y4mVideoSource video("rush_hour_444.y4m", 0, 5);
|
||||
|
||||
cfg_.g_profile = 1;
|
||||
cfg_.g_timebase = video.timebase();
|
||||
cfg_.rc_target_bitrate = 2000;
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
cfg_.rc_min_quantizer = 0;
|
||||
cfg_.rc_max_quantizer = 0;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
const double psnr_lossless = GetMinPsnr();
|
||||
EXPECT_GE(psnr_lossless, kMaxPsnr);
|
||||
}
|
||||
|
||||
TEST_P(LosslessTestLarge, TestLossLessEncodingCtrl) {
|
||||
const aom_rational timebase = { 33333333, 1000000000 };
|
||||
cfg_.g_timebase = timebase;
|
||||
cfg_.rc_target_bitrate = 2000;
|
||||
cfg_.g_lag_in_frames = 25;
|
||||
// Intentionally set Q > 0, to make sure control can be used to activate
|
||||
// lossless
|
||||
cfg_.rc_min_quantizer = 10;
|
||||
cfg_.rc_max_quantizer = 20;
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
timebase.den, timebase.num, 0, 5);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
const double psnr_lossless = GetMinPsnr();
|
||||
EXPECT_GE(psnr_lossless, kMaxPsnr);
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(LosslessTestLarge,
|
||||
::testing::Values(::libaom_test::kOnePassGood,
|
||||
::libaom_test::kTwoPassGood));
|
||||
} // namespace
|
||||
627
media/libaom/src/test/lpf_test.cc
Normal file
627
media/libaom/src/test/lpf_test.cc
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
#include "av1/common/av1_loopfilter.h"
|
||||
#include "av1/common/entropy.h"
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
// Horizontally and Vertically need 32x32: 8 Coeffs preceeding filtered section
|
||||
// 16 Coefs within filtered section
|
||||
// 8 Coeffs following filtered section
|
||||
const int kNumCoeffs = 1024;
|
||||
|
||||
const int number_of_iterations = 10000;
|
||||
|
||||
const int kSpeedTestNum = 500000;
|
||||
|
||||
#define LOOP_PARAM \
|
||||
int p, const uint8_t *blimit, const uint8_t *limit, const uint8_t *thresh
|
||||
#define DUAL_LOOP_PARAM \
|
||||
int p, const uint8_t *blimit0, const uint8_t *limit0, \
|
||||
const uint8_t *thresh0, const uint8_t *blimit1, const uint8_t *limit1, \
|
||||
const uint8_t *thresh1
|
||||
|
||||
typedef void (*loop_op_t)(uint8_t *s, LOOP_PARAM);
|
||||
typedef void (*dual_loop_op_t)(uint8_t *s, DUAL_LOOP_PARAM);
|
||||
typedef void (*hbdloop_op_t)(uint16_t *s, LOOP_PARAM, int bd);
|
||||
typedef void (*hbddual_loop_op_t)(uint16_t *s, DUAL_LOOP_PARAM, int bd);
|
||||
|
||||
typedef ::testing::tuple<hbdloop_op_t, hbdloop_op_t, int> hbdloop_param_t;
|
||||
typedef ::testing::tuple<hbddual_loop_op_t, hbddual_loop_op_t, int>
|
||||
hbddual_loop_param_t;
|
||||
typedef ::testing::tuple<loop_op_t, loop_op_t, int> loop_param_t;
|
||||
typedef ::testing::tuple<dual_loop_op_t, dual_loop_op_t, int> dual_loop_param_t;
|
||||
|
||||
template <typename Pixel_t, int PIXEL_WIDTH_t>
|
||||
void InitInput(Pixel_t *s, Pixel_t *ref_s, ACMRandom *rnd, const uint8_t limit,
|
||||
const int mask, const int32_t p, const int i) {
|
||||
uint16_t tmp_s[kNumCoeffs];
|
||||
|
||||
for (int j = 0; j < kNumCoeffs;) {
|
||||
const uint8_t val = rnd->Rand8();
|
||||
if (val & 0x80) { // 50% chance to choose a new value.
|
||||
tmp_s[j] = rnd->Rand16();
|
||||
j++;
|
||||
} else { // 50% chance to repeat previous value in row X times.
|
||||
int k = 0;
|
||||
while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
|
||||
if (j < 1) {
|
||||
tmp_s[j] = rnd->Rand16();
|
||||
} else if (val & 0x20) { // Increment by a value within the limit.
|
||||
tmp_s[j] = tmp_s[j - 1] + (limit - 1);
|
||||
} else { // Decrement by a value within the limit.
|
||||
tmp_s[j] = tmp_s[j - 1] - (limit - 1);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < kNumCoeffs;) {
|
||||
const uint8_t val = rnd->Rand8();
|
||||
if (val & 0x80) {
|
||||
j++;
|
||||
} else { // 50% chance to repeat previous value in column X times.
|
||||
int k = 0;
|
||||
while (k++ < ((val & 0x1f) + 1) && j < kNumCoeffs) {
|
||||
if (j < 1) {
|
||||
tmp_s[j] = rnd->Rand16();
|
||||
} else if (val & 0x20) { // Increment by a value within the limit.
|
||||
tmp_s[(j % 32) * 32 + j / 32] =
|
||||
tmp_s[((j - 1) % 32) * 32 + (j - 1) / 32] + (limit - 1);
|
||||
} else { // Decrement by a value within the limit.
|
||||
tmp_s[(j % 32) * 32 + j / 32] =
|
||||
tmp_s[((j - 1) % 32) * 32 + (j - 1) / 32] - (limit - 1);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < kNumCoeffs; j++) {
|
||||
if (i % 2) {
|
||||
s[j] = tmp_s[j] & mask;
|
||||
} else {
|
||||
s[j] = tmp_s[p * (j % p) + j / p] & mask;
|
||||
}
|
||||
ref_s[j] = s[j];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GetOuterThresh(ACMRandom *rnd) {
|
||||
return static_cast<uint8_t>(rnd->PseudoUniform(3 * MAX_LOOP_FILTER + 5));
|
||||
}
|
||||
|
||||
uint8_t GetInnerThresh(ACMRandom *rnd) {
|
||||
return static_cast<uint8_t>(rnd->PseudoUniform(MAX_LOOP_FILTER + 1));
|
||||
}
|
||||
|
||||
uint8_t GetHevThresh(ACMRandom *rnd) {
|
||||
return static_cast<uint8_t>(rnd->PseudoUniform(MAX_LOOP_FILTER + 1) >> 4);
|
||||
}
|
||||
|
||||
template <typename func_type_t, typename params_t>
|
||||
class LoopTestParam : public ::testing::TestWithParam<params_t> {
|
||||
public:
|
||||
virtual ~LoopTestParam() {}
|
||||
virtual void SetUp() {
|
||||
loopfilter_op_ = ::testing::get<0>(this->GetParam());
|
||||
ref_loopfilter_op_ = ::testing::get<1>(this->GetParam());
|
||||
bit_depth_ = ::testing::get<2>(this->GetParam());
|
||||
mask_ = (1 << bit_depth_) - 1;
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
int bit_depth_;
|
||||
int mask_;
|
||||
func_type_t loopfilter_op_;
|
||||
func_type_t ref_loopfilter_op_;
|
||||
};
|
||||
|
||||
void call_filter(uint16_t *s, LOOP_PARAM, int bd, hbdloop_op_t op) {
|
||||
op(s, p, blimit, limit, thresh, bd);
|
||||
}
|
||||
void call_filter(uint8_t *s, LOOP_PARAM, int bd, loop_op_t op) {
|
||||
(void)bd;
|
||||
op(s, p, blimit, limit, thresh);
|
||||
}
|
||||
void call_dualfilter(uint16_t *s, DUAL_LOOP_PARAM, int bd,
|
||||
hbddual_loop_op_t op) {
|
||||
op(s, p, blimit0, limit0, thresh0, blimit1, limit1, thresh1, bd);
|
||||
}
|
||||
void call_dualfilter(uint8_t *s, DUAL_LOOP_PARAM, int bd, dual_loop_op_t op) {
|
||||
(void)bd;
|
||||
op(s, p, blimit0, limit0, thresh0, blimit1, limit1, thresh1);
|
||||
};
|
||||
|
||||
typedef LoopTestParam<hbdloop_op_t, hbdloop_param_t> Loop8Test6Param_hbd;
|
||||
typedef LoopTestParam<loop_op_t, loop_param_t> Loop8Test6Param_lbd;
|
||||
typedef LoopTestParam<hbddual_loop_op_t, hbddual_loop_param_t>
|
||||
Loop8Test9Param_hbd;
|
||||
typedef LoopTestParam<dual_loop_op_t, dual_loop_param_t> Loop8Test9Param_lbd;
|
||||
|
||||
#define OPCHECK(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = number_of_iterations; \
|
||||
const int32_t p = kNumCoeffs / 32; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
DECLARE_ALIGNED(b, a, ref_s[kNumCoeffs]); \
|
||||
int err_count_total = 0; \
|
||||
int first_failure = -1; \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
int err_count = 0; \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
InitInput<a, b>(s, ref_s, &rnd, *limit, mask_, p, i); \
|
||||
call_filter(ref_s + 8 + p * 8, p, blimit, limit, thresh, bit_depth_, \
|
||||
ref_loopfilter_op_); \
|
||||
ASM_REGISTER_STATE_CHECK(call_filter(s + 8 + p * 8, p, blimit, limit, \
|
||||
thresh, bit_depth_, loopfilter_op_)); \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
err_count += ref_s[j] != s[j]; \
|
||||
} \
|
||||
if (err_count && !err_count_total) { \
|
||||
first_failure = i; \
|
||||
} \
|
||||
err_count_total += err_count; \
|
||||
} \
|
||||
EXPECT_EQ(0, err_count_total) \
|
||||
<< "Error: Loop8Test6Param, C output doesn't match SIMD " \
|
||||
"loopfilter output. " \
|
||||
<< "First failed at test case " << first_failure;
|
||||
|
||||
TEST_P(Loop8Test6Param_hbd, OperationCheck) { OPCHECK(uint16_t, 16); }
|
||||
TEST_P(Loop8Test6Param_lbd, OperationCheck) { OPCHECK(uint8_t, 8); }
|
||||
|
||||
#define VALCHECK(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = number_of_iterations; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
DECLARE_ALIGNED(b, a, ref_s[kNumCoeffs]); \
|
||||
int err_count_total = 0; \
|
||||
int first_failure = -1; \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
int err_count = 0; \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
int32_t p = kNumCoeffs / 32; \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
s[j] = rnd.Rand16() & mask_; \
|
||||
ref_s[j] = s[j]; \
|
||||
} \
|
||||
call_filter(ref_s + 8 + p * 8, p, blimit, limit, thresh, bit_depth_, \
|
||||
ref_loopfilter_op_); \
|
||||
ASM_REGISTER_STATE_CHECK(call_filter(s + 8 + p * 8, p, blimit, limit, \
|
||||
thresh, bit_depth_, loopfilter_op_)); \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
err_count += ref_s[j] != s[j]; \
|
||||
} \
|
||||
if (err_count && !err_count_total) { \
|
||||
first_failure = i; \
|
||||
} \
|
||||
err_count_total += err_count; \
|
||||
} \
|
||||
EXPECT_EQ(0, err_count_total) \
|
||||
<< "Error: Loop8Test6Param, C output doesn't match SIMD " \
|
||||
"loopfilter output. " \
|
||||
<< "First failed at test case " << first_failure;
|
||||
|
||||
TEST_P(Loop8Test6Param_hbd, ValueCheck) { VALCHECK(uint16_t, 16); }
|
||||
TEST_P(Loop8Test6Param_lbd, ValueCheck) { VALCHECK(uint8_t, 8); }
|
||||
|
||||
#define SPEEDCHECK(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = kSpeedTestNum; \
|
||||
const int32_t bd = bit_depth_; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
int32_t p = kNumCoeffs / 32; \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
s[j] = rnd.Rand16() & mask_; \
|
||||
} \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
call_filter(s + 8 + p * 8, p, blimit, limit, thresh, bd, loopfilter_op_); \
|
||||
}
|
||||
|
||||
TEST_P(Loop8Test6Param_hbd, DISABLED_Speed) { SPEEDCHECK(uint16_t, 16); }
|
||||
TEST_P(Loop8Test6Param_lbd, DISABLED_Speed) { SPEEDCHECK(uint8_t, 8); }
|
||||
|
||||
#define OPCHECKd(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = number_of_iterations; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
DECLARE_ALIGNED(b, a, ref_s[kNumCoeffs]); \
|
||||
int err_count_total = 0; \
|
||||
int first_failure = -1; \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
int err_count = 0; \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
int32_t p = kNumCoeffs / 32; \
|
||||
const uint8_t limit = *limit0 < *limit1 ? *limit0 : *limit1; \
|
||||
InitInput<a, b>(s, ref_s, &rnd, limit, mask_, p, i); \
|
||||
call_dualfilter(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1, \
|
||||
limit1, thresh1, bit_depth_, ref_loopfilter_op_); \
|
||||
ASM_REGISTER_STATE_CHECK( \
|
||||
call_dualfilter(s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1, \
|
||||
limit1, thresh1, bit_depth_, loopfilter_op_)); \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
err_count += ref_s[j] != s[j]; \
|
||||
} \
|
||||
if (err_count && !err_count_total) { \
|
||||
first_failure = i; \
|
||||
} \
|
||||
err_count_total += err_count; \
|
||||
} \
|
||||
EXPECT_EQ(0, err_count_total) \
|
||||
<< "Error: Loop8Test9Param, C output doesn't match SIMD " \
|
||||
"loopfilter output. " \
|
||||
<< "First failed at test case " << first_failure;
|
||||
|
||||
TEST_P(Loop8Test9Param_hbd, OperationCheck) { OPCHECKd(uint16_t, 16); }
|
||||
TEST_P(Loop8Test9Param_lbd, OperationCheck) { OPCHECKd(uint8_t, 8); }
|
||||
|
||||
#define VALCHECKd(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = number_of_iterations; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
DECLARE_ALIGNED(b, a, ref_s[kNumCoeffs]); \
|
||||
int err_count_total = 0; \
|
||||
int first_failure = -1; \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
int err_count = 0; \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
int32_t p = kNumCoeffs / 32; \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
s[j] = rnd.Rand16() & mask_; \
|
||||
ref_s[j] = s[j]; \
|
||||
} \
|
||||
call_dualfilter(ref_s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1, \
|
||||
limit1, thresh1, bit_depth_, ref_loopfilter_op_); \
|
||||
ASM_REGISTER_STATE_CHECK( \
|
||||
call_dualfilter(s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1, \
|
||||
limit1, thresh1, bit_depth_, loopfilter_op_)); \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
err_count += ref_s[j] != s[j]; \
|
||||
} \
|
||||
if (err_count && !err_count_total) { \
|
||||
first_failure = i; \
|
||||
} \
|
||||
err_count_total += err_count; \
|
||||
} \
|
||||
EXPECT_EQ(0, err_count_total) \
|
||||
<< "Error: Loop8Test9Param, C output doesn't match SIMD " \
|
||||
"loopfilter output. " \
|
||||
<< "First failed at test case " << first_failure;
|
||||
|
||||
TEST_P(Loop8Test9Param_hbd, ValueCheck) { VALCHECKd(uint16_t, 16); }
|
||||
TEST_P(Loop8Test9Param_lbd, ValueCheck) { VALCHECKd(uint8_t, 8); }
|
||||
|
||||
#define SPEEDCHECKd(a, b) \
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed()); \
|
||||
const int count_test_block = kSpeedTestNum; \
|
||||
DECLARE_ALIGNED(b, a, s[kNumCoeffs]); \
|
||||
uint8_t tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh0[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetOuterThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
blimit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetInnerThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
limit1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
tmp = GetHevThresh(&rnd); \
|
||||
DECLARE_ALIGNED(16, const uint8_t, \
|
||||
thresh1[16]) = { tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp, \
|
||||
tmp, tmp, tmp, tmp, tmp, tmp, tmp, tmp }; \
|
||||
int32_t p = kNumCoeffs / 32; \
|
||||
for (int j = 0; j < kNumCoeffs; ++j) { \
|
||||
s[j] = rnd.Rand16() & mask_; \
|
||||
} \
|
||||
for (int i = 0; i < count_test_block; ++i) { \
|
||||
call_dualfilter(s + 8 + p * 8, p, blimit0, limit0, thresh0, blimit1, \
|
||||
limit1, thresh1, bit_depth_, loopfilter_op_); \
|
||||
}
|
||||
|
||||
TEST_P(Loop8Test9Param_hbd, DISABLED_Speed) { SPEEDCHECKd(uint16_t, 16); }
|
||||
TEST_P(Loop8Test9Param_lbd, DISABLED_Speed) { SPEEDCHECKd(uint8_t, 8); }
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
#if HAVE_SSE2
|
||||
|
||||
const hbdloop_param_t kHbdLoop8Test6[] = {
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
|
||||
8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_sse2, &aom_highbd_lpf_horizontal_6_c,
|
||||
8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
|
||||
8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_sse2, &aom_highbd_lpf_vertical_6_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 8),
|
||||
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_sse2, &aom_highbd_lpf_vertical_14_c,
|
||||
8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
|
||||
10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_sse2, &aom_highbd_lpf_horizontal_6_c,
|
||||
10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
|
||||
10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_sse2, &aom_highbd_lpf_vertical_6_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_sse2, &aom_highbd_lpf_vertical_14_c,
|
||||
10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_sse2, &aom_highbd_lpf_horizontal_4_c,
|
||||
12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_sse2, &aom_highbd_lpf_vertical_4_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_sse2, &aom_highbd_lpf_horizontal_6_c,
|
||||
12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_sse2, &aom_highbd_lpf_horizontal_8_c,
|
||||
12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_sse2, &aom_highbd_lpf_vertical_14_c,
|
||||
12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_sse2, &aom_highbd_lpf_vertical_6_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_sse2, &aom_highbd_lpf_vertical_8_c, 12)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param_hbd,
|
||||
::testing::ValuesIn(kHbdLoop8Test6));
|
||||
|
||||
const loop_param_t kLoop8Test6[] = {
|
||||
make_tuple(&aom_lpf_horizontal_4_sse2, &aom_lpf_horizontal_4_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_8_sse2, &aom_lpf_horizontal_8_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_6_sse2, &aom_lpf_horizontal_6_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_6_sse2, &aom_lpf_vertical_6_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_14_sse2, &aom_lpf_horizontal_14_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_4_sse2, &aom_lpf_vertical_4_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_8_sse2, &aom_lpf_vertical_8_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_14_sse2, &aom_lpf_vertical_14_c, 8),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test6Param_lbd,
|
||||
::testing::ValuesIn(kLoop8Test6));
|
||||
|
||||
const dual_loop_param_t kLoop8Test9[] = {
|
||||
make_tuple(&aom_lpf_horizontal_4_dual_sse2, &aom_lpf_horizontal_4_dual_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_4_dual_sse2, &aom_lpf_vertical_4_dual_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_6_dual_sse2, &aom_lpf_horizontal_6_dual_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_6_dual_sse2, &aom_lpf_vertical_6_dual_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_8_dual_sse2, &aom_lpf_horizontal_8_dual_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_8_dual_sse2, &aom_lpf_vertical_8_dual_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_14_dual_sse2, &aom_lpf_horizontal_14_dual_c,
|
||||
8),
|
||||
make_tuple(&aom_lpf_vertical_14_dual_sse2, &aom_lpf_vertical_14_dual_c, 8)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param_lbd,
|
||||
::testing::ValuesIn(kLoop8Test9));
|
||||
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_SSE2
|
||||
const hbddual_loop_param_t kHbdLoop8Test9[] = {
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_6_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_6_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_14_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_6_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_6_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_14_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_6_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_6_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_14_dual_sse2,
|
||||
&aom_highbd_lpf_horizontal_14_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_6_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_6_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_14_dual_sse2,
|
||||
&aom_highbd_lpf_vertical_14_dual_c, 12),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSE2, Loop8Test9Param_hbd,
|
||||
::testing::ValuesIn(kHbdLoop8Test9));
|
||||
|
||||
#endif // HAVE_SSE2
|
||||
|
||||
#if HAVE_NEON
|
||||
const loop_param_t kLoop8Test6[] = {
|
||||
make_tuple(&aom_lpf_vertical_14_neon, &aom_lpf_vertical_14_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_8_neon, &aom_lpf_vertical_8_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_6_neon, &aom_lpf_vertical_6_c, 8),
|
||||
make_tuple(&aom_lpf_vertical_4_neon, &aom_lpf_vertical_4_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_14_neon, &aom_lpf_horizontal_14_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_8_neon, &aom_lpf_horizontal_8_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_6_neon, &aom_lpf_horizontal_6_c, 8),
|
||||
make_tuple(&aom_lpf_horizontal_4_neon, &aom_lpf_horizontal_4_c, 8)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NEON, Loop8Test6Param_lbd,
|
||||
::testing::ValuesIn(kLoop8Test6));
|
||||
#endif // HAVE_NEON
|
||||
|
||||
#if HAVE_AVX2
|
||||
const hbddual_loop_param_t kHbdLoop8Test9Avx2[] = {
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_4_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_4_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_horizontal_8_dual_avx2,
|
||||
&aom_highbd_lpf_horizontal_8_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_4_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_4_dual_c, 12),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 8),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 10),
|
||||
make_tuple(&aom_highbd_lpf_vertical_8_dual_avx2,
|
||||
&aom_highbd_lpf_vertical_8_dual_c, 12),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, Loop8Test9Param_hbd,
|
||||
::testing::ValuesIn(kHbdLoop8Test9Avx2));
|
||||
#endif
|
||||
} // namespace
|
||||
342
media/libaom/src/test/masked_sad_test.cc
Normal file
342
media/libaom/src/test/masked_sad_test.cc
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom/aom_integer.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
const int number_of_iterations = 200;
|
||||
|
||||
typedef unsigned int (*MaskedSADFunc)(const uint8_t *src, int src_stride,
|
||||
const uint8_t *ref, int ref_stride,
|
||||
const uint8_t *second_pred,
|
||||
const uint8_t *msk, int msk_stride,
|
||||
int invert_mask);
|
||||
typedef ::testing::tuple<MaskedSADFunc, MaskedSADFunc> MaskedSADParam;
|
||||
|
||||
class MaskedSADTest : public ::testing::TestWithParam<MaskedSADParam> {
|
||||
public:
|
||||
virtual ~MaskedSADTest() {}
|
||||
virtual void SetUp() {
|
||||
maskedSAD_op_ = GET_PARAM(0);
|
||||
ref_maskedSAD_op_ = GET_PARAM(1);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
void runMaskedSADTest(int run_times);
|
||||
|
||||
protected:
|
||||
MaskedSADFunc maskedSAD_op_;
|
||||
MaskedSADFunc ref_maskedSAD_op_;
|
||||
};
|
||||
void MaskedSADTest::runMaskedSADTest(int run_times) {
|
||||
unsigned int ref_ret = 0, ret = 1;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint8_t, src_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, ref_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, second_pred_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int src_stride = MAX_SB_SIZE;
|
||||
int ref_stride = MAX_SB_SIZE;
|
||||
int msk_stride = MAX_SB_SIZE;
|
||||
const int iters = run_times == 1 ? number_of_iterations : 1;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE * MAX_SB_SIZE; j++) {
|
||||
src_ptr[j] = rnd.Rand8();
|
||||
ref_ptr[j] = rnd.Rand8();
|
||||
second_pred_ptr[j] = rnd.Rand8();
|
||||
msk_ptr[j] = ((rnd.Rand8() & 0x7f) > 64) ? rnd.Rand8() & 0x3f : 64;
|
||||
assert(msk_ptr[j] <= 64);
|
||||
}
|
||||
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int repeat = 0; repeat < run_times; ++repeat) {
|
||||
ref_ret = ref_maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride,
|
||||
second_pred_ptr, msk_ptr, msk_stride,
|
||||
invert_mask);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
if (run_times == 1) {
|
||||
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src_ptr, src_stride,
|
||||
ref_ptr, ref_stride,
|
||||
second_pred_ptr, msk_ptr,
|
||||
msk_stride, invert_mask));
|
||||
} else {
|
||||
for (int repeat = 0; repeat < run_times; ++repeat) {
|
||||
ret =
|
||||
maskedSAD_op_(src_ptr, src_stride, ref_ptr, ref_stride,
|
||||
second_pred_ptr, msk_ptr, msk_stride, invert_mask);
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 10) {
|
||||
printf("%7.2f/%7.2fns", time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
if (ret != ref_ret) {
|
||||
err_count++;
|
||||
if (first_failure == -1) first_failure = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, err_count) << "Error: Masked SAD Test, output doesn't match. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
TEST_P(MaskedSADTest, OperationCheck) { runMaskedSADTest(1); }
|
||||
|
||||
TEST_P(MaskedSADTest, DISABLED_Speed) { runMaskedSADTest(2000000); }
|
||||
|
||||
typedef unsigned int (*HighbdMaskedSADFunc)(const uint8_t *src, int src_stride,
|
||||
const uint8_t *ref, int ref_stride,
|
||||
const uint8_t *second_pred,
|
||||
const uint8_t *msk, int msk_stride,
|
||||
int invert_mask);
|
||||
typedef ::testing::tuple<HighbdMaskedSADFunc, HighbdMaskedSADFunc>
|
||||
HighbdMaskedSADParam;
|
||||
|
||||
class HighbdMaskedSADTest
|
||||
: public ::testing::TestWithParam<HighbdMaskedSADParam> {
|
||||
public:
|
||||
virtual ~HighbdMaskedSADTest() {}
|
||||
virtual void SetUp() {
|
||||
maskedSAD_op_ = GET_PARAM(0);
|
||||
ref_maskedSAD_op_ = GET_PARAM(1);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
void runHighbdMaskedSADTest(int run_times);
|
||||
|
||||
protected:
|
||||
HighbdMaskedSADFunc maskedSAD_op_;
|
||||
HighbdMaskedSADFunc ref_maskedSAD_op_;
|
||||
};
|
||||
void HighbdMaskedSADTest::runHighbdMaskedSADTest(int run_times) {
|
||||
unsigned int ref_ret = 0, ret = 1;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint16_t, src_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint16_t, ref_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint16_t, second_pred_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[MAX_SB_SIZE * MAX_SB_SIZE]);
|
||||
uint8_t *src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
|
||||
uint8_t *ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
|
||||
uint8_t *second_pred8_ptr = CONVERT_TO_BYTEPTR(second_pred_ptr);
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int src_stride = MAX_SB_SIZE;
|
||||
int ref_stride = MAX_SB_SIZE;
|
||||
int msk_stride = MAX_SB_SIZE;
|
||||
const int iters = run_times == 1 ? number_of_iterations : 1;
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
for (int j = 0; j < MAX_SB_SIZE * MAX_SB_SIZE; j++) {
|
||||
src_ptr[j] = rnd.Rand16() & 0xfff;
|
||||
ref_ptr[j] = rnd.Rand16() & 0xfff;
|
||||
second_pred_ptr[j] = rnd.Rand16() & 0xfff;
|
||||
msk_ptr[j] = ((rnd.Rand8() & 0x7f) > 64) ? rnd.Rand8() & 0x3f : 64;
|
||||
}
|
||||
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
aom_usec_timer timer;
|
||||
aom_usec_timer_start(&timer);
|
||||
for (int repeat = 0; repeat < run_times; ++repeat) {
|
||||
ref_ret = ref_maskedSAD_op_(src8_ptr, src_stride, ref8_ptr, ref_stride,
|
||||
second_pred8_ptr, msk_ptr, msk_stride,
|
||||
invert_mask);
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time1 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
aom_usec_timer_start(&timer);
|
||||
if (run_times == 1) {
|
||||
ASM_REGISTER_STATE_CHECK(ret = maskedSAD_op_(src8_ptr, src_stride,
|
||||
ref8_ptr, ref_stride,
|
||||
second_pred8_ptr, msk_ptr,
|
||||
msk_stride, invert_mask));
|
||||
} else {
|
||||
for (int repeat = 0; repeat < run_times; ++repeat) {
|
||||
ret =
|
||||
maskedSAD_op_(src8_ptr, src_stride, ref8_ptr, ref_stride,
|
||||
second_pred8_ptr, msk_ptr, msk_stride, invert_mask);
|
||||
}
|
||||
}
|
||||
aom_usec_timer_mark(&timer);
|
||||
const double time2 = static_cast<double>(aom_usec_timer_elapsed(&timer));
|
||||
if (run_times > 10) {
|
||||
printf("%7.2f/%7.2fns", time1, time2);
|
||||
printf("(%3.2f)\n", time1 / time2);
|
||||
}
|
||||
if (ret != ref_ret) {
|
||||
err_count++;
|
||||
if (first_failure == -1) first_failure = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(0, err_count)
|
||||
<< "Error: High BD Masked SAD Test, output doesn't match. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
TEST_P(HighbdMaskedSADTest, OperationCheck) { runHighbdMaskedSADTest(1); }
|
||||
|
||||
TEST_P(HighbdMaskedSADTest, DISABLED_Speed) { runHighbdMaskedSADTest(1000000); }
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
#if HAVE_SSSE3
|
||||
const MaskedSADParam msad_test[] = {
|
||||
make_tuple(&aom_masked_sad4x4_ssse3, &aom_masked_sad4x4_c),
|
||||
make_tuple(&aom_masked_sad4x8_ssse3, &aom_masked_sad4x8_c),
|
||||
make_tuple(&aom_masked_sad8x4_ssse3, &aom_masked_sad8x4_c),
|
||||
make_tuple(&aom_masked_sad8x8_ssse3, &aom_masked_sad8x8_c),
|
||||
make_tuple(&aom_masked_sad8x16_ssse3, &aom_masked_sad8x16_c),
|
||||
make_tuple(&aom_masked_sad16x8_ssse3, &aom_masked_sad16x8_c),
|
||||
make_tuple(&aom_masked_sad16x16_ssse3, &aom_masked_sad16x16_c),
|
||||
make_tuple(&aom_masked_sad16x32_ssse3, &aom_masked_sad16x32_c),
|
||||
make_tuple(&aom_masked_sad32x16_ssse3, &aom_masked_sad32x16_c),
|
||||
make_tuple(&aom_masked_sad32x32_ssse3, &aom_masked_sad32x32_c),
|
||||
make_tuple(&aom_masked_sad32x64_ssse3, &aom_masked_sad32x64_c),
|
||||
make_tuple(&aom_masked_sad64x32_ssse3, &aom_masked_sad64x32_c),
|
||||
make_tuple(&aom_masked_sad64x64_ssse3, &aom_masked_sad64x64_c),
|
||||
make_tuple(&aom_masked_sad64x128_ssse3, &aom_masked_sad64x128_c),
|
||||
make_tuple(&aom_masked_sad128x64_ssse3, &aom_masked_sad128x64_c),
|
||||
make_tuple(&aom_masked_sad128x128_ssse3, &aom_masked_sad128x128_c),
|
||||
make_tuple(&aom_masked_sad4x16_ssse3, &aom_masked_sad4x16_c),
|
||||
make_tuple(&aom_masked_sad16x4_ssse3, &aom_masked_sad16x4_c),
|
||||
make_tuple(&aom_masked_sad8x32_ssse3, &aom_masked_sad8x32_c),
|
||||
make_tuple(&aom_masked_sad32x8_ssse3, &aom_masked_sad32x8_c),
|
||||
make_tuple(&aom_masked_sad16x64_ssse3, &aom_masked_sad16x64_c),
|
||||
make_tuple(&aom_masked_sad64x16_ssse3, &aom_masked_sad64x16_c),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, MaskedSADTest, ::testing::ValuesIn(msad_test));
|
||||
|
||||
const HighbdMaskedSADParam hbd_msad_test[] = {
|
||||
make_tuple(&aom_highbd_masked_sad4x4_ssse3, &aom_highbd_masked_sad4x4_c),
|
||||
make_tuple(&aom_highbd_masked_sad4x8_ssse3, &aom_highbd_masked_sad4x8_c),
|
||||
make_tuple(&aom_highbd_masked_sad8x4_ssse3, &aom_highbd_masked_sad8x4_c),
|
||||
make_tuple(&aom_highbd_masked_sad8x8_ssse3, &aom_highbd_masked_sad8x8_c),
|
||||
make_tuple(&aom_highbd_masked_sad8x16_ssse3, &aom_highbd_masked_sad8x16_c),
|
||||
make_tuple(&aom_highbd_masked_sad16x8_ssse3, &aom_highbd_masked_sad16x8_c),
|
||||
make_tuple(&aom_highbd_masked_sad16x16_ssse3, &aom_highbd_masked_sad16x16_c),
|
||||
make_tuple(&aom_highbd_masked_sad16x32_ssse3, &aom_highbd_masked_sad16x32_c),
|
||||
make_tuple(&aom_highbd_masked_sad32x16_ssse3, &aom_highbd_masked_sad32x16_c),
|
||||
make_tuple(&aom_highbd_masked_sad32x32_ssse3, &aom_highbd_masked_sad32x32_c),
|
||||
make_tuple(&aom_highbd_masked_sad32x64_ssse3, &aom_highbd_masked_sad32x64_c),
|
||||
make_tuple(&aom_highbd_masked_sad64x32_ssse3, &aom_highbd_masked_sad64x32_c),
|
||||
make_tuple(&aom_highbd_masked_sad64x64_ssse3, &aom_highbd_masked_sad64x64_c),
|
||||
make_tuple(&aom_highbd_masked_sad64x128_ssse3,
|
||||
&aom_highbd_masked_sad64x128_c),
|
||||
make_tuple(&aom_highbd_masked_sad128x64_ssse3,
|
||||
&aom_highbd_masked_sad128x64_c),
|
||||
make_tuple(&aom_highbd_masked_sad128x128_ssse3,
|
||||
&aom_highbd_masked_sad128x128_c),
|
||||
make_tuple(&aom_highbd_masked_sad4x16_ssse3, &aom_highbd_masked_sad4x16_c),
|
||||
make_tuple(&aom_highbd_masked_sad16x4_ssse3, &aom_highbd_masked_sad16x4_c),
|
||||
make_tuple(&aom_highbd_masked_sad8x32_ssse3, &aom_highbd_masked_sad8x32_c),
|
||||
make_tuple(&aom_highbd_masked_sad32x8_ssse3, &aom_highbd_masked_sad32x8_c),
|
||||
make_tuple(&aom_highbd_masked_sad16x64_ssse3, &aom_highbd_masked_sad16x64_c),
|
||||
make_tuple(&aom_highbd_masked_sad64x16_ssse3, &aom_highbd_masked_sad64x16_c),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3, HighbdMaskedSADTest,
|
||||
::testing::ValuesIn(hbd_msad_test));
|
||||
#endif // HAVE_SSSE3
|
||||
|
||||
#if HAVE_AVX2
|
||||
const MaskedSADParam msad_avx2_test[] = {
|
||||
make_tuple(&aom_masked_sad4x4_avx2, &aom_masked_sad4x4_ssse3),
|
||||
make_tuple(&aom_masked_sad4x8_avx2, &aom_masked_sad4x8_ssse3),
|
||||
make_tuple(&aom_masked_sad8x4_avx2, &aom_masked_sad8x4_ssse3),
|
||||
make_tuple(&aom_masked_sad8x8_avx2, &aom_masked_sad8x8_ssse3),
|
||||
make_tuple(&aom_masked_sad8x16_avx2, &aom_masked_sad8x16_ssse3),
|
||||
make_tuple(&aom_masked_sad16x8_avx2, &aom_masked_sad16x8_ssse3),
|
||||
make_tuple(&aom_masked_sad16x16_avx2, &aom_masked_sad16x16_ssse3),
|
||||
make_tuple(&aom_masked_sad16x32_avx2, &aom_masked_sad16x32_ssse3),
|
||||
make_tuple(&aom_masked_sad32x16_avx2, &aom_masked_sad32x16_ssse3),
|
||||
make_tuple(&aom_masked_sad32x32_avx2, &aom_masked_sad32x32_ssse3),
|
||||
make_tuple(&aom_masked_sad32x64_avx2, &aom_masked_sad32x64_ssse3),
|
||||
make_tuple(&aom_masked_sad64x32_avx2, &aom_masked_sad64x32_ssse3),
|
||||
make_tuple(&aom_masked_sad64x64_avx2, &aom_masked_sad64x64_ssse3),
|
||||
make_tuple(&aom_masked_sad64x128_avx2, &aom_masked_sad64x128_ssse3),
|
||||
make_tuple(&aom_masked_sad128x64_avx2, &aom_masked_sad128x64_ssse3),
|
||||
make_tuple(&aom_masked_sad128x128_avx2, &aom_masked_sad128x128_ssse3),
|
||||
make_tuple(&aom_masked_sad4x16_avx2, &aom_masked_sad4x16_ssse3),
|
||||
make_tuple(&aom_masked_sad16x4_avx2, &aom_masked_sad16x4_ssse3),
|
||||
make_tuple(&aom_masked_sad8x32_avx2, &aom_masked_sad8x32_ssse3),
|
||||
make_tuple(&aom_masked_sad32x8_avx2, &aom_masked_sad32x8_ssse3),
|
||||
make_tuple(&aom_masked_sad16x64_avx2, &aom_masked_sad16x64_ssse3),
|
||||
make_tuple(&aom_masked_sad64x16_avx2, &aom_masked_sad64x16_ssse3)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, MaskedSADTest,
|
||||
::testing::ValuesIn(msad_avx2_test));
|
||||
|
||||
const HighbdMaskedSADParam hbd_msad_avx2_test[] = {
|
||||
make_tuple(&aom_highbd_masked_sad4x4_avx2, &aom_highbd_masked_sad4x4_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad4x8_avx2, &aom_highbd_masked_sad4x8_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad8x4_avx2, &aom_highbd_masked_sad8x4_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad8x8_avx2, &aom_highbd_masked_sad8x8_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad8x16_avx2, &aom_highbd_masked_sad8x16_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad16x8_avx2, &aom_highbd_masked_sad16x8_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad16x16_avx2,
|
||||
&aom_highbd_masked_sad16x16_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad16x32_avx2,
|
||||
&aom_highbd_masked_sad16x32_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad32x16_avx2,
|
||||
&aom_highbd_masked_sad32x16_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad32x32_avx2,
|
||||
&aom_highbd_masked_sad32x32_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad32x64_avx2,
|
||||
&aom_highbd_masked_sad32x64_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad64x32_avx2,
|
||||
&aom_highbd_masked_sad64x32_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad64x64_avx2,
|
||||
&aom_highbd_masked_sad64x64_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad64x128_avx2,
|
||||
&aom_highbd_masked_sad64x128_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad128x64_avx2,
|
||||
&aom_highbd_masked_sad128x64_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad128x128_avx2,
|
||||
&aom_highbd_masked_sad128x128_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad4x16_avx2, &aom_highbd_masked_sad4x16_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad16x4_avx2, &aom_highbd_masked_sad16x4_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad8x32_avx2, &aom_highbd_masked_sad8x32_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad32x8_avx2, &aom_highbd_masked_sad32x8_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad16x64_avx2,
|
||||
&aom_highbd_masked_sad16x64_ssse3),
|
||||
make_tuple(&aom_highbd_masked_sad64x16_avx2,
|
||||
&aom_highbd_masked_sad64x16_ssse3)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AVX2, HighbdMaskedSADTest,
|
||||
::testing::ValuesIn(hbd_msad_avx2_test));
|
||||
#endif // HAVE_AVX2
|
||||
|
||||
} // namespace
|
||||
459
media/libaom/src/test/masked_variance_test.cc
Normal file
459
media/libaom/src/test/masked_variance_test.cc
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/acm_random.h"
|
||||
#include "test/clear_system_state.h"
|
||||
#include "test/register_state_check.h"
|
||||
#include "test/util.h"
|
||||
|
||||
#include "config/aom_config.h"
|
||||
#include "config/aom_dsp_rtcd.h"
|
||||
|
||||
#include "aom/aom_codec.h"
|
||||
#include "aom/aom_integer.h"
|
||||
#include "aom_dsp/aom_filter.h"
|
||||
#include "aom_mem/aom_mem.h"
|
||||
|
||||
using libaom_test::ACMRandom;
|
||||
|
||||
namespace {
|
||||
const int number_of_iterations = 200;
|
||||
|
||||
typedef unsigned int (*MaskedSubPixelVarianceFunc)(
|
||||
const uint8_t *src, int src_stride, int xoffset, int yoffset,
|
||||
const uint8_t *ref, int ref_stride, const uint8_t *second_pred,
|
||||
const uint8_t *msk, int msk_stride, int invert_mask, unsigned int *sse);
|
||||
|
||||
typedef ::testing::tuple<MaskedSubPixelVarianceFunc, MaskedSubPixelVarianceFunc>
|
||||
MaskedSubPixelVarianceParam;
|
||||
|
||||
class MaskedSubPixelVarianceTest
|
||||
: public ::testing::TestWithParam<MaskedSubPixelVarianceParam> {
|
||||
public:
|
||||
virtual ~MaskedSubPixelVarianceTest() {}
|
||||
virtual void SetUp() {
|
||||
opt_func_ = GET_PARAM(0);
|
||||
ref_func_ = GET_PARAM(1);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
MaskedSubPixelVarianceFunc opt_func_;
|
||||
MaskedSubPixelVarianceFunc ref_func_;
|
||||
};
|
||||
|
||||
TEST_P(MaskedSubPixelVarianceTest, OperationCheck) {
|
||||
unsigned int ref_ret, opt_ret;
|
||||
unsigned int ref_sse, opt_sse;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
// Note: We pad out the input array to a multiple of 16 bytes wide, so that
|
||||
// consecutive rows keep the 16-byte alignment.
|
||||
DECLARE_ALIGNED(16, uint8_t, src_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, ref_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t,
|
||||
second_pred_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int src_stride = (MAX_SB_SIZE + 16);
|
||||
int ref_stride = (MAX_SB_SIZE + 16);
|
||||
int msk_stride = (MAX_SB_SIZE + 16);
|
||||
int xoffset;
|
||||
int yoffset;
|
||||
|
||||
for (int i = 0; i < number_of_iterations; ++i) {
|
||||
int xoffsets[] = { 0, 4, rnd(BIL_SUBPEL_SHIFTS) };
|
||||
int yoffsets[] = { 0, 4, rnd(BIL_SUBPEL_SHIFTS) };
|
||||
for (int j = 0; j < (MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16); j++) {
|
||||
src_ptr[j] = rnd.Rand8();
|
||||
ref_ptr[j] = rnd.Rand8();
|
||||
second_pred_ptr[j] = rnd.Rand8();
|
||||
msk_ptr[j] = rnd(65);
|
||||
}
|
||||
for (int k = 0; k < 3; k++) {
|
||||
for (int l = 0; l < 3; l++) {
|
||||
xoffset = xoffsets[k];
|
||||
yoffset = yoffsets[l];
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
ref_ret = ref_func_(src_ptr, src_stride, xoffset, yoffset, ref_ptr,
|
||||
ref_stride, second_pred_ptr, msk_ptr, msk_stride,
|
||||
invert_mask, &ref_sse);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
opt_ret = opt_func_(src_ptr, src_stride, xoffset, yoffset,
|
||||
ref_ptr, ref_stride, second_pred_ptr, msk_ptr,
|
||||
msk_stride, invert_mask, &opt_sse));
|
||||
|
||||
if (opt_ret != ref_ret || opt_sse != ref_sse) {
|
||||
err_count++;
|
||||
if (first_failure == -1) first_failure = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, err_count)
|
||||
<< "Error: Masked Sub Pixel Variance Test OperationCheck,"
|
||||
<< "C output doesn't match SSSE3 output. "
|
||||
<< "First failed at test case " << first_failure;
|
||||
}
|
||||
|
||||
TEST_P(MaskedSubPixelVarianceTest, ExtremeValues) {
|
||||
unsigned int ref_ret, opt_ret;
|
||||
unsigned int ref_sse, opt_sse;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint8_t, src_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, ref_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t,
|
||||
second_pred_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16)]);
|
||||
int first_failure_x = -1;
|
||||
int first_failure_y = -1;
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int src_stride = (MAX_SB_SIZE + 16);
|
||||
int ref_stride = (MAX_SB_SIZE + 16);
|
||||
int msk_stride = (MAX_SB_SIZE + 16);
|
||||
|
||||
for (int xoffset = 0; xoffset < BIL_SUBPEL_SHIFTS; xoffset++) {
|
||||
for (int yoffset = 0; yoffset < BIL_SUBPEL_SHIFTS; yoffset++) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
memset(src_ptr, (i & 0x1) ? 255 : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16));
|
||||
memset(ref_ptr, (i & 0x2) ? 255 : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16));
|
||||
memset(second_pred_ptr, (i & 0x4) ? 255 : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16));
|
||||
memset(msk_ptr, (i & 0x8) ? 64 : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 16));
|
||||
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
ref_ret = ref_func_(src_ptr, src_stride, xoffset, yoffset, ref_ptr,
|
||||
ref_stride, second_pred_ptr, msk_ptr, msk_stride,
|
||||
invert_mask, &ref_sse);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
opt_ret = opt_func_(src_ptr, src_stride, xoffset, yoffset,
|
||||
ref_ptr, ref_stride, second_pred_ptr, msk_ptr,
|
||||
msk_stride, invert_mask, &opt_sse));
|
||||
|
||||
if (opt_ret != ref_ret || opt_sse != ref_sse) {
|
||||
err_count++;
|
||||
if (first_failure == -1) {
|
||||
first_failure = i;
|
||||
first_failure_x = xoffset;
|
||||
first_failure_y = yoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, err_count) << "Error: Masked Variance Test ExtremeValues,"
|
||||
<< "C output doesn't match SSSE3 output. "
|
||||
<< "First failed at test case " << first_failure
|
||||
<< " x_offset = " << first_failure_x
|
||||
<< " y_offset = " << first_failure_y;
|
||||
}
|
||||
|
||||
typedef ::testing::tuple<MaskedSubPixelVarianceFunc, MaskedSubPixelVarianceFunc,
|
||||
aom_bit_depth_t>
|
||||
HighbdMaskedSubPixelVarianceParam;
|
||||
|
||||
class HighbdMaskedSubPixelVarianceTest
|
||||
: public ::testing::TestWithParam<HighbdMaskedSubPixelVarianceParam> {
|
||||
public:
|
||||
virtual ~HighbdMaskedSubPixelVarianceTest() {}
|
||||
virtual void SetUp() {
|
||||
opt_func_ = GET_PARAM(0);
|
||||
ref_func_ = GET_PARAM(1);
|
||||
bit_depth_ = GET_PARAM(2);
|
||||
}
|
||||
|
||||
virtual void TearDown() { libaom_test::ClearSystemState(); }
|
||||
|
||||
protected:
|
||||
MaskedSubPixelVarianceFunc opt_func_;
|
||||
MaskedSubPixelVarianceFunc ref_func_;
|
||||
aom_bit_depth_t bit_depth_;
|
||||
};
|
||||
|
||||
TEST_P(HighbdMaskedSubPixelVarianceTest, OperationCheck) {
|
||||
unsigned int ref_ret, opt_ret;
|
||||
unsigned int ref_sse, opt_sse;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint16_t, src_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint16_t, ref_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint16_t,
|
||||
second_pred_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
uint8_t *src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
|
||||
uint8_t *ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
|
||||
uint8_t *second_pred8_ptr = CONVERT_TO_BYTEPTR(second_pred_ptr);
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int first_failure_x = -1;
|
||||
int first_failure_y = -1;
|
||||
int src_stride = (MAX_SB_SIZE + 8);
|
||||
int ref_stride = (MAX_SB_SIZE + 8);
|
||||
int msk_stride = (MAX_SB_SIZE + 8);
|
||||
int xoffset, yoffset;
|
||||
|
||||
for (int i = 0; i < number_of_iterations; ++i) {
|
||||
for (int j = 0; j < (MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8); j++) {
|
||||
src_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
|
||||
ref_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
|
||||
second_pred_ptr[j] = rnd.Rand16() & ((1 << bit_depth_) - 1);
|
||||
msk_ptr[j] = rnd(65);
|
||||
}
|
||||
for (xoffset = 0; xoffset < BIL_SUBPEL_SHIFTS; xoffset++) {
|
||||
for (yoffset = 0; yoffset < BIL_SUBPEL_SHIFTS; yoffset++) {
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
ref_ret = ref_func_(src8_ptr, src_stride, xoffset, yoffset, ref8_ptr,
|
||||
ref_stride, second_pred8_ptr, msk_ptr, msk_stride,
|
||||
invert_mask, &ref_sse);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
opt_ret = opt_func_(src8_ptr, src_stride, xoffset, yoffset,
|
||||
ref8_ptr, ref_stride, second_pred8_ptr,
|
||||
msk_ptr, msk_stride, invert_mask, &opt_sse));
|
||||
|
||||
if (opt_ret != ref_ret || opt_sse != ref_sse) {
|
||||
err_count++;
|
||||
if (first_failure == -1) {
|
||||
first_failure = i;
|
||||
first_failure_x = xoffset;
|
||||
first_failure_y = yoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, err_count)
|
||||
<< "Error: Masked Sub Pixel Variance Test OperationCheck,"
|
||||
<< "C output doesn't match SSSE3 output. "
|
||||
<< "First failed at test case " << first_failure
|
||||
<< " x_offset = " << first_failure_x << " y_offset = " << first_failure_y;
|
||||
}
|
||||
|
||||
TEST_P(HighbdMaskedSubPixelVarianceTest, ExtremeValues) {
|
||||
unsigned int ref_ret, opt_ret;
|
||||
unsigned int ref_sse, opt_sse;
|
||||
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
||||
DECLARE_ALIGNED(16, uint16_t, src_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint16_t, ref_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint8_t, msk_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
DECLARE_ALIGNED(16, uint16_t,
|
||||
second_pred_ptr[(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8)]);
|
||||
uint8_t *src8_ptr = CONVERT_TO_BYTEPTR(src_ptr);
|
||||
uint8_t *ref8_ptr = CONVERT_TO_BYTEPTR(ref_ptr);
|
||||
uint8_t *second_pred8_ptr = CONVERT_TO_BYTEPTR(second_pred_ptr);
|
||||
int first_failure_x = -1;
|
||||
int first_failure_y = -1;
|
||||
int err_count = 0;
|
||||
int first_failure = -1;
|
||||
int src_stride = (MAX_SB_SIZE + 8);
|
||||
int ref_stride = (MAX_SB_SIZE + 8);
|
||||
int msk_stride = (MAX_SB_SIZE + 8);
|
||||
|
||||
for (int xoffset = 0; xoffset < BIL_SUBPEL_SHIFTS; xoffset++) {
|
||||
for (int yoffset = 0; yoffset < BIL_SUBPEL_SHIFTS; yoffset++) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
aom_memset16(src_ptr, (i & 0x1) ? ((1 << bit_depth_) - 1) : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8));
|
||||
aom_memset16(ref_ptr, (i & 0x2) ? ((1 << bit_depth_) - 1) : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8));
|
||||
aom_memset16(second_pred_ptr, (i & 0x4) ? ((1 << bit_depth_) - 1) : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8));
|
||||
memset(msk_ptr, (i & 0x8) ? 64 : 0,
|
||||
(MAX_SB_SIZE + 1) * (MAX_SB_SIZE + 8));
|
||||
|
||||
for (int invert_mask = 0; invert_mask < 2; ++invert_mask) {
|
||||
ref_ret = ref_func_(src8_ptr, src_stride, xoffset, yoffset, ref8_ptr,
|
||||
ref_stride, second_pred8_ptr, msk_ptr, msk_stride,
|
||||
invert_mask, &ref_sse);
|
||||
ASM_REGISTER_STATE_CHECK(
|
||||
opt_ret = opt_func_(src8_ptr, src_stride, xoffset, yoffset,
|
||||
ref8_ptr, ref_stride, second_pred8_ptr,
|
||||
msk_ptr, msk_stride, invert_mask, &opt_sse));
|
||||
|
||||
if (opt_ret != ref_ret || opt_sse != ref_sse) {
|
||||
err_count++;
|
||||
if (first_failure == -1) {
|
||||
first_failure = i;
|
||||
first_failure_x = xoffset;
|
||||
first_failure_y = yoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, err_count) << "Error: Masked Variance Test ExtremeValues,"
|
||||
<< "C output doesn't match SSSE3 output. "
|
||||
<< "First failed at test case " << first_failure
|
||||
<< " x_offset = " << first_failure_x
|
||||
<< " y_offset = " << first_failure_y;
|
||||
}
|
||||
|
||||
using ::testing::make_tuple;
|
||||
|
||||
#if HAVE_SSSE3
|
||||
|
||||
const MaskedSubPixelVarianceParam sub_pel_var_test[] = {
|
||||
make_tuple(&aom_masked_sub_pixel_variance128x128_ssse3,
|
||||
&aom_masked_sub_pixel_variance128x128_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance128x64_ssse3,
|
||||
&aom_masked_sub_pixel_variance128x64_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance64x128_ssse3,
|
||||
&aom_masked_sub_pixel_variance64x128_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance64x64_ssse3,
|
||||
&aom_masked_sub_pixel_variance64x64_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance64x32_ssse3,
|
||||
&aom_masked_sub_pixel_variance64x32_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance32x64_ssse3,
|
||||
&aom_masked_sub_pixel_variance32x64_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance32x32_ssse3,
|
||||
&aom_masked_sub_pixel_variance32x32_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance32x16_ssse3,
|
||||
&aom_masked_sub_pixel_variance32x16_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance16x32_ssse3,
|
||||
&aom_masked_sub_pixel_variance16x32_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance16x16_ssse3,
|
||||
&aom_masked_sub_pixel_variance16x16_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance16x8_ssse3,
|
||||
&aom_masked_sub_pixel_variance16x8_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance8x16_ssse3,
|
||||
&aom_masked_sub_pixel_variance8x16_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance8x8_ssse3,
|
||||
&aom_masked_sub_pixel_variance8x8_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance8x4_ssse3,
|
||||
&aom_masked_sub_pixel_variance8x4_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance4x8_ssse3,
|
||||
&aom_masked_sub_pixel_variance4x8_c),
|
||||
make_tuple(&aom_masked_sub_pixel_variance4x4_ssse3,
|
||||
&aom_masked_sub_pixel_variance4x4_c)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3_C_COMPARE, MaskedSubPixelVarianceTest,
|
||||
::testing::ValuesIn(sub_pel_var_test));
|
||||
|
||||
const HighbdMaskedSubPixelVarianceParam hbd_sub_pel_var_test[] = {
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance128x128_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance128x128_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance128x64_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance128x64_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance64x128_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance64x128_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance64x64_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance64x64_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance64x32_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance64x32_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance32x64_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance32x64_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance32x32_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance32x32_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance32x16_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance32x16_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance16x32_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance16x32_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance16x16_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance16x16_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance16x8_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance16x8_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance8x16_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance8x16_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance8x8_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance8x8_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance8x4_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance8x4_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance4x8_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance4x8_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_8_masked_sub_pixel_variance4x4_ssse3,
|
||||
&aom_highbd_8_masked_sub_pixel_variance4x4_c, AOM_BITS_8),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance128x128_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance128x128_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance128x64_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance128x64_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance64x128_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance64x128_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance64x64_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance64x64_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance64x32_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance64x32_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance32x64_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance32x64_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance32x32_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance32x32_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance32x16_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance32x16_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance16x32_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance16x32_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance16x16_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance16x16_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance16x8_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance16x8_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance8x16_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance8x16_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance8x8_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance8x8_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance8x4_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance8x4_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance4x8_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance4x8_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_10_masked_sub_pixel_variance4x4_ssse3,
|
||||
&aom_highbd_10_masked_sub_pixel_variance4x4_c, AOM_BITS_10),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance128x128_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance128x128_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance128x64_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance128x64_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance64x128_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance64x128_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance64x64_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance64x64_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance64x32_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance64x32_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance32x64_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance32x64_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance32x32_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance32x32_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance32x16_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance32x16_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance16x32_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance16x32_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance16x16_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance16x16_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance16x8_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance16x8_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance8x16_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance8x16_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance8x8_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance8x8_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance8x4_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance8x4_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance4x8_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance4x8_c, AOM_BITS_12),
|
||||
make_tuple(&aom_highbd_12_masked_sub_pixel_variance4x4_ssse3,
|
||||
&aom_highbd_12_masked_sub_pixel_variance4x4_c, AOM_BITS_12)
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SSSE3_C_COMPARE, HighbdMaskedSubPixelVarianceTest,
|
||||
::testing::ValuesIn(hbd_sub_pel_var_test));
|
||||
#endif // HAVE_SSSE3
|
||||
} // namespace
|
||||
76
media/libaom/src/test/md5_helper.h
Normal file
76
media/libaom/src/test/md5_helper.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#ifndef AOM_TEST_MD5_HELPER_H_
|
||||
#define AOM_TEST_MD5_HELPER_H_
|
||||
|
||||
#include "aom/aom_decoder.h"
|
||||
#include "common/md5_utils.h"
|
||||
|
||||
namespace libaom_test {
|
||||
class MD5 {
|
||||
public:
|
||||
MD5() { MD5Init(&md5_); }
|
||||
|
||||
void Add(const aom_image_t *img) {
|
||||
for (int plane = 0; plane < 3; ++plane) {
|
||||
const uint8_t *buf = img->planes[plane];
|
||||
// Calculate the width and height to do the md5 check. For the chroma
|
||||
// plane, we never want to round down and thus skip a pixel so if
|
||||
// we are shifting by 1 (chroma_shift) we add 1 before doing the shift.
|
||||
// This works only for chroma_shift of 0 and 1.
|
||||
const int bytes_per_sample =
|
||||
(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
|
||||
const int h =
|
||||
plane ? (img->d_h + img->y_chroma_shift) >> img->y_chroma_shift
|
||||
: img->d_h;
|
||||
const int w =
|
||||
(plane ? (img->d_w + img->x_chroma_shift) >> img->x_chroma_shift
|
||||
: img->d_w) *
|
||||
bytes_per_sample;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
MD5Update(&md5_, buf, w);
|
||||
buf += img->stride[plane];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Add(const uint8_t *data, size_t size) {
|
||||
MD5Update(&md5_, data, static_cast<uint32_t>(size));
|
||||
}
|
||||
|
||||
const char *Get(void) {
|
||||
static const char hex[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
};
|
||||
uint8_t tmp[16];
|
||||
MD5Context ctx_tmp = md5_;
|
||||
|
||||
MD5Final(tmp, &ctx_tmp);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
res_[i * 2 + 0] = hex[tmp[i] >> 4];
|
||||
res_[i * 2 + 1] = hex[tmp[i] & 0xf];
|
||||
}
|
||||
res_[32] = 0;
|
||||
|
||||
return res_;
|
||||
}
|
||||
|
||||
protected:
|
||||
char res_[33];
|
||||
MD5Context md5_;
|
||||
};
|
||||
|
||||
} // namespace libaom_test
|
||||
|
||||
#endif // AOM_TEST_MD5_HELPER_H_
|
||||
422
media/libaom/src/test/metrics_template.html
Normal file
422
media/libaom/src/test/metrics_template.html
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Video Codec Test Results</title>
|
||||
<style type="text/css">
|
||||
<!-- Begin 960 reset -->
|
||||
a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,c
|
||||
ode,dd,del,details,dfn,dialog,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,h1,h2,h
|
||||
3,h4,h5,h6,header,hgroup,hr,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,meter,nav,object,ol,
|
||||
output,p,pre,progress,q,rp,rt,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbo
|
||||
dy,td,tfoot,th,thead,time,tr,tt,u,ul,var,video,xmp{border:0;margin:0;padding:0;font-size:100%}html,b
|
||||
ody{height:100%}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{displa
|
||||
y:block}b,strong{font-weight:bold}img{color:transparent;font-size:0;vertical-align:middle;-ms-interp
|
||||
olation-mode:bicubic}ol,ul{list-style:none}li{display:list-item}table{border-collapse:collapse;borde
|
||||
r-spacing:0}th,td,caption{font-weight:normal;vertical-align:top;text-align:left}q{quotes:none}q:befo
|
||||
re,q:after{content:'';content:none}sub,sup,small{font-size:75%}sub,sup{line-height:0;position:relati
|
||||
ve;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}svg{overflow:hidden}
|
||||
<!-- End 960 reset -->
|
||||
<!-- Begin 960 text -->
|
||||
body{font:13px/1.5 'Helvetica Neue',Arial,'Liberation Sans',FreeSans,sans-serif}pre,code{font-family
|
||||
:'DejaVu Sans Mono',Menlo,Consolas,monospace}hr{border:0 #ccc solid;border-top-width:1px;clear:both;
|
||||
height:0}h1{font-size:25px}h2{font-size:23px}h3{font-size:21px}h4{font-size:19px}h5{font-size:17px}h
|
||||
6{font-size:15px}ol{list-style:decimal}ul{list-style:disc}li{margin-left:30px}p,dl,hr,h1,h2,h3,h4,h5
|
||||
,h6,ol,ul,pre,table,address,fieldset,figure{margin-bottom:20px}
|
||||
<!-- End 960 text -->
|
||||
<!-- Begin 960 grid (fluid variant)
|
||||
12 columns, 1152px total width
|
||||
http://960.gs/ | http://grids.heroku.com/ -->
|
||||
.container_12{width:92%;margin-left:4%;margin-right:4%}.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid
|
||||
_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12{display:inline;float:left;position:relative;ma
|
||||
rgin-left:1%;margin-right:1%}.alpha{margin-left:0}.omega{margin-right:0}.container_12 .grid_1{width:
|
||||
6.333%}.container_12 .grid_2{width:14.667%}.container_12 .grid_3{width:23.0%}.container_12 .grid_4{w
|
||||
idth:31.333%}.container_12 .grid_5{width:39.667%}.container_12 .grid_6{width:48.0%}.container_12 .gr
|
||||
id_7{width:56.333%}.container_12 .grid_8{width:64.667%}.container_12 .grid_9{width:73.0%}.container_
|
||||
12 .grid_10{width:81.333%}.container_12 .grid_11{width:89.667%}.container_12 .grid_12{width:98.0%}.c
|
||||
ontainer_12 .prefix_1{padding-left:8.333%}.container_12 .prefix_2{padding-left:16.667%}.container_12
|
||||
.prefix_3{padding-left:25.0%}.container_12 .prefix_4{padding-left:33.333%}.container_12 .prefix_5{p
|
||||
adding-left:41.667%}.container_12 .prefix_6{padding-left:50.0%}.container_12 .prefix_7{padding-left:
|
||||
58.333%}.container_12 .prefix_8{padding-left:66.667%}.container_12 .prefix_9{padding-left:75.0%}.con
|
||||
tainer_12 .prefix_10{padding-left:83.333%}.container_12 .prefix_11{padding-left:91.667%}.container_1
|
||||
2 .suffix_1{padding-right:8.333%}.container_12 .suffix_2{padding-right:16.667%}.container_12 .suffix
|
||||
_3{padding-right:25.0%}.container_12 .suffix_4{padding-right:33.333%}.container_12 .suffix_5{padding
|
||||
-right:41.667%}.container_12 .suffix_6{padding-right:50.0%}.container_12 .suffix_7{padding-right:58.
|
||||
333%}.container_12 .suffix_8{padding-right:66.667%}.container_12 .suffix_9{padding-right:75.0%}.cont
|
||||
ainer_12 .suffix_10{padding-right:83.333%}.container_12 .suffix_11{padding-right:91.667%}.container_
|
||||
12 .push_1{left:8.333%}.container_12 .push_2{left:16.667%}.container_12 .push_3{left:25.0%}.containe
|
||||
r_12 .push_4{left:33.333%}.container_12 .push_5{left:41.667%}.container_12 .push_6{left:50.0%}.conta
|
||||
iner_12 .push_7{left:58.333%}.container_12 .push_8{left:66.667%}.container_12 .push_9{left:75.0%}.co
|
||||
ntainer_12 .push_10{left:83.333%}.container_12 .push_11{left:91.667%}.container_12 .pull_1{left:-8.3
|
||||
33%}.container_12 .pull_2{left:-16.667%}.container_12 .pull_3{left:-25.0%}.container_12 .pull_4{left
|
||||
:-33.333%}.container_12 .pull_5{left:-41.667%}.container_12 .pull_6{left:-50.0%}.container_12 .pull_
|
||||
7{left:-58.333%}.container_12 .pull_8{left:-66.667%}.container_12 .pull_9{left:-75.0%}.container_12
|
||||
.pull_10{left:-83.333%}.container_12 .pull_11{left:-91.667%}.clear{clear:both;display:block;overflow
|
||||
:hidden;visibility:hidden;width:0;height:0}.clearfix:after{clear:both;content:' ';display:block;font
|
||||
-size:0;line-height:0;visibility:hidden;width:0;height:0}.clearfix{display:inline-block}* html .clea
|
||||
rfix{height:1%}.clearfix{display:block}
|
||||
<!-- End 960 grid -->
|
||||
|
||||
div.metricgraph {
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
}
|
||||
|
||||
div.header {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.header h2 {
|
||||
margin: .5em auto;
|
||||
}
|
||||
|
||||
div.radio {
|
||||
font-family: Arial, sans-serif;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div.main {
|
||||
|
||||
}
|
||||
|
||||
div.cliplist {
|
||||
font-family: Arial, sans-serif;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
div.chartarea {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.indicators {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
margin-top: 6px;
|
||||
min-height: 600px;
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
div.indicators div.content {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
div.indicators div.content h5 {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.indicators div.content ul {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.indicators div.content ul li {
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
div.indicators div.content p:first-child {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
span.google-visualization-table-sortind {
|
||||
color: #000;
|
||||
}
|
||||
.header-style {
|
||||
font-weight: bold;
|
||||
border: 1px solid #fff;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
td.header-style+td {
|
||||
|
||||
}
|
||||
|
||||
.orange-background {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.light-gray-background {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript">
|
||||
var chart_left = 40;
|
||||
var chart_top = 6;
|
||||
var chart_height = document.documentElement.clientHeight-100;
|
||||
var chart_width = "100%";
|
||||
ftable='filestable_avg'
|
||||
var snrs = [];
|
||||
var filestable_dsnr = [];
|
||||
var filestable_drate = [];
|
||||
var filestable_avg = [];
|
||||
|
||||
// Python template code replaces the following 2 lines.
|
||||
//%%metrics_js%%//
|
||||
//%%filestable_dpsnr%%//
|
||||
//%%filestable_avg%%//
|
||||
//%%filestable_drate%%//
|
||||
//%%snrs%%//
|
||||
|
||||
var selected = 0
|
||||
var imagestr = '';
|
||||
var bettertable=0;
|
||||
var chart=0;
|
||||
var better=0;
|
||||
var metricdata=0;
|
||||
var metricView=0;
|
||||
var column=1;
|
||||
var formatter=0;
|
||||
|
||||
function changeColumn(col) {
|
||||
column = col;
|
||||
console.log(col)
|
||||
draw_files();
|
||||
}
|
||||
|
||||
function changeMetric(m) {
|
||||
ftable=m
|
||||
draw_files()
|
||||
}
|
||||
|
||||
function setup_vis() {
|
||||
chart = new google.visualization.ScatterChart(
|
||||
document.getElementById("metricgraph"));
|
||||
|
||||
bettertable = new google.visualization.Table(
|
||||
document.getElementById("bettertable"));
|
||||
|
||||
draw_files();
|
||||
build_metrics_radio();
|
||||
}
|
||||
|
||||
function build_metrics_radio() {
|
||||
for (metric=1; metric < metrics.length; metric++) {
|
||||
var rb = document.createElement('input');
|
||||
var l = document.createElement('label');
|
||||
rb.setAttribute('type','radio');
|
||||
rb.setAttribute('name','metric');
|
||||
rb.setAttribute('onClick', "changeColumn('"+metric.toString()+"')");
|
||||
l.innerHTML = metrics[metric];
|
||||
document.getElementById('metrics').appendChild(rb);
|
||||
document.getElementById('metrics').appendChild(l);
|
||||
}
|
||||
}
|
||||
|
||||
function draw_files() {
|
||||
var options = {'allowHtml': true, 'width': "100%", 'height': "50%"};
|
||||
if (better != 0) delete better;
|
||||
|
||||
col=eval(ftable+'[column]')
|
||||
better = new google.visualization.DataTable(col)
|
||||
|
||||
// Python Template code replaces the following line with a list of
|
||||
// formatters.
|
||||
if (ftable == 'filestable_dsnr')
|
||||
formatter = new google.visualization.NumberFormat(
|
||||
{fractionDigits: 4, suffix:" db"});
|
||||
else
|
||||
formatter = new google.visualization.NumberFormat(
|
||||
{fractionDigits: 4, suffix:"%"});
|
||||
|
||||
//%%formatters%%//
|
||||
|
||||
bettertable.draw(better,options);
|
||||
google.visualization.events.addListener(bettertable, 'select',
|
||||
selectBetterHandler);
|
||||
query_file()
|
||||
}
|
||||
|
||||
function query_file() {
|
||||
imagestr = better.getFormattedValue(selected, 0)
|
||||
var metricjson = eval('(' + snrs[column][selected] + ')');
|
||||
metricdata = new google.visualization.DataTable(metricjson, 0.6);
|
||||
if( metricView != 0 ) delete metricView;
|
||||
metricView = new google.visualization.DataView(metricdata);
|
||||
|
||||
chart.draw(metricView, {curveType:'function',
|
||||
explorer: {},
|
||||
chartArea:{left:chart_left, top:chart_top, width:chart_width,
|
||||
height:chart_height-90},
|
||||
hAxis:{title:"Datarate in kbps"},
|
||||
vAxis:{title:"Quality in decibels", format: '##.0', textPosition: 'in'},
|
||||
legend:{position:"in"}, title:imagestr, pointSize:2, lineWidth:1,
|
||||
width:chart_width, height:chart_height-50 });
|
||||
|
||||
google.visualization.events.addListener(chart, 'select', chartSelect);
|
||||
google.visualization.events.addListener(chart, 'onmouseover', chartMouseOver);
|
||||
google.visualization.events.addListener(chart, 'onmouseout', chartMouseOut);
|
||||
}
|
||||
|
||||
function chartMouseOut(e) {
|
||||
statusbar = document.getElementById('status');
|
||||
statusbar.style.display = 'none';
|
||||
}
|
||||
|
||||
function chartMouseOver(e) {
|
||||
pointDifference(e.row, e.column)
|
||||
}
|
||||
|
||||
function pointDifference(row, col) {
|
||||
if(!row || !col)
|
||||
return;
|
||||
|
||||
var cols = metricdata.getNumberOfColumns();
|
||||
var rows = metricdata.getNumberOfRows();
|
||||
|
||||
var sel_bitrate = metricView.getValue(row, 0 );
|
||||
var sel_metric = metricView.getValue(row, col);
|
||||
|
||||
var message = '<ul>' + metricView.getColumnLabel(col) +
|
||||
' (' + sel_bitrate.toFixed(0) + ' kbps, ' + sel_metric.toFixed(2) + ')' + ' is ';
|
||||
|
||||
|
||||
// col 0 is datarate
|
||||
for( var i=1;i<cols;++i) {
|
||||
|
||||
var metric_greatest_thats_less = 0;
|
||||
var rate_greatest_thats_less = 0;
|
||||
var metric_smallest_thats_greater = 999;
|
||||
var rate_smallest_thats_greater = 0;
|
||||
|
||||
if(i==col)
|
||||
continue;
|
||||
|
||||
// Find the lowest metric for the column that's greater than sel_metric and
|
||||
// the highest metric for this column that's less than the metric.
|
||||
for(var line_count = 0; line_count < rows; ++line_count) {
|
||||
this_metric = metricdata.getValue(line_count, i)
|
||||
this_rate = metricdata.getValue(line_count, 0)
|
||||
if(!this_metric)
|
||||
continue;
|
||||
|
||||
if(this_metric > metric_greatest_thats_less &&
|
||||
this_metric <= sel_metric) {
|
||||
metric_greatest_thats_less = this_metric;
|
||||
rate_greatest_thats_less = this_rate;
|
||||
}
|
||||
if(this_metric < metric_smallest_thats_greater &&
|
||||
this_metric > sel_metric) {
|
||||
metric_smallest_thats_greater = this_metric;
|
||||
rate_smallest_thats_greater = this_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if(rate_smallest_thats_greater == 0 || rate_greatest_thats_less == 0) {
|
||||
message = message + " <li> Couldn't find a point on both sides.</li>"
|
||||
} else {
|
||||
metric_slope = ( rate_smallest_thats_greater - rate_greatest_thats_less) /
|
||||
( metric_smallest_thats_greater - metric_greatest_thats_less);
|
||||
|
||||
projected_rate = ( sel_metric - metric_greatest_thats_less) *
|
||||
metric_slope + rate_greatest_thats_less;
|
||||
|
||||
difference = 100 * (projected_rate / sel_bitrate - 1);
|
||||
|
||||
|
||||
if (difference > 0)
|
||||
message = message + "<li> " + difference.toFixed(2) +
|
||||
"% smaller than <em>" +
|
||||
metricdata.getColumnLabel(i) + "</em></li> "
|
||||
else
|
||||
message = message + "<li> " + -difference.toFixed(2) +
|
||||
"% bigger than <em>" +
|
||||
metricdata.getColumnLabel(i) + "</em></li> "
|
||||
}
|
||||
|
||||
}
|
||||
message = message + "</ul>"
|
||||
statusbar = document.getElementById('status');
|
||||
statusbar.innerHTML = "<p>" + message + "</p>";
|
||||
statusbar.style.display = 'block';
|
||||
}
|
||||
|
||||
function chartSelect() {
|
||||
var selection = chart.getSelection();
|
||||
var message = '';
|
||||
var min = metricView.getFormattedValue(selection[0].row, 0);
|
||||
var max = metricView.getFormattedValue(selection[selection.length-1].row, 0);
|
||||
var val = metricView.getFormattedValue(selection[0].row,selection[0].column);
|
||||
|
||||
pointDifference(selection[0].row, selection[0].column)
|
||||
min = min / 3
|
||||
max = max * 3
|
||||
metricView.setRows(metricdata.getFilteredRows(
|
||||
[{column: 0,minValue: min, maxValue:max}]));
|
||||
|
||||
chart.draw(metricView, {curveType:'function',
|
||||
chartArea:{left:40, top:10, width:chart_width, height:chart_height - 110},
|
||||
hAxis:{title:"datarate in kbps"}, vAxis:{title:"quality in decibels"},
|
||||
legend:{position:"in"}, title:imagestr, pointSize:2, lineWidth:1,
|
||||
width:chart_width, height:chart_height - 50});
|
||||
}
|
||||
|
||||
function selectBetterHandler() {
|
||||
var selection = bettertable.getSelection();
|
||||
for (var i = 0; i < selection.length; i++) {
|
||||
item = selection[i];
|
||||
}
|
||||
selected = item.row
|
||||
query_file()
|
||||
}
|
||||
|
||||
|
||||
google.load('visualization', '1', {'packages' : ['corechart','table']});
|
||||
google.setOnLoadCallback(setup_vis);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container_12">
|
||||
|
||||
<div class="grid_12 header">
|
||||
<h2>Codec Comparison Results</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid_12 radio">
|
||||
|
||||
<form name="myform">
|
||||
Method For Combining Points
|
||||
<input type="radio" checked name="column" value="1"
|
||||
onClick="changeMetric('filestable_avg')" />Average of bitrates difference
|
||||
<input type="radio" name="column" value="2"
|
||||
onClick="changeMetric('filestable_dsnr')" />BDSNR
|
||||
<input type="radio" name="column" value="3"
|
||||
onClick="changeMetric('filestable_drate')" />BDRATE
|
||||
</form>
|
||||
|
||||
<form id="metrics" name="myform">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="grid_12 main">
|
||||
|
||||
<div class="grid_5 alpha cliplist">
|
||||
<div id="bettertable"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid_5 chartarea">
|
||||
<div id="metricgraph"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid_2 omega indicators">
|
||||
<div class="content">
|
||||
<h5>Indicators</h5>
|
||||
<hr>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
130
media/libaom/src/test/monochrome_test.cc
Normal file
130
media/libaom/src/test/monochrome_test.cc
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/i420_video_source.h"
|
||||
#include "test/video_source.h"
|
||||
#include "test/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class MonochromeTest
|
||||
: public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
MonochromeTest() : EncoderTest(GET_PARAM(0)), frame0_psnr_y_(0.) {}
|
||||
|
||||
virtual ~MonochromeTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(GET_PARAM(1));
|
||||
}
|
||||
|
||||
virtual void DecompressedFrameHook(const aom_image_t &img,
|
||||
aom_codec_pts_t pts) {
|
||||
(void)pts;
|
||||
|
||||
// Get value of top-left corner pixel of U plane
|
||||
int chroma_value = img.planes[AOM_PLANE_U][0];
|
||||
|
||||
bool is_chroma_constant =
|
||||
ComparePlaneToValue(img, AOM_PLANE_U, chroma_value) &&
|
||||
ComparePlaneToValue(img, AOM_PLANE_V, chroma_value);
|
||||
|
||||
// Chroma planes should be constant
|
||||
EXPECT_TRUE(is_chroma_constant);
|
||||
|
||||
// Monochrome flag on image should be set
|
||||
EXPECT_EQ(img.monochrome, 1);
|
||||
|
||||
chroma_value_list_.push_back(chroma_value);
|
||||
}
|
||||
|
||||
// Returns true if all pixels on the plane are equal to value, and returns
|
||||
// false otherwise.
|
||||
bool ComparePlaneToValue(const aom_image_t &img, const int plane,
|
||||
const int value) {
|
||||
const int w = aom_img_plane_width(&img, plane);
|
||||
const int h = aom_img_plane_height(&img, plane);
|
||||
const uint8_t *const buf = img.planes[plane];
|
||||
const int stride = img.stride[plane];
|
||||
|
||||
for (int r = 0; r < h; ++r) {
|
||||
for (int c = 0; c < w; ++c) {
|
||||
if (buf[r * stride + c] != value) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) {
|
||||
// Check that the initial Y PSNR value is 'high enough', and check that
|
||||
// subsequent Y PSNR values are 'close' to this initial value.
|
||||
if (frame0_psnr_y_ == 0.) {
|
||||
frame0_psnr_y_ = pkt->data.psnr.psnr[1];
|
||||
EXPECT_GT(frame0_psnr_y_, 29.);
|
||||
}
|
||||
EXPECT_NEAR(pkt->data.psnr.psnr[1], frame0_psnr_y_, 2.5);
|
||||
}
|
||||
|
||||
std::vector<int> chroma_value_list_;
|
||||
double frame0_psnr_y_;
|
||||
};
|
||||
|
||||
TEST_P(MonochromeTest, TestMonochromeEncoding) {
|
||||
::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
|
||||
30, 1, 0, 5);
|
||||
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
cfg_.g_w = 352;
|
||||
cfg_.g_h = 288;
|
||||
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_min_quantizer = 2;
|
||||
cfg_.rc_max_quantizer = 56;
|
||||
cfg_.rc_undershoot_pct = 50;
|
||||
cfg_.rc_overshoot_pct = 50;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.kf_mode = AOM_KF_AUTO;
|
||||
cfg_.g_lag_in_frames = 1;
|
||||
cfg_.kf_min_dist = cfg_.kf_max_dist = 3000;
|
||||
// Enable dropped frames.
|
||||
cfg_.rc_dropframe_thresh = 1;
|
||||
// Disable error_resilience mode.
|
||||
cfg_.g_error_resilient = 0;
|
||||
// Run at low bitrate.
|
||||
cfg_.rc_target_bitrate = 40;
|
||||
// Set monochrome encoding flag
|
||||
cfg_.monochrome = 1;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
|
||||
|
||||
// Check that the chroma planes are equal across all frames
|
||||
std::vector<int>::const_iterator iter = chroma_value_list_.begin();
|
||||
int initial_chroma_value = *iter;
|
||||
for (; iter != chroma_value_list_.end(); ++iter) {
|
||||
// Check that all decoded frames have the same constant chroma planes.
|
||||
EXPECT_EQ(*iter, initial_chroma_value);
|
||||
}
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(MonochromeTest,
|
||||
::testing::Values(::libaom_test::kTwoPassGood));
|
||||
|
||||
} // namespace
|
||||
105
media/libaom/src/test/motion_vector_test.cc
Normal file
105
media/libaom/src/test/motion_vector_test.cc
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Alliance for Open Media. All rights reserved
|
||||
*
|
||||
* This source code is subject to the terms of the BSD 2 Clause License and
|
||||
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
||||
* was not distributed with this source code in the LICENSE file, you can
|
||||
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
||||
* Media Patent License 1.0 was not distributed with this source code in the
|
||||
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
||||
*/
|
||||
|
||||
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
|
||||
|
||||
#include "test/codec_factory.h"
|
||||
#include "test/encode_test_driver.h"
|
||||
#include "test/util.h"
|
||||
#include "test/yuv_video_source.h"
|
||||
|
||||
namespace {
|
||||
#define MAX_EXTREME_MV 1
|
||||
#define MIN_EXTREME_MV 2
|
||||
|
||||
// Encoding modes
|
||||
const libaom_test::TestMode kEncodingModeVectors[] = {
|
||||
::libaom_test::kTwoPassGood,
|
||||
::libaom_test::kOnePassGood,
|
||||
};
|
||||
|
||||
// Encoding speeds
|
||||
const int kCpuUsedVectors[] = { 1, 5 };
|
||||
|
||||
// MV test modes: 1 - always use maximum MV; 2 - always use minimum MV.
|
||||
const int kMVTestModes[] = { MAX_EXTREME_MV, MIN_EXTREME_MV };
|
||||
|
||||
class MotionVectorTestLarge
|
||||
: public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
|
||||
int>,
|
||||
public ::libaom_test::EncoderTest {
|
||||
protected:
|
||||
MotionVectorTestLarge()
|
||||
: EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
|
||||
cpu_used_(GET_PARAM(2)), mv_test_mode_(GET_PARAM(3)) {}
|
||||
|
||||
virtual ~MotionVectorTestLarge() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
InitializeConfig();
|
||||
SetMode(encoding_mode_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
cfg_.g_lag_in_frames = 3;
|
||||
cfg_.rc_end_usage = AOM_VBR;
|
||||
} else {
|
||||
cfg_.g_lag_in_frames = 0;
|
||||
cfg_.rc_end_usage = AOM_CBR;
|
||||
cfg_.rc_buf_sz = 1000;
|
||||
cfg_.rc_buf_initial_sz = 500;
|
||||
cfg_.rc_buf_optimal_sz = 600;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
|
||||
::libaom_test::Encoder *encoder) {
|
||||
if (video->frame() == 1) {
|
||||
encoder->Control(AOME_SET_CPUUSED, cpu_used_);
|
||||
encoder->Control(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, mv_test_mode_);
|
||||
if (encoding_mode_ != ::libaom_test::kRealTime) {
|
||||
encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
|
||||
encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
|
||||
encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libaom_test::TestMode encoding_mode_;
|
||||
int cpu_used_;
|
||||
int mv_test_mode_;
|
||||
};
|
||||
|
||||
TEST_P(MotionVectorTestLarge, OverallTest) {
|
||||
int width = 3840;
|
||||
int height = 2160;
|
||||
|
||||
// Reduce the test clip's resolution while testing on 32-bit system.
|
||||
if (sizeof(void *) == 4) {
|
||||
width = 2048;
|
||||
height = 360;
|
||||
}
|
||||
|
||||
cfg_.rc_target_bitrate = 24000;
|
||||
cfg_.g_profile = 0;
|
||||
init_flags_ = AOM_CODEC_USE_PSNR;
|
||||
|
||||
testing::internal::scoped_ptr<libaom_test::VideoSource> video;
|
||||
video.reset(new libaom_test::YUVVideoSource(
|
||||
"niklas_640_480_30.yuv", AOM_IMG_FMT_I420, width, height, 30, 1, 0, 3));
|
||||
|
||||
ASSERT_TRUE(video.get() != NULL);
|
||||
ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
|
||||
}
|
||||
|
||||
AV1_INSTANTIATE_TEST_CASE(MotionVectorTestLarge,
|
||||
::testing::ValuesIn(kEncodingModeVectors),
|
||||
::testing::ValuesIn(kCpuUsedVectors),
|
||||
::testing::ValuesIn(kMVTestModes));
|
||||
} // namespace
|
||||
1343
media/libaom/src/test/noise_model_test.cc
Normal file
1343
media/libaom/src/test/noise_model_test.cc
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue