blob: c292298cba7f119ae6ae1fd1a394b8b853556368 [file] [log] [blame]
Harish Mahendrakar1cf21782019-06-20 13:57:20 -07001/******************************************************************************
2 *
3 * Copyright (C) 2019 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 */
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070020
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070021#include <stddef.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <algorithm>
28#include <memory>
29
30#include "ih264_typedefs.h"
31#include "ih264d.h"
32#include "iv.h"
33#include "ivd.h"
34
35#define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
36#define ivd_api_function ih264d_api_function
37const IV_COLOR_FORMAT_T supportedColorFormats[] = {
38 IV_YUV_420P, IV_YUV_420SP_UV, IV_YUV_420SP_VU,
39 IV_YUV_422ILE, IV_RGB_565, IV_RGBA_8888};
40
Harish Mahendrakar82b7f932019-08-26 16:03:03 -070041/* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
42 * decoder defaults to a supported configuration. So same set of supported
43 * architectures can be used in arm/arm64/x86 builds */
44const IVD_ARCH_T supportedArchitectures[] = {
45 ARCH_ARM_NONEON, ARCH_ARM_A9Q, ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
46 ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
47
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070048enum {
49 OFFSET_COLOR_FORMAT = 6,
50 OFFSET_NUM_CORES,
Harish Mahendrakar82b7f932019-08-26 16:03:03 -070051 OFFSET_ARCH,
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070052 /* Should be the last entry */
53 OFFSET_MAX,
54};
55
Harish Mahendrakar82b7f932019-08-26 16:03:03 -070056const static int kMaxNumDecodeCalls = 100;
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070057const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
Harish Mahendrakar82b7f932019-08-26 16:03:03 -070058const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070059const static int kMaxCores = 4;
60void *iv_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
Harish Mahendrakar9aefe922019-09-09 16:14:50 -070061 void *buf = NULL;
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070062 (void)ctxt;
Harish Mahendrakar9aefe922019-09-09 16:14:50 -070063 if (0 != posix_memalign(&buf, alignment, size)) {
64 return NULL;
65 }
66 return buf;
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070067}
68
69void iv_aligned_free(void *ctxt, void *buf) {
70 (void)ctxt;
71 free(buf);
72}
73
74class Codec {
75 public:
76 Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
77 ~Codec();
78
79 void createCodec();
80 void deleteCodec();
81 void resetCodec();
82 void setCores();
83 void allocFrame();
84 void freeFrame();
85 void decodeHeader(const uint8_t *data, size_t size);
86 IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
87 size_t *bytesConsumed);
88 void setParams(IVD_VIDEO_DECODE_MODE_T mode);
Harish Mahendrakar82b7f932019-08-26 16:03:03 -070089 void setArchitecture(IVD_ARCH_T arch);
Harish Mahendrakar1cf21782019-06-20 13:57:20 -070090
91 private:
92 IV_COLOR_FORMAT_T mColorFormat;
93 size_t mNumCores;
94 iv_obj_t *mCodec;
95 ivd_out_bufdesc_t mOutBufHandle;
96 uint32_t mWidth;
97 uint32_t mHeight;
98};
99
100Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
101 mColorFormat = colorFormat;
102 mNumCores = numCores;
103 mCodec = nullptr;
104 mWidth = 0;
105 mHeight = 0;
106
107 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
108}
109Codec::~Codec() {}
110void Codec::createCodec() {
111 IV_API_CALL_STATUS_T ret;
112 ih264d_create_ip_t create_ip;
113 ih264d_create_op_t create_op;
114 void *fxns = (void *)&ivd_api_function;
115
116 create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
117 create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
118 create_ip.s_ivd_create_ip_t.e_output_format = mColorFormat;
119 create_ip.s_ivd_create_ip_t.pf_aligned_alloc = iv_aligned_malloc;
120 create_ip.s_ivd_create_ip_t.pf_aligned_free = iv_aligned_free;
121 create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
122 create_ip.s_ivd_create_ip_t.u4_size = sizeof(ih264d_create_ip_t);
123 create_op.s_ivd_create_op_t.u4_size = sizeof(ih264d_create_op_t);
124
125 ret = ivd_api_function(NULL, (void *)&create_ip, (void *)&create_op);
126 if (ret != IV_SUCCESS) {
127 return;
128 }
129 mCodec = (iv_obj_t *)create_op.s_ivd_create_op_t.pv_handle;
130 mCodec->pv_fxns = fxns;
131 mCodec->u4_size = sizeof(iv_obj_t);
132}
133
134void Codec::deleteCodec() {
135 ivd_delete_ip_t delete_ip;
136 ivd_delete_op_t delete_op;
137
138 delete_ip.e_cmd = IVD_CMD_DELETE;
139 delete_ip.u4_size = sizeof(ivd_delete_ip_t);
140 delete_op.u4_size = sizeof(ivd_delete_op_t);
141
142 ivd_api_function(mCodec, (void *)&delete_ip, (void *)&delete_op);
143}
144void Codec::resetCodec() {
145 ivd_ctl_reset_ip_t s_ctl_ip;
146 ivd_ctl_reset_op_t s_ctl_op;
147
148 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
149 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
150 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
151 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
152
153 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
154}
155
156void Codec::setCores() {
157 ih264d_ctl_set_num_cores_ip_t s_ctl_ip;
158 ih264d_ctl_set_num_cores_op_t s_ctl_op;
159
160 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
161 s_ctl_ip.e_sub_cmd =
162 (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES;
163 s_ctl_ip.u4_num_cores = mNumCores;
164 s_ctl_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);
165 s_ctl_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);
166
167 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
168}
169
170void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
171 ivd_ctl_set_config_ip_t s_ctl_ip;
172 ivd_ctl_set_config_op_t s_ctl_op;
173
174 s_ctl_ip.u4_disp_wd = 0;
175 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
176 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
177 s_ctl_ip.e_vid_dec_mode = mode;
178 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
179 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
180 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
181 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
182
183 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
184}
185
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700186void Codec::setArchitecture(IVD_ARCH_T arch) {
187 ih264d_ctl_set_processor_ip_t s_ctl_ip;
188 ih264d_ctl_set_processor_op_t s_ctl_op;
189
190 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
191 s_ctl_ip.e_sub_cmd =
192 (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_PROCESSOR;
193 s_ctl_ip.u4_arch = arch;
194 s_ctl_ip.u4_soc = SOC_GENERIC;
195 s_ctl_ip.u4_size = sizeof(ih264d_ctl_set_processor_ip_t);
196 s_ctl_op.u4_size = sizeof(ih264d_ctl_set_processor_op_t);
197
198 ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
199}
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700200void Codec::freeFrame() {
201 for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
202 if (mOutBufHandle.pu1_bufs[i]) {
203 free(mOutBufHandle.pu1_bufs[i]);
204 mOutBufHandle.pu1_bufs[i] = nullptr;
205 }
206 }
207}
208void Codec::allocFrame() {
209 size_t sizes[4] = {0};
210 size_t num_bufs = 0;
211
212 freeFrame();
213
214 memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
215
216 switch (mColorFormat) {
217 case IV_YUV_420SP_UV:
218 [[fallthrough]];
219 case IV_YUV_420SP_VU:
220 sizes[0] = mWidth * mHeight;
221 sizes[1] = mWidth * mHeight >> 1;
222 num_bufs = 2;
223 break;
224 case IV_YUV_422ILE:
225 sizes[0] = mWidth * mHeight * 2;
226 num_bufs = 1;
227 break;
228 case IV_RGB_565:
229 sizes[0] = mWidth * mHeight * 2;
230 num_bufs = 1;
231 break;
232 case IV_RGBA_8888:
233 sizes[0] = mWidth * mHeight * 4;
234 num_bufs = 1;
235 break;
236 case IV_YUV_420P:
237 [[fallthrough]];
238 default:
239 sizes[0] = mWidth * mHeight;
240 sizes[1] = mWidth * mHeight >> 2;
241 sizes[2] = mWidth * mHeight >> 2;
242 num_bufs = 3;
243 break;
244 }
245 mOutBufHandle.u4_num_bufs = num_bufs;
246 for (int i = 0; i < num_bufs; i++) {
247 mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
Harish Mahendrakar9aefe922019-09-09 16:14:50 -0700248 mOutBufHandle.pu1_bufs[i] = (UWORD8 *)iv_aligned_malloc(NULL, 16, sizes[i]);
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700249 }
250}
251void Codec::decodeHeader(const uint8_t *data, size_t size) {
252 setParams(IVD_DECODE_HEADER);
253
254 while (size > 0) {
255 IV_API_CALL_STATUS_T ret;
256 ivd_video_decode_ip_t dec_ip;
257 ivd_video_decode_op_t dec_op;
258 size_t bytes_consumed;
259
260 memset(&dec_ip, 0, sizeof(dec_ip));
261 memset(&dec_op, 0, sizeof(dec_op));
262
263 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
264 dec_ip.u4_ts = 0;
265 dec_ip.pv_stream_buffer = (void *)data;
266 dec_ip.u4_num_Bytes = size;
267 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
268 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
269
270 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
271
272 bytes_consumed = dec_op.u4_num_bytes_consumed;
273 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
274 * to feed next data */
275 if (!bytes_consumed) bytes_consumed = 4;
276
277 bytes_consumed = std::min(size, bytes_consumed);
278
279 data += bytes_consumed;
280 size -= bytes_consumed;
281
282 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
283 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
284
285 /* Break after successful header decode */
286 if (mWidth && mHeight) {
287 break;
288 }
289 }
290 /* if width / height are invalid, set them to defaults */
291 if (!mWidth) mWidth = 1920;
292 if (!mHeight) mHeight = 1088;
293}
294
295IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
296 size_t *bytesConsumed) {
297 IV_API_CALL_STATUS_T ret;
298 ivd_video_decode_ip_t dec_ip;
299 ivd_video_decode_op_t dec_op;
300
301 memset(&dec_ip, 0, sizeof(dec_ip));
302 memset(&dec_op, 0, sizeof(dec_op));
303
304 dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
305 dec_ip.u4_ts = 0;
306 dec_ip.pv_stream_buffer = (void *)data;
307 dec_ip.u4_num_Bytes = size;
308 dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
309 dec_ip.s_out_buffer = mOutBufHandle;
310
311 dec_op.u4_size = sizeof(ivd_video_decode_op_t);
312
313 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
314
315 /* In case of change in resolution, reset codec and feed the same data again
316 */
317 if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
318 resetCodec();
319 ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
320 }
321 *bytesConsumed = dec_op.u4_num_bytes_consumed;
322
323 /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
324 * to feed next data */
325 if (!*bytesConsumed) *bytesConsumed = 4;
326
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700327 if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
328 (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700329 mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
330 mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
331 allocFrame();
332 }
333
334 return ret;
335}
336
337extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
338 if (size < 1) {
339 return 0;
340 }
341 size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
342 size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700343 size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
344 size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
345 IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700346 size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
347 IV_COLOR_FORMAT_T colorFormat =
348 (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
349 uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700350 size_t numDecodeCalls = 0;
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700351 Codec *codec = new Codec(colorFormat, numCores);
352 codec->createCodec();
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700353 codec->setArchitecture(arch);
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700354 codec->setCores();
355 codec->decodeHeader(data, size);
356 codec->setParams(IVD_DECODE_FRAME);
357 codec->allocFrame();
358
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700359 while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700360 IV_API_CALL_STATUS_T ret;
361 size_t bytesConsumed;
362 ret = codec->decodeFrame(data, size, &bytesConsumed);
363
364 bytesConsumed = std::min(size, bytesConsumed);
365 data += bytesConsumed;
366 size -= bytesConsumed;
Harish Mahendrakar82b7f932019-08-26 16:03:03 -0700367 numDecodeCalls++;
Harish Mahendrakar1cf21782019-06-20 13:57:20 -0700368 }
369
370 codec->freeFrame();
371 codec->deleteCodec();
372 delete codec;
373 return 0;
374}