1 /*
2 * Copyright (c) 2018, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 #include <cstdio>
13 #include <cstdlib>
14 #include <string>
15
16 #include "aom_mem/aom_mem.h"
17 #include "test/codec_factory.h"
18 #include "test/encode_test_driver.h"
19 #include "test/i420_video_source.h"
20 #include "test/md5_helper.h"
21 #include "test/util.h"
22 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
23
24 namespace {
25
26 static const int kNumMultiThreadDecoders = 3;
27
28 class AV1DecodeMultiThreadedTest
29 : public ::libaom_test::CodecTestWith5Params<int, int, int, int, int>,
30 public ::libaom_test::EncoderTest {
31 protected:
AV1DecodeMultiThreadedTest()32 AV1DecodeMultiThreadedTest()
33 : EncoderTest(GET_PARAM(0)), md5_single_thread_(), md5_multi_thread_(),
34 n_tile_cols_(GET_PARAM(1)), n_tile_rows_(GET_PARAM(2)),
35 n_tile_groups_(GET_PARAM(3)), set_cpu_used_(GET_PARAM(4)),
36 row_mt_(GET_PARAM(5)) {
37 init_flags_ = AOM_CODEC_USE_PSNR;
38 aom_codec_dec_cfg_t cfg = aom_codec_dec_cfg_t();
39 cfg.w = 704;
40 cfg.h = 576;
41 cfg.threads = 1;
42 cfg.allow_lowbitdepth = 1;
43 single_thread_dec_ = codec_->CreateDecoder(cfg, 0);
44
45 // Test cfg.threads == powers of 2.
46 for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
47 cfg.threads <<= 1;
48 multi_thread_dec_[i] = codec_->CreateDecoder(cfg, 0);
49 multi_thread_dec_[i]->Control(AV1D_SET_ROW_MT, row_mt_);
50 }
51
52 if (single_thread_dec_->IsAV1()) {
53 single_thread_dec_->Control(AV1D_EXT_TILE_DEBUG, 1);
54 single_thread_dec_->Control(AV1_SET_DECODE_TILE_ROW, -1);
55 single_thread_dec_->Control(AV1_SET_DECODE_TILE_COL, -1);
56 }
57 for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
58 if (multi_thread_dec_[i]->IsAV1()) {
59 multi_thread_dec_[i]->Control(AV1D_EXT_TILE_DEBUG, 1);
60 multi_thread_dec_[i]->Control(AV1_SET_DECODE_TILE_ROW, -1);
61 multi_thread_dec_[i]->Control(AV1_SET_DECODE_TILE_COL, -1);
62 }
63 }
64 }
65
~AV1DecodeMultiThreadedTest()66 virtual ~AV1DecodeMultiThreadedTest() {
67 delete single_thread_dec_;
68 for (int i = 0; i < kNumMultiThreadDecoders; ++i)
69 delete multi_thread_dec_[i];
70 }
71
SetUp()72 virtual void SetUp() {
73 InitializeConfig();
74 SetMode(libaom_test::kTwoPassGood);
75 }
76
PreEncodeFrameHook(libaom_test::VideoSource * video,libaom_test::Encoder * encoder)77 virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
78 libaom_test::Encoder *encoder) {
79 if (video->frame() == 0) {
80 encoder->Control(AV1E_SET_TILE_COLUMNS, n_tile_cols_);
81 encoder->Control(AV1E_SET_TILE_ROWS, n_tile_rows_);
82 encoder->Control(AV1E_SET_NUM_TG, n_tile_groups_);
83 encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
84 }
85 }
86
UpdateMD5(::libaom_test::Decoder * dec,const aom_codec_cx_pkt_t * pkt,::libaom_test::MD5 * md5)87 void UpdateMD5(::libaom_test::Decoder *dec, const aom_codec_cx_pkt_t *pkt,
88 ::libaom_test::MD5 *md5) {
89 const aom_codec_err_t res = dec->DecodeFrame(
90 reinterpret_cast<uint8_t *>(pkt->data.frame.buf), pkt->data.frame.sz);
91 if (res != AOM_CODEC_OK) {
92 abort_ = true;
93 ASSERT_EQ(AOM_CODEC_OK, res);
94 }
95 const aom_image_t *img = dec->GetDxData().Next();
96 md5->Add(img);
97 }
98
FramePktHook(const aom_codec_cx_pkt_t * pkt)99 virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
100 UpdateMD5(single_thread_dec_, pkt, &md5_single_thread_);
101
102 for (int i = 0; i < kNumMultiThreadDecoders; ++i)
103 UpdateMD5(multi_thread_dec_[i], pkt, &md5_multi_thread_[i]);
104 }
105
DoTest()106 void DoTest() {
107 const aom_rational timebase = { 33333333, 1000000000 };
108 cfg_.g_timebase = timebase;
109 cfg_.rc_target_bitrate = 500;
110 cfg_.g_lag_in_frames = 12;
111 cfg_.rc_end_usage = AOM_VBR;
112
113 libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 704, 576,
114 timebase.den, timebase.num, 0, 5);
115 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
116
117 const char *md5_single_thread_str = md5_single_thread_.Get();
118
119 for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
120 const char *md5_multi_thread_str = md5_multi_thread_[i].Get();
121 ASSERT_STREQ(md5_single_thread_str, md5_multi_thread_str);
122 }
123 }
124
125 ::libaom_test::MD5 md5_single_thread_;
126 ::libaom_test::MD5 md5_multi_thread_[kNumMultiThreadDecoders];
127 ::libaom_test::Decoder *single_thread_dec_;
128 ::libaom_test::Decoder *multi_thread_dec_[kNumMultiThreadDecoders];
129
130 private:
131 int n_tile_cols_;
132 int n_tile_rows_;
133 int n_tile_groups_;
134 int set_cpu_used_;
135 int row_mt_;
136 };
137
138 // run an encode and do the decode both in single thread
139 // and multi thread. Ensure that the MD5 of the output in both cases
140 // is identical. If so, the test passes.
TEST_P(AV1DecodeMultiThreadedTest,MD5Match)141 TEST_P(AV1DecodeMultiThreadedTest, MD5Match) {
142 cfg_.large_scale_tile = 0;
143 single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
144 for (int i = 0; i < kNumMultiThreadDecoders; ++i)
145 multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
146 DoTest();
147 }
148
149 class AV1DecodeMultiThreadedTestLarge : public AV1DecodeMultiThreadedTest {};
150
TEST_P(AV1DecodeMultiThreadedTestLarge,MD5Match)151 TEST_P(AV1DecodeMultiThreadedTestLarge, MD5Match) {
152 cfg_.large_scale_tile = 0;
153 single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
154 for (int i = 0; i < kNumMultiThreadDecoders; ++i)
155 multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
156 DoTest();
157 }
158
159 // TODO(ranjit): More tests have to be added using pre-generated MD5.
160 AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTest, ::testing::Values(1, 2),
161 ::testing::Values(1, 2), ::testing::Values(1),
162 ::testing::Values(3), ::testing::Values(0, 1));
163 AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedTestLarge,
164 ::testing::Values(0, 1, 2, 6),
165 ::testing::Values(0, 1, 2, 6),
166 ::testing::Values(1, 4), ::testing::Values(0),
167 ::testing::Values(0, 1));
168
169 class AV1DecodeMultiThreadedLSTestLarge
170 : public AV1DecodeMultiThreadedTestLarge {};
171
TEST_P(AV1DecodeMultiThreadedLSTestLarge,MD5Match)172 TEST_P(AV1DecodeMultiThreadedLSTestLarge, MD5Match) {
173 cfg_.large_scale_tile = 1;
174 single_thread_dec_->Control(AV1_SET_TILE_MODE, 1);
175 for (int i = 0; i < kNumMultiThreadDecoders; ++i)
176 multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 1);
177 DoTest();
178 }
179
180 AV1_INSTANTIATE_TEST_CASE(AV1DecodeMultiThreadedLSTestLarge,
181 ::testing::Values(6), ::testing::Values(6),
182 ::testing::Values(1), ::testing::Values(0, 3),
183 ::testing::Values(0, 1));
184
185 } // namespace
186