• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <iostream>
24 #include <sys/stat.h>
25 #include <vector>
26 
27 #include "aacenc_lib.h"
28 
29 class AACEncoder {
30    private:
31     HANDLE_AACENCODER mAACEncoder;
32     AACENC_InfoStruct mEncInfo;
33     const AUDIO_OBJECT_TYPE mProfile;
34     const CHANNEL_MODE mChannelCount;
35     const int mSampleRate;
36     const int mBitRate;
37 
38    public:
AACEncoder(int sampleRate,int bitRate,AUDIO_OBJECT_TYPE profile,CHANNEL_MODE channelCount)39     AACEncoder(int sampleRate, int bitRate, AUDIO_OBJECT_TYPE profile, CHANNEL_MODE channelCount)
40         : mAACEncoder(nullptr), mProfile(profile), mChannelCount(channelCount),
41         mSampleRate(sampleRate), mBitRate(bitRate) {}
42 
initialize()43     bool initialize() {
44         if (aacEncOpen(&mAACEncoder, 0, 0) != AACENC_OK) {
45             ALOGE("Failed to initialize AAC encoder");
46             return false;
47         }
48 
49         if (aacEncoder_SetParam(mAACEncoder, AACENC_AOT, mProfile) != AACENC_OK
50             || aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mSampleRate) != AACENC_OK
51             || aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE, mChannelCount) != AACENC_OK
52             || aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mBitRate) != AACENC_OK
53             || aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW) != AACENC_OK) {
54             ALOGE("Failed to set AAC encoder parameters");
55             return false;
56         }
57 
58         if (aacEncEncode(mAACEncoder, nullptr, nullptr, nullptr, nullptr) != AACENC_OK) {
59             ALOGE("Unable to initialize encoder for profile:%d, sample-rate: %d, bit-rate: %d, "
60                 "channels: %d", mProfile, mSampleRate, mBitRate, mChannelCount);
61             return false;
62         }
63 
64         if (aacEncInfo(mAACEncoder, &mEncInfo) != AACENC_OK) {
65             ALOGE("Failed to get AAC encoder info");
66             return false;
67         }
68         return true;
69     }
70 
~AACEncoder()71     ~AACEncoder() {
72         if (mAACEncoder) {
73             aacEncClose(&mAACEncoder);
74         }
75     }
76 
getChannels() const77     int getChannels() const { return aacEncoder_GetParam(mAACEncoder, AACENC_CHANNELMODE); }
getSampleRate() const78     int getSampleRate() const { return aacEncoder_GetParam(mAACEncoder, AACENC_SAMPLERATE); }
getBitRate() const79     int getBitRate() const { return aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); }
getProfile() const80     int getProfile() const { return aacEncoder_GetParam(mAACEncoder, AACENC_AOT); }
81 
encode(const std::vector<uint8_t> & pcmFrames)82     bool encode(const std::vector<uint8_t>& pcmFrames) {
83         size_t frameSize = mEncInfo.frameLength * mChannelCount * sizeof(uint16_t);
84         std::vector<uint8_t> encodedBuffer(frameSize);
85         AACENC_BufDesc inBufDesc, outBufDesc;
86         AACENC_InArgs inArgs;
87         AACENC_OutArgs outArgs;
88 
89         void* outBuffer[] = {encodedBuffer.data()};
90         int outBufferIds[] = {OUT_BITSTREAM_DATA};
91         int outBufferSize[] = {static_cast<int>(encodedBuffer.size())};
92         int outBufferElSize[] = {sizeof(UCHAR)};
93 
94         outBufDesc.numBufs = sizeof(outBuffer) / sizeof(void*);
95         outBufDesc.bufs = (void**)&outBuffer;
96         outBufDesc.bufferIdentifiers = outBufferIds;
97         outBufDesc.bufSizes = outBufferSize;
98         outBufDesc.bufElSizes = outBufferElSize;
99 
100         size_t numFrames = pcmFrames.size() / frameSize;
101 
102         for (size_t frameIdx = 0; ; ++frameIdx) {
103 
104             const uint8_t* frameData = nullptr;
105             void* inBuffer[1];
106             int inBufferSize[1];
107             if (frameIdx < numFrames) {
108                 frameData = pcmFrames.data() + frameIdx * frameSize;
109             }
110 
111             if (frameData != nullptr) {
112                 inBuffer[0] = const_cast<uint8_t*>(frameData);
113                 inBufferSize[0] = static_cast<int>(frameSize);
114                 inArgs.numInSamples = frameSize / sizeof(uint16_t);
115             } else {
116                 inBuffer[0] = nullptr;
117                 inBufferSize[0] = 0;
118                 inArgs.numInSamples = -1;
119             }
120 
121             int inBufferIds[] = {IN_AUDIO_DATA};
122             int inBufferElSize[] = {sizeof(int16_t)};
123 
124             inBufDesc.numBufs = sizeof(inBuffer) / sizeof(void*);
125             inBufDesc.bufs = (void**)&inBuffer;
126             inBufDesc.bufferIdentifiers = inBufferIds;
127             inBufDesc.bufSizes = inBufferSize;
128             inBufDesc.bufElSizes = inBufferElSize;
129             AACENC_ERROR err =
130                 aacEncEncode(mAACEncoder, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
131             if (err != AACENC_OK) {
132                 if (err == AACENC_ENCODE_EOF) {
133                     break;
134                 }
135                 ALOGE("Failed to encode AAC frame");
136                 return false;
137             }
138         }
139         return true;
140     }
141 };
142 
readInputFile(const std::string & folderPath,const std::string & pcmFile)143 std::vector<uint8_t> readInputFile(const std::string& folderPath, const std::string& pcmFile) {
144     std::string fullPcmPath = folderPath + "/" + pcmFile;
145     std::vector<uint8_t> inputBuffer;
146 
147     FILE* pcmFilePtr = fopen(fullPcmPath.c_str(), "rb");
148     if (!pcmFilePtr) {
149         ALOGE("Failed to open pcm file %s", fullPcmPath.c_str());
150         return inputBuffer;
151     }
152 
153     struct stat fileStat;
154     int fd = fileno(pcmFilePtr);
155 
156     if (fstat(fd, &fileStat) == -1) {
157         ALOGE("Error occured while accessing the pcm file");
158         return inputBuffer;
159     }
160     size_t fileSize = fileStat.st_size;
161     inputBuffer.resize(fileSize);
162     size_t bytesRead = fread(inputBuffer.data(), sizeof(uint8_t), inputBuffer.size(), pcmFilePtr);
163     if (bytesRead != fileSize) {
164         ALOGE("Failed to read the complete pcm data");
165         return std::vector<uint8_t>();
166     }
167 
168     fclose(pcmFilePtr);
169     return inputBuffer;
170 }
171 
BM_EncodeAAC(benchmark::State & state,const std::string & inpFolderPath,const std::string & pcmFile,const int sampleRate,const int bitRate,const AUDIO_OBJECT_TYPE profile,const CHANNEL_MODE channelCount)172 static void BM_EncodeAAC(benchmark::State& state, const std::string& inpFolderPath,
173                          const std::string& pcmFile, const int sampleRate, const int bitRate,
174                          const AUDIO_OBJECT_TYPE profile, const CHANNEL_MODE channelCount) {
175     auto inputBuffer = readInputFile(inpFolderPath, pcmFile);
176     if (inputBuffer.empty()) {
177         state.SkipWithError("Failed to read input from pcm file");
178         return;
179     }
180     AACEncoder encoder(sampleRate, bitRate, profile, channelCount);
181 
182     if (!encoder.initialize()) {
183         state.SkipWithError("Unable to initialize encoder");
184         return;
185     }
186 
187     for (auto _ : state) {
188         if (!encoder.encode(inputBuffer)) {
189             state.SkipWithError("Unable to encode the Stream");
190             return;
191         }
192     }
193 
194     state.SetLabel(pcmFile + ", " + std::to_string(encoder.getChannels()) + ", "
195                    + std::to_string(encoder.getSampleRate()) + ", "
196                    + std::to_string(encoder.getBitRate()) + ", "
197                    + std::to_string(encoder.getProfile()));
198 }
199 
RegisterBenchmarks(const std::string & folderPath)200 void RegisterBenchmarks(const std::string& folderPath) {
201     // testlabel, BM function, folderpath, pcm file, sampleRate, bitRate, profile, ChannelCount
202     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_8kHz_48kbps_lc", BM_EncodeAAC,
203                                 folderPath, "bbb_1ch_8kHz.pcm", 8000, 48000, AOT_AAC_LC,
204                                 MODE_1);
205     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_48kHz_128kbps_lc", BM_EncodeAAC,
206                                 folderPath, "bbb_1ch_48kHz.pcm", 48000, 128000, AOT_AAC_LC,
207                                 MODE_1);
208     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_48kHz_128kbps_lc", BM_EncodeAAC,
209                                 folderPath, "bbb_2ch_48kHz.pcm", 48000, 128000, AOT_AAC_LC,
210                                 MODE_2);
211     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_6ch_48kHz_128kbps_lc", BM_EncodeAAC,
212                                 folderPath, "bbb_6ch_48kHz.pcm", 48000, 128000, AOT_AAC_LC,
213                                 MODE_1_2_2_1);
214     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_16kHz_48kbps_he", BM_EncodeAAC,
215                                 folderPath, "bbb_1ch_16kHz.pcm", 16000, 48000, AOT_SBR,
216                                 MODE_1);
217     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_48kHz_128kbps_he", BM_EncodeAAC,
218                                 folderPath, "bbb_1ch_48kHz.pcm", 48000, 128000, AOT_SBR,
219                                 MODE_1);
220     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_48kHz_128kbps_he", BM_EncodeAAC,
221                                 folderPath, "bbb_2ch_48kHz.pcm", 48000, 128000, AOT_SBR,
222                                 MODE_2);
223     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_16kHz_48kbps_hev2", BM_EncodeAAC,
224                                 folderPath, "bbb_2ch_16kHz.pcm", 16000, 48000, AOT_PS,
225                                 MODE_2);
226     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_48kHz_128kbps_hev2", BM_EncodeAAC,
227                                 folderPath, "bbb_2ch_48kHz.pcm", 48000, 128000, AOT_PS,
228                                 MODE_2);
229     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_48kHz_128kbps_ld", BM_EncodeAAC,
230                                 folderPath, "bbb_1ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_LD,
231                                 MODE_1);
232     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_48kHz_128kbps_ld", BM_EncodeAAC,
233                                 folderPath, "bbb_2ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_LD,
234                                 MODE_2);
235     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_6ch_48kHz_128kbps_ld", BM_EncodeAAC,
236                                 folderPath, "bbb_6ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_LD,
237                                 MODE_1_2_2_1);
238     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_16kHz_64kbps_eld", BM_EncodeAAC,
239                                 folderPath, "bbb_1ch_16kHz.pcm", 16000, 64000, AOT_ER_AAC_ELD,
240                                 MODE_1);
241     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_1ch_48kHz_128kbps_eld", BM_EncodeAAC,
242                                 folderPath, "bbb_1ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_ELD,
243                                 MODE_1);
244     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_16kHz_64kbps_eld", BM_EncodeAAC,
245                                 folderPath, "bbb_2ch_16kHz.pcm", 16000, 64000, AOT_ER_AAC_ELD,
246                                 MODE_2);
247     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_2ch_48kHz_128kbps_eld", BM_EncodeAAC,
248                                 folderPath, "bbb_2ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_ELD,
249                                 MODE_2);
250     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_6ch_16kHz_64kbps_eld", BM_EncodeAAC,
251                                 folderPath, "bbb_6ch_16kHz.pcm", 16000, 64000, AOT_ER_AAC_ELD,
252                                 MODE_1_2_2_1);
253     benchmark::RegisterBenchmark("BM_EncodeAAC/bbb_6ch_48kHz_128kbps_eld", BM_EncodeAAC,
254                                 folderPath, "bbb_6ch_48kHz.pcm", 48000, 128000, AOT_ER_AAC_ELD,
255                                 MODE_1_2_2_1);
256 }
257 
258 class CustomCsvReporter : public benchmark::BenchmarkReporter {
259    public:
CustomCsvReporter()260     CustomCsvReporter() : mPrintedHeader(false) {};
261     virtual bool ReportContext(const Context& context);
262     virtual void ReportRuns(const std::vector<Run>& reports);
263 
264    private:
265     void PrintRunData(const Run& report);
266     bool mPrintedHeader;
267     std::vector<std::string> mHeaders = {"File",    "Channels",      "SampleRate",  "BitRate",
268                                          "profile", "real_time(ns)", "cpu_time(ns)"};
269 };
270 
ReportContext(const Context & context)271 bool CustomCsvReporter::ReportContext(const Context& context /* __unused */) { return true; }
272 
ReportRuns(const std::vector<Run> & reports)273 void CustomCsvReporter::ReportRuns(const std::vector<Run>& reports) {
274     std::ostream& Out = GetOutputStream();
275 
276     if (!mPrintedHeader) {
277         // print the header
278         for (auto header = mHeaders.begin(); header != mHeaders.end();) {
279             Out << *header++;
280             if (header != mHeaders.end()) Out << ",";
281         }
282         Out << "\n";
283         mPrintedHeader = true;
284     }
285 
286     // print results for each run
287     for (const auto& run : reports) {
288         PrintRunData(run);
289     }
290 }
291 
PrintRunData(const Run & run)292 void CustomCsvReporter::PrintRunData(const Run& run) {
293     if (run.skipped) {
294         return;
295     }
296     std::ostream& Out = GetOutputStream();
297     Out << run.report_label << ",";
298     Out << run.GetAdjustedRealTime() << ",";
299     Out << run.GetAdjustedCPUTime() << ",";
300     Out << '\n';
301 }
302 
main(int argc,char ** argv)303 int main(int argc, char** argv) {
304     std::unique_ptr<benchmark::BenchmarkReporter> csvReporter;
305     std::string pathArg, inpFolderPath;
306 
307     for (int i = 1; i < argc; ++i) {
308         // pass --path=/path/to/resourcefolder in command line while running without atest
309         // to specify where resources are present
310         if (std::string(argv[i]).find("--path") != std::string ::npos) {
311             pathArg = argv[i];
312             auto separator = pathArg.find('=');
313             if (separator != std::string::npos) {
314                 inpFolderPath = pathArg.substr(separator + 1);
315             }
316         }
317         // pass --benchmark_out=/path/to/.csv in command line to generate csv report
318         if (std::string(argv[i]).find("--benchmark_out") != std::string::npos) {
319             csvReporter.reset(new CustomCsvReporter);
320             break;
321         }
322     }
323 
324     if (inpFolderPath.empty()) {
325         inpFolderPath = "/sdcard/test/AacEncBenchmark-1.0";
326     }
327 
328     FILE* pcmFilePath = fopen(inpFolderPath.c_str(), "r");
329     if (!pcmFilePath) {
330         std::cerr << "Error: Invalid path provided: " << inpFolderPath << std::endl;
331         return -1;
332     }
333     fclose(pcmFilePath);
334 
335     RegisterBenchmarks(inpFolderPath);
336     benchmark::Initialize(&argc, argv);
337     benchmark::RunSpecifiedBenchmarks(nullptr, csvReporter.get());
338     benchmark::Shutdown();
339     return 0;
340 }
341