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