Ticket #1853: libswscale-test.c

File libswscale-test.c, 7.5 KB (added by divVerent, 4 years ago)
Line 
1#include <time.h>
2#include <assert.h>
3#include <stdio.h>
4#include <stdbool.h>
5#include <libswscale/swscale.h>
6#include <libavutil/pixfmt.h>
7#include <libavutil/pixdesc.h>
8#include <libavutil/imgutils.h>
9
10#define MINSIZE 8
11#define MAXSIZE 128
12#define SWS_ALIGN 16
13
14typedef uint8_t *ImagePlane;
15
16typedef struct
17{
18        ImagePlane plane[4];
19        int stride[4];
20        int pix_fmt;
21        const const AVPixFmtDescriptor *pix_fmt_desc;
22        int w, h;
23}
24Image;
25
26Image *alloc_image(enum AVPixelFormat pix_fmt, int w, int h)
27{
28        Image *img = av_malloc(sizeof(Image));
29        assert(img);
30
31        img->w = w;
32        img->h = h;
33        img->pix_fmt = pix_fmt;
34        img->pix_fmt_desc = &av_pix_fmt_descriptors[pix_fmt];
35        assert(img->pix_fmt_desc);
36
37        int sz = av_image_alloc(img->plane, img->stride, w, h, pix_fmt, SWS_ALIGN);
38        assert(sz > 0);
39        assert(img->plane[0]);
40        memset(img->plane[0], 0, sz);
41
42        return img;
43}
44
45void free_image(Image *img)
46{
47        av_freep(&img->plane[0]);
48        av_free(img);
49}
50
51void fill_image(Image *img)
52{
53        int i, x, y;
54        for(i = 0; i < img->pix_fmt_desc->nb_components; ++i)
55        {
56                int thisW = img->w;
57                int thisH = img->h;
58                uint16_t comp = rand() & ((1 << (img->pix_fmt_desc->comp[i].depth_minus1 + 1)) - 1);
59                if(i > 0 && i < ((img->pix_fmt_desc->nb_components - 1) | 1) && !(img->pix_fmt_desc->flags & PIX_FMT_RGB))
60                {
61                        thisW = -((-thisW) >> img->pix_fmt_desc->log2_chroma_w);
62                        thisH = -((-thisH) >> img->pix_fmt_desc->log2_chroma_h);
63                }
64                uint16_t buf[thisW];
65                for(x = 0; x < thisW; ++x)
66                        buf[x] = comp;
67                for(y = 0; y < thisH; ++y)
68                        av_write_image_line(buf, img->plane, img->stride, img->pix_fmt_desc, 0, y, i, thisW);
69        }
70}
71
72bool is_solid_color(Image *img, int ignore_x, int ignore_y, int ignore_w, int ignore_h)
73{
74        int i, x, y;
75        for(i = 0; i < img->pix_fmt_desc->nb_components; ++i)
76        {
77                int val = -1;
78                int thisW = img->w;
79                int thisH = img->h;
80                int thisIgnoreX = ignore_x;
81                int thisIgnoreY = ignore_y;
82                int thisIgnoreW = ignore_w;
83                int thisIgnoreH = ignore_h;
84                if(i > 0 && i < ((img->pix_fmt_desc->nb_components - 1) | 1) && !(img->pix_fmt_desc->flags & PIX_FMT_RGB))
85                {
86                        thisW = -((-thisW) >> img->pix_fmt_desc->log2_chroma_w);
87                        thisH = -((-thisH) >> img->pix_fmt_desc->log2_chroma_h);
88                        thisIgnoreX >>= img->pix_fmt_desc->log2_chroma_w;
89                        thisIgnoreY >>= img->pix_fmt_desc->log2_chroma_h;
90                        thisIgnoreW = -((-thisIgnoreW) >> img->pix_fmt_desc->log2_chroma_w);
91                        thisIgnoreH = -((-thisIgnoreH) >> img->pix_fmt_desc->log2_chroma_h);
92                }
93                uint16_t buf[thisW];
94                for(y = 0; y < thisH; ++y)
95                {
96                        av_read_image_line(buf, (const uint8_t **) img->plane, img->stride, img->pix_fmt_desc, 0, y, i, thisW, 0);
97                        for(x = 0; x < thisW; ++x)
98                        {
99                                if(y >= thisIgnoreY && y < thisIgnoreY + thisIgnoreH)
100                                        if(x >= thisIgnoreX && x < thisIgnoreX + thisIgnoreW)
101                                                continue;
102                                if(val == -1)
103                                        val = buf[x];
104                                if(val != buf[x])
105                                {
106                                        printf(" (failed in comp=%d x=%d y=%d expected=%d got=%d)", i, x, y, val, buf[x]);
107                                        return 0;
108                                }
109                        }
110                }
111        }
112        return 1;
113}
114
115bool set_to_cropped_image(Image *cropped, Image *orig, int x, int y, int w, int h)
116{
117        if(x < 0)
118                return 0;
119        if(y < 0)
120                return 0;
121        if(x + w > orig->w)
122                return 0;
123        if(y + h > orig->h)
124                return 0;
125        if(w < MINSIZE)
126                return 0;
127        if(h < MINSIZE)
128                return 0;
129        if(!(orig->pix_fmt_desc->flags & PIX_FMT_RGB))
130                if(orig->pix_fmt_desc->nb_components >= 3)
131                {
132                        // we have chroma
133                        // so only allow subrectangles that take whole chroma pixels
134                        if(x & ((1 << orig->pix_fmt_desc->log2_chroma_w) - 1))
135                                return 0;
136                        if(y & ((1 << orig->pix_fmt_desc->log2_chroma_h) - 1))
137                                return 0;
138                        if(w & ((1 << orig->pix_fmt_desc->log2_chroma_w) - 1))
139                                return 0;
140                        if(h & ((1 << orig->pix_fmt_desc->log2_chroma_h) - 1))
141                                return 0;
142                }
143
144        memset(cropped, 0, sizeof(*cropped));
145        cropped->pix_fmt = orig->pix_fmt;
146        cropped->pix_fmt_desc = orig->pix_fmt_desc;
147        cropped->w = w;
148        cropped->h = h;
149
150        int p, c;
151        for(p = 0; p < 4; ++p)
152        {
153                bool componentExists = 0;
154                int thisOffset = 0;
155                int thisY = 0;
156                for(c = 0; c < orig->pix_fmt_desc->nb_components; ++c)
157                {
158                        if(orig->pix_fmt_desc->comp[c].plane != p)
159                                continue;
160                        int step = orig->pix_fmt_desc->comp[c].step_minus1 + 1;
161                        int thisThisX = x;
162                        int thisThisY = y;
163                        int thisThisW = w;
164                        int thisThisH = h;
165                        if(c > 0 && c < ((orig->pix_fmt_desc->nb_components - 1) | 1) && !(orig->pix_fmt_desc->flags & PIX_FMT_RGB))
166                        {
167                                thisThisX >>= orig->pix_fmt_desc->log2_chroma_w;
168                                thisThisY >>= orig->pix_fmt_desc->log2_chroma_h;
169                                thisThisW = -((-thisThisW) >> orig->pix_fmt_desc->log2_chroma_w);
170                                thisThisH = -((-thisThisH) >> orig->pix_fmt_desc->log2_chroma_w);
171                        }
172                        int thisThisOffset = thisThisX * step;
173                        if(orig->pix_fmt_desc->flags & PIX_FMT_BITSTREAM)
174                        {
175                                if(thisThisOffset % 8 || thisThisW * step % 8)
176                                {
177                                        memset(cropped, 0, sizeof(*cropped));
178                                        return 0;
179                                }
180                                thisThisOffset /= 8;
181                        }
182                        if(componentExists)
183                        {
184                                assert(thisThisY == thisY);
185                                assert(thisThisOffset == thisOffset);
186                        }
187                        else
188                        {
189                                thisY = thisThisY;
190                                thisOffset = thisThisOffset;
191                                componentExists = 1;
192                        }
193                }
194                if(!componentExists)
195                        continue;
196                cropped->plane[p] = orig->plane[p] + orig->stride[p] * thisY + thisOffset;
197                cropped->stride[p] = orig->stride[p];
198        }
199
200        return 1;
201}
202
203int main(int argc, char **argv)
204{
205        if(argc != 3)
206        {
207                printf("Usage: %s srcFormat dstFormat\n", argv[0]);
208                return 1;
209        }
210
211        enum AVPixelFormat srcFormat = av_get_pix_fmt(argv[1]);
212        assert(srcFormat >= 0);
213
214        enum AVPixelFormat dstFormat = av_get_pix_fmt(argv[2]);
215        assert(dstFormat >= 0);
216
217        srand(31337);
218        struct SwsContext *ctx = NULL;
219
220        for(;;)
221        {
222                int w1 = MINSIZE + rand() % (MAXSIZE - MINSIZE + 1);
223                int h1 = MINSIZE + rand() % (MAXSIZE - MINSIZE + 1);
224                // w1 = ((w1 - 1) | (SWS_ALIGN - 1)) + 1;
225                // h1 = ((h1 - 1) | (SWS_ALIGN - 1)) + 1;
226
227                int w2 = MINSIZE + rand() % (MAXSIZE - MINSIZE + 1);
228                int h2 = MINSIZE + rand() % (MAXSIZE - MINSIZE + 1);
229                // w2 = ((w2 - 1) | (SWS_ALIGN - 1)) + 1;
230                // h2 = ((h2 - 1) | (SWS_ALIGN - 1)) + 1;
231
232                // now choose a random subsection of image 1
233                int w3 = rand() % w1 + 1;
234                int h3 = rand() % h1 + 1;
235                int x3 = rand() % (w1 - w3 + 1);
236                int y3 = rand() % (h1 - h3 + 1);
237
238                printf("TEST: %dx%d -> %dx%d+%d+%d @ %dx%d:",
239                        w2, h2,
240                        w3, h3, x3, y3,
241                        w1, h1);
242                fflush(stdout);
243
244                Image *i1 = alloc_image(dstFormat, w1, h1);
245                Image *i2 = alloc_image(srcFormat, w2, h2);
246
247                fill_image(i1);
248                assert(is_solid_color(i1, 0, 0, 0, 0));
249                fill_image(i2);
250                assert(is_solid_color(i2, 0, 0, 0, 0));
251
252                // create an Image aliasing this
253                Image i3;
254                if(set_to_cropped_image(&i3, i1, x3, y3, w3, h3))
255                {
256                        assert(is_solid_color(&i3, 0, 0, 0, 0));
257                        int swsFlags =
258                                (1 << (rand() % 11)) | // 0x1 to 0x400 (scaler selection)
259                                // SWS_PRINT_INFO |
260                                (rand() & 1 ? SWS_DIRECT_BGR : 0) |
261                                (rand() & 1 ? SWS_ACCURATE_RND : 0) |
262                                (rand() & 1 ? SWS_BITEXACT : 0);
263                        ctx = sws_getCachedContext(ctx,
264                                i2->w, i2->h, i2->pix_fmt,
265                                i3.w, i3.h, i3.pix_fmt,
266                                swsFlags, NULL,
267                                NULL, NULL);
268                        if(ctx)
269                        {
270                                printf(" swsFlags=0x%x", swsFlags);
271                                int scaleResult = sws_scale(ctx, (const uint8_t * const*) i2->plane, i2->stride, 0, i2->h, i3.plane, i3.stride);
272                                assert(scaleResult == i3.h);
273                                int bad = 0;
274                                if(!is_solid_color(&i3, 0, 0, 0, 0))
275                                {
276                                        printf(" output image is not solid!");
277                                        bad = 1;
278                                }
279                                if(!is_solid_color(i1, x3, y3, w3, h3))
280                                {
281                                        printf(" wrote beyond bounds!");
282                                        bad = 1;
283                                }
284                                if(bad)
285                                        printf(" FAILED\n");
286                                else
287                                        printf(" OK\n");
288                        }
289                        else
290                                printf(" could not get sws context, skipped\n");
291                }
292                else
293                        printf(" invalid target dimensions, skipped\n");
294
295                free_image(i2);
296                free_image(i1);
297        }
298}