Coverage Report

Created: 2026-01-16 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}