|
| 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: |
| 37 | + AACDecoder() : mAACDecoder(nullptr), mStreamInfo(nullptr) {} |
| 38 | + |
| 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 | + |
| 54 | + ~AACDecoder() { |
| 55 | + if (mAACDecoder) { |
| 56 | + aacDecoder_Close(mAACDecoder); |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + int getChannels() const { return mStreamInfo ? mStreamInfo->numChannels : 0; } |
| 61 | + int getFrameSize() const { return mStreamInfo ? mStreamInfo->frameSize : 0; } |
| 62 | + int getSampleRate() const { return mStreamInfo ? mStreamInfo->sampleRate : 0; } |
| 63 | + |
| 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: |
| 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 | + |
| 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 | + |
| 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 | + |
| 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 |
| 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: |
| 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 | + |
| 259 | +bool CustomCsvReporter::ReportContext(const Context& context /* __unused */) { return true; } |
| 260 | + |
| 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 | + |
| 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 | + |
| 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 | +} |
0 commit comments