/src/ffmpeg/tools/target_sws_fuzzer.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2024 Michael Niedermayer <michael-ffmpeg@niedermayer.cc> |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "config.h" |
22 | | #include "libavutil/avassert.h" |
23 | | #include "libavutil/avstring.h" |
24 | | #include "libavutil/cpu.h" |
25 | | #include "libavutil/imgutils.h" |
26 | | #include "libavutil/intreadwrite.h" |
27 | | #include "libavutil/mem.h" |
28 | | #include "libavutil/opt.h" |
29 | | |
30 | | #include "libavcodec/bytestream.h" |
31 | | |
32 | | #include "libswscale/swscale.h" |
33 | | |
34 | | |
35 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); |
36 | | |
37 | | static void error(const char *err) |
38 | 0 | { |
39 | 0 | fprintf(stderr, "%s", err); |
40 | 0 | exit(1); |
41 | 0 | } |
42 | | |
43 | | static int alloc_plane(uint8_t *data[AV_VIDEO_MAX_PLANES], int stride[AV_VIDEO_MAX_PLANES], int w, int h, int format, int *hshift, int *vshift) |
44 | 32.5k | { |
45 | 32.5k | size_t size[AV_VIDEO_MAX_PLANES]; |
46 | 32.5k | ptrdiff_t ptrdiff_stride[AV_VIDEO_MAX_PLANES]; |
47 | 32.5k | int ret = av_image_fill_linesizes(stride, format, w); |
48 | 32.5k | if (ret < 0) |
49 | 5 | return -1; |
50 | | |
51 | 32.5k | av_assert0(AV_VIDEO_MAX_PLANES == 4); // Some of the libavutil API has 4 hardcoded so this has undefined behaviour if its not 4 |
52 | | |
53 | 32.5k | av_pix_fmt_get_chroma_sub_sample(format, hshift, vshift); |
54 | | |
55 | 162k | for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) { |
56 | 130k | stride[p] = |
57 | 130k | ptrdiff_stride[p] = FFALIGN(stride[p], 32); |
58 | 130k | } |
59 | 32.5k | ret = av_image_fill_plane_sizes(size, format, h, ptrdiff_stride); |
60 | 32.5k | if (ret < 0) |
61 | 0 | return ret; |
62 | | |
63 | 162k | for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) { |
64 | 130k | if (size[p]) { |
65 | 57.0k | data[p] = av_mallocz(size[p] + 32); |
66 | 57.0k | if (!data[p]) |
67 | 0 | return -1; |
68 | 57.0k | } else |
69 | 73.1k | data[p] = NULL; |
70 | 130k | } |
71 | 32.5k | return 0; |
72 | 32.5k | } |
73 | | |
74 | | static void free_plane(uint8_t *data[AV_VIDEO_MAX_PLANES]) |
75 | 32.5k | { |
76 | 162k | for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) |
77 | 130k | av_freep(&data[p]); |
78 | 32.5k | } |
79 | | |
80 | 32.5k | static void mapres(unsigned *r0, unsigned *r1) { |
81 | 32.5k | double d = (double)(*r0*10ll - 9ll*UINT32_MAX) / UINT32_MAX; |
82 | 32.5k | double a = exp(d) * 16384 / exp(1) ; |
83 | 32.5k | int ai = (int)round(a); |
84 | 32.5k | uint64_t maxb = 16384 / ai; |
85 | 32.5k | *r0 = ai; |
86 | 32.5k | *r1 = 1 + (*r1 * maxb) / UINT32_MAX; |
87 | 32.5k | } |
88 | | |
89 | 16.2k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
90 | 16.2k | int srcW= 48, srcH = 48; |
91 | 16.2k | int dstW= 48, dstH = 48; |
92 | 16.2k | int srcHShift, srcVShift; |
93 | 16.2k | int dstHShift, dstVShift; |
94 | 16.2k | unsigned flags = 1; |
95 | 16.2k | int srcStride[AV_VIDEO_MAX_PLANES] = {0}; |
96 | 16.2k | int dstStride[AV_VIDEO_MAX_PLANES] = {0}; |
97 | 16.2k | int ret; |
98 | 16.2k | const uint8_t *end = data + size; |
99 | 16.2k | enum AVPixelFormat srcFormat = AV_PIX_FMT_YUV420P; |
100 | 16.2k | enum AVPixelFormat dstFormat = AV_PIX_FMT_YUV420P; |
101 | 16.2k | uint8_t *src[AV_VIDEO_MAX_PLANES] = { 0 }; |
102 | 16.2k | uint8_t *dst[AV_VIDEO_MAX_PLANES] = { 0 }; |
103 | 16.2k | struct SwsContext *sws = NULL; |
104 | 16.2k | const AVPixFmtDescriptor *desc_src, *desc_dst; |
105 | | |
106 | 16.2k | if (size > 128) { |
107 | 16.2k | GetByteContext gbc; |
108 | 16.2k | int64_t flags64; |
109 | | |
110 | 16.2k | size -= 128; |
111 | 16.2k | bytestream2_init(&gbc, data + size, 128); |
112 | 16.2k | srcW = bytestream2_get_le32(&gbc); |
113 | 16.2k | srcH = bytestream2_get_le32(&gbc); |
114 | 16.2k | dstW = bytestream2_get_le32(&gbc); |
115 | 16.2k | dstH = bytestream2_get_le32(&gbc); |
116 | | |
117 | 16.2k | mapres(&srcW, &srcH); |
118 | 16.2k | mapres(&dstW, &dstH); |
119 | | |
120 | 16.2k | flags = bytestream2_get_le32(&gbc); |
121 | | |
122 | 16.2k | unsigned mask = flags & (SWS_POINT | |
123 | 16.2k | SWS_AREA | |
124 | 16.2k | SWS_BILINEAR | |
125 | 16.2k | SWS_FAST_BILINEAR | |
126 | 16.2k | SWS_BICUBIC | |
127 | 16.2k | SWS_X | |
128 | 16.2k | SWS_GAUSS | |
129 | 16.2k | SWS_LANCZOS | |
130 | 16.2k | SWS_SINC | |
131 | 16.2k | SWS_SPLINE | |
132 | 16.2k | SWS_BICUBLIN); |
133 | 16.2k | mask &= flags; |
134 | 16.2k | if (mask && (mask & (mask -1))) |
135 | 3 | return 0; // multiple scalers are set, not possible |
136 | | |
137 | 16.2k | srcFormat = bytestream2_get_le32(&gbc) % AV_PIX_FMT_NB; |
138 | 16.2k | dstFormat = bytestream2_get_le32(&gbc) % AV_PIX_FMT_NB; |
139 | | |
140 | 16.2k | flags64 = bytestream2_get_le64(&gbc); |
141 | 16.2k | if (flags64 & 0x10) |
142 | 5.14k | av_force_cpu_flags(0); |
143 | | |
144 | 16.2k | if (av_image_check_size(srcW, srcH, srcFormat, NULL) < 0) |
145 | 0 | srcW = srcH = 23; |
146 | 16.2k | if (av_image_check_size(dstW, dstH, dstFormat, NULL) < 0) |
147 | 0 | dstW = dstH = 23; |
148 | | //TODO alphablend |
149 | 16.2k | } |
150 | | |
151 | 16.2k | desc_src = av_pix_fmt_desc_get(srcFormat); |
152 | 16.2k | desc_dst = av_pix_fmt_desc_get(dstFormat); |
153 | | |
154 | | // fprintf(stderr, "%d x %d %s -> %d x %d %s\n", srcW, srcH, desc_src->name, dstW, dstH, desc_dst->name); |
155 | | |
156 | 16.2k | ret = alloc_plane(src, srcStride, srcW, srcH, srcFormat, &srcHShift, &srcVShift); |
157 | 16.2k | if (ret < 0) |
158 | 1 | goto end; |
159 | | |
160 | 16.2k | ret = alloc_plane(dst, dstStride, dstW, dstH, dstFormat, &dstHShift, &dstVShift); |
161 | 16.2k | if (ret < 0) |
162 | 4 | goto end; |
163 | | |
164 | | |
165 | 81.3k | for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) { |
166 | 65.0k | int psize = srcStride[p] * AV_CEIL_RSHIFT(srcH, (p == 1 || p == 2) ? srcVShift : 0); |
167 | 65.0k | if (psize > size) |
168 | 31.3k | psize = size; |
169 | 65.0k | if (psize) { |
170 | 18.1k | memcpy(src[p], data, psize); |
171 | 18.1k | data += psize; |
172 | 18.1k | size -= psize; |
173 | 18.1k | } |
174 | 65.0k | } |
175 | | |
176 | 16.2k | sws = sws_alloc_context(); |
177 | 16.2k | if (!sws) |
178 | 0 | error("Failed sws allocation"); |
179 | | |
180 | 16.2k | av_opt_set_int(sws, "sws_flags", flags, 0); |
181 | 16.2k | av_opt_set_int(sws, "srcw", srcW, 0); |
182 | 16.2k | av_opt_set_int(sws, "srch", srcH, 0); |
183 | 16.2k | av_opt_set_int(sws, "dstw", dstW, 0); |
184 | 16.2k | av_opt_set_int(sws, "dsth", dstH, 0); |
185 | 16.2k | av_opt_set_int(sws, "src_format", srcFormat, 0); |
186 | 16.2k | av_opt_set_int(sws, "dst_format", dstFormat, 0); |
187 | 16.2k | av_opt_set(sws, "alphablend", "none", 0); |
188 | | |
189 | 16.2k | ret = sws_init_context(sws, NULL, NULL); |
190 | 16.2k | if (ret < 0) |
191 | 31 | goto end; |
192 | | |
193 | | //TODO Slices |
194 | 16.2k | sws_scale(sws, (const uint8_t * const*)src, srcStride, 0, srcH, dst, dstStride); |
195 | | |
196 | 16.2k | end: |
197 | 16.2k | sws_freeContext(sws); |
198 | | |
199 | 16.2k | free_plane(src); |
200 | 16.2k | free_plane(dst); |
201 | | |
202 | 16.2k | return 0; |
203 | 16.2k | } |