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