Ticket #1853: libswscale-test.c

File libswscale-test.c, 7.5 KB (added by Rudolf Polzer, 14 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}