xref: /aosp_15_r20/external/libaom/test/decode_multithreaded_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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 "gtest/gtest.h"
18 #include "test/codec_factory.h"
19 #include "test/encode_test_driver.h"
20 #include "test/i420_video_source.h"
21 #include "test/md5_helper.h"
22 #include "test/util.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   ~AV1DecodeMultiThreadedTest() override {
67     delete single_thread_dec_;
68     for (int i = 0; i < kNumMultiThreadDecoders; ++i)
69       delete multi_thread_dec_[i];
70   }
71 
SetUp()72   void SetUp() override { InitializeConfig(libaom_test::kTwoPassGood); }
73 
PreEncodeFrameHook(libaom_test::VideoSource * video,libaom_test::Encoder * encoder)74   void PreEncodeFrameHook(libaom_test::VideoSource *video,
75                           libaom_test::Encoder *encoder) override {
76     if (video->frame() == 0) {
77       encoder->Control(AV1E_SET_TILE_COLUMNS, n_tile_cols_);
78       encoder->Control(AV1E_SET_TILE_ROWS, n_tile_rows_);
79       encoder->Control(AV1E_SET_NUM_TG, n_tile_groups_);
80       encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
81     }
82   }
83 
UpdateMD5(::libaom_test::Decoder * dec,const aom_codec_cx_pkt_t * pkt,::libaom_test::MD5 * md5)84   void UpdateMD5(::libaom_test::Decoder *dec, const aom_codec_cx_pkt_t *pkt,
85                  ::libaom_test::MD5 *md5) {
86     const aom_codec_err_t res = dec->DecodeFrame(
87         reinterpret_cast<uint8_t *>(pkt->data.frame.buf), pkt->data.frame.sz);
88     if (res != AOM_CODEC_OK) {
89       abort_ = true;
90       ASSERT_EQ(AOM_CODEC_OK, res);
91     }
92     const aom_image_t *img = dec->GetDxData().Next();
93     md5->Add(img);
94   }
95 
FramePktHook(const aom_codec_cx_pkt_t * pkt)96   void FramePktHook(const aom_codec_cx_pkt_t *pkt) override {
97     UpdateMD5(single_thread_dec_, pkt, &md5_single_thread_);
98 
99     for (int i = 0; i < kNumMultiThreadDecoders; ++i)
100       UpdateMD5(multi_thread_dec_[i], pkt, &md5_multi_thread_[i]);
101   }
102 
DoTest()103   void DoTest() {
104     const aom_rational timebase = { 33333333, 1000000000 };
105     cfg_.g_timebase = timebase;
106     cfg_.rc_target_bitrate = 500;
107     cfg_.g_lag_in_frames = 12;
108     cfg_.rc_end_usage = AOM_VBR;
109 
110     libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 704, 576,
111                                        timebase.den, timebase.num, 0, 2);
112     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
113 
114     const char *md5_single_thread_str = md5_single_thread_.Get();
115 
116     for (int i = 0; i < kNumMultiThreadDecoders; ++i) {
117       const char *md5_multi_thread_str = md5_multi_thread_[i].Get();
118       ASSERT_STREQ(md5_single_thread_str, md5_multi_thread_str);
119     }
120   }
121 
122   ::libaom_test::MD5 md5_single_thread_;
123   ::libaom_test::MD5 md5_multi_thread_[kNumMultiThreadDecoders];
124   ::libaom_test::Decoder *single_thread_dec_;
125   ::libaom_test::Decoder *multi_thread_dec_[kNumMultiThreadDecoders];
126 
127  private:
128   int n_tile_cols_;
129   int n_tile_rows_;
130   int n_tile_groups_;
131   int set_cpu_used_;
132   int row_mt_;
133 };
134 
135 // run an encode and do the decode both in single thread
136 // and multi thread. Ensure that the MD5 of the output in both cases
137 // is identical. If so, the test passes.
TEST_P(AV1DecodeMultiThreadedTest,MD5Match)138 TEST_P(AV1DecodeMultiThreadedTest, MD5Match) {
139   cfg_.large_scale_tile = 0;
140   single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
141   for (int i = 0; i < kNumMultiThreadDecoders; ++i)
142     multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
143   DoTest();
144 }
145 
146 class AV1DecodeMultiThreadedTestLarge : public AV1DecodeMultiThreadedTest {};
147 
TEST_P(AV1DecodeMultiThreadedTestLarge,MD5Match)148 TEST_P(AV1DecodeMultiThreadedTestLarge, MD5Match) {
149   cfg_.large_scale_tile = 0;
150   single_thread_dec_->Control(AV1_SET_TILE_MODE, 0);
151   for (int i = 0; i < kNumMultiThreadDecoders; ++i)
152     multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 0);
153   DoTest();
154 }
155 
156 // TODO(ranjit): More tests have to be added using pre-generated MD5.
157 AV1_INSTANTIATE_TEST_SUITE(AV1DecodeMultiThreadedTest, ::testing::Values(1, 2),
158                            ::testing::Values(1, 2), ::testing::Values(1),
159                            ::testing::Values(3), ::testing::Values(0, 1));
160 AV1_INSTANTIATE_TEST_SUITE(AV1DecodeMultiThreadedTestLarge,
161                            ::testing::Values(0, 1, 2, 6),
162                            ::testing::Values(0, 1, 2, 6),
163                            ::testing::Values(1, 4), ::testing::Values(0),
164                            ::testing::Values(0, 1));
165 
166 class AV1DecodeMultiThreadedLSTestLarge
167     : public AV1DecodeMultiThreadedTestLarge {};
168 
TEST_P(AV1DecodeMultiThreadedLSTestLarge,MD5Match)169 TEST_P(AV1DecodeMultiThreadedLSTestLarge, MD5Match) {
170   cfg_.large_scale_tile = 1;
171   single_thread_dec_->Control(AV1_SET_TILE_MODE, 1);
172   for (int i = 0; i < kNumMultiThreadDecoders; ++i)
173     multi_thread_dec_[i]->Control(AV1_SET_TILE_MODE, 1);
174   DoTest();
175 }
176 
177 AV1_INSTANTIATE_TEST_SUITE(AV1DecodeMultiThreadedLSTestLarge,
178                            ::testing::Values(6), ::testing::Values(6),
179                            ::testing::Values(1), ::testing::Values(0, 3),
180                            ::testing::Values(0, 1));
181 
182 }  // namespace
183