1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * Native media transcoder library benchmark tests.
19  *
20  * How to run the benchmark:
21  *
22  * 1. Download the media assets from http://go/transcodingbenchmark and push the directory
23  *    ("TranscodingBenchmark") to /data/local/tmp.
24  *
25  * 2. Compile the benchmark and sync to device:
26  *      $ mm -j72 && adb sync
27  *
28  * 3. Run:
29  *      $ adb shell /data/nativetest64/MediaTranscoderBenchmark/MediaTranscoderBenchmark
30  */
31 
32 #include <benchmark/benchmark.h>
33 #include <binder/ProcessState.h>
34 #include <fcntl.h>
35 #include <media/MediaTranscoder.h>
36 #include <media/NdkCommon.h>
37 
38 #include <iostream>
39 
40 #include "BenchmarkCommon.h"
41 
42 using namespace android;
43 
44 const std::string PARAM_VIDEO_FRAME_RATE = "VideoFrameRate";
45 
46 class TranscoderCallbacks : public MediaTranscoder::CallbackInterface {
47 public:
onFinished(const MediaTranscoder * transcoder __unused)48     virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
49         std::unique_lock<std::mutex> lock(mMutex);
50         mFinished = true;
51         mCondition.notify_all();
52     }
53 
onError(const MediaTranscoder * transcoder __unused,media_status_t error)54     virtual void onError(const MediaTranscoder* transcoder __unused,
55                          media_status_t error) override {
56         std::unique_lock<std::mutex> lock(mMutex);
57         mFinished = true;
58         mStatus = error;
59         mCondition.notify_all();
60     }
61 
onProgressUpdate(const MediaTranscoder * transcoder __unused,int32_t progress __unused)62     virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
63                                   int32_t progress __unused) override {}
64 
onHeartBeat(const MediaTranscoder * transcoder __unused)65     virtual void onHeartBeat(const MediaTranscoder* transcoder __unused) override {}
66 
onCodecResourceLost(const MediaTranscoder * transcoder __unused,const std::shared_ptr<ndk::ScopedAParcel> & pausedState __unused)67     virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
68                                      const std::shared_ptr<ndk::ScopedAParcel>& pausedState
69                                              __unused) override {}
70 
waitForTranscodingFinished()71     bool waitForTranscodingFinished() {
72         std::unique_lock<std::mutex> lock(mMutex);
73         while (!mFinished) {
74             if (mCondition.wait_for(lock, std::chrono::minutes(5)) == std::cv_status::timeout) {
75                 return false;
76             }
77         }
78         return true;
79     }
80 
81     media_status_t mStatus = AMEDIA_OK;
82 
83 private:
84     std::mutex mMutex;
85     std::condition_variable mCondition;
86     bool mFinished = false;
87 };
88 
CreateDefaultVideoFormat()89 static AMediaFormat* CreateDefaultVideoFormat() {
90     // Default bitrate
91     static constexpr int32_t kVideoBitRate = 20 * 1000 * 1000;  // 20Mbs
92 
93     AMediaFormat* videoFormat = AMediaFormat_new();
94     AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate);
95     AMediaFormat_setString(videoFormat, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
96     return videoFormat;
97 }
98 
99 /**
100  * Callback to configure tracks for transcoding.
101  * @param mime The source track mime type.
102  * @param dstFormat The destination format if the track should be transcoded or nullptr if the track
103  * should be passed through.
104  * @return True if the track should be included in the output file.
105  */
106 using TrackSelectionCallback = std::function<bool(const char* mime, AMediaFormat** dstFormat)>;
107 
TranscodeMediaFile(benchmark::State & state,const std::string & srcFileName,const std::string & dstFileName,TrackSelectionCallback trackSelectionCallback)108 static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName,
109                                const std::string& dstFileName,
110                                TrackSelectionCallback trackSelectionCallback) {
111     // Write-only, create file if non-existent.
112     static constexpr int kDstOpenFlags = O_WRONLY | O_CREAT;
113     // User R+W permission.
114     static constexpr int kDstFileMode = S_IRUSR | S_IWUSR;
115 
116     // Transcoding configuration params to be logged
117     int64_t trackDurationUs = 0;
118     int32_t width = 0;
119     int32_t height = 0;
120     std::string sourceMime = "NA";
121     std::string targetMime = "NA";
122     bool includeAudio = false;
123     bool transcodeVideo = false;
124     int32_t targetBitrate = 0;
125 
126     int srcFd = 0;
127     int dstFd = 0;
128 
129     std::string srcPath = kAssetDirectory + srcFileName;
130     std::string dstPath = kAssetDirectory + dstFileName;
131 
132     media_status_t status = AMEDIA_OK;
133 
134     if ((srcFd = open(srcPath.c_str(), O_RDONLY)) < 0) {
135         state.SkipWithError("Unable to open source file: " + srcPath);
136         goto exit;
137     }
138     if ((dstFd = open(dstPath.c_str(), kDstOpenFlags, kDstFileMode)) < 0) {
139         state.SkipWithError("Unable to open destination file: " + dstPath);
140         goto exit;
141     }
142 
143     for (auto _ : state) {
144         auto callbacks = std::make_shared<TranscoderCallbacks>();
145         auto transcoder = MediaTranscoder::create(callbacks);
146 
147         status = transcoder->configureSource(srcFd);
148         if (status != AMEDIA_OK) {
149             state.SkipWithError("Unable to configure transcoder source");
150             goto exit;
151         }
152 
153         status = transcoder->configureDestination(dstFd);
154         if (status != AMEDIA_OK) {
155             state.SkipWithError("Unable to configure transcoder destination");
156             goto exit;
157         }
158 
159         std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
160         for (int i = 0; i < trackFormats.size(); ++i) {
161             AMediaFormat* srcFormat = trackFormats[i].get();
162             AMediaFormat* dstFormat = nullptr;
163 
164             const char* mime = nullptr;
165             if (!AMediaFormat_getString(srcFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
166                 state.SkipWithError("Source track format does not have MIME type");
167                 goto exit;
168             }
169 
170             if (strncmp(mime, "video/", 6) == 0) {
171                 int32_t frameCount;
172                 if (AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount)) {
173                     state.counters[PARAM_VIDEO_FRAME_RATE] = benchmark::Counter(
174                             frameCount, benchmark::Counter::kIsIterationInvariantRate);
175                 }
176                 if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH, &width)) {
177                     state.SkipWithError("Video source track format does not have width");
178                     goto exit;
179                 }
180                 if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
181                     state.SkipWithError("Video source track format does not have height");
182                     goto exit;
183                 }
184                 AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &trackDurationUs);
185                 sourceMime = mime;
186             }
187 
188             if (trackSelectionCallback(mime, &dstFormat)) {
189                 status = transcoder->configureTrackFormat(i, dstFormat);
190                 if (strncmp(mime, "video/", 6) == 0 && dstFormat != nullptr) {
191                     const char* mime = nullptr;
192                     if (AMediaFormat_getString(dstFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
193                         targetMime = mime;
194                     }
195                     AMediaFormat_getInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, &targetBitrate);
196                     transcodeVideo = true;
197                 } else if (strncmp(mime, "audio/", 6) == 0) {
198                     includeAudio = true;
199                 }
200             }
201 
202             if (dstFormat != nullptr) {
203                 AMediaFormat_delete(dstFormat);
204             }
205             if (status != AMEDIA_OK) {
206                 state.SkipWithError("Unable to configure track");
207                 goto exit;
208             }
209         }
210 
211         status = transcoder->start();
212         if (status != AMEDIA_OK) {
213             state.SkipWithError("Unable to start transcoder");
214             goto exit;
215         }
216 
217         if (!callbacks->waitForTranscodingFinished()) {
218             transcoder->cancel();
219             state.SkipWithError("Transcoder timed out");
220             goto exit;
221         }
222         if (callbacks->mStatus != AMEDIA_OK) {
223             state.SkipWithError("Transcoder error when running");
224             goto exit;
225         }
226     }
227 
228     // Set transcoding configuration params in benchmark label
229     state.SetLabel(srcFileName + "," +
230                    std::to_string(width) + "x" + std::to_string(height) + "," +
231                    sourceMime + "," +
232                    std::to_string(trackDurationUs/1000) + "," +
233                    (includeAudio ? "Yes" : "No") + "," +
234                    (transcodeVideo ? "Yes" : "No") + "," +
235                    targetMime + "," +
236                    std::to_string(targetBitrate)
237                    );
238 
239 exit:
240     if (srcFd > 0) close(srcFd);
241     if (dstFd > 0) close(dstFd);
242 }
243 
244 /**
245  * Callback to edit track format for transcoding.
246  * @param dstFormat The default track format for the track type.
247  */
248 using TrackFormatEditCallback = std::function<void(AMediaFormat* dstFormat)>;
249 
TranscodeMediaFile(benchmark::State & state,const std::string & srcFileName,const std::string & dstFileName,bool includeAudio,bool transcodeVideo,const TrackFormatEditCallback & videoFormatEditor=nullptr)250 static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName,
251                                const std::string& dstFileName, bool includeAudio,
252                                bool transcodeVideo,
253                                const TrackFormatEditCallback& videoFormatEditor = nullptr) {
254     TranscodeMediaFile(state, srcFileName, dstFileName,
255                        [=](const char* mime, AMediaFormat** dstFormatOut) -> bool {
256                            *dstFormatOut = nullptr;
257                            if (strncmp(mime, "video/", 6) == 0 && transcodeVideo) {
258                                *dstFormatOut = CreateDefaultVideoFormat();
259                                if (videoFormatEditor != nullptr) {
260                                    videoFormatEditor(*dstFormatOut);
261                                }
262                            } else if (strncmp(mime, "audio/", 6) == 0 && !includeAudio) {
263                                return false;
264                            }
265                            return true;
266                        });
267 }
268 
SetMaxOperatingRate(AMediaFormat * format)269 static void SetMaxOperatingRate(AMediaFormat* format) {
270     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX);
271     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_PRIORITY, 1);
272 }
273 
274 //-------------------------------- AVC to AVC Benchmarks -------------------------------------------
275 
BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State & state)276 static void BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
277     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
278                        "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4",
279                        true /* includeAudio */, true /* transcodeVideo */);
280 }
281 
BM_TranscodeAvc2AvcVideo2Video(benchmark::State & state)282 static void BM_TranscodeAvc2AvcVideo2Video(benchmark::State& state) {
283     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
284                        "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4",
285                        false /* includeAudio */, true /* transcodeVideo */);
286 }
287 
BM_TranscodeAvc2AvcAV2AVMaxOperatingRate(benchmark::State & state)288 static void BM_TranscodeAvc2AvcAV2AVMaxOperatingRate(benchmark::State& state) {
289     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
290                        "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4",
291                        true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
292 }
293 
BM_TranscodeAvc2AvcV2VMaxOperatingRate(benchmark::State & state)294 static void BM_TranscodeAvc2AvcV2VMaxOperatingRate(benchmark::State& state) {
295     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
296                        "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4",
297                        false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
298 }
299 
BM_TranscodeAvc2AvcAV2AV720P(benchmark::State & state)300 static void BM_TranscodeAvc2AvcAV2AV720P(benchmark::State& state) {
301     TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
302                        "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
303                        true /* includeAudio */, true /* transcodeVideo */);
304 }
305 
BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate(benchmark::State & state)306 static void BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
307     TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
308                        "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
309                        true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
310 }
311 //-------------------------------- HEVC to AVC Benchmarks ------------------------------------------
312 
BM_TranscodeHevc2AvcAudioVideo2AudioVideo(benchmark::State & state)313 static void BM_TranscodeHevc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
314     TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac.mp4",
315                        "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac_transcoded_AV.mp4",
316                        true /* includeAudio */, true /* transcodeVideo */);
317 }
318 
BM_TranscodeHevc2AvcVideo2Video(benchmark::State & state)319 static void BM_TranscodeHevc2AvcVideo2Video(benchmark::State& state) {
320     TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps.mp4",
321                        "video_1920x1080_3863frame_hevc_4Mbps_30fps_transcoded_V.mp4",
322                        false /* includeAudio */, true /* transcodeVideo */);
323 }
324 
BM_TranscodeHevc2AvcAV2AVMaxOperatingRate(benchmark::State & state)325 static void BM_TranscodeHevc2AvcAV2AVMaxOperatingRate(benchmark::State& state) {
326     TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac.mp4",
327                        "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac_transcoded_AV.mp4",
328                        true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
329 }
330 
BM_TranscodeHevc2AvcV2VMaxOperatingRate(benchmark::State & state)331 static void BM_TranscodeHevc2AvcV2VMaxOperatingRate(benchmark::State& state) {
332     TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps.mp4",
333                        "video_1920x1080_3863frame_hevc_4Mbps_30fps_transcoded_V.mp4",
334                        false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
335 }
336 
BM_TranscodeHevc2AvcAV2AV720P(benchmark::State & state)337 static void BM_TranscodeHevc2AvcAV2AV720P(benchmark::State& state) {
338     TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
339                        "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
340                        true /* includeAudio */, true /* transcodeVideo */);
341 }
342 
BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate(benchmark::State & state)343 static void BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
344     TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
345                        "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
346                        true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
347 }
348 
349 //-------------------------------- Passthrough Benchmarks ------------------------------------------
350 
BM_TranscodeAudioVideoPassthrough(benchmark::State & state)351 static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) {
352     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
353                        "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_passthrough_AV.mp4",
354                        true /* includeAudio */, false /* transcodeVideo */);
355 }
BM_TranscodeVideoPassthrough(benchmark::State & state)356 static void BM_TranscodeVideoPassthrough(benchmark::State& state) {
357     TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
358                        "video_1920x1080_3648frame_h264_22Mbps_30fps_passthrough_AV.mp4",
359                        false /* includeAudio */, false /* transcodeVideo */);
360 }
361 
362 //---------------------------- Codecs, Resolutions, Bitrate  ---------------------------------------
SetMimeBitrate(AMediaFormat * format,std::string mime,int32_t bitrate)363 static void SetMimeBitrate(AMediaFormat* format, std::string mime, int32_t bitrate) {
364     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime.c_str());
365     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
366 }
367 
BM_1920x1080_Avc22Mbps2Avc12Mbps(benchmark::State & state)368 static void BM_1920x1080_Avc22Mbps2Avc12Mbps(benchmark::State& state) {
369     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_22Mbps.mp4",
370                        "tx_bm_1920_1080_30fps_h264_22Mbps_transcoded_h264_12Mbps.mp4",
371                        false /* includeAudio */, true /* transcodeVideo */,
372                        [mime = "video/avc", bitrate = 12000000](AMediaFormat* dstFormat) {
373                            SetMimeBitrate(dstFormat, mime, bitrate);
374                        });
375 }
376 
BM_1920x1080_Avc15Mbps2Avc8Mbps(benchmark::State & state)377 static void BM_1920x1080_Avc15Mbps2Avc8Mbps(benchmark::State& state) {
378     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps.mp4",
379                        "tx_bm_1920_1080_30fps_h264_15Mbps_transcoded_h264_8Mbps.mp4",
380                        false /* includeAudio */, true /* transcodeVideo */,
381                        [mime = "video/avc", bitrate = 8000000](AMediaFormat* dstFormat) {
382                            SetMimeBitrate(dstFormat, mime, bitrate);
383                        });
384 }
385 
BM_1920x1080_Avc15Mbps2AvcPassthrough(benchmark::State & state)386 static void BM_1920x1080_Avc15Mbps2AvcPassthrough(benchmark::State& state) {
387     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps.mp4",
388                        "tx_bm_1920_1080_30fps_h264_15Mbps_passthrough_V.mp4",
389                        false /* includeAudio */, false /* transcodeVideo */);
390 }
391 
BM_1920x1080_Avc15MbpsAac2Avc8Mbps(benchmark::State & state)392 static void BM_1920x1080_Avc15MbpsAac2Avc8Mbps(benchmark::State& state) {
393     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps_aac.mp4",
394                        "tx_bm_1920_1080_30fps_h264_15Mbps_aac_transcoded_h264_8Mbps.mp4",
395                        false /* includeAudio */, true /* transcodeVideo */,
396                        [mime = "video/avc", bitrate = 8000000](AMediaFormat* dstFormat) {
397                            SetMimeBitrate(dstFormat, mime, bitrate);
398                        });
399 }
400 
BM_1920x1080_Avc15MbpsAac2Avc8MbpsAac(benchmark::State & state)401 static void BM_1920x1080_Avc15MbpsAac2Avc8MbpsAac(benchmark::State& state) {
402     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps_aac.mp4",
403                        "tx_bm_1920_1080_30fps_h264_15Mbps_aac_transcoded_h264_8Mbps_aac.mp4",
404                        true /* includeAudio */, true /* transcodeVideo */,
405                        [mime = "video/avc", bitrate = 8000000](AMediaFormat* dstFormat) {
406                            SetMimeBitrate(dstFormat, mime, bitrate);
407                        });
408 }
409 
BM_1920x1080_Avc15MbpsAac2AvcPassthrough(benchmark::State & state)410 static void BM_1920x1080_Avc15MbpsAac2AvcPassthrough(benchmark::State& state) {
411     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps_aac.mp4",
412                        "tx_bm_1920_1080_30fps_h264_15Mbps_aac_passthrough_V.mp4",
413                        false /* includeAudio */, false /* transcodeVideo */);
414 }
415 
BM_1920x1080_Avc15MbpsAac2AvcAacPassthrough(benchmark::State & state)416 static void BM_1920x1080_Avc15MbpsAac2AvcAacPassthrough(benchmark::State& state) {
417     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_h264_15Mbps_aac.mp4",
418                        "tx_bm_1920_1080_30fps_h264_15Mbps_aac_passthrough_AV.mp4",
419                        true /* includeAudio */, false /* transcodeVideo */);
420 }
421 
BM_1920x1080_Hevc17Mbps2Hevc8Mbps(benchmark::State & state)422 static void BM_1920x1080_Hevc17Mbps2Hevc8Mbps(benchmark::State& state) {
423     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_hevc_17Mbps.mp4",
424                        "tx_bm_1920_1080_30fps_hevc_17Mbps_transcoded_hevc_8Mbps.mp4",
425                        false /* includeAudio */, true /* transcodeVideo */,
426                        [mime = "video/hevc", bitrate = 8000000](AMediaFormat* dstFormat) {
427                            SetMimeBitrate(dstFormat, mime, bitrate);
428                        });
429 }
430 
BM_1920x1080_Hevc17Mbps2Avc12Mbps(benchmark::State & state)431 static void BM_1920x1080_Hevc17Mbps2Avc12Mbps(benchmark::State& state) {
432     TranscodeMediaFile(state, "tx_bm_1920_1080_30fps_hevc_17Mbps.mp4",
433                        "tx_bm_1920_1080_30fps_hevc_17Mbps_transcoded_h264_12Mbps.mp4",
434                        false /* includeAudio */, true /* transcodeVideo */,
435                        [mime = "video/avc", bitrate = 12000000](AMediaFormat* dstFormat) {
436                            SetMimeBitrate(dstFormat, mime, bitrate);
437                        });
438 }
439 
BM_1920x1080_60fps_Hevc28Mbps2Avc15Mbps(benchmark::State & state)440 static void BM_1920x1080_60fps_Hevc28Mbps2Avc15Mbps(benchmark::State& state) {
441     TranscodeMediaFile(state, "tx_bm_1920_1080_60fps_hevc_28Mbps.mp4",
442                        "tx_bm_1920_1080_60fps_hevc_28Mbps_transcoded_h264_15Mbps.mp4",
443                        false /* includeAudio */, true /* transcodeVideo */,
444                        [mime = "video/avc", bitrate = 15000000](AMediaFormat* dstFormat) {
445                            SetMimeBitrate(dstFormat, mime, bitrate);
446                        });
447 }
448 
BM_1280x720_Avc10Mbps2Avc4Mbps(benchmark::State & state)449 static void BM_1280x720_Avc10Mbps2Avc4Mbps(benchmark::State& state) {
450     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps.mp4",
451                        "tx_bm_1280_720_30fps_h264_10Mbps_transcoded_h264_4Mbps.mp4",
452                        false /* includeAudio */, true /* transcodeVideo */,
453                        [mime = "video/avc", bitrate = 4000000](AMediaFormat* dstFormat) {
454                            SetMimeBitrate(dstFormat, mime, bitrate);
455                        });
456 }
457 
BM_1280x720_Avc10Mbps2AvcPassthrough(benchmark::State & state)458 static void BM_1280x720_Avc10Mbps2AvcPassthrough(benchmark::State& state) {
459     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps.mp4",
460                        "tx_bm_1280_720_30fps_h264_10Mbps_passthrough_V.mp4",
461                        false /* includeAudio */, false /* transcodeVideo */);
462 }
463 
BM_1280x720_Avc10MbpsAac2Avc4Mbps(benchmark::State & state)464 static void BM_1280x720_Avc10MbpsAac2Avc4Mbps(benchmark::State& state) {
465     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps_aac.mp4",
466                        "tx_bm_1280_720_30fps_h264_10Mbps_aac_transcoded_h264_4Mbps.mp4",
467                        false /* includeAudio */, true /* transcodeVideo */,
468                        [mime = "video/avc", bitrate = 4000000](AMediaFormat* dstFormat) {
469                            SetMimeBitrate(dstFormat, mime, bitrate);
470                        });
471 }
472 
BM_1280x720_Avc10MbpsAac2Avc4MbpsAac(benchmark::State & state)473 static void BM_1280x720_Avc10MbpsAac2Avc4MbpsAac(benchmark::State& state) {
474     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps_aac.mp4",
475                        "tx_bm_1280_720_30fps_h264_10Mbps_aac_transcoded_h264_4Mbps_aac.mp4",
476                        true /* includeAudio */, true /* transcodeVideo */,
477                        [mime = "video/avc", bitrate = 4000000](AMediaFormat* dstFormat) {
478                            SetMimeBitrate(dstFormat, mime, bitrate);
479                        });
480 }
481 
BM_1280x720_Avc10MbpsAac2AvcPassthrough(benchmark::State & state)482 static void BM_1280x720_Avc10MbpsAac2AvcPassthrough(benchmark::State& state) {
483     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps_aac.mp4",
484                        "tx_bm_1280_720_30fps_h264_10Mbps_aac_passthrough_V.mp4",
485                        false /* includeAudio */, false /* transcodeVideo */);
486 }
487 
BM_1280x720_Avc10MbpsAac2AvcAacPassthrough(benchmark::State & state)488 static void BM_1280x720_Avc10MbpsAac2AvcAacPassthrough(benchmark::State& state) {
489     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_h264_10Mbps_aac.mp4",
490                        "tx_bm_1280_720_30fps_h264_10Mbps_aac_passthrough_AV.mp4",
491                        true /* includeAudio */, false /* transcodeVideo */);
492 }
493 
BM_1280x720_Hevc8Mbps2Avc4Mbps(benchmark::State & state)494 static void BM_1280x720_Hevc8Mbps2Avc4Mbps(benchmark::State& state) {
495     TranscodeMediaFile(state, "tx_bm_1280_720_30fps_hevc_8Mbps.mp4",
496                        "tx_bm_1280_720_30fps_hevc_8Mbps_transcoded_h264_4Mbps.mp4",
497                        false /* includeAudio */, true /* transcodeVideo */,
498                        [mime = "video/avc", bitrate = 4000000](AMediaFormat* dstFormat) {
499                            SetMimeBitrate(dstFormat, mime, bitrate);
500                        });
501 }
502 
BM_1080x1920_Avc15Mbps2Avc8Mbps(benchmark::State & state)503 static void BM_1080x1920_Avc15Mbps2Avc8Mbps(benchmark::State& state) {
504     TranscodeMediaFile(state, "tx_bm_1080_1920_30fps_h264_15Mbps.mp4",
505                        "tx_bm_1080_1920_30fps_h264_15Mbps_transcoded_h264_8Mbps.mp4",
506                        false /* includeAudio */, true /* transcodeVideo */,
507                        [mime = "video/avc", bitrate = 8000000](AMediaFormat* dstFormat) {
508                            SetMimeBitrate(dstFormat, mime, bitrate);
509                        });
510 }
511 
BM_720x1280_Avc10Mbps2Avc4Mbps(benchmark::State & state)512 static void BM_720x1280_Avc10Mbps2Avc4Mbps(benchmark::State& state) {
513     TranscodeMediaFile(state, "tx_bm_720_1280_30fps_h264_10Mbps.mp4",
514                        "tx_bm_720_1280_30fps_h264_10Mbps_transcoded_h264_4Mbps.mp4",
515                        false /* includeAudio */, true /* transcodeVideo */,
516                        [mime = "video/avc", bitrate = 4000000](AMediaFormat* dstFormat) {
517                            SetMimeBitrate(dstFormat, mime, bitrate);
518                        });
519 }
520 
BM_3840x2160_Hevc42Mbps2Avc20Mbps(benchmark::State & state)521 static void BM_3840x2160_Hevc42Mbps2Avc20Mbps(benchmark::State& state) {
522     TranscodeMediaFile(state, "tx_bm_3840_2160_30fps_hevc_42Mbps.mp4",
523                        "tx_bm_3840_2160_30fps_hevc_42Mbps_transcoded_h264_4Mbps.mp4",
524                        false /* includeAudio */, true /* transcodeVideo */,
525                        [mime = "video/avc", bitrate = 20000000](AMediaFormat* dstFormat) {
526                            SetMimeBitrate(dstFormat, mime, bitrate);
527                        });
528 }
529 
530 //-------------------------------- Benchmark Registration ------------------------------------------
531 
532 // Benchmark registration wrapper for transcoding.
533 #define TRANSCODER_BENCHMARK(func) \
534     BENCHMARK(func)->UseRealTime()->MeasureProcessCPUTime()->Unit(benchmark::kMillisecond)
535 
536 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2AudioVideo);
537 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video);
538 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AVMaxOperatingRate);
539 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcV2VMaxOperatingRate);
540 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720P);
541 TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate);
542 
543 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAudioVideo2AudioVideo);
544 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcVideo2Video);
545 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AVMaxOperatingRate);
546 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcV2VMaxOperatingRate);
547 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720P);
548 TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate);
549 
550 TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough);
551 TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough);
552 
553 TRANSCODER_BENCHMARK(BM_1920x1080_Avc22Mbps2Avc12Mbps);
554 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15Mbps2Avc8Mbps);
555 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15Mbps2AvcPassthrough);
556 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15MbpsAac2Avc8Mbps);
557 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15MbpsAac2Avc8MbpsAac);
558 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15MbpsAac2AvcPassthrough);
559 TRANSCODER_BENCHMARK(BM_1920x1080_Avc15MbpsAac2AvcAacPassthrough);
560 TRANSCODER_BENCHMARK(BM_1920x1080_Hevc17Mbps2Hevc8Mbps);
561 TRANSCODER_BENCHMARK(BM_1920x1080_Hevc17Mbps2Avc12Mbps);
562 TRANSCODER_BENCHMARK(BM_1920x1080_60fps_Hevc28Mbps2Avc15Mbps);
563 
564 TRANSCODER_BENCHMARK(BM_1280x720_Avc10Mbps2Avc4Mbps);
565 TRANSCODER_BENCHMARK(BM_1280x720_Avc10Mbps2AvcPassthrough);
566 TRANSCODER_BENCHMARK(BM_1280x720_Avc10MbpsAac2Avc4Mbps);
567 TRANSCODER_BENCHMARK(BM_1280x720_Avc10MbpsAac2Avc4MbpsAac);
568 TRANSCODER_BENCHMARK(BM_1280x720_Avc10MbpsAac2AvcPassthrough);
569 TRANSCODER_BENCHMARK(BM_1280x720_Avc10MbpsAac2AvcAacPassthrough);
570 TRANSCODER_BENCHMARK(BM_1280x720_Hevc8Mbps2Avc4Mbps);
571 
572 TRANSCODER_BENCHMARK(BM_1080x1920_Avc15Mbps2Avc8Mbps);
573 TRANSCODER_BENCHMARK(BM_720x1280_Avc10Mbps2Avc4Mbps);
574 
575 TRANSCODER_BENCHMARK(BM_3840x2160_Hevc42Mbps2Avc20Mbps);
576 
577 class CustomCsvReporter : public benchmark::BenchmarkReporter {
578 public:
CustomCsvReporter()579     CustomCsvReporter() : mPrintedHeader(false) {}
580     virtual bool ReportContext(const Context& context);
581     virtual void ReportRuns(const std::vector<Run>& reports);
582 
583 private:
584     void PrintRunData(const Run& report);
585 
586     bool mPrintedHeader;
587     std::vector<std::string> mHeaders = {
588         "File",          "Resolution",     "SourceMime", "VideoTrackDuration(ms)",
589         "IncludeAudio",  "TranscodeVideo", "TargetMime", "TargetBirate(bps)",
590         "real_time(ms)", "cpu_time(ms)",   PARAM_VIDEO_FRAME_RATE
591     };
592 };
593 
ReportContext(const Context & context __unused)594 bool CustomCsvReporter::ReportContext(const Context& context __unused) {
595     return true;
596 }
597 
ReportRuns(const std::vector<Run> & reports)598 void CustomCsvReporter::ReportRuns(const std::vector<Run>& reports) {
599     std::ostream& Out = GetOutputStream();
600 
601     if (!mPrintedHeader) {
602         // print the header
603         for (auto header = mHeaders.begin(); header != mHeaders.end();) {
604             Out << *header++;
605             if (header != mHeaders.end()) Out << ",";
606         }
607         Out << "\n";
608         mPrintedHeader = true;
609     }
610 
611     // print results for each run
612     for (const auto& run : reports) {
613         PrintRunData(run);
614     }
615 }
616 
PrintRunData(const Run & run)617 void CustomCsvReporter::PrintRunData(const Run& run) {
618     if (run.skipped) {
619         return;
620     }
621     std::ostream& Out = GetOutputStream();
622     // Log the transcoding params reported through label
623     Out << run.report_label << ",";
624     Out << run.GetAdjustedRealTime() << ",";
625     Out << run.GetAdjustedCPUTime() << ",";
626     auto frameRate = run.counters.find(PARAM_VIDEO_FRAME_RATE);
627     if (frameRate == run.counters.end()) {
628         Out << "NA"
629             << ",";
630     } else {
631         Out << frameRate->second << ",";
632     }
633     Out << '\n';
634 }
635 
main(int argc,char ** argv)636 int main(int argc, char** argv) {
637     android::ProcessState::self()->startThreadPool();
638     std::unique_ptr<benchmark::BenchmarkReporter> fileReporter;
639     for (int i = 1; i < argc; ++i) {
640         if (std::string(argv[i]).find("--benchmark_out") != std::string::npos) {
641             fileReporter.reset(new CustomCsvReporter);
642             break;
643         }
644     }
645     ::benchmark::Initialize(&argc, argv);
646     if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
647     ::benchmark::RunSpecifiedBenchmarks(nullptr, fileReporter.get());
648 }
649