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