xref: /aosp_15_r20/external/aac/tests/AacDecBenchmark/AacDecBenchmark.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
1 /******************************************************************************
2  *
3  * Copyright (C) 2024 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  */
19 
20 #include <benchmark/benchmark.h>
21 #include <log/log.h>
22 
23 #include <cstdio>
24 #include <iostream>
25 #include <memory>
26 #include <string>
27 #include <vector>
28 
29 #include "aacdecoder_lib.h"
30 
31 class AACDecoder {
32    private:
33     HANDLE_AACDECODER mAACDecoder;
34     CStreamInfo* mStreamInfo;
35 
36    public:
AACDecoder()37     AACDecoder() : mAACDecoder(nullptr), mStreamInfo(nullptr) {}
38 
initialize()39     bool initialize() {
40         mAACDecoder = aacDecoder_Open(TT_MP4_RAW, 1);
41         if (!mAACDecoder) {
42             ALOGE("Failed to initialize AAC decoder");
43             return false;
44         }
45 
46         mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
47         if (!mStreamInfo) {
48             ALOGE("Failed to get stream info after initialization");
49             return false;
50         }
51         return true;
52     }
53 
~AACDecoder()54     ~AACDecoder() {
55         if (mAACDecoder) {
56             aacDecoder_Close(mAACDecoder);
57         }
58     }
59 
getChannels() const60     int getChannels() const { return mStreamInfo ? mStreamInfo->numChannels : 0; }
getFrameSize() const61     int getFrameSize() const { return mStreamInfo ? mStreamInfo->frameSize : 0; }
getSampleRate() const62     int getSampleRate() const { return mStreamInfo ? mStreamInfo->sampleRate : 0; }
63 
decode(const std::vector<std::pair<std::vector<uint8_t>,int>> & inputBuffers)64     bool decode(const std::vector<std::pair<std::vector<uint8_t>, int>>& inputBuffers) {
65         for (const auto& [buffer, flag] : inputBuffers) {
66             std::vector<INT_PCM> frameOutput;
67             if (flag == 2) {
68                 if (!configureDecoder(buffer)) {
69                     return false;
70                 }
71             } else {
72                 if (!decodeFrame(buffer, frameOutput)) {
73                     return false;
74                 }
75             }
76         }
77         return true;
78     }
79 
80    private:
configureDecoder(const std::vector<uint8_t> & configBuffer)81     bool configureDecoder(const std::vector<uint8_t>& configBuffer) {
82         UINT bytesRead = configBuffer.size();
83         UCHAR* configData = const_cast<UCHAR*>(configBuffer.data());
84         UCHAR* configArray[1] = {configData};
85 
86         AAC_DECODER_ERROR err = aacDecoder_ConfigRaw(mAACDecoder, configArray, &bytesRead);
87         if (err != AAC_DEC_OK) {
88             ALOGE("Failed to configure decoder: error %d", err);
89             return false;
90         }
91         return true;
92     }
93 
decodeFrame(const std::vector<uint8_t> & inputBuffer,std::vector<INT_PCM> & outputBuffer)94     bool decodeFrame(const std::vector<uint8_t>& inputBuffer, std::vector<INT_PCM>& outputBuffer) {
95         constexpr size_t kOutputBufferSize = 10240;
96         UINT bytesRead = inputBuffer.size();
97         UINT validBytes = bytesRead;
98         UCHAR* inputPtr = const_cast<UCHAR*>(inputBuffer.data());
99         UCHAR* bufferArray[1] = {inputPtr};
100 
101         AAC_DECODER_ERROR err = aacDecoder_Fill(mAACDecoder, bufferArray, &bytesRead, &validBytes);
102         if (err != AAC_DEC_OK) {
103             ALOGE("Failed to fill decoder buffer: error %d", err);
104             return false;
105         }
106 
107         outputBuffer.resize(kOutputBufferSize);  // Ensure buffer is large enough
108         err = aacDecoder_DecodeFrame(mAACDecoder, outputBuffer.data(), outputBuffer.size(), 0);
109         if (err != AAC_DEC_OK) {
110             ALOGE("Failed to decode frame: error %d", err);
111             return false;
112         }
113 
114         outputBuffer.resize(mStreamInfo->numChannels * mStreamInfo->frameSize);
115         return true;
116     }
117 };
118 
readInputFiles(const std::string & folderPath,const std::string & bitstreamFile,const std::string & infoFile)119 std::vector<std::pair<std::vector<uint8_t>, int>> readInputFiles(const std::string& folderPath,
120                                                                  const std::string& bitstreamFile,
121                                                                  const std::string& infoFile) {
122     std::string fullBitstreamPath = folderPath + "/" + bitstreamFile;
123     std::string fullInfoPath = folderPath + "/" + infoFile;
124     std::vector<std::pair<std::vector<uint8_t>, int>> inputBuffers;
125 
126     FILE* bitStreamFilePtr = fopen(fullBitstreamPath.c_str(), "rb");
127     if (!bitStreamFilePtr) {
128         ALOGE("Failed to open bitstream file %s", fullBitstreamPath.c_str());
129         return inputBuffers;
130     }
131 
132     FILE* infoFilePtr = fopen(fullInfoPath.c_str(), "r");
133     if (!infoFilePtr) {
134         ALOGE("Failed to open info file %s", fullInfoPath.c_str());
135         return inputBuffers;
136     }
137 
138     int bufferSize, flag;
139     long pts;
140 
141     while (fscanf(infoFilePtr, "%d %d %ld", &bufferSize, &flag, &pts) == 3) {
142         std::vector<uint8_t> buffer(bufferSize);
143         size_t bytesRead = fread(buffer.data(), 1, bufferSize, bitStreamFilePtr);
144         if (bytesRead != bufferSize) {
145             ALOGE("Failed to read input data");
146             return std::vector<std::pair<std::vector<uint8_t>, int>>();
147         }
148         inputBuffers.emplace_back(std::move(buffer), flag);
149     }
150 
151     fclose(bitStreamFilePtr);
152     fclose(infoFilePtr);
153     return inputBuffers;
154 }
155 
BM_DecodeAAC(benchmark::State & state,const std::string & inpFolderPath,const std::string & bitstreamFile,const std::string & infoFile)156 static void BM_DecodeAAC(benchmark::State& state, const std::string& inpFolderPath,
157                          const std::string& bitstreamFile, const std::string& infoFile) {
158     auto inputBuffers = readInputFiles(inpFolderPath, bitstreamFile, infoFile);
159     if(inputBuffers.empty()) {
160         state.SkipWithError("Failed to read input data completely");
161     }
162     AACDecoder decoder;
163 
164     if (!decoder.initialize()) {
165         state.SkipWithError("Unable to initialize decoder");
166     }
167 
168     for (auto _ : state) {
169         if(!decoder.decode(inputBuffers)) {
170             state.SkipWithError("Unable to decode the Stream");
171         }
172     }
173 
174     state.SetLabel(bitstreamFile + ", " + std::to_string(decoder.getChannels()) + ", "
175                    + std::to_string(decoder.getSampleRate()) + ", "
176                    + std::to_string(decoder.getFrameSize()));
177 }
178 
179 // Function to register benchmarks
RegisterBenchmarks(const std::string & folderPath)180 void RegisterBenchmarks(const std::string& folderPath) {
181     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_8kHz_64kbps_lc", BM_DecodeAAC,
182                                  folderPath, "bbb_1ch_8kHz_64kbps_lc.bin",
183                                  "bbb_1ch_8kHz_64kbps_lc.info");
184     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_lc", BM_DecodeAAC,
185                                  folderPath, "bbb_1ch_48kHz_128kbps_lc.bin",
186                                  "bbb_1ch_48kHz_128kbps_lc.info");
187     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_8kHz_64kbps_lc", BM_DecodeAAC,
188                                  folderPath, "bbb_2ch_8kHz_64kbps_lc.bin",
189                                  "bbb_2ch_8kHz_64kbps_lc.info");
190     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_lc", BM_DecodeAAC,
191                                  folderPath, "bbb_2ch_48kHz_128kbps_lc.bin",
192                                  "bbb_2ch_48kHz_128kbps_lc.info");
193     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_8kHz_64kbps_lc", BM_DecodeAAC,
194                                  folderPath, "bbb_6ch_8kHz_64kbps_lc.bin",
195                                  "bbb_6ch_8kHz_64kbps_lc.info");
196     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_lc", BM_DecodeAAC,
197                                  folderPath, "bbb_6ch_48kHz_128kbps_lc.bin",
198                                  "bbb_6ch_48kHz_128kbps_lc.info");
199     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_16kHz_64kbps_he", BM_DecodeAAC,
200                                  folderPath, "bbb_1ch_16kHz_64kbps_he.bin",
201                                  "bbb_1ch_16kHz_64kbps_he.info");
202     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_he", BM_DecodeAAC,
203                                  folderPath, "bbb_1ch_48kHz_128kbps_he.bin",
204                                  "bbb_1ch_48kHz_128kbps_he.info");
205     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_he", BM_DecodeAAC,
206                                  folderPath, "bbb_2ch_16kHz_64kbps_he.bin",
207                                  "bbb_2ch_16kHz_64kbps_he.info");
208     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_he", BM_DecodeAAC,
209                                  folderPath, "bbb_2ch_48kHz_128kbps_he.bin",
210                                  "bbb_2ch_48kHz_128kbps_he.info");
211     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_hev2", BM_DecodeAAC,
212                                  folderPath, "bbb_2ch_16kHz_64kbps_hev2.bin",
213                                  "bbb_2ch_16kHz_64kbps_hev2.info");
214     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_hev2", BM_DecodeAAC,
215                                  folderPath, "bbb_2ch_48kHz_128kbps_hev2.bin",
216                                  "bbb_2ch_48kHz_128kbps_hev2.info");
217     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_ld", BM_DecodeAAC,
218                                  folderPath, "bbb_1ch_48kHz_128kbps_ld.bin",
219                                  "bbb_1ch_48kHz_128kbps_ld.info");
220     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_ld", BM_DecodeAAC,
221                                  folderPath, "bbb_2ch_48kHz_128kbps_ld.bin",
222                                  "bbb_2ch_48kHz_128kbps_ld.info");
223     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_ld", BM_DecodeAAC,
224                                  folderPath, "bbb_6ch_48kHz_128kbps_ld.bin",
225                                  "bbb_6ch_48kHz_128kbps_ld.info");
226     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_16kHz_64kbps_eld", BM_DecodeAAC,
227                                  folderPath, "bbb_1ch_16kHz_64kbps_eld.bin",
228                                  "bbb_1ch_16kHz_64kbps_eld.info");
229     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_1ch_48kHz_128kbps_eld", BM_DecodeAAC,
230                                  folderPath, "bbb_1ch_48kHz_128kbps_eld.bin",
231                                  "bbb_1ch_48kHz_128kbps_eld.info");
232     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_16kHz_64kbps_eld", BM_DecodeAAC,
233                                  folderPath, "bbb_2ch_16kHz_64kbps_eld.bin",
234                                  "bbb_2ch_16kHz_64kbps_eld.info");
235     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_2ch_48kHz_128kbps_eld", BM_DecodeAAC,
236                                  folderPath, "bbb_2ch_48kHz_128kbps_eld.bin",
237                                  "bbb_2ch_48kHz_128kbps_eld.info");
238     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_16kHz_64kbps_eld", BM_DecodeAAC,
239                                  folderPath, "bbb_6ch_16kHz_64kbps_eld.bin",
240                                  "bbb_6ch_16kHz_64kbps_eld.info");
241     benchmark::RegisterBenchmark("BM_DecodeAAC/bbb_6ch_48kHz_128kbps_eld", BM_DecodeAAC,
242                                  folderPath, "bbb_6ch_48kHz_128kbps_eld.bin",
243                                  "bbb_6ch_48kHz_128kbps_eld.info");
244 }
245 
246 class CustomCsvReporter : public benchmark::BenchmarkReporter {
247    public:
CustomCsvReporter()248     CustomCsvReporter() : mPrintedHeader(false) {}
249     virtual bool ReportContext(const Context& context);
250     virtual void ReportRuns(const std::vector<Run>& reports);
251 
252    private:
253     void PrintRunData(const Run& report);
254     bool mPrintedHeader;
255     std::vector<std::string> mHeaders = {"File",      "Channels",      "SampleRate",
256                                          "FrameSize", "real_time(ns)", "cpu_time(ns)"};
257 };
258 
ReportContext(const Context & context)259 bool CustomCsvReporter::ReportContext(const Context& context /* __unused */) { return true; }
260 
ReportRuns(const std::vector<Run> & reports)261 void CustomCsvReporter::ReportRuns(const std::vector<Run>& reports) {
262     std::ostream& Out = GetOutputStream();
263 
264     if (!mPrintedHeader) {
265         // print the header
266         for (auto header = mHeaders.begin(); header != mHeaders.end();) {
267             Out << *header++;
268             if (header != mHeaders.end()) Out << ",";
269         }
270         Out << "\n";
271         mPrintedHeader = true;
272     }
273 
274     // print results for each run
275     for (const auto& run : reports) {
276         PrintRunData(run);
277     }
278 }
279 
PrintRunData(const Run & run)280 void CustomCsvReporter::PrintRunData(const Run& run) {
281     if (run.skipped) {
282         return;
283     }
284     std::ostream& Out = GetOutputStream();
285     Out << run.report_label << ",";
286     Out << run.GetAdjustedRealTime() << ",";
287     Out << run.GetAdjustedCPUTime() << ",";
288     Out << '\n';
289 }
290 
main(int argc,char ** argv)291 int main(int argc, char** argv) {
292     std::unique_ptr<benchmark::BenchmarkReporter> csvReporter;
293     std::string pathArg, inpFolderPath;
294 
295     for (int i = 1; i < argc; ++i) {
296         // pass --path=/path/to/resourcefolder in command line while running without atest
297         // to specify where resources are present
298         if (std::string(argv[i]).find("--path") != std::string ::npos) {
299             pathArg = argv[i];
300             auto separator = pathArg.find('=');
301             if (separator != std::string::npos) {
302                 inpFolderPath = pathArg.substr(separator + 1);
303             }
304         }
305         // pass --benchmark_out=/path/to/.csv in command line to generate csv report
306         if (std::string(argv[i]).find("--benchmark_out") != std::string::npos) {
307             csvReporter.reset(new CustomCsvReporter);
308             break;
309         }
310     }
311 
312     if (inpFolderPath.empty()) {
313         inpFolderPath = "/sdcard/test/AacDecBenchmark-1.0";
314     }
315     RegisterBenchmarks(inpFolderPath);
316     benchmark::Initialize(&argc, argv);
317     benchmark::RunSpecifiedBenchmarks(nullptr, csvReporter.get());
318     benchmark::Shutdown();
319     return 0;
320 }
321