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