• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 #include <malloc.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <algorithm>
28 #include <memory>
29 
30 #include "iv_datatypedef.h"
31 #include "iv.h"
32 #include "ivd.h"
33 #include "impeg2d.h"
34 
35 #define ALIGN2(x) ((((x) + 1) >> 1) << 1)
36 #define MAX_FRAME_WIDTH 3840
37 #define MAX_FRAME_HEIGHT 2160
38 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0]))
39 #define ivd_api_function impeg2d_api_function
40 const IV_COLOR_FORMAT_T supportedColorFormats[] = {IV_YUV_420P, IV_YUV_420SP_UV,
41                                                    IV_YUV_420SP_VU};
42 
43 /* Decoder ignores invalid arch, i.e. for arm build, if SSSE3 is requested,
44  * decoder defaults to a supported configuration. So same set of supported
45  * architectures can be used in arm/arm64/x86 builds */
46 const IVD_ARCH_T supportedArchitectures[] = {
47     ARCH_ARM_NONEON,  ARCH_ARM_A9Q,   ARCH_ARM_NEONINTR, ARCH_ARMV8_GENERIC,
48     ARCH_X86_GENERIC, ARCH_X86_SSSE3, ARCH_X86_SSE42};
49 
50 enum {
51   OFFSET_COLOR_FORMAT = 6,
52   OFFSET_NUM_CORES,
53   OFFSET_ARCH,
54   /* Should be the last entry */
55   OFFSET_MAX,
56 };
57 
58 const static int kMaxNumDecodeCalls = 100;
59 const static int kSupportedColorFormats = NELEMENTS(supportedColorFormats);
60 const static int kSupportedArchitectures = NELEMENTS(supportedArchitectures);
61 const static int kMaxCores = 4;
62 
63 class Codec {
64  public:
65   Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores);
66   ~Codec();
67 
68   void createCodec();
69   void deleteCodec();
70   void resetCodec();
71   void setCores();
72   void allocFrame();
73   void freeFrame();
74   void decodeHeader(const uint8_t *data, size_t size);
75   IV_API_CALL_STATUS_T decodeFrame(const uint8_t *data, size_t size,
76                                    size_t *bytesConsumed);
77   void setParams(IVD_VIDEO_DECODE_MODE_T mode);
78   void setArchitecture(IVD_ARCH_T arch);
79 
80  private:
81   IV_COLOR_FORMAT_T mColorFormat;
82   size_t mNumCores;
83   iv_obj_t *mCodec;
84   ivd_out_bufdesc_t mOutBufHandle;
85   uint32_t mWidth;
86   uint32_t mHeight;
87   uint32_t mDeinterlace;
88   iv_mem_rec_t *mMemRecords;
89 };
90 
Codec(IV_COLOR_FORMAT_T colorFormat,size_t numCores)91 Codec::Codec(IV_COLOR_FORMAT_T colorFormat, size_t numCores) {
92   mColorFormat = colorFormat;
93   mNumCores = numCores;
94   mCodec = nullptr;
95   mWidth = 0;
96   mHeight = 0;
97   mDeinterlace = 1;
98   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
99 }
100 
~Codec()101 Codec::~Codec() {}
102 
createCodec()103 void Codec::createCodec() {
104   IV_API_CALL_STATUS_T ret;
105   UWORD32 numMemRecords;
106   size_t i;
107   void *fxns = (void *)&ivd_api_function;
108 
109   iv_num_mem_rec_ip_t get_mem_ip;
110   iv_num_mem_rec_op_t get_mem_op;
111 
112   get_mem_ip.u4_size = sizeof(get_mem_ip);
113   get_mem_op.u4_size = sizeof(get_mem_op);
114   get_mem_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
115 
116   ret = ivd_api_function(NULL, (void *)&get_mem_ip, (void *)&get_mem_op);
117   if (ret != IV_SUCCESS) {
118     return;
119   }
120 
121   numMemRecords = get_mem_op.u4_num_mem_rec;
122 
123   mMemRecords = (iv_mem_rec_t *)malloc(numMemRecords * sizeof(iv_mem_rec_t));
124   if (mMemRecords == NULL) {
125     return;
126   }
127 
128   impeg2d_fill_mem_rec_ip_t fill_mem_ip;
129   impeg2d_fill_mem_rec_op_t fill_mem_op;
130 
131   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
132   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location =
133       (iv_mem_rec_t *)mMemRecords;
134   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = MAX_FRAME_WIDTH;
135   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = MAX_FRAME_HEIGHT;
136   fill_mem_ip.u4_share_disp_buf = 0;
137   fill_mem_ip.u4_deinterlace = mDeinterlace;
138   fill_mem_ip.e_output_format = mColorFormat;
139 
140   fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
141       sizeof(impeg2d_fill_mem_rec_ip_t);
142   fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
143       sizeof(impeg2d_fill_mem_rec_op_t);
144 
145   for (i = 0; i < numMemRecords; i++)
146     mMemRecords[i].u4_size = sizeof(iv_mem_rec_t);
147 
148   ret = ivd_api_function(NULL, (void *)&fill_mem_ip, (void *)&fill_mem_op);
149 
150   if (ret != IV_SUCCESS) {
151     return;
152   }
153   numMemRecords = fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
154 
155   iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *)mMemRecords;
156 
157   for (i = 0; i < numMemRecords; i++) {
158     ps_mem_rec->pv_base =
159         memalign(ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
160     if (ps_mem_rec->pv_base == NULL) {
161       return;
162     }
163 
164     ps_mem_rec++;
165   }
166 
167   mCodec = (iv_obj_t *)(iv_obj_t *)mMemRecords[0].pv_base;
168   mCodec->pv_fxns = fxns;
169   mCodec->u4_size = sizeof(iv_obj_t);
170 
171   impeg2d_init_ip_t init_ip;
172   impeg2d_init_op_t init_op;
173 
174   init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
175   init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
176   init_ip.s_ivd_init_ip_t.u4_frm_max_wd = MAX_FRAME_WIDTH;
177   init_ip.s_ivd_init_ip_t.u4_frm_max_ht = MAX_FRAME_HEIGHT;
178 
179   init_ip.u4_share_disp_buf = 0;
180   init_ip.u4_deinterlace = mDeinterlace;
181   init_ip.s_ivd_init_ip_t.u4_num_mem_rec = numMemRecords;
182   init_ip.s_ivd_init_ip_t.e_output_format = mColorFormat;
183   init_ip.s_ivd_init_ip_t.u4_size = sizeof(impeg2d_init_ip_t);
184   init_op.s_ivd_init_op_t.u4_size = sizeof(impeg2d_init_op_t);
185 
186   ret = ivd_api_function(mCodec, (void *)&init_ip, (void *)&init_op);
187   if (ret != IV_SUCCESS) {
188     return;
189   }
190 }
191 
deleteCodec()192 void Codec::deleteCodec() {
193   IV_API_CALL_STATUS_T ret;
194   iv_retrieve_mem_rec_ip_t retrieve_ip;
195   iv_retrieve_mem_rec_op_t retrieve_op;
196   retrieve_ip.pv_mem_rec_location = (iv_mem_rec_t *)mMemRecords;
197 
198   retrieve_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
199   retrieve_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
200   retrieve_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
201 
202   ret = ivd_api_function(mCodec, (void *)&retrieve_ip, (void *)&retrieve_op);
203 
204   if (ret != IV_SUCCESS) {
205     return;
206   }
207 
208   iv_mem_rec_t *ps_mem_rec = retrieve_ip.pv_mem_rec_location;
209   for (size_t i = 0; i < retrieve_op.u4_num_mem_rec_filled; i++) {
210     free(ps_mem_rec->pv_base);
211     ps_mem_rec++;
212   }
213   free(retrieve_ip.pv_mem_rec_location);
214 }
215 
resetCodec()216 void Codec::resetCodec() {
217   ivd_ctl_reset_ip_t s_ctl_ip;
218   ivd_ctl_reset_op_t s_ctl_op;
219 
220   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
221   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
222   s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
223   s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
224 
225   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
226 }
227 
setCores()228 void Codec::setCores() {
229   impeg2d_ctl_set_num_cores_ip_t s_ctl_ip;
230   impeg2d_ctl_set_num_cores_op_t s_ctl_op;
231 
232   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
233   s_ctl_ip.e_sub_cmd =
234       (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES;
235   s_ctl_ip.u4_num_cores = mNumCores;
236   s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_num_cores_ip_t);
237   s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_num_cores_op_t);
238 
239   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
240 }
241 
setParams(IVD_VIDEO_DECODE_MODE_T mode)242 void Codec::setParams(IVD_VIDEO_DECODE_MODE_T mode) {
243   ivd_ctl_set_config_ip_t s_ctl_ip;
244   ivd_ctl_set_config_op_t s_ctl_op;
245 
246   s_ctl_ip.u4_disp_wd = 0;
247   s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
248   s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
249   s_ctl_ip.e_vid_dec_mode = mode;
250   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
251   s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
252   s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
253   s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
254 
255   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
256 }
257 
setArchitecture(IVD_ARCH_T arch)258 void Codec::setArchitecture(IVD_ARCH_T arch) {
259   impeg2d_ctl_set_processor_ip_t s_ctl_ip;
260   impeg2d_ctl_set_processor_op_t s_ctl_op;
261 
262   s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
263   s_ctl_ip.e_sub_cmd =
264       (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_PROCESSOR;
265   s_ctl_ip.u4_arch = arch;
266   s_ctl_ip.u4_soc = SOC_GENERIC;
267   s_ctl_ip.u4_size = sizeof(impeg2d_ctl_set_processor_ip_t);
268   s_ctl_op.u4_size = sizeof(impeg2d_ctl_set_processor_op_t);
269 
270   ivd_api_function(mCodec, (void *)&s_ctl_ip, (void *)&s_ctl_op);
271 }
freeFrame()272 void Codec::freeFrame() {
273   for (int i = 0; i < mOutBufHandle.u4_num_bufs; i++) {
274     if (mOutBufHandle.pu1_bufs[i]) {
275       free(mOutBufHandle.pu1_bufs[i]);
276       mOutBufHandle.pu1_bufs[i] = nullptr;
277     }
278   }
279 }
280 
allocFrame()281 void Codec::allocFrame() {
282   size_t sizes[4] = {0};
283   size_t num_bufs = 0;
284 
285   freeFrame();
286 
287   memset(&mOutBufHandle, 0, sizeof(mOutBufHandle));
288 
289   switch (mColorFormat) {
290     case IV_YUV_420SP_UV:
291       [[fallthrough]];
292     case IV_YUV_420SP_VU:
293       sizes[0] = mWidth * mHeight;
294       sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 1;
295       num_bufs = 2;
296       break;
297     case IV_YUV_422ILE:
298       sizes[0] = mWidth * mHeight * 2;
299       num_bufs = 1;
300       break;
301     case IV_RGB_565:
302       sizes[0] = mWidth * mHeight * 2;
303       num_bufs = 1;
304       break;
305     case IV_RGBA_8888:
306       sizes[0] = mWidth * mHeight * 4;
307       num_bufs = 1;
308       break;
309     case IV_YUV_420P:
310       [[fallthrough]];
311     default:
312       sizes[0] = mWidth * mHeight;
313       sizes[1] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
314       sizes[2] = ALIGN2(mWidth) * ALIGN2(mHeight) >> 2;
315       num_bufs = 3;
316       break;
317   }
318   mOutBufHandle.u4_num_bufs = num_bufs;
319   for (int i = 0; i < num_bufs; i++) {
320     mOutBufHandle.u4_min_out_buf_size[i] = sizes[i];
321     mOutBufHandle.pu1_bufs[i] = (UWORD8 *)memalign(16, sizes[i]);
322   }
323 }
324 
decodeHeader(const uint8_t * data,size_t size)325 void Codec::decodeHeader(const uint8_t *data, size_t size) {
326   setParams(IVD_DECODE_HEADER);
327 
328   while (size > 0) {
329     IV_API_CALL_STATUS_T ret;
330     ivd_video_decode_ip_t dec_ip;
331     ivd_video_decode_op_t dec_op;
332     size_t bytes_consumed;
333 
334     memset(&dec_ip, 0, sizeof(dec_ip));
335     memset(&dec_op, 0, sizeof(dec_op));
336 
337     dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
338     dec_ip.u4_ts = 0;
339     dec_ip.pv_stream_buffer = (void *)data;
340     dec_ip.u4_num_Bytes = size;
341     dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
342     dec_op.u4_size = sizeof(ivd_video_decode_op_t);
343 
344     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
345 
346     bytes_consumed = dec_op.u4_num_bytes_consumed;
347     /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
348      * to feed next data */
349     if (!bytes_consumed) bytes_consumed = 4;
350 
351     bytes_consumed = std::min(size, bytes_consumed);
352 
353     data += bytes_consumed;
354     size -= bytes_consumed;
355 
356     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
357     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
358 
359     /* Break after successful header decode */
360     if (mWidth && mHeight) {
361       break;
362     }
363   }
364   /* if width / height are invalid, set them to defaults */
365   if (!mWidth) mWidth = 1920;
366   if (!mHeight) mHeight = 1088;
367 }
368 
decodeFrame(const uint8_t * data,size_t size,size_t * bytesConsumed)369 IV_API_CALL_STATUS_T Codec::decodeFrame(const uint8_t *data, size_t size,
370                                         size_t *bytesConsumed) {
371   IV_API_CALL_STATUS_T ret;
372   ivd_video_decode_ip_t dec_ip;
373   ivd_video_decode_op_t dec_op;
374 
375   memset(&dec_ip, 0, sizeof(dec_ip));
376   memset(&dec_op, 0, sizeof(dec_op));
377 
378   dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
379   dec_ip.u4_ts = 0;
380   dec_ip.pv_stream_buffer = (void *)data;
381   dec_ip.u4_num_Bytes = size;
382   dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);
383   dec_ip.s_out_buffer = mOutBufHandle;
384 
385   dec_op.u4_size = sizeof(ivd_video_decode_op_t);
386 
387   ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
388   if (IMPEG2D_UNSUPPORTED_DIMENSIONS == dec_op.u4_error_code) {
389     /* In case of unsupported resolution, reset codec */
390     resetCodec();
391   } else if (IVD_RES_CHANGED == (dec_op.u4_error_code & 0xFF)) {
392     /* In case of change in resolution, reset codec and feed the same data
393      * again */
394     resetCodec();
395     ret = ivd_api_function(mCodec, (void *)&dec_ip, (void *)&dec_op);
396   }
397   *bytesConsumed = dec_op.u4_num_bytes_consumed;
398 
399   /* If no bytes are consumed, then consume 4 bytes to ensure fuzzer proceeds
400    * to feed next data */
401   if (!*bytesConsumed) *bytesConsumed = 4;
402 
403   if (dec_op.u4_pic_wd && dec_op.u4_pic_ht &&
404       (mWidth != dec_op.u4_pic_wd || mHeight != dec_op.u4_pic_ht)) {
405     mWidth = std::min(dec_op.u4_pic_wd, (UWORD32)10240);
406     mHeight = std::min(dec_op.u4_pic_ht, (UWORD32)10240);
407     allocFrame();
408   }
409 
410   return ret;
411 }
412 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)413 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
414   if (size < 1) {
415     return 0;
416   }
417   size_t colorFormatOfst = std::min((size_t)OFFSET_COLOR_FORMAT, size - 1);
418   size_t numCoresOfst = std::min((size_t)OFFSET_NUM_CORES, size - 1);
419   size_t architectureOfst = std::min((size_t)OFFSET_ARCH, size - 1);
420   size_t architectureIdx = data[architectureOfst] % kSupportedArchitectures;
421   IVD_ARCH_T arch = (IVD_ARCH_T)supportedArchitectures[architectureIdx];
422   size_t colorFormatIdx = data[colorFormatOfst] % kSupportedColorFormats;
423   IV_COLOR_FORMAT_T colorFormat =
424       (IV_COLOR_FORMAT_T)(supportedColorFormats[colorFormatIdx]);
425   uint32_t numCores = (data[numCoresOfst] % kMaxCores) + 1;
426   size_t numDecodeCalls = 0;
427   Codec *codec = new Codec(colorFormat, numCores);
428   codec->createCodec();
429   codec->setArchitecture(arch);
430   codec->setCores();
431   codec->decodeHeader(data, size);
432   codec->setParams(IVD_DECODE_FRAME);
433   codec->allocFrame();
434 
435   while (size > 0 && numDecodeCalls < kMaxNumDecodeCalls) {
436     IV_API_CALL_STATUS_T ret;
437     size_t bytesConsumed;
438     ret = codec->decodeFrame(data, size, &bytesConsumed);
439 
440     bytesConsumed = std::min(size, bytesConsumed);
441     data += bytesConsumed;
442     size -= bytesConsumed;
443     numDecodeCalls++;
444   }
445 
446   codec->freeFrame();
447   codec->deleteCodec();
448   delete codec;
449   return 0;
450 }
451