1 /*
2  * Copyright (C) 2022 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 #include <NdkMediaCodecFuzzerBase.h>
17 
18 constexpr int32_t kMaxNdkCodecAPIs = 12;
19 
20 class NdkSyncCodecFuzzer : public NdkMediaCodecFuzzerBase {
21   public:
NdkSyncCodecFuzzer(const uint8_t * data,size_t size)22     NdkSyncCodecFuzzer(const uint8_t* data, size_t size)
23         : NdkMediaCodecFuzzerBase(), mFdp(data, size) {
24         setFdp(&mFdp);
25     };
26     void invokeSyncCodeConfigAPI();
27 
CodecOnFrameRendered(AMediaCodec * codec,void * userdata,int64_t mediaTimeUs,int64_t systemNano)28     static void CodecOnFrameRendered(AMediaCodec* codec, void* userdata, int64_t mediaTimeUs,
29                                      int64_t systemNano) {
30         (void)codec;
31         (void)userdata;
32         (void)mediaTimeUs;
33         (void)systemNano;
34     };
35 
36   private:
37     FuzzedDataProvider mFdp;
38     AMediaCodec* mCodec = nullptr;
39     void invokekSyncCodecAPIs(bool isEncoder);
40 };
41 
invokekSyncCodecAPIs(bool isEncoder)42 void NdkSyncCodecFuzzer::invokekSyncCodecAPIs(bool isEncoder) {
43     ANativeWindow* nativeWindow = nullptr;
44     int32_t numOfFrames = mFdp.ConsumeIntegralInRange<size_t>(kMinIterations, kMaxIterations);
45     int32_t count = 0;
46     while (++count <= numOfFrames) {
47         int32_t ndkcodecAPI = mFdp.ConsumeIntegralInRange<size_t>(kMinAPICase, kMaxNdkCodecAPIs);
48         switch (ndkcodecAPI) {
49             case 0: {  // configure the codec
50                 AMediaCodec_configure(mCodec, getCodecFormat(), nativeWindow, nullptr /* crypto */,
51                                       (isEncoder ? AMEDIACODEC_CONFIGURE_FLAG_ENCODE : 0));
52                 break;
53             }
54             case 1: {  // start codec
55                 AMediaCodec_start(mCodec);
56                 break;
57             }
58             case 2: {  // stop codec
59                 AMediaCodec_stop(mCodec);
60                 break;
61             }
62             case 3: {  // create persistent input surface
63                 AMediaCodec_createPersistentInputSurface(&nativeWindow);
64                 break;
65             }
66             case 4: {  // buffer operation APIs
67                 invokeInputBufferOperationAPI(mCodec);
68                 break;
69             }
70             case 5: {
71                 invokeOutputBufferOperationAPI(mCodec);
72                 break;
73             }
74             case 6: {  // get input and output Format
75                 invokeCodecFormatAPI(mCodec);
76                 break;
77             }
78             case 7: {
79                 AMediaCodec_signalEndOfInputStream(mCodec);
80                 break;
81             }
82             case 8: {  // set parameters
83                 // Create a new parameter and set
84                 AMediaFormat* params = AMediaFormat_new();
85                 AMediaFormat_setInt32(
86                         params, "video-bitrate",
87                         mFdp.ConsumeIntegralInRange<size_t>(kMinIntKeyValue, kMaxIntKeyValue));
88                 AMediaCodec_setParameters(mCodec, params);
89                 AMediaFormat_delete(params);
90                 break;
91             }
92             case 9: {  // flush codec
93                 AMediaCodec_flush(mCodec);
94                 if (mFdp.ConsumeBool()) {
95                     AMediaCodec_start(mCodec);
96                 }
97                 break;
98             }
99             case 10: {  // get the codec name
100                 char* name = nullptr;
101                 AMediaCodec_getName(mCodec, &name);
102                 AMediaCodec_releaseName(mCodec, name);
103                 break;
104             }
105             case 11: {  // set callback API for frame render output
106                 std::vector<uint8_t> userData = mFdp.ConsumeBytes<uint8_t>(
107                         mFdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
108                 AMediaCodecOnFrameRendered callback = CodecOnFrameRendered;
109                 AMediaCodec_setOnFrameRenderedCallback(mCodec, callback, userData.data());
110                 break;
111             }
112             case 12:
113             default: {  // set persistent input surface
114                 AMediaCodec_setInputSurface(mCodec, nativeWindow);
115             }
116         }
117     }
118     if (nativeWindow) {
119         ANativeWindow_release(nativeWindow);
120     }
121 }
122 
invokeSyncCodeConfigAPI()123 void NdkSyncCodecFuzzer::invokeSyncCodeConfigAPI() {
124     while (mFdp.remaining_bytes() > 0) {
125         bool isEncoder = mFdp.ConsumeBool();
126         mCodec = createCodec(isEncoder, mFdp.ConsumeBool() /* isCodecForClient */);
127         if (mCodec) {
128             invokekSyncCodecAPIs(isEncoder);
129             AMediaCodec_delete(mCodec);
130         }
131     }
132 }
133 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)134 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
135     NdkSyncCodecFuzzer ndkSyncCodecFuzzer(data, size);
136     ndkSyncCodecFuzzer.invokeSyncCodeConfigAPI();
137     return 0;
138 }
139