1 /******************************************************************************
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 */
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <algorithm>
24
25 #ifdef __cplusplus
26 extern "C"
27 {
28 #include "ih264_typedefs.h"
29 #include "imvcd.h"
30 }
31 #endif
32
33 #define MAX_NUM_VIEWS 6
34
35 #define NUM_COMPONENTS 3
36
37 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
38
39 typedef enum ARG_OFFSETS_T
40 {
41 OFFSET_COLOR_FORMAT = 6,
42 OFFSET_NUM_CORES,
43 OFFSET_ARCH,
44 /* Should be the last entry */
45 OFFSET_MAX,
46 } ARG_OFFSETS_T;
47
48 static const IV_COLOR_FORMAT_T supportedColorFormats[] = {IV_YUV_420P};
49 static const IVD_ARCH_T supportedArchitectures[] = {ARCH_ARM_NEONINTR, ARCH_X86_GENERIC,
50 ARCH_X86_SSSE3, ARCH_X86_SSE42};
51 static const int kMaxNumDecodeCalls = 1000;
52 static const int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
53 static const int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
54 static const int kMaxCores = 3;
55
mvcd_aligned_malloc(void * pv_ctxt,WORD32 alignment,WORD32 i4_size)56 static inline void *mvcd_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size)
57 {
58 void *buf = nullptr;
59 (void) pv_ctxt;
60
61 if(0 != posix_memalign(&buf, alignment, i4_size))
62 {
63 return nullptr;
64 }
65
66 return buf;
67 }
68
mvcd_aligned_free(void * pv_ctxt,void * pv_buf)69 static inline void mvcd_aligned_free(void *pv_ctxt, void *pv_buf)
70 {
71 (void) pv_ctxt;
72 free(pv_buf);
73 }
74
75 class Codec
76 {
77 public:
78 Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
79 ~Codec();
80
81 void resetCodec();
82 WORD32 allocFrame();
83 void freeFrame();
84 IV_API_CALL_STATUS_T decodeHeader(const uint8_t *data, size_t size);
85 IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size, size_t *bytesConsumed);
86 void setArchitecture(IVD_ARCH_T arch);
87 void setBufInfo();
88 void setCores();
89
getOutBuf()90 ivd_out_bufdesc_t *getOutBuf() { return &mOutBufHandle; }
91
getViewDispBuf(UWORD16 u2_view_id=0)92 iv_yuv_buf_t *getViewDispBuf(UWORD16 u2_view_id = 0) { return &as_view_disp_bufs[u2_view_id]; }
93
getNumViews()94 UWORD32 getNumViews() { return mBufInfo.s_mvc_buf_info.u2_num_views; }
95
getCodecHandle()96 iv_obj_t *getCodecHandle() { return mCodec; }
97
98 private:
99 iv_obj_t *mCodec;
100 ivd_out_bufdesc_t mOutBufHandle;
101 iv_yuv_buf_t as_view_disp_bufs[MAX_NUM_VIEWS];
102 imvcd_get_buf_info_op_t mBufInfo;
103 IV_COLOR_FORMAT_T mColorFormat;
104 size_t mNumCores;
105 uint32_t mWidth;
106 uint32_t mHeight;
107 };
108
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)109 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores)
110 : mCodec(nullptr), mColorFormat(colorFormat), mNumCores(numCores), mWidth(0), mHeight(0)
111 {
112 imvcd_create_ip_t s_create_ip;
113 imvcd_create_op_t s_create_op;
114
115 s_create_ip.s_ivd_ip.e_cmd = IVD_CMD_CREATE;
116 s_create_ip.s_ivd_ip.e_output_format = colorFormat;
117 s_create_ip.s_ivd_ip.pf_aligned_alloc = mvcd_aligned_malloc;
118 s_create_ip.s_ivd_ip.pf_aligned_free = mvcd_aligned_free;
119 s_create_ip.s_ivd_ip.u4_share_disp_buf = 0;
120 s_create_ip.s_ivd_ip.pv_mem_ctxt = nullptr;
121
122 s_create_ip.s_ivd_ip.u4_size = sizeof(s_create_ip.s_ivd_ip);
123 s_create_op.s_ivd_op.u4_size = sizeof(s_create_op.s_ivd_op);
124
125 imvcd_api_function(NULL, &s_create_ip, &s_create_op);
126
127 mCodec = static_cast<iv_obj_t *>(s_create_op.s_ivd_op.pv_handle);
128
129 setCores();
130
131 memset(getOutBuf(), 0, sizeof(getOutBuf()[0]));
132 }
133
~Codec()134 Codec::~Codec()
135 {
136 imvcd_delete_ip_t s_delete_ip;
137 imvcd_delete_op_t s_delete_op;
138
139 s_delete_ip.s_ivd_ip.e_cmd = IVD_CMD_DELETE;
140
141 s_delete_ip.s_ivd_ip.u4_size = sizeof(s_delete_ip.s_ivd_ip);
142 s_delete_op.s_ivd_op.u4_size = sizeof(s_delete_op.s_ivd_op);
143
144 imvcd_api_function(mCodec, &s_delete_ip, &s_delete_op);
145 }
146
setCores()147 void Codec::setCores()
148 {
149 imvcd_set_num_cores_ip_t s_ctl_ip;
150 imvcd_set_num_cores_op_t s_ctl_op;
151
152 s_ctl_ip.u4_size = sizeof(s_ctl_ip);
153 s_ctl_op.u4_size = sizeof(s_ctl_op);
154 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
155 s_ctl_ip.e_sub_cmd = static_cast<IVD_CONTROL_API_COMMAND_TYPE_T>(IMVCD_CTL_SET_NUM_CORES);
156 s_ctl_ip.u4_num_cores = mNumCores;
157
158 imvcd_api_function(mCodec, &s_ctl_ip, &s_ctl_op);
159 }
160
setArchitecture(IVD_ARCH_T e_arch)161 void Codec::setArchitecture(IVD_ARCH_T e_arch)
162 {
163 imvcd_set_arch_ip_t s_ctl_ip;
164 imvcd_set_arch_op_t s_ctl_op;
165
166 s_ctl_ip.u4_size = sizeof(s_ctl_ip);
167 s_ctl_op.u4_size = sizeof(s_ctl_op);
168 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
169 s_ctl_ip.e_sub_cmd = static_cast<IVD_CONTROL_API_COMMAND_TYPE_T>(IMVCD_CTL_SET_PROCESSOR);
170 s_ctl_ip.e_arch = e_arch;
171 s_ctl_ip.e_soc = SOC_GENERIC;
172
173 imvcd_api_function(mCodec, &s_ctl_ip, &s_ctl_op);
174 }
175
setBufInfo()176 void Codec::setBufInfo()
177 {
178 imvcd_get_buf_info_ip_t s_ctl_ip;
179 imvcd_get_buf_info_op_t s_ctl_op;
180
181 s_ctl_ip.s_ivd_ip.u4_size = sizeof(s_ctl_ip.s_ivd_ip);
182 s_ctl_op.s_ivd_op.u4_size = sizeof(s_ctl_op.s_ivd_op);
183 s_ctl_ip.s_ivd_ip.e_cmd = IVD_CMD_VIDEO_CTL;
184 s_ctl_ip.s_ivd_ip.e_sub_cmd =
185 static_cast<IVD_CONTROL_API_COMMAND_TYPE_T>(IVD_CMD_CTL_GETBUFINFO);
186
187 imvcd_api_function(mCodec, &s_ctl_ip, &s_ctl_op);
188
189 mBufInfo = s_ctl_op;
190 }
191
allocFrame()192 WORD32 Codec::allocFrame()
193 {
194 if(getNumViews() > MAX_NUM_VIEWS)
195 {
196 return IV_FAIL;
197 }
198
199 if(mBufInfo.s_ivd_op.u4_min_num_out_bufs < (NUM_COMPONENTS * getNumViews()))
200 {
201 return IV_FAIL;
202 }
203
204 getOutBuf()->u4_num_bufs = mBufInfo.s_ivd_op.u4_min_num_out_bufs;
205
206 for(UWORD32 i = 0; i < getOutBuf()->u4_num_bufs; i++)
207 {
208 getOutBuf()->u4_min_out_buf_size[i] = mBufInfo.s_ivd_op.u4_min_out_buf_size[i];
209 getOutBuf()->pu1_bufs[i] =
210 (UWORD8 *) mvcd_aligned_malloc(nullptr, 16, mBufInfo.s_ivd_op.u4_min_out_buf_size[i]);
211
212 if(getOutBuf()->pu1_bufs[i] == nullptr)
213 {
214 return IV_FAIL;
215 }
216 }
217
218 return IV_SUCCESS;
219 }
220
freeFrame()221 void Codec::freeFrame()
222 {
223 for(UWORD32 i = 0; i < getOutBuf()->u4_num_bufs; i++)
224 {
225 if(getOutBuf()->pu1_bufs[i])
226 {
227 mvcd_aligned_free(nullptr, getOutBuf()->pu1_bufs[i]);
228 getOutBuf()->pu1_bufs[i] = nullptr;
229 }
230 }
231 }
232
sendDecodeSignal(iv_obj_t * psCodec,IVD_VIDEO_DECODE_MODE_T eDecMode)233 static void sendDecodeSignal(iv_obj_t *psCodec, IVD_VIDEO_DECODE_MODE_T eDecMode)
234 {
235 imvcd_set_config_ip_t s_ctl_ip;
236 imvcd_set_config_op_t s_ctl_op;
237
238 s_ctl_ip.s_ivd_ip.u4_size = sizeof(s_ctl_ip.s_ivd_ip);
239 s_ctl_op.s_ivd_op.u4_size = sizeof(s_ctl_op.s_ivd_op);
240 s_ctl_ip.s_ivd_ip.e_cmd = IVD_CMD_VIDEO_CTL;
241 s_ctl_ip.s_ivd_ip.e_sub_cmd =
242 static_cast<IVD_CONTROL_API_COMMAND_TYPE_T>(IVD_CMD_CTL_SETPARAMS);
243
244 s_ctl_ip.s_ivd_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
245 s_ctl_ip.s_ivd_ip.e_frm_skip_mode = IVD_SKIP_NONE;
246 s_ctl_ip.s_ivd_ip.e_vid_dec_mode = eDecMode;
247
248 imvcd_api_function(psCodec, &s_ctl_ip, &s_ctl_op);
249 }
250
decodeHeader(const uint8_t * data,size_t size)251 IV_API_CALL_STATUS_T Codec::decodeHeader(const uint8_t *data, size_t size)
252 {
253 IV_API_CALL_STATUS_T ret;
254
255 WORD32 numBytesRemaining = size;
256
257 sendDecodeSignal(mCodec, IVD_DECODE_HEADER);
258
259 while(size > 0)
260 {
261 imvcd_video_decode_ip_t s_video_decode_ip;
262 imvcd_video_decode_op_t s_video_decode_op;
263
264 UWORD32 u4_num_bytes_dec = 0;
265
266 memset(&s_video_decode_ip, 0, sizeof(s_video_decode_ip));
267 memset(&s_video_decode_op, 0, sizeof(s_video_decode_op));
268
269 s_video_decode_ip.s_ivd_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
270 s_video_decode_ip.s_ivd_ip.u4_ts = 0;
271 s_video_decode_ip.s_ivd_ip.pv_stream_buffer =
272 static_cast<void *>(const_cast<uint8_t *>(data));
273 s_video_decode_ip.s_ivd_ip.u4_num_Bytes = numBytesRemaining;
274 s_video_decode_ip.s_ivd_ip.s_out_buffer = getOutBuf()[0];
275 s_video_decode_op.ps_view_disp_bufs = getViewDispBuf();
276
277 s_video_decode_ip.s_ivd_ip.u4_size = sizeof(s_video_decode_ip.s_ivd_ip);
278 s_video_decode_op.s_ivd_op.u4_size = sizeof(s_video_decode_op.s_ivd_op);
279
280 ret = imvcd_api_function(mCodec, &s_video_decode_ip, &s_video_decode_op);
281
282 if(IV_SUCCESS != ret)
283 {
284 return IV_FAIL;
285 }
286
287 u4_num_bytes_dec = s_video_decode_op.s_ivd_op.u4_num_bytes_consumed;
288
289 data += u4_num_bytes_dec;
290 numBytesRemaining -= u4_num_bytes_dec;
291 mWidth = s_video_decode_op.s_ivd_op.u4_pic_wd;
292 mHeight = s_video_decode_op.s_ivd_op.u4_pic_ht;
293
294 /* Break after successful header decode */
295 if(mWidth && mHeight)
296 {
297 break;
298 }
299 }
300
301 /* if width / height are invalid, set them to defaults */
302 if(!mWidth)
303 {
304 mWidth = 1920;
305 }
306
307 if(!mHeight)
308 {
309 mHeight = 1080;
310 }
311
312 setBufInfo();
313
314 return IV_SUCCESS;
315 }
316
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)317 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size, size_t *bytesConsumed)
318 {
319 imvcd_video_decode_ip_t s_video_decode_ip;
320 imvcd_video_decode_op_t s_video_decode_op;
321
322 IV_API_CALL_STATUS_T ret;
323
324 memset(&s_video_decode_ip, 0, sizeof(s_video_decode_ip));
325 memset(&s_video_decode_op, 0, sizeof(s_video_decode_op));
326
327 sendDecodeSignal(mCodec, IVD_DECODE_FRAME);
328
329 s_video_decode_ip.s_ivd_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
330 s_video_decode_ip.s_ivd_ip.u4_ts = 0;
331 s_video_decode_ip.s_ivd_ip.pv_stream_buffer = static_cast<void *>(const_cast<uint8_t *>(data));
332 s_video_decode_ip.s_ivd_ip.u4_num_Bytes = size;
333 s_video_decode_ip.s_ivd_ip.s_out_buffer = getOutBuf()[0];
334 s_video_decode_op.ps_view_disp_bufs = getViewDispBuf();
335
336 s_video_decode_ip.s_ivd_ip.u4_size = sizeof(s_video_decode_ip.s_ivd_ip);
337 s_video_decode_op.s_ivd_op.u4_size = sizeof(s_video_decode_op.s_ivd_op);
338
339 ret = imvcd_api_function(mCodec, &s_video_decode_ip, &s_video_decode_op);
340
341 bytesConsumed[0] = s_video_decode_op.s_ivd_op.u4_num_bytes_consumed;
342
343 if(s_video_decode_op.s_ivd_op.u4_pic_wd && s_video_decode_op.s_ivd_op.u4_pic_ht &&
344 ((mWidth != s_video_decode_op.s_ivd_op.u4_pic_wd) ||
345 (mHeight != s_video_decode_op.s_ivd_op.u4_pic_ht)))
346 {
347 mWidth = s_video_decode_op.s_ivd_op.u4_pic_wd;
348 mHeight = s_video_decode_op.s_ivd_op.u4_pic_ht;
349 freeFrame();
350 allocFrame();
351 }
352
353 return ret;
354 }
355
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)356 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
357 {
358 if(size < 1)
359 {
360 return 0;
361 }
362
363 WORD32 ret;
364
365 size_t colorFormatOfst = std::min((size_t) OFFSET_COLOR_FORMAT, size - 1);
366 size_t numCoresOfst = std::min((size_t) OFFSET_NUM_CORES, size - 1);
367 size_t architectureOfst = std::min((size_t) OFFSET_ARCH, size - 1);
368 size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
369 size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
370 uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
371 uint32_t numDecodeCalls = 0;
372
373 IVD_ARCH_T arch = (IVD_ARCH_T) supportedArchitectures[architectureIdx];
374 IV_COLOR_FORMAT_T colorFormat = (IV_COLOR_FORMAT_T) (supportedColorFormats[colorFormatIdx]);
375
376 Codec cCodec = Codec(colorFormat, numCores);
377
378 cCodec.setArchitecture(arch);
379
380 ret = cCodec.decodeHeader(data, size);
381
382 if(IV_SUCCESS != ret)
383 {
384 return 0;
385 }
386
387 ret = cCodec.allocFrame();
388
389 if(IV_SUCCESS != ret)
390 {
391 cCodec.freeFrame();
392
393 return 0;
394 }
395
396 while((size > 0) && (numDecodeCalls < kMaxNumDecodeCalls))
397 {
398 size_t bytesConsumed;
399
400 IV_API_CALL_STATUS_T ret = cCodec.decodeFrame(data, size, &bytesConsumed);
401
402 if(ret != IV_SUCCESS)
403 {
404 break;
405 }
406
407 bytesConsumed = std::min(size, bytesConsumed);
408 data += bytesConsumed;
409 size -= bytesConsumed;
410 numDecodeCalls++;
411 }
412
413 cCodec.freeFrame();
414
415 return 0;
416 }
417