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