• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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