1 /******************************************************************************
2 *
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 #include <C2Config.h>
21 #include <android/binder_process.h>
22 #include <fcntl.h>
23 #include <media/MediaTranscoder.h>
24 #include <media/NdkCommon.h>
25 #include <stdio.h>
26
27 #define UNUSED_PARAM __attribute__((unused))
28 #define SRC_FILE "sourceTranscodingFile"
29 #define DEST_FILE "destTranscodingFile"
30
31 using namespace std;
32 using namespace android;
33
34 const char* kMimeType[] = {AMEDIA_MIMETYPE_VIDEO_AVC, AMEDIA_MIMETYPE_VIDEO_HEVC};
35 const C2Config::profile_t kAvcProfile[] = {C2Config::PROFILE_AVC_BASELINE,
36 C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
37 C2Config::PROFILE_AVC_MAIN};
38 const C2Config::level_t kAvcLevel[] = {
39 C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, C2Config::LEVEL_AVC_1_1,
40 C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2,
41 C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2, C2Config::LEVEL_AVC_3,
42 C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4,
43 C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2, C2Config::LEVEL_AVC_5,
44 };
45 const C2Config::profile_t kHevcProfile[] = {C2Config::PROFILE_HEVC_MAIN,
46 C2Config::PROFILE_HEVC_MAIN_STILL};
47 const C2Config::level_t kHevcLevel[] = {
48 C2Config::LEVEL_HEVC_MAIN_1, C2Config::LEVEL_HEVC_MAIN_2, C2Config::LEVEL_HEVC_MAIN_2_1,
49 C2Config::LEVEL_HEVC_MAIN_3, C2Config::LEVEL_HEVC_MAIN_3_1, C2Config::LEVEL_HEVC_MAIN_4,
50 C2Config::LEVEL_HEVC_MAIN_4_1, C2Config::LEVEL_HEVC_MAIN_5, C2Config::LEVEL_HEVC_MAIN_5_1,
51 C2Config::LEVEL_HEVC_MAIN_5_2};
52 const size_t kNumAvcProfile = size(kAvcProfile);
53 const size_t kNumAvcLevel = size(kAvcLevel);
54 const size_t kNumHevcProfile = size(kHevcProfile);
55 const size_t kNumHevcLevel = size(kHevcLevel);
56 const size_t kMaxBitrate = 500000000;
57
58 enum {
59 IDX_MIME_TYPE = 0,
60 IDX_PROFILE,
61 IDX_LEVEL,
62 IDX_BITRATE_BYTE_1,
63 IDX_BITRATE_BYTE_2,
64 IDX_LAST
65 };
66
67 class TestCallbacks : public MediaTranscoder::CallbackInterface {
68 public:
onFinished(const MediaTranscoder * transcoder UNUSED_PARAM)69 virtual void onFinished(const MediaTranscoder* transcoder UNUSED_PARAM) override {
70 unique_lock<mutex> lock(mMutex);
71 mFinished = true;
72 mCondition.notify_all();
73 }
74
onError(const MediaTranscoder * transcoder UNUSED_PARAM,media_status_t error UNUSED_PARAM)75 virtual void onError(const MediaTranscoder* transcoder UNUSED_PARAM,
76 media_status_t error UNUSED_PARAM) override {
77 unique_lock<mutex> lock(mMutex);
78 mFinished = true;
79 mCondition.notify_all();
80 }
81
onProgressUpdate(const MediaTranscoder * transcoder UNUSED_PARAM,int32_t progress)82 virtual void onProgressUpdate(const MediaTranscoder* transcoder UNUSED_PARAM,
83 int32_t progress) override {
84 unique_lock<mutex> lock(mMutex);
85 if (progress > 0 && !mProgressMade) {
86 mProgressMade = true;
87 mCondition.notify_all();
88 }
89 }
90
onHeartBeat(const MediaTranscoder * transcoder UNUSED_PARAM)91 virtual void onHeartBeat(const MediaTranscoder* transcoder UNUSED_PARAM) override {}
92
onCodecResourceLost(const MediaTranscoder * transcoder UNUSED_PARAM,const shared_ptr<ndk::ScopedAParcel> & pausedState UNUSED_PARAM)93 virtual void onCodecResourceLost(const MediaTranscoder* transcoder UNUSED_PARAM,
94 const shared_ptr<ndk::ScopedAParcel>& pausedState
95 UNUSED_PARAM) override {}
96
waitForTranscodingFinished()97 void waitForTranscodingFinished() {
98 unique_lock<mutex> lock(mMutex);
99 while (!mFinished) {
100 mCondition.wait(lock);
101 }
102 }
103
104 private:
105 mutex mMutex;
106 condition_variable mCondition;
107 bool mFinished = false;
108 bool mProgressMade = false;
109 };
110
111 class MediaTranscoderFuzzer {
112 public:
113 void init();
114 void invokeTranscoder(const uint8_t* data, size_t size);
115 void deInit();
116
117 private:
getFormat(AMediaFormat * sourceFormat)118 AMediaFormat* getFormat(AMediaFormat* sourceFormat) {
119 AMediaFormat* format = nullptr;
120 const char* mime = nullptr;
121 AMediaFormat_getString(sourceFormat, AMEDIAFORMAT_KEY_MIME, &mime);
122 if (mime != nullptr) {
123 if (strncmp(mime, "video/", 6) == 0 && (mDestMime != nullptr)) {
124 format = AMediaFormat_new();
125 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mDestMime);
126 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_PROFILE, mProfile);
127 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_LEVEL, mLevel);
128 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, mBitrate);
129 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_OPERATING_RATE, INT32_MAX);
130 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_PRIORITY, 1);
131 }
132 }
133 return format;
134 }
135
136 shared_ptr<TestCallbacks> mCallbacks;
137 int mSrcFd = 0;
138 int mDestFd = 0;
139 const char* mDestMime;
140 C2Config::profile_t mProfile;
141 C2Config::level_t mLevel;
142 uint64_t mBitrate = 0;
143 };
144
init()145 void MediaTranscoderFuzzer::init() {
146 mCallbacks = make_shared<TestCallbacks>();
147 ABinderProcess_startThreadPool();
148 }
149
deInit()150 void MediaTranscoderFuzzer::deInit() {
151 mCallbacks.reset();
152 if (mSrcFd) {
153 close(mSrcFd);
154 }
155 if (mDestFd) {
156 close(mDestFd);
157 }
158 }
159
invokeTranscoder(const uint8_t * data,size_t size)160 void MediaTranscoderFuzzer::invokeTranscoder(const uint8_t* data, size_t size) {
161 auto transcoder = MediaTranscoder::create(mCallbacks);
162 if (transcoder == nullptr) {
163 return;
164 }
165
166 mDestMime = kMimeType[data[IDX_MIME_TYPE] & 0x01];
167 mBitrate = (((data[IDX_BITRATE_BYTE_1] << 8) | data[IDX_BITRATE_BYTE_2]) * 1000) % kMaxBitrate;
168 if (mDestMime == AMEDIA_MIMETYPE_VIDEO_AVC) {
169 mProfile = kAvcProfile[data[IDX_PROFILE] % kNumAvcProfile];
170 mLevel = kAvcLevel[data[IDX_LEVEL] % kNumAvcLevel];
171 } else {
172 mProfile = kHevcProfile[data[IDX_PROFILE] % kNumHevcProfile];
173 mLevel = kHevcLevel[data[IDX_LEVEL] % kNumHevcLevel];
174 }
175
176 data += IDX_LAST;
177 size -= IDX_LAST;
178
179 mSrcFd = memfd_create(SRC_FILE, MFD_ALLOW_SEALING);
180 write(mSrcFd, data, size);
181
182 transcoder->configureSource(mSrcFd);
183 vector<shared_ptr<AMediaFormat>> trackFormats = transcoder->getTrackFormats();
184 for (int i = 0; i < trackFormats.size(); ++i) {
185 AMediaFormat* format = getFormat(trackFormats[i].get());
186 transcoder->configureTrackFormat(i, format);
187
188 if (format != nullptr) {
189 AMediaFormat_delete(format);
190 }
191 }
192 mDestFd = memfd_create(DEST_FILE, MFD_ALLOW_SEALING);
193 transcoder->configureDestination(mDestFd);
194 if (transcoder->start() == AMEDIA_OK) {
195 mCallbacks->waitForTranscodingFinished();
196 transcoder->cancel();
197 }
198 close(mSrcFd);
199 close(mDestFd);
200 }
201
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)202 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
203 if (size < IDX_LAST + 1) {
204 return 0;
205 }
206 MediaTranscoderFuzzer transcoderFuzzer;
207 transcoderFuzzer.init();
208 transcoderFuzzer.invokeTranscoder(data, size);
209 transcoderFuzzer.deInit();
210 return 0;
211 }
212