xref: /aosp_15_r20/external/libavc/fuzzer/mvc_dec_fuzzer.cpp (revision 495ae853bb871d1e5a258cb02c2cc13cde8ddb9a)
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