/src/libhevc/fuzzer/hevc_enc_fuzzer.cpp
Line | Count | Source |
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 <algorithm> |
21 | | #include <memory> |
22 | | #include <string.h> |
23 | | |
24 | | #include "ihevc_typedefs.h" |
25 | | #include "itt_video_api.h" |
26 | | #include "ihevce_api.h" |
27 | | #include "ihevce_plugin.h" |
28 | | #include "ihevce_profile.h" |
29 | | |
30 | | #define NELEMENTS(x) (sizeof(x) / sizeof(x[0])) |
31 | | constexpr size_t kRcType[] = {2, 3, 5}; |
32 | | constexpr IHEVCE_QUALITY_CONFIG_T kQuality[] = { |
33 | | IHEVCE_QUALITY_P0, IHEVCE_QUALITY_P2, IHEVCE_QUALITY_P3, IHEVCE_QUALITY_P4, |
34 | | IHEVCE_QUALITY_P5, IHEVCE_QUALITY_P6, IHEVCE_QUALITY_P7}; |
35 | | |
36 | | constexpr size_t kRcTypeNum = NELEMENTS(kRcType); |
37 | | constexpr size_t kQualityNum = NELEMENTS(kQuality); |
38 | | constexpr size_t kMaxQP = 51; |
39 | | constexpr size_t kMaxGopPeriod = 16; |
40 | | constexpr size_t kMaxWidth = 10240; |
41 | | constexpr size_t kMaxHeight = 10240; |
42 | | constexpr size_t kMaxBitrate = 500000000; |
43 | | |
44 | | enum { |
45 | | IDX_WD_BYTE_1, |
46 | | IDX_WD_BYTE_2, |
47 | | IDX_HT_BYTE_1, |
48 | | IDX_HT_BYTE_2, |
49 | | IDX_MAX_INTRA_TX_DEPTH, |
50 | | IDX_MAX_INTER_TX_DEPTH, |
51 | | IDX_CU_RC, |
52 | | IDX_RC_MODE, |
53 | | IDX_FRAME_QP, |
54 | | IDX_PRESET, |
55 | | IDX_BITRATE_BYTE_1, |
56 | | IDX_BITRATE_BYTE_2, |
57 | | IDX_ENABLE_ENTROPY_SYNC, |
58 | | IDX_DEBLOCKING_TYPE, |
59 | | IDX_USE_SC_MTX, |
60 | | IDX_MAX_TEMPORAL_LAYERS, |
61 | | IDX_MAX_CLOSED_GOP, |
62 | | IDX_MIN_CLOSED_GOP, |
63 | | IDX_MAX_I_OPEN_GOP, |
64 | | IDX_MAX_CRA_OPEN_GOP, |
65 | | IDX_ENABLE_SPS_AT_CDR, |
66 | | IDX_ENABLE_VUI, |
67 | | IDX_ENABLE_SEI, |
68 | | IDX_ARCH_TYPE, |
69 | | IDX_ENABLE_FORCE_IDR, |
70 | | IDX_ENABLE_DYNAMIC_BITRATE, |
71 | | IDX_FORCE_IDR_INTERVAL, |
72 | | IDX_DYNAMIC_BITRATE_INTERVAL, |
73 | | IDX_LAST |
74 | | }; |
75 | | |
76 | | class Codec { |
77 | | public: |
78 | 6.84k | Codec() = default; |
79 | 7.66k | ~Codec() { deInitEncoder(); } |
80 | | bool initEncoder(const uint8_t *data); |
81 | | void deInitEncoder(); |
82 | | void encodeFrames(const uint8_t *data, size_t size); |
83 | | |
84 | | private: |
85 | | bool mIsForceIdrEnabled = false; |
86 | | bool mIsDynamicBitrateChangeEnabled = false; |
87 | | size_t mWidth = 352; |
88 | | size_t mHeight = 288; |
89 | | size_t mForceIdrInterval = 0; // in number of frames |
90 | | size_t mDynamicBitrateInterval = 0; // in number of frames |
91 | | uint64_t mBitrate = 5000000; |
92 | | void *mCodecCtx = nullptr; |
93 | | ihevce_static_cfg_params_t mEncParams = {}; |
94 | | }; |
95 | | |
96 | 6.84k | bool Codec::initEncoder(const uint8_t *data) { |
97 | | // default configuration |
98 | 6.84k | if (IHEVCE_EOK != ihevce_set_def_params(&mEncParams)) { |
99 | 0 | return false; |
100 | 0 | } |
101 | 6.84k | mWidth = ((data[IDX_WD_BYTE_1] << 8) | data[IDX_WD_BYTE_2]) % kMaxWidth; |
102 | 6.84k | mHeight = ((data[IDX_HT_BYTE_1] << 8) | data[IDX_HT_BYTE_2]) % kMaxHeight; |
103 | | |
104 | | // update configuration |
105 | 6.84k | mEncParams.s_src_prms.i4_width = mWidth; |
106 | 6.84k | mEncParams.s_src_prms.i4_height = mHeight; |
107 | | |
108 | 6.84k | mEncParams.s_config_prms.i4_max_tr_tree_depth_I = (data[IDX_MAX_INTRA_TX_DEPTH] % 3) + 1; |
109 | 6.84k | mEncParams.s_config_prms.i4_max_tr_tree_depth_nI = (data[IDX_MAX_INTER_TX_DEPTH] & 0x03) + 1; |
110 | 6.84k | mEncParams.s_config_prms.i4_cu_level_rc = data[IDX_CU_RC] & 0x01; |
111 | 6.84k | mEncParams.s_config_prms.i4_rate_control_mode = kRcType[data[IDX_RC_MODE] % kRcTypeNum]; |
112 | | |
113 | 6.84k | mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_frame_qp[0] = (data[IDX_FRAME_QP] % kMaxQP) + 1; |
114 | 6.84k | mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = |
115 | 6.84k | kQuality[data[IDX_PRESET] % kQualityNum]; |
116 | 6.84k | mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] = |
117 | 6.84k | (((data[IDX_BITRATE_BYTE_1] << 8) | data[IDX_BITRATE_BYTE_2]) * 1000) % kMaxBitrate; |
118 | 6.84k | mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_peak_bitrate[0] = |
119 | 6.84k | ((((data[IDX_BITRATE_BYTE_1] << 8) | data[IDX_BITRATE_BYTE_2]) * 1000) % kMaxBitrate) << 1; |
120 | 6.84k | mEncParams.s_coding_tools_prms.i4_enable_entropy_sync = data[IDX_ENABLE_ENTROPY_SYNC] & 0x01; |
121 | 6.84k | mEncParams.s_coding_tools_prms.i4_deblocking_type = data[IDX_DEBLOCKING_TYPE] & 0x01; |
122 | 6.84k | mEncParams.s_coding_tools_prms.i4_use_default_sc_mtx = data[IDX_USE_SC_MTX] & 0x01; |
123 | 6.84k | mEncParams.s_coding_tools_prms.i4_max_temporal_layers = data[IDX_MAX_TEMPORAL_LAYERS] & 0x02; |
124 | 6.84k | mEncParams.s_coding_tools_prms.i4_max_closed_gop_period = |
125 | 6.84k | data[IDX_MAX_CLOSED_GOP] % kMaxGopPeriod; |
126 | 6.84k | mEncParams.s_coding_tools_prms.i4_min_closed_gop_period = |
127 | 6.84k | data[IDX_MIN_CLOSED_GOP] % kMaxGopPeriod; |
128 | 6.84k | mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = |
129 | 6.84k | data[IDX_MAX_I_OPEN_GOP] % kMaxGopPeriod; |
130 | 6.84k | mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = |
131 | 6.84k | data[IDX_MAX_CRA_OPEN_GOP] % kMaxGopPeriod; |
132 | | |
133 | 6.84k | mEncParams.s_out_strm_prms.i4_sps_at_cdr_enable = data[IDX_ENABLE_SPS_AT_CDR] & 0x01; |
134 | 6.84k | mEncParams.s_out_strm_prms.i4_vui_enable = data[IDX_ENABLE_VUI] & 0x01; |
135 | 6.84k | mEncParams.s_out_strm_prms.i4_sei_enable_flag = data[IDX_ENABLE_SEI] & 0x01; |
136 | | |
137 | 6.84k | mEncParams.e_arch_type = ((data[IDX_ARCH_TYPE] & 0x03) == 0x00) ? ARCH_ARM_NONEON : ARCH_NA; |
138 | 6.84k | mIsForceIdrEnabled = data[IDX_ENABLE_FORCE_IDR] & 0x01; |
139 | 6.84k | mIsDynamicBitrateChangeEnabled = data[IDX_ENABLE_DYNAMIC_BITRATE] & 0x01; |
140 | 6.84k | mForceIdrInterval = data[IDX_FORCE_IDR_INTERVAL] & 0x07; |
141 | 6.84k | mDynamicBitrateInterval = data[IDX_DYNAMIC_BITRATE_INTERVAL] & 0x07; |
142 | | |
143 | 6.84k | if (IHEVCE_EOK != ihevce_init(&mEncParams, &mCodecCtx)) { |
144 | 35 | return false; |
145 | 35 | } |
146 | 6.81k | return true; |
147 | 6.84k | } |
148 | | |
149 | 6.81k | void Codec::encodeFrames(const uint8_t *data, size_t size) { |
150 | 6.81k | size_t frameSize = (mWidth * mHeight * 3) / 2; |
151 | | |
152 | 6.81k | ihevce_out_buf_t sHeaderOp{}; |
153 | 6.81k | ihevce_encode_header(mCodecCtx, &sHeaderOp); |
154 | 6.81k | size_t frameNumber = 0; |
155 | 6.81k | uint8_t *tmpData = new uint8_t[frameSize]; |
156 | 103k | while (size > 0) { |
157 | 96.3k | ihevce_inp_buf_t sEncodeIp{}; |
158 | 96.3k | ihevce_out_buf_t sEncodeOp{}; |
159 | 96.3k | size_t bytesConsumed = std::min(size, frameSize); |
160 | 96.3k | if (bytesConsumed < frameSize) { |
161 | 6.30k | memset(&tmpData[bytesConsumed], data[0], frameSize - bytesConsumed); |
162 | 6.30k | } |
163 | 96.3k | memcpy(tmpData, data, bytesConsumed); |
164 | 96.3k | int32_t yStride = mWidth; |
165 | 96.3k | int32_t uStride = mWidth >> 1; |
166 | 96.3k | int32_t vStride = mWidth >> 1; |
167 | | |
168 | 96.3k | sEncodeIp.apv_inp_planes[0] = tmpData; |
169 | 96.3k | sEncodeIp.apv_inp_planes[1] = tmpData + (mWidth * mHeight); |
170 | 96.3k | sEncodeIp.apv_inp_planes[2] = tmpData + ((mWidth * mHeight) * 5) / 4; |
171 | | |
172 | 96.3k | sEncodeIp.ai4_inp_strd[0] = yStride; |
173 | 96.3k | sEncodeIp.ai4_inp_strd[1] = uStride; |
174 | 96.3k | sEncodeIp.ai4_inp_strd[2] = vStride; |
175 | | |
176 | 96.3k | sEncodeIp.ai4_inp_size[0] = yStride * mHeight; |
177 | 96.3k | sEncodeIp.ai4_inp_size[1] = uStride * mHeight >> 1; |
178 | 96.3k | sEncodeIp.ai4_inp_size[2] = vStride * mHeight >> 1; |
179 | | |
180 | 96.3k | sEncodeIp.i4_force_idr_flag = 0; |
181 | 96.3k | sEncodeIp.i4_curr_bitrate = mBitrate; |
182 | 96.3k | sEncodeIp.i4_curr_peak_bitrate = mBitrate << 1; |
183 | 96.3k | sEncodeIp.u8_pts = 0; |
184 | 96.3k | if (mIsForceIdrEnabled) { |
185 | 31.9k | if (frameNumber == mForceIdrInterval) { |
186 | 1.04k | sEncodeIp.i4_force_idr_flag = 1; |
187 | 1.04k | } |
188 | 31.9k | } |
189 | 96.3k | if (mIsDynamicBitrateChangeEnabled) { |
190 | 34.9k | if (frameNumber == mDynamicBitrateInterval) { |
191 | 1.35k | mBitrate = mBitrate << 1; |
192 | 1.35k | } |
193 | 34.9k | } |
194 | 96.3k | ihevce_encode(mCodecCtx, &sEncodeIp, &sEncodeOp); |
195 | 96.3k | ++frameNumber; |
196 | 96.3k | data += bytesConsumed; |
197 | 96.3k | size -= bytesConsumed; |
198 | 96.3k | } |
199 | 6.81k | delete[] tmpData; |
200 | 6.81k | } |
201 | | |
202 | 6.84k | void Codec::deInitEncoder() { |
203 | 6.84k | if (mCodecCtx) { |
204 | 6.81k | ihevce_close(mCodecCtx); |
205 | 6.81k | mCodecCtx = nullptr; |
206 | 6.81k | } |
207 | 6.84k | return; |
208 | 6.84k | } |
209 | | |
210 | 6.85k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
211 | 6.85k | if (size < IDX_LAST) { |
212 | 5 | return 0; |
213 | 5 | } |
214 | 6.84k | Codec *codec = new Codec(); |
215 | 6.84k | if (codec->initEncoder(data)) { |
216 | 6.81k | data += IDX_LAST; |
217 | 6.81k | size -= IDX_LAST; |
218 | 6.81k | codec->encodeFrames(data, size); |
219 | 6.81k | } |
220 | 6.84k | delete codec; |
221 | 6.84k | return 0; |
222 | 6.85k | } |