blob: 93a08d10f691820515013eb3aa3153bd150bbabb [file] [log] [blame]
Linus Nilsson8f0b8762020-07-23 17:12:45 -07001/*
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 <fcntl.h>
34#include <media/MediaTranscoder.h>
35
36using namespace android;
37
38class TranscoderCallbacks : public MediaTranscoder::CallbackInterface {
39public:
40 virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
41 std::unique_lock<std::mutex> lock(mMutex);
42 mFinished = true;
43 mCondition.notify_all();
44 }
45
46 virtual void onError(const MediaTranscoder* transcoder __unused,
47 media_status_t error) override {
48 std::unique_lock<std::mutex> lock(mMutex);
49 mFinished = true;
50 mStatus = error;
51 mCondition.notify_all();
52 }
53
54 virtual void onProgressUpdate(const MediaTranscoder* transcoder __unused,
55 int32_t progress __unused) override {}
56
57 virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
Chong Zhange4e088f2020-10-21 19:10:42 -070058 const std::shared_ptr<ndk::ScopedAParcel>& pausedState
Linus Nilsson8f0b8762020-07-23 17:12:45 -070059 __unused) override {}
60
61 bool waitForTranscodingFinished() {
62 std::unique_lock<std::mutex> lock(mMutex);
63 while (!mFinished) {
64 if (mCondition.wait_for(lock, std::chrono::minutes(5)) == std::cv_status::timeout) {
65 return false;
66 }
67 }
68 return true;
69 }
70
71 media_status_t mStatus = AMEDIA_OK;
72
73private:
74 std::mutex mMutex;
75 std::condition_variable mCondition;
76 bool mFinished = false;
77};
78
Linus Nilsson16d772b2020-09-29 19:21:11 -070079static AMediaFormat* CreateDefaultVideoFormat() {
Linus Nilsson8f0b8762020-07-23 17:12:45 -070080 // Default bitrate
81 static constexpr int32_t kVideoBitRate = 20 * 1000 * 1000; // 20Mbs
Linus Nilsson16d772b2020-09-29 19:21:11 -070082
83 AMediaFormat* videoFormat = AMediaFormat_new();
84 AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate);
85 return videoFormat;
86}
87
88/**
89 * Callback to configure tracks for transcoding.
90 * @param mime The source track mime type.
91 * @param dstFormat The destination format if the track should be transcoded or nullptr if the track
92 * should be passed through.
93 * @return True if the track should be included in the output file.
94 */
95using TrackSelectionCallback = std::function<bool(const char* mime, AMediaFormat** dstFormat)>;
96
97static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName,
98 const std::string& dstFileName,
99 TrackSelectionCallback trackSelectionCallback) {
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700100 // Write-only, create file if non-existent.
101 static constexpr int kDstOpenFlags = O_WRONLY | O_CREAT;
102 // User R+W permission.
103 static constexpr int kDstFileMode = S_IRUSR | S_IWUSR;
104 // Asset directory
105 static const std::string kAssetDirectory = "/data/local/tmp/TranscodingBenchmark/";
106
107 int srcFd = 0;
108 int dstFd = 0;
109
110 std::string srcPath = kAssetDirectory + srcFileName;
111 std::string dstPath = kAssetDirectory + dstFileName;
112
113 auto callbacks = std::make_shared<TranscoderCallbacks>();
114 media_status_t status = AMEDIA_OK;
115
116 if ((srcFd = open(srcPath.c_str(), O_RDONLY)) < 0) {
117 state.SkipWithError("Unable to open source file");
118 goto exit;
119 }
120 if ((dstFd = open(dstPath.c_str(), kDstOpenFlags, kDstFileMode)) < 0) {
121 state.SkipWithError("Unable to open destination file");
122 goto exit;
123 }
124
125 for (auto _ : state) {
Chong Zhangbbb4eac2020-11-18 11:12:06 -0800126 auto transcoder = MediaTranscoder::create(callbacks);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700127
128 status = transcoder->configureSource(srcFd);
129 if (status != AMEDIA_OK) {
130 state.SkipWithError("Unable to configure transcoder source");
131 goto exit;
132 }
133
134 status = transcoder->configureDestination(dstFd);
135 if (status != AMEDIA_OK) {
136 state.SkipWithError("Unable to configure transcoder destination");
137 goto exit;
138 }
139
140 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
141 for (int i = 0; i < trackFormats.size(); ++i) {
142 AMediaFormat* srcFormat = trackFormats[i].get();
143 AMediaFormat* dstFormat = nullptr;
144
145 const char* mime = nullptr;
146 if (!AMediaFormat_getString(srcFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
147 state.SkipWithError("Source track format does not have MIME type");
148 goto exit;
149 }
150
151 if (strncmp(mime, "video/", 6) == 0) {
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700152 int32_t frameCount;
153 if (AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount)) {
154 state.counters["VideoFrameRate"] =
155 benchmark::Counter(frameCount, benchmark::Counter::kIsRate);
156 }
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700157 }
158
Linus Nilsson16d772b2020-09-29 19:21:11 -0700159 if (trackSelectionCallback(mime, &dstFormat)) {
160 status = transcoder->configureTrackFormat(i, dstFormat);
161 }
162
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700163 if (dstFormat != nullptr) {
164 AMediaFormat_delete(dstFormat);
165 }
166 if (status != AMEDIA_OK) {
167 state.SkipWithError("Unable to configure track");
168 goto exit;
169 }
170 }
171
172 status = transcoder->start();
173 if (status != AMEDIA_OK) {
174 state.SkipWithError("Unable to start transcoder");
175 goto exit;
176 }
177
178 if (!callbacks->waitForTranscodingFinished()) {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700179 transcoder->cancel();
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700180 state.SkipWithError("Transcoder timed out");
181 goto exit;
182 }
183 if (callbacks->mStatus != AMEDIA_OK) {
184 state.SkipWithError("Transcoder error when running");
185 goto exit;
186 }
187 }
188
189exit:
190 if (srcFd > 0) close(srcFd);
191 if (dstFd > 0) close(dstFd);
192}
193
Linus Nilsson6bf46532020-10-07 11:58:02 -0700194/**
195 * Callback to edit track format for transcoding.
196 * @param dstFormat The default track format for the track type.
197 */
198using TrackFormatEditCallback = std::function<void(AMediaFormat* dstFormat)>;
199
Linus Nilsson16d772b2020-09-29 19:21:11 -0700200static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName,
201 const std::string& dstFileName, bool includeAudio,
Linus Nilsson6bf46532020-10-07 11:58:02 -0700202 bool transcodeVideo,
203 const TrackFormatEditCallback& videoFormatEditor = nullptr) {
Linus Nilsson16d772b2020-09-29 19:21:11 -0700204 TranscodeMediaFile(state, srcFileName, dstFileName,
205 [=](const char* mime, AMediaFormat** dstFormatOut) -> bool {
206 *dstFormatOut = nullptr;
207 if (strncmp(mime, "video/", 6) == 0 && transcodeVideo) {
208 *dstFormatOut = CreateDefaultVideoFormat();
Linus Nilsson6bf46532020-10-07 11:58:02 -0700209 if (videoFormatEditor != nullptr) {
210 videoFormatEditor(*dstFormatOut);
211 }
Linus Nilsson16d772b2020-09-29 19:21:11 -0700212 } else if (strncmp(mime, "audio/", 6) == 0 && !includeAudio) {
213 return false;
214 }
215 return true;
216 });
217}
218
Linus Nilsson6bf46532020-10-07 11:58:02 -0700219static void SetMaxOperatingRate(AMediaFormat* format) {
220 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX);
221 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_PRIORITY, 1);
222}
223
224//-------------------------------- AVC to AVC Benchmarks -------------------------------------------
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700225
226static void BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
227 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
228 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4",
Linus Nilsson16d772b2020-09-29 19:21:11 -0700229 true /* includeAudio */, true /* transcodeVideo */);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700230}
231
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700232static void BM_TranscodeAvc2AvcVideo2Video(benchmark::State& state) {
233 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
234 "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4",
Linus Nilsson16d772b2020-09-29 19:21:11 -0700235 false /* includeAudio */, true /* transcodeVideo */);
236}
237
238static void BM_TranscodeAvc2AvcAV2AVMaxOperatingRate(benchmark::State& state) {
239 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
240 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4",
Linus Nilsson6bf46532020-10-07 11:58:02 -0700241 true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
Linus Nilsson16d772b2020-09-29 19:21:11 -0700242}
243
244static void BM_TranscodeAvc2AvcV2VMaxOperatingRate(benchmark::State& state) {
245 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
246 "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4",
Linus Nilsson6bf46532020-10-07 11:58:02 -0700247 false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700248}
249
Linus Nilssona7aa2f62020-10-29 13:19:35 -0700250static void BM_TranscodeAvc2AvcAV2AV720P(benchmark::State& state) {
251 TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
252 "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
253 true /* includeAudio */, true /* transcodeVideo */);
254}
255
256static void BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
257 TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
258 "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
259 true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
260}
Linus Nilsson6bf46532020-10-07 11:58:02 -0700261//-------------------------------- HEVC to AVC Benchmarks ------------------------------------------
262
263static void BM_TranscodeHevc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
264 TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac.mp4",
265 "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac_transcoded_AV.mp4",
266 true /* includeAudio */, true /* transcodeVideo */);
267}
268
269static void BM_TranscodeHevc2AvcVideo2Video(benchmark::State& state) {
270 TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps.mp4",
271 "video_1920x1080_3863frame_hevc_4Mbps_30fps_transcoded_V.mp4",
272 false /* includeAudio */, true /* transcodeVideo */);
273}
274
275static void BM_TranscodeHevc2AvcAV2AVMaxOperatingRate(benchmark::State& state) {
276 TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac.mp4",
277 "video_1920x1080_3863frame_hevc_4Mbps_30fps_aac_transcoded_AV.mp4",
278 true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
279}
280
281static void BM_TranscodeHevc2AvcV2VMaxOperatingRate(benchmark::State& state) {
282 TranscodeMediaFile(state, "video_1920x1080_3863frame_hevc_4Mbps_30fps.mp4",
283 "video_1920x1080_3863frame_hevc_4Mbps_30fps_transcoded_V.mp4",
284 false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
285}
286
Linus Nilssona7aa2f62020-10-29 13:19:35 -0700287static void BM_TranscodeHevc2AvcAV2AV720P(benchmark::State& state) {
288 TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
289 "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
290 true /* includeAudio */, true /* transcodeVideo */);
291}
292
293static void BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
294 TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
295 "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
296 true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
297}
298
Linus Nilsson6bf46532020-10-07 11:58:02 -0700299//-------------------------------- Passthrough Benchmarks ------------------------------------------
300
Linus Nilsson6233fed2020-08-13 15:15:14 -0700301static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) {
302 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
303 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_passthrough_AV.mp4",
304 true /* includeAudio */, false /* transcodeVideo */);
305}
306static void BM_TranscodeVideoPassthrough(benchmark::State& state) {
307 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
308 "video_1920x1080_3648frame_h264_22Mbps_30fps_passthrough_AV.mp4",
309 false /* includeAudio */, false /* transcodeVideo */);
310}
311
Linus Nilsson6bf46532020-10-07 11:58:02 -0700312//-------------------------------- Benchmark Registration ------------------------------------------
313
314// Benchmark registration wrapper for transcoding.
315#define TRANSCODER_BENCHMARK(func) \
316 BENCHMARK(func)->UseRealTime()->MeasureProcessCPUTime()->Unit(benchmark::kMillisecond)
317
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700318TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2AudioVideo);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700319TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video);
Linus Nilsson16d772b2020-09-29 19:21:11 -0700320TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AVMaxOperatingRate);
321TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcV2VMaxOperatingRate);
Linus Nilssona7aa2f62020-10-29 13:19:35 -0700322TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720P);
323TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate);
Linus Nilsson6bf46532020-10-07 11:58:02 -0700324
325TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAudioVideo2AudioVideo);
326TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcVideo2Video);
327TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AVMaxOperatingRate);
328TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcV2VMaxOperatingRate);
Linus Nilssona7aa2f62020-10-29 13:19:35 -0700329TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720P);
330TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate);
Linus Nilsson6bf46532020-10-07 11:58:02 -0700331
Linus Nilsson6233fed2020-08-13 15:15:14 -0700332TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough);
333TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700334
335BENCHMARK_MAIN();