FreeRDP
Loading...
Searching...
No Matches
TestFreeRDPCodecInterleaved.c
1
2#include <freerdp/config.h>
3
4#include <math.h>
5
6#include <winpr/crt.h>
7#include <winpr/print.h>
8#include <winpr/json.h>
9#include <winpr/path.h>
10
11#include <freerdp/freerdp.h>
12#include <freerdp/codec/color.h>
13#include <freerdp/codec/bitmap.h>
14#include <freerdp/codec/interleaved.h>
15#include <winpr/crypto.h>
16#include <freerdp/utils/profiler.h>
17
18#include "TestFreeRDPHelpers.h"
19
20// #define CREATE_TEST_OUTPUT
21
22static bool run_encode_decode_single(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
23 BITMAP_INTERLEAVED_CONTEXT* decoder
24#if defined(WITH_PROFILER)
25 ,
26 PROFILER* profiler_comp, PROFILER* profiler_decomp
27#endif
28)
29{
30 bool rc2 = false;
31 bool rc = 0;
32 const UINT32 w = 64;
33 const UINT32 h = 64;
34 const UINT32 x = 0;
35 const UINT32 y = 0;
36 const UINT32 format = PIXEL_FORMAT_RGBX32;
37 const UINT32 bstep = FreeRDPGetBytesPerPixel(format);
38 const size_t step = (13ULL + w) * 4ULL;
39 const size_t SrcSize = step * h;
40 const int maxDiff = 4 * ((bpp < 24) ? 2 : 1);
41 UINT32 DstSize = SrcSize;
42 BYTE* pSrcData = calloc(1, SrcSize);
43 BYTE* pDstData = calloc(1, SrcSize);
44 BYTE* tmp = calloc(1, SrcSize);
45
46 if (!pSrcData || !pDstData || !tmp)
47 goto fail;
48
49 winpr_RAND(pSrcData, SrcSize);
50
51 if (!bitmap_interleaved_context_reset(encoder) || !bitmap_interleaved_context_reset(decoder))
52 goto fail;
53
54 PROFILER_ENTER(profiler_comp)
55 rc =
56 interleaved_compress(encoder, tmp, &DstSize, w, h, pSrcData, format, step, x, y, NULL, bpp);
57 PROFILER_EXIT(profiler_comp)
58
59 if (!rc)
60 goto fail;
61
62 PROFILER_ENTER(profiler_decomp)
63 rc = interleaved_decompress(decoder, tmp, DstSize, w, h, bpp, pDstData, format, step, x, y, w,
64 h, NULL);
65 PROFILER_EXIT(profiler_decomp)
66
67 if (!rc)
68 goto fail;
69
70 for (UINT32 i = 0; i < h; i++)
71 {
72 const BYTE* srcLine = &pSrcData[i * step];
73 const BYTE* dstLine = &pDstData[i * step];
74
75 for (UINT32 j = 0; j < w; j++)
76 {
77 BYTE r = 0;
78 BYTE g = 0;
79 BYTE b = 0;
80 BYTE dr = 0;
81 BYTE dg = 0;
82 BYTE db = 0;
83 const UINT32 srcColor = FreeRDPReadColor(&srcLine[1ULL * j * bstep], format);
84 const UINT32 dstColor = FreeRDPReadColor(&dstLine[1ULL * j * bstep], format);
85 FreeRDPSplitColor(srcColor, format, &r, &g, &b, NULL, NULL);
86 FreeRDPSplitColor(dstColor, format, &dr, &dg, &db, NULL, NULL);
87
88 if (abs(r - dr) > maxDiff)
89 goto fail;
90
91 if (abs(g - dg) > maxDiff)
92 goto fail;
93
94 if (abs(b - db) > maxDiff)
95 goto fail;
96 }
97 }
98
99 rc2 = true;
100fail:
101 free(pSrcData);
102 free(pDstData);
103 free(tmp);
104 return rc2;
105}
106
107static const char* get_profiler_name(bool encode, UINT16 bpp)
108{
109 switch (bpp)
110 {
111 case 24:
112 if (encode)
113 return "interleaved_compress 24bpp";
114 else
115 return "interleaved_decompress 24bpp";
116
117 case 16:
118 if (encode)
119 return "interleaved_compress 16bpp";
120 else
121 return "interleaved_decompress 16bpp";
122
123 case 15:
124 if (encode)
125 return "interleaved_compress 15bpp";
126 else
127 return "interleaved_decompress 15bpp";
128
129 default:
130 return "configuration error!";
131 }
132}
133
134static bool run_encode_decode(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
135 BITMAP_INTERLEAVED_CONTEXT* decoder)
136{
137 bool rc = false;
138 PROFILER_DEFINE(profiler_comp)
139 PROFILER_DEFINE(profiler_decomp)
140 PROFILER_CREATE(profiler_comp, get_profiler_name(true, bpp))
141 PROFILER_CREATE(profiler_decomp, get_profiler_name(false, bpp))
142
143 for (UINT32 x = 0; x < 50; x++)
144 {
145 if (!run_encode_decode_single(bpp, encoder, decoder
146#if defined(WITH_PROFILER)
147 ,
148 profiler_comp, profiler_decomp
149#endif
150 ))
151 goto fail;
152 }
153
154 rc = true;
155fail:
156 PROFILER_PRINT_HEADER
157 PROFILER_PRINT(profiler_comp)
158 PROFILER_PRINT(profiler_decomp)
159 PROFILER_PRINT_FOOTER
160 PROFILER_FREE(profiler_comp)
161 PROFILER_FREE(profiler_decomp)
162 return rc;
163}
164
165static bool TestColorConversion(void)
166{
167 const UINT32 formats[] = { PIXEL_FORMAT_RGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_ABGR15,
168 PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_RGB16 };
169
170 /* Check color conversion 15/16 -> 32bit maps to proper values */
171 for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
172 {
173 const UINT32 dstFormat = PIXEL_FORMAT_RGBA32;
174 const UINT32 format = formats[x];
175 const UINT32 colorLow = FreeRDPGetColor(format, 0, 0, 0, 255);
176 const UINT32 colorHigh = FreeRDPGetColor(format, 255, 255, 255, 255);
177 const UINT32 colorLow32 = FreeRDPConvertColor(colorLow, format, dstFormat, NULL);
178 const UINT32 colorHigh32 = FreeRDPConvertColor(colorHigh, format, dstFormat, NULL);
179 BYTE r = 0;
180 BYTE g = 0;
181 BYTE b = 0;
182 BYTE a = 0;
183 FreeRDPSplitColor(colorLow32, dstFormat, &r, &g, &b, &a, NULL);
184 if ((r != 0) || (g != 0) || (b != 0))
185 return false;
186
187 FreeRDPSplitColor(colorHigh32, dstFormat, &r, &g, &b, &a, NULL);
188 if ((r != 255) || (g != 255) || (b != 255))
189 return false;
190 }
191
192 return true;
193}
194
195static bool RunEncoderTest(const char* name, uint32_t format, uint32_t width, uint32_t height,
196 uint32_t step, uint32_t bpp)
197{
198 bool rc = false;
199 void* data = NULL;
200 void* encdata = NULL;
201 BITMAP_INTERLEAVED_CONTEXT* encoder = bitmap_interleaved_context_new(true);
202 if (!encoder)
203 goto fail;
204
205 size_t srclen = 0;
206 data = test_codec_helper_read_data("interleaved", "bmp", name, &srclen);
207 if (!data)
208 goto fail;
209
210 encdata = calloc(srclen, 1);
211 if (!encdata)
212 goto fail;
213
214 for (size_t x = 0; x < 42; x++)
215 {
216 uint32_t enclen = WINPR_ASSERTING_INT_CAST(uint32_t, srclen);
217 if (!interleaved_compress(encoder, encdata, &enclen, width, height, data, format, step, 0,
218 0, NULL, bpp))
219 goto fail;
220
221 char encname[128] = { 0 };
222 (void)_snprintf(encname, sizeof(encname), "enc-%" PRIu32, bpp);
223#if defined(CREATE_TEST_OUTPUT)
224 test_codec_helper_write_data("interleaved", encname, name, encdata, enclen);
225#else
226 if (!test_codec_helper_compare("interleaved", encname, name, encdata, enclen))
227 goto fail;
228#endif
229 }
230
231 rc = true;
232
233fail:
234 free(data);
235 free(encdata);
236 bitmap_interleaved_context_free(encoder);
237 return rc;
238}
239
240static bool RunDecoderTest(const char* name, uint32_t format, uint32_t width, uint32_t height,
241 uint32_t step, uint32_t bpp)
242{
243 bool rc = false;
244 void* data = NULL;
245 void* decdata = NULL;
246 BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(false);
247 if (!decoder)
248 goto fail;
249
250 char encname[128] = { 0 };
251 (void)_snprintf(encname, sizeof(encname), "enc-%" PRIu32, bpp);
252
253 size_t srclen = 0;
254 data = test_codec_helper_read_data("interleaved", encname, name, &srclen);
255 if (!data)
256 goto fail;
257
258 const size_t declen = 1ULL * step * height;
259 decdata = calloc(step, height);
260 if (!decdata)
261 goto fail;
262
263 for (size_t x = 0; x < 42; x++)
264 {
265 if (!interleaved_decompress(decoder, data, WINPR_ASSERTING_INT_CAST(uint32_t, srclen),
266 width, height, bpp, decdata, format, step, 0, 0, width, height,
267 NULL))
268 goto fail;
269
270 char decname[128] = { 0 };
271 (void)_snprintf(decname, sizeof(decname), "dec-%s", encname);
272#if defined(CREATE_TEST_OUTPUT)
273 test_codec_helper_write_data("interleaved", decname, name, decdata, declen);
274#else
275 if (!test_codec_helper_compare("interleaved", decname, name, decdata, declen))
276 goto fail;
277#endif
278 }
279
280 rc = true;
281
282fail:
283 free(data);
284 free(decdata);
285 bitmap_interleaved_context_free(decoder);
286 return rc;
287}
288
289/* The encoder expects a JSON that describes a test cast:
290 *
291 * [
292 * {
293 * "name": "somestring",
294 * "format": "somestring",
295 * "width": <someint>,
296 * "height": <someint>,
297 * "step": <someint>,
298 * "bpp": <someint>
299 * },
300 * {...},
301 * ...
302 * ]
303 */
304static bool isObjectValid(const WINPR_JSON* obj)
305{
306 if (!obj || !WINPR_JSON_IsObject(obj))
307 return false;
308
309 const char* strvalues[] = { "name", "format" };
310 for (size_t x = 0; x < ARRAYSIZE(strvalues); x++)
311 {
312 const char* val = strvalues[x];
313
314 if (!WINPR_JSON_HasObjectItem(obj, val))
315 return false;
316
317 WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
318 if (!jval)
319 return false;
320
321 if (!WINPR_JSON_IsString(jval))
322 return false;
323 }
324
325 const char* values[] = { "width", "height", "step" };
326 for (size_t x = 0; x < ARRAYSIZE(values); x++)
327 {
328 const char* val = values[x];
329 if (!WINPR_JSON_HasObjectItem(obj, val))
330 return false;
331 WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
332 if (!jval)
333 return false;
334 if (!WINPR_JSON_IsNumber(jval))
335 return false;
336 const double dval = WINPR_JSON_GetNumberValue(jval);
337 if (dval <= 0.0)
338 return false;
339 }
340
341 {
342 const char* val = "bpp";
343
344 if (!WINPR_JSON_HasObjectItem(obj, val))
345 return false;
346
347 WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
348 if (!jval)
349 return false;
350
351 if (!WINPR_JSON_IsArray(jval))
352 return false;
353
354 for (size_t x = 0; x < WINPR_JSON_GetArraySize(jval); x++)
355 {
356 WINPR_JSON* aval = WINPR_JSON_GetArrayItem(jval, x);
357 if (!jval || !WINPR_JSON_IsNumber(aval))
358 return false;
359 }
360 }
361 return true;
362}
363
364static bool TestEncoder(void)
365{
366 bool rc = false;
367 WINPR_JSON* json = NULL;
368 char* file = NULL;
369 char* path = GetCombinedPath(CMAKE_CURRENT_SOURCE_DIR, "interleaved");
370 if (!path)
371 goto fail;
372 file = GetCombinedPath(path, "encoder.json");
373 if (!file)
374 goto fail;
375
376 json = WINPR_JSON_ParseFromFile(file);
377 if (!json)
378 goto fail;
379
380 if (!WINPR_JSON_IsArray(json))
381 goto fail;
382
383 for (size_t x = 0; x < WINPR_JSON_GetArraySize(json); x++)
384 {
385 WINPR_JSON* obj = WINPR_JSON_GetArrayItem(json, x);
386 if (!isObjectValid(obj))
387 goto fail;
388
389 const char* name = WINPR_JSON_GetStringValue(WINPR_JSON_GetObjectItem(obj, "name"));
390 const uint32_t format = WINPR_ASSERTING_INT_CAST(
391 uint32_t, FreeRDPGetColorFromatFromName(
393 const uint32_t width = WINPR_ASSERTING_INT_CAST(
394 uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetObjectItem(obj, "width")));
395 const uint32_t height = WINPR_ASSERTING_INT_CAST(
396 uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetObjectItem(obj, "height")));
397 const uint32_t step = WINPR_ASSERTING_INT_CAST(
399
400 WINPR_JSON* jbpp = WINPR_JSON_GetObjectItem(obj, "bpp");
401 for (size_t x = 0; x < WINPR_JSON_GetArraySize(jbpp); x++)
402 {
403 const uint32_t bpp = WINPR_ASSERTING_INT_CAST(
405 if (!RunEncoderTest(name, format, width, height, step, bpp))
406 goto fail;
407 if (!RunDecoderTest(name, format, width, height, step, bpp))
408 goto fail;
409 }
410 }
411
412 rc = true;
413fail:
414 WINPR_JSON_Delete(json);
415 free(path);
416 free(file);
417 return rc;
418}
419
420int TestFreeRDPCodecInterleaved(int argc, char* argv[])
421{
422 BITMAP_INTERLEAVED_CONTEXT* encoder = NULL;
423 BITMAP_INTERLEAVED_CONTEXT* decoder = NULL;
424 int rc = -1;
425 WINPR_UNUSED(argc);
426 WINPR_UNUSED(argv);
427 encoder = bitmap_interleaved_context_new(true);
428 decoder = bitmap_interleaved_context_new(false);
429
430 if (!encoder || !decoder)
431 goto fail;
432
433 if (!run_encode_decode(24, encoder, decoder))
434 goto fail;
435
436 if (!run_encode_decode(16, encoder, decoder))
437 goto fail;
438
439 if (!run_encode_decode(15, encoder, decoder))
440 goto fail;
441
442 if (!TestColorConversion())
443 goto fail;
444
445 if (!TestEncoder())
446 goto fail;
447
448 rc = 0;
449fail:
450 bitmap_interleaved_context_free(encoder);
451 bitmap_interleaved_context_free(decoder);
452 return rc;
453}
WINPR_API BOOL WINPR_JSON_HasObjectItem(const WINPR_JSON *object, const char *string)
Check if JSON has an object matching the name.
Definition c-json.c:132
WINPR_API WINPR_JSON * WINPR_JSON_GetObjectItem(const WINPR_JSON *object, const char *string)
Return a pointer to an JSON object item.
Definition c-json.c:122
WINPR_API BOOL WINPR_JSON_IsString(const WINPR_JSON *item)
Check if JSON item is of type String.
Definition c-json.c:182
WINPR_API double WINPR_JSON_GetNumberValue(const WINPR_JSON *item)
Return the Number value of a JSON item.
Definition c-json.c:147
WINPR_API WINPR_JSON * WINPR_JSON_ParseFromFile(const char *filename)
Parse a JSON string read from a file filename.
Definition json.c:27
WINPR_API BOOL WINPR_JSON_IsNumber(const WINPR_JSON *item)
Check if JSON item is of type Number.
Definition c-json.c:177
WINPR_API WINPR_JSON * WINPR_JSON_GetArrayItem(const WINPR_JSON *array, size_t index)
Return a pointer to an item in the array.
Definition c-json.c:108
WINPR_API BOOL WINPR_JSON_IsObject(const WINPR_JSON *item)
Check if JSON item is of type Object.
Definition c-json.c:192
WINPR_API const char * WINPR_JSON_GetStringValue(WINPR_JSON *item)
Return the String value of a JSON item.
Definition c-json.c:142
WINPR_API void WINPR_JSON_Delete(WINPR_JSON *item)
Delete a WinPR JSON wrapper object.
Definition c-json.c:103
WINPR_API size_t WINPR_JSON_GetArraySize(const WINPR_JSON *array)
Get the number of arrayitems from an array.
Definition c-json.c:114
WINPR_API BOOL WINPR_JSON_IsArray(const WINPR_JSON *item)
Check if JSON item is of type Array.
Definition c-json.c:187