1 /*
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 #include <algorithm>
17 #include "mp4enc_api.h"
18
19 constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
20 constexpr MP4RateControlType krcType[] = {CONSTANT_Q, CBR_1, VBR_1, CBR_2, VBR_2, CBR_LOWDELAY};
21 #ifdef MPEG4
22 constexpr MP4EncodingMode kEncodingMode[] = {SHORT_HEADER, SHORT_HEADER_WITH_ERR_RES,
23 DATA_PARTITIONING_MODE, COMBINE_MODE_NO_ERR_RES,
24 COMBINE_MODE_WITH_ERR_RES};
25 constexpr size_t kMaxWidth = 10240;
26 constexpr size_t kMaxHeight = 10240;
27 #else
28 constexpr MP4EncodingMode kEncodingMode[] = {H263_MODE, H263_MODE_WITH_ERR_RES};
29 constexpr int kWidth[] = {128, 176, 352, 704, 1408};
30 constexpr int kHeight[] = {96, 144, 288, 576, 1152};
31 constexpr size_t kWidthNum = std::size(kWidth);
32 constexpr size_t kHeightNum = std::size(kHeight);
33 #endif
34
35 constexpr size_t krcTypeNum = std::size(krcType);
36 constexpr size_t kEncodingModeNum = std::size(kEncodingMode);
37 constexpr size_t kMaxQP = 51;
38
39 enum {
40 IDX_WD_BYTE_1,
41 IDX_WD_BYTE_2,
42 IDX_HT_BYTE_1,
43 IDX_HT_BYTE_2,
44 IDX_FRAME_RATE,
45 IDX_RC_TYPE,
46 IDX_PACKET_SIZE,
47 IDX_I_FRAME_QP,
48 IDX_P_FRAME_QP,
49 IDX_ENABLE_RVLC,
50 IDX_QUANT_TYPE,
51 IDX_NO_FRAME_SKIPPED_FLAG,
52 IDX_ENABLE_SCENE_DETECT,
53 IDX_NUM_INTRA_MB,
54 IDX_SEARCH_RANGE,
55 IDX_ENABLE_MV_8x8,
56 IDX_USE_AC_PRED,
57 IDX_INTRA_DC_VLC_THRESHOLD,
58 IDX_ENC_MODE,
59 IDX_LAST
60 };
61
62 class Codec {
63 public:
64 Codec() = default;
~Codec()65 ~Codec() { deInitEncoder(); }
66 bool initEncoder(const uint8_t *data);
67 void encodeFrames(const uint8_t *data, size_t size);
68 void deInitEncoder();
69
70 private:
71 int32_t mFrameWidth = 352;
72 int32_t mFrameHeight = 288;
73 float mFrameRate = 25.0f;
74 VideoEncOptions *mEncodeHandle = nullptr;
75 VideoEncControls *mEncodeControl = nullptr;
76 };
77
initEncoder(const uint8_t * data)78 bool Codec::initEncoder(const uint8_t *data) {
79 mEncodeHandle = new VideoEncOptions;
80 if (!mEncodeHandle) {
81 return false;
82 }
83 memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
84 mEncodeControl = new VideoEncControls;
85 if (!mEncodeControl) {
86 return false;
87 }
88 memset(mEncodeControl, 0, sizeof(VideoEncControls));
89 PVGetDefaultEncOption(mEncodeHandle, 0);
90
91 #ifdef MPEG4
92 mFrameWidth = ((data[IDX_WD_BYTE_1] << 8) | data[IDX_WD_BYTE_2]) % kMaxWidth;
93 mFrameHeight = ((data[IDX_HT_BYTE_1] << 8) | data[IDX_HT_BYTE_2]) % kMaxHeight;
94 #else
95 mFrameWidth = kWidth[data[IDX_WD_BYTE_1] % kWidthNum];
96 mFrameHeight = kHeight[data[IDX_HT_BYTE_1] % kHeightNum];
97 #endif
98 mFrameRate = data[IDX_FRAME_RATE];
99 mEncodeHandle->rcType = krcType[data[IDX_RC_TYPE] % krcTypeNum];
100 mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
101 mEncodeHandle->packetSize = data[IDX_PACKET_SIZE];
102 mEncodeHandle->iQuant[0] = (data[IDX_I_FRAME_QP] % kMaxQP) + 1;
103 mEncodeHandle->pQuant[0] = (data[IDX_P_FRAME_QP] % kMaxQP) + 1;
104 mEncodeHandle->rvlcEnable = (data[IDX_ENABLE_RVLC] & 0x01) ? PV_OFF : PV_ON;
105 mEncodeHandle->quantType[0] = (data[IDX_QUANT_TYPE] & 0x01) ? 0 : 1;
106 mEncodeHandle->noFrameSkipped = (data[IDX_NO_FRAME_SKIPPED_FLAG] & 0x01) ? PV_OFF : PV_ON;
107 mEncodeHandle->sceneDetect = (data[IDX_ENABLE_SCENE_DETECT] & 0x01) ? PV_OFF : PV_ON;
108 mEncodeHandle->numIntraMB = data[IDX_NUM_INTRA_MB] & 0x07;
109 mEncodeHandle->searchRange = data[IDX_SEARCH_RANGE] & 0x1F;
110 mEncodeHandle->mv8x8Enable = (data[IDX_ENABLE_MV_8x8] & 0x01) ? PV_OFF : PV_ON;
111 mEncodeHandle->useACPred = (data[IDX_USE_AC_PRED] & 0x01) ? PV_OFF : PV_ON;
112 mEncodeHandle->intraDCVlcTh = data[IDX_INTRA_DC_VLC_THRESHOLD] & 0x07;
113 mEncodeHandle->encMode = kEncodingMode[data[IDX_ENC_MODE] % kEncodingModeNum];
114 mEncodeHandle->encWidth[0] = mFrameWidth;
115 mEncodeHandle->encHeight[0] = mFrameHeight;
116 mEncodeHandle->encFrameRate[0] = mFrameRate;
117 mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
118 mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
119 if (!PVInitVideoEncoder(mEncodeControl, mEncodeHandle)) {
120 return false;
121 }
122 return true;
123 }
124
deInitEncoder()125 void Codec::deInitEncoder() {
126 if (mEncodeControl) {
127 PVCleanUpVideoEncoder(mEncodeControl);
128 delete mEncodeControl;
129 mEncodeControl = nullptr;
130 }
131 if (mEncodeHandle) {
132 delete mEncodeHandle;
133 mEncodeHandle = nullptr;
134 }
135 }
136
encodeFrames(const uint8_t * data,size_t size)137 void Codec::encodeFrames(const uint8_t *data, size_t size) {
138 size_t inputBufferSize = (mFrameWidth * mFrameHeight * 3) / 2;
139 size_t outputBufferSize = inputBufferSize * 2;
140 uint8_t *outputBuffer = new uint8_t[outputBufferSize];
141 uint8_t *inputBuffer = new uint8_t[inputBufferSize];
142
143 // Get VOL header.
144 int32_t sizeOutputBuffer = outputBufferSize;
145 PVGetVolHeader(mEncodeControl, outputBuffer, &sizeOutputBuffer, 0);
146
147 size_t numFrame = 0;
148 while (size > 0) {
149 size_t bytesConsumed = std::min(size, inputBufferSize);
150 memcpy(inputBuffer, data, bytesConsumed);
151 if (bytesConsumed < inputBufferSize) {
152 memset(inputBuffer + bytesConsumed, data[0], inputBufferSize - bytesConsumed);
153 }
154 VideoEncFrameIO videoIn{}, videoOut{};
155 videoIn.height = mFrameHeight;
156 videoIn.pitch = mFrameWidth;
157 videoIn.timestamp = (numFrame * 1000) / mFrameRate;
158 videoIn.yChan = inputBuffer;
159 videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
160 videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
161 uint32_t modTimeMs = 0;
162 int32_t dataLength = outputBufferSize;
163 int32_t nLayer = 0;
164 PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, outputBuffer,
165 &dataLength, &nLayer);
166 MP4HintTrack hintTrack;
167 PVGetHintTrack(mEncodeControl, &hintTrack);
168 PVGetOverrunBuffer(mEncodeControl);
169 ++numFrame;
170 data += bytesConsumed;
171 size -= bytesConsumed;
172 }
173 delete[] inputBuffer;
174 delete[] outputBuffer;
175 }
176
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)177 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
178 if (size < IDX_LAST) {
179 return 0;
180 }
181 Codec *codec = new Codec();
182 if (!codec) {
183 return 0;
184 }
185 if (codec->initEncoder(data)) {
186 data += IDX_LAST;
187 size -= IDX_LAST;
188 codec->encodeFrames(data, size);
189 }
190 delete codec;
191 return 0;
192 }
193