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