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