• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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