blob: ccd9353800abf0d553f255729d5c970e4d6dd0f6 [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,
58 const std::shared_ptr<const Parcel>& pausedState
59 __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
79static void TranscodeMediaFile(benchmark::State& state, const std::string& srcFileName,
Linus Nilsson6233fed2020-08-13 15:15:14 -070080 const std::string& dstFileName, bool includeAudio,
81 bool transcodeVideo = true) {
Linus Nilsson8f0b8762020-07-23 17:12:45 -070082 // Default bitrate
83 static constexpr int32_t kVideoBitRate = 20 * 1000 * 1000; // 20Mbs
84 // Write-only, create file if non-existent.
85 static constexpr int kDstOpenFlags = O_WRONLY | O_CREAT;
86 // User R+W permission.
87 static constexpr int kDstFileMode = S_IRUSR | S_IWUSR;
88 // Asset directory
89 static const std::string kAssetDirectory = "/data/local/tmp/TranscodingBenchmark/";
90
91 int srcFd = 0;
92 int dstFd = 0;
93
94 std::string srcPath = kAssetDirectory + srcFileName;
95 std::string dstPath = kAssetDirectory + dstFileName;
96
97 auto callbacks = std::make_shared<TranscoderCallbacks>();
98 media_status_t status = AMEDIA_OK;
99
100 if ((srcFd = open(srcPath.c_str(), O_RDONLY)) < 0) {
101 state.SkipWithError("Unable to open source file");
102 goto exit;
103 }
104 if ((dstFd = open(dstPath.c_str(), kDstOpenFlags, kDstFileMode)) < 0) {
105 state.SkipWithError("Unable to open destination file");
106 goto exit;
107 }
108
109 for (auto _ : state) {
110 auto transcoder = MediaTranscoder::create(callbacks, nullptr);
111
112 status = transcoder->configureSource(srcFd);
113 if (status != AMEDIA_OK) {
114 state.SkipWithError("Unable to configure transcoder source");
115 goto exit;
116 }
117
118 status = transcoder->configureDestination(dstFd);
119 if (status != AMEDIA_OK) {
120 state.SkipWithError("Unable to configure transcoder destination");
121 goto exit;
122 }
123
124 std::vector<std::shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
125 for (int i = 0; i < trackFormats.size(); ++i) {
126 AMediaFormat* srcFormat = trackFormats[i].get();
127 AMediaFormat* dstFormat = nullptr;
128
129 const char* mime = nullptr;
130 if (!AMediaFormat_getString(srcFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
131 state.SkipWithError("Source track format does not have MIME type");
132 goto exit;
133 }
134
135 if (strncmp(mime, "video/", 6) == 0) {
Linus Nilsson6233fed2020-08-13 15:15:14 -0700136 if (transcodeVideo) {
137 dstFormat = AMediaFormat_new();
138 AMediaFormat_setInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, kVideoBitRate);
139 }
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700140
141 int32_t frameCount;
142 if (AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT, &frameCount)) {
143 state.counters["VideoFrameRate"] =
144 benchmark::Counter(frameCount, benchmark::Counter::kIsRate);
145 }
146 } else if (!includeAudio && strncmp(mime, "audio/", 6) == 0) {
147 continue;
148 }
149
150 status = transcoder->configureTrackFormat(i, dstFormat);
151 if (dstFormat != nullptr) {
152 AMediaFormat_delete(dstFormat);
153 }
154 if (status != AMEDIA_OK) {
155 state.SkipWithError("Unable to configure track");
156 goto exit;
157 }
158 }
159
160 status = transcoder->start();
161 if (status != AMEDIA_OK) {
162 state.SkipWithError("Unable to start transcoder");
163 goto exit;
164 }
165
166 if (!callbacks->waitForTranscodingFinished()) {
Linus Nilssonb09aac22020-07-29 11:56:53 -0700167 transcoder->cancel();
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700168 state.SkipWithError("Transcoder timed out");
169 goto exit;
170 }
171 if (callbacks->mStatus != AMEDIA_OK) {
172 state.SkipWithError("Transcoder error when running");
173 goto exit;
174 }
175 }
176
177exit:
178 if (srcFd > 0) close(srcFd);
179 if (dstFd > 0) close(dstFd);
180}
181
182// Benchmark registration wrapper for transcoding.
183#define TRANSCODER_BENCHMARK(func) \
184 BENCHMARK(func)->UseRealTime()->MeasureProcessCPUTime()->Unit(benchmark::kMillisecond)
185
186static void BM_TranscodeAvc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
187 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
188 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_AV.mp4",
189 true /* includeAudio */);
190}
191
192static void BM_TranscodeAvc2AvcAudioVideo2Video(benchmark::State& state) {
193 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
194 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_transcoded_V.mp4",
195 false /* includeAudio */);
196}
197
198static void BM_TranscodeAvc2AvcVideo2Video(benchmark::State& state) {
199 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
200 "video_1920x1080_3648frame_h264_22Mbps_30fps_transcoded_V.mp4",
201 false /* includeAudio */);
202}
203
Linus Nilsson6233fed2020-08-13 15:15:14 -0700204static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) {
205 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps_aac.mp4",
206 "video_1920x1080_3648frame_h264_22Mbps_30fps_aac_passthrough_AV.mp4",
207 true /* includeAudio */, false /* transcodeVideo */);
208}
209static void BM_TranscodeVideoPassthrough(benchmark::State& state) {
210 TranscodeMediaFile(state, "video_1920x1080_3648frame_h264_22Mbps_30fps.mp4",
211 "video_1920x1080_3648frame_h264_22Mbps_30fps_passthrough_AV.mp4",
212 false /* includeAudio */, false /* transcodeVideo */);
213}
214
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700215TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2AudioVideo);
216TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAudioVideo2Video);
217TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video);
Linus Nilsson6233fed2020-08-13 15:15:14 -0700218TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough);
219TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough);
Linus Nilsson8f0b8762020-07-23 17:12:45 -0700220
221BENCHMARK_MAIN();