FreeRDP
Loading...
Searching...
No Matches
TestFreeRDPCodecPlanar.c
1
2#include <math.h>
3
4#include <winpr/crt.h>
5#include <winpr/print.h>
6#include <winpr/crypto.h>
7#include <winpr/path.h>
8
9#include <freerdp/freerdp.h>
10#include <freerdp/codec/color.h>
11#include <freerdp/codec/bitmap.h>
12#include <freerdp/codec/planar.h>
13
14static const UINT32 colorFormatList[] = {
15 PIXEL_FORMAT_RGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_RGB16, PIXEL_FORMAT_BGR16,
16 PIXEL_FORMAT_RGB24, PIXEL_FORMAT_BGR24, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_ABGR32,
17 PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_BGRX32
18
19};
20static const UINT32 colorFormatCount = sizeof(colorFormatList) / sizeof(colorFormatList[0]);
21
22static BOOL CompareBitmap(const BYTE* srcA, UINT32 srcAFormat, const BYTE* srcB, UINT32 srcBFormat,
23 UINT32 width, UINT32 height)
24{
25 double maxDiff = NAN;
26 const UINT32 srcABits = FreeRDPGetBitsPerPixel(srcAFormat);
27 const UINT32 srcBBits = FreeRDPGetBitsPerPixel(srcBFormat);
28 UINT32 diff = WINPR_ASSERTING_INT_CAST(uint32_t, fabs((double)srcABits - srcBBits));
29
30 /* No support for 8bpp */
31 if ((srcABits < 15) || (srcBBits < 15))
32 return FALSE;
33
34 /* Compare with following granularity:
35 * 32 --> 24 bpp: Each color channel has 8bpp, no difference expected
36 * 24/32 --> 15/16 bpp: 8bit per channel against 5/6bit per channel, +/- 3bit
37 * 16 --> 15bpp: 5/6bit per channel against 5 bit per channel, +/- 1bit
38 */
39 switch (diff)
40 {
41 case 1:
42 maxDiff = 2 * 2.0;
43 break;
44
45 case 8:
46 case 9:
47 case 16:
48 case 17:
49 maxDiff = 2 * 8.0;
50 break;
51
52 default:
53 maxDiff = 0.0;
54 break;
55 }
56
57 if ((srcABits == 32) || (srcBBits == 32))
58 {
59 if (diff == 8)
60 maxDiff = 0.0;
61 }
62
63 for (size_t y = 0; y < height; y++)
64 {
65 const BYTE* lineA = &srcA[y * width * FreeRDPGetBytesPerPixel(srcAFormat)];
66 const BYTE* lineB = &srcB[y * width * FreeRDPGetBytesPerPixel(srcBFormat)];
67
68 for (size_t x = 0; x < width; x++)
69 {
70 BYTE sR = 0;
71 BYTE sG = 0;
72 BYTE sB = 0;
73 BYTE sA = 0;
74 BYTE dR = 0;
75 BYTE dG = 0;
76 BYTE dB = 0;
77 BYTE dA = 0;
78 const BYTE* a = &lineA[x * FreeRDPGetBytesPerPixel(srcAFormat)];
79 const BYTE* b = &lineB[x * FreeRDPGetBytesPerPixel(srcBFormat)];
80 UINT32 colorA = FreeRDPReadColor(a, srcAFormat);
81 UINT32 colorB = FreeRDPReadColor(b, srcBFormat);
82 FreeRDPSplitColor(colorA, srcAFormat, &sR, &sG, &sB, &sA, NULL);
83 FreeRDPSplitColor(colorB, srcBFormat, &dR, &dG, &dB, &dA, NULL);
84
85 if (fabs((double)sR - dR) > maxDiff)
86 return FALSE;
87
88 if (fabs((double)sG - dG) > maxDiff)
89 return FALSE;
90
91 if (fabs((double)sB - dB) > maxDiff)
92 return FALSE;
93
94 if (fabs((double)sA - dA) > maxDiff)
95 return FALSE;
96 }
97 }
98
99 return TRUE;
100}
101
102static char* get_path(const char* type, const char* name)
103{
104 char path[500] = { 0 };
105 (void)snprintf(path, sizeof(path), "planar-%s-%s.bin", type, name);
106 char* s1 = GetCombinedPath(CMAKE_CURRENT_SOURCE_DIR, "planar");
107 if (!s1)
108 return NULL;
109
110 char* s2 = GetCombinedPath(s1, path);
111 free(s1);
112 return s2;
113}
114
115static void* read_data(const char* type, const char* name, size_t* plength)
116{
117 WINPR_ASSERT(type);
118 WINPR_ASSERT(name);
119 WINPR_ASSERT(plength);
120
121 void* rc = NULL;
122 void* cmp = NULL;
123
124 *plength = 0;
125 char* path = get_path(type, name);
126 if (!path)
127 return NULL;
128
129 FILE* fp = winpr_fopen(path, "rb");
130 free(path);
131 if (!fp)
132 return NULL;
133
134 if (_fseeki64(fp, 0, SEEK_END) != 0)
135 goto fail;
136
137 const size_t pos = _ftelli64(fp);
138
139 if (_fseeki64(fp, 0, SEEK_SET) != 0)
140 goto fail;
141
142 cmp = calloc(pos, 1);
143 if (!cmp)
144 goto fail;
145
146 if (fread(cmp, 1, pos, fp) != pos)
147 goto fail;
148
149 *plength = pos;
150 rc = cmp;
151 cmp = NULL;
152
153fail:
154 free(cmp);
155 (void)fclose(fp);
156 return rc;
157}
158
159static void write_data(const char* type, const char* name, const void* data, size_t length)
160{
161 WINPR_ASSERT(type);
162 WINPR_ASSERT(name);
163
164 char* path = get_path(type, name);
165 if (!path)
166 return;
167
168 FILE* fp = winpr_fopen(path, "wb");
169 free(path);
170 if (!fp)
171 return;
172
173 if (fwrite(data, 1, length, fp) != length)
174 goto fail;
175
176fail:
177 fclose(fp);
178}
179
180static BOOL compare(const char* type, const char* name, const void* data, size_t length)
181{
182 BOOL rc = FALSE;
183 size_t cmplen = 0;
184 void* cmp = read_data(type, name, &cmplen);
185 if (!cmp)
186 goto fail;
187 if (cmplen != length)
188 goto fail;
189 if (memcmp(data, cmp, length) != 0)
190 goto fail;
191 rc = TRUE;
192fail:
193 free(cmp);
194 return rc;
195}
196
197static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* encplanar, BITMAP_PLANAR_CONTEXT* decplanar,
198 const char* name, const UINT32 srcFormat, const UINT32 dstFormat,
199 const UINT32 width, const UINT32 height)
200{
201 WINPR_ASSERT(encplanar);
202 WINPR_ASSERT(decplanar);
203 BOOL rc = FALSE;
204 UINT32 dstSize = 0;
205 size_t srclen = 0;
206 BYTE* srcBitmap = read_data("bmp", name, &srclen);
207 if (!srcBitmap)
208 return FALSE;
209
210 BYTE* compressedBitmap = freerdp_bitmap_compress_planar(encplanar, srcBitmap, srcFormat, width,
211 height, 0, NULL, &dstSize);
212 BYTE* decompressedBitmap =
213 (BYTE*)calloc(height, 1ULL * width * FreeRDPGetBytesPerPixel(dstFormat));
214
215 if (!compare("bmp", name, srcBitmap,
216 1ull * width * height * FreeRDPGetBytesPerPixel(srcFormat)))
217 goto fail;
218
219 if (!compare("enc", name, compressedBitmap, dstSize))
220 goto fail;
221
222 (void)printf("%s [%s] --> [%s]: ", __func__, FreeRDPGetColorFormatName(srcFormat),
223 FreeRDPGetColorFormatName(dstFormat));
224
225 if (!compressedBitmap || !decompressedBitmap)
226 goto fail;
227
228 if (!planar_decompress(decplanar, compressedBitmap, dstSize, width, height, decompressedBitmap,
229 dstFormat, 0, 0, 0, width, height, FALSE))
230 {
231 printf("failed to decompress experimental bitmap 01: width: %" PRIu32 " height: %" PRIu32
232 "\n",
233 width, height);
234 goto fail;
235 }
236
237#if 0
238 if (!compare("dec", name, decompressedBitmap,
239 1ull * width * height * FreeRDPGetBytesPerPixel(dstFormat)))
240 goto fail;
241
242 if (!CompareBitmap(decompressedBitmap, dstFormat, srcBitmap, srcFormat, width, height))
243 {
244 printf("FAIL");
245 goto fail;
246 }
247#endif
248
249 printf("SUCCESS");
250 rc = TRUE;
251fail:
252 free(srcBitmap);
253 free(compressedBitmap);
254 free(decompressedBitmap);
255 (void)printf("\n");
256 (void)fflush(stdout);
257 return rc;
258}
259
260static BOOL RunTestPlanarSingleColor(BITMAP_PLANAR_CONTEXT* planar, const UINT32 srcFormat,
261 const UINT32 dstFormat)
262{
263 BOOL rc = FALSE;
264 (void)printf("%s: [%s] --> [%s]: ", __func__, FreeRDPGetColorFormatName(srcFormat),
265 FreeRDPGetColorFormatName(dstFormat));
266 (void)fflush(stdout);
267
268 for (UINT32 j = 0; j < 32; j += 8)
269 {
270 for (UINT32 i = 4; i < 32; i += 8)
271 {
272 UINT32 compressedSize = 0;
273 const UINT32 fill = j;
274 const UINT32 color = FreeRDPGetColor(srcFormat, (fill >> 8) & 0xF, (fill >> 4) & 0xF,
275 (fill) & 0xF, 0xFF);
276 const UINT32 width = i;
277 const UINT32 height = i;
278 BOOL failed = TRUE;
279 const UINT32 srcSize = width * height * FreeRDPGetBytesPerPixel(srcFormat);
280 const UINT32 dstSize = width * height * FreeRDPGetBytesPerPixel(dstFormat);
281 BYTE* compressedBitmap = NULL;
282 BYTE* bmp = malloc(srcSize);
283 BYTE* decompressedBitmap = (BYTE*)malloc(dstSize);
284
285 if (!bmp || !decompressedBitmap)
286 goto fail_loop;
287
288 for (size_t y = 0; y < height; y++)
289 {
290 BYTE* line = &bmp[y * width * FreeRDPGetBytesPerPixel(srcFormat)];
291
292 for (size_t x = 0; x < width; x++)
293 {
294 FreeRDPWriteColor(line, srcFormat, color);
295 line += FreeRDPGetBytesPerPixel(srcFormat);
296 }
297 }
298
299 compressedBitmap = freerdp_bitmap_compress_planar(planar, bmp, srcFormat, width, height,
300 0, NULL, &compressedSize);
301
302 if (!compressedBitmap)
303 goto fail_loop;
304
305 if (!planar_decompress(planar, compressedBitmap, compressedSize, width, height,
306 decompressedBitmap, dstFormat, 0, 0, 0, width, height, FALSE))
307 goto fail_loop;
308
309 if (!CompareBitmap(decompressedBitmap, dstFormat, bmp, srcFormat, width, height))
310 goto fail_loop;
311
312 failed = FALSE;
313 fail_loop:
314 free(bmp);
315 free(compressedBitmap);
316 free(decompressedBitmap);
317
318 if (failed)
319 {
320 printf("FAIL");
321 goto fail;
322 }
323 }
324 }
325
326 (void)printf("SUCCESS");
327 rc = TRUE;
328fail:
329 (void)printf("\n");
330 (void)fflush(stdout);
331 return rc;
332}
333
334static BOOL TestPlanar(const UINT32 format)
335{
336 BOOL rc = FALSE;
337 const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
338 BITMAP_PLANAR_CONTEXT* encplanar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
339 BITMAP_PLANAR_CONTEXT* decplanar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
340
341 if (!encplanar || !decplanar)
342 goto fail;
343
344 if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_01", PIXEL_FORMAT_RGBX32,
345 format, 64, 64))
346 goto fail;
347
348 if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_02", PIXEL_FORMAT_RGBX32,
349 format, 64, 64))
350 goto fail;
351
352 if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_03", PIXEL_FORMAT_RGBX32,
353 format, 64, 64))
354 goto fail;
355
356 if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_UNCOMPRESSED_BITMAP_16BPP",
357 PIXEL_FORMAT_RGB16, format, 32, 32))
358 goto fail;
359
360 for (UINT32 x = 0; x < colorFormatCount; x++)
361 {
362 if (!RunTestPlanarSingleColor(encplanar, format, colorFormatList[x]))
363 goto fail;
364 }
365
366 rc = TRUE;
367fail:
368 freerdp_bitmap_planar_context_free(encplanar);
369 freerdp_bitmap_planar_context_free(decplanar);
370 return rc;
371}
372
373static UINT32 prand(UINT32 max)
374{
375 UINT32 tmp = 0;
376 if (max <= 1)
377 return 1;
378 winpr_RAND(&tmp, sizeof(tmp));
379 return tmp % (max - 1) + 1;
380}
381
382static BOOL FuzzPlanar(void)
383{
384 BOOL rc = FALSE;
385 const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
386 BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
387
388 if (!planar)
389 goto fail;
390
391 for (UINT32 x = 0; x < 100; x++)
392 {
393 BYTE data[0x10000] = { 0 };
394 size_t dataSize = 0x10000;
395 BYTE dstData[0x10000] = { 0 };
396
397 UINT32 DstFormat = 0;
398 UINT32 nDstStep = 0;
399 UINT32 nXDst = 0;
400 UINT32 nYDst = 0;
401 UINT32 nDstWidth = 0;
402 UINT32 nDstHeight = 0;
403 BOOL invalid = TRUE;
404 do
405 {
406 switch (prand(17) - 1)
407 {
408 case 0:
409 DstFormat = PIXEL_FORMAT_RGB8;
410 break;
411 case 1:
412 DstFormat = PIXEL_FORMAT_BGR15;
413 break;
414 case 2:
415 DstFormat = PIXEL_FORMAT_RGB15;
416 break;
417 case 3:
418 DstFormat = PIXEL_FORMAT_ABGR15;
419 break;
420 case 4:
421 DstFormat = PIXEL_FORMAT_ABGR15;
422 break;
423 case 5:
424 DstFormat = PIXEL_FORMAT_BGR16;
425 break;
426 case 6:
427 DstFormat = PIXEL_FORMAT_RGB16;
428 break;
429 case 7:
430 DstFormat = PIXEL_FORMAT_BGR24;
431 break;
432 case 8:
433 DstFormat = PIXEL_FORMAT_RGB24;
434 break;
435 case 9:
436 DstFormat = PIXEL_FORMAT_BGRA32;
437 break;
438 case 10:
439 DstFormat = PIXEL_FORMAT_BGRX32;
440 break;
441 case 11:
442 DstFormat = PIXEL_FORMAT_RGBA32;
443 break;
444 case 12:
445 DstFormat = PIXEL_FORMAT_RGBX32;
446 break;
447 case 13:
448 DstFormat = PIXEL_FORMAT_ABGR32;
449 break;
450 case 14:
451 DstFormat = PIXEL_FORMAT_XBGR32;
452 break;
453 case 15:
454 DstFormat = PIXEL_FORMAT_ARGB32;
455 break;
456 case 16:
457 DstFormat = PIXEL_FORMAT_XRGB32;
458 break;
459 default:
460 break;
461 }
462 nDstStep = prand(sizeof(dstData));
463 nXDst = prand(nDstStep);
464 nYDst = prand(sizeof(dstData) / nDstStep);
465 nDstWidth = prand(nDstStep / FreeRDPGetBytesPerPixel(DstFormat));
466 nDstHeight = prand(sizeof(dstData) / nDstStep);
467 invalid = nXDst * FreeRDPGetBytesPerPixel(DstFormat) + (nYDst + nDstHeight) * nDstStep >
468 sizeof(dstData);
469 } while (invalid);
470 printf("DstFormat=%s, nXDst=%" PRIu32 ", nYDst=%" PRIu32 ", nDstWidth=%" PRIu32
471 ", nDstHeight=%" PRIu32 ", nDstStep=%" PRIu32 ", total size=%" PRIuz "\n",
472 FreeRDPGetColorFormatName(DstFormat), nXDst, nYDst, nDstWidth, nDstHeight, nDstStep,
473 sizeof(dstData));
474 freerdp_planar_switch_bgr(planar, ((prand(2) % 2) != 0) ? TRUE : FALSE);
475 planar_decompress(planar, data, dataSize, prand(4096), prand(4096), dstData, DstFormat,
476 nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
477 ((prand(2) % 2) != 0) ? TRUE : FALSE);
478 }
479
480 rc = TRUE;
481fail:
482 freerdp_bitmap_planar_context_free(planar);
483 return rc;
484}
485
486int TestFreeRDPCodecPlanar(int argc, char* argv[])
487{
488 int rc = -1;
489 WINPR_UNUSED(argc);
490 WINPR_UNUSED(argv);
491
492 if (!FuzzPlanar())
493 goto fail;
494
495 for (UINT32 x = 0; x < colorFormatCount; x++)
496 {
497 if (!TestPlanar(colorFormatList[x]))
498 goto fail;
499 }
500
501 rc = 0;
502fail:
503 printf("test returned %d\n", rc);
504 return rc;
505}