FreeRDP
Loading...
Searching...
No Matches
TestFreeRDPCodecProgressive.c
1#include <errno.h>
2
3#include <winpr/wtypes.h>
4#include <winpr/crt.h>
5#include <winpr/string.h>
6#include <winpr/path.h>
7#include <winpr/image.h>
8#include <winpr/print.h>
9#include <winpr/wlog.h>
10#include <winpr/sysinfo.h>
11#include <winpr/file.h>
12
13#include <freerdp/codec/region.h>
14
15#include <freerdp/codecs.h>
16#include <freerdp/utils/gfx.h>
17
18#include <freerdp/codec/progressive.h>
19#include <freerdp/channels/rdpgfx.h>
20#include <freerdp/crypto/crypto.h>
21
22#include "../progressive.h"
23
138typedef struct
139{
140 BYTE* buffer;
141 size_t size;
142} EGFX_SAMPLE_FILE;
143
144static int g_Width = 0;
145static int g_Height = 0;
146static int g_DstStep = 0;
147static BYTE* g_DstData = NULL;
148
149static void sample_file_free(EGFX_SAMPLE_FILE* file)
150{
151 if (!file)
152 return;
153
154 free(file->buffer);
155 file->buffer = NULL;
156 file->size = 0;
157}
158
159static void test_fill_image_alpha_channel(BYTE* data, UINT32 width, UINT32 height, BYTE value)
160{
161 UINT32* pixel = NULL;
162
163 for (UINT32 i = 0; i < height; i++)
164 {
165 for (UINT32 j = 0; j < width; j++)
166 {
167 pixel = (UINT32*)&data[((1ULL * i * width) + j) * 4ULL];
168 *pixel = ((*pixel & 0x00FFFFFF) | (value << 24));
169 }
170 }
171}
172
173static void* test_image_memset32(UINT32* ptr, UINT32 fill, size_t length)
174{
175 while (length--)
176 {
177 *ptr++ = fill;
178 }
179
180 return (void*)ptr;
181}
182
183static int test_image_fill(BYTE* pDstData, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
184 UINT32 nWidth, UINT32 nHeight, UINT32 color)
185{
186 UINT32* pDstPixel = NULL;
187
188 if (nDstStep < 0)
189 nDstStep = 4 * nWidth;
190
191 for (UINT32 y = 0; y < nHeight; y++)
192 {
193 pDstPixel = (UINT32*)&pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
194 test_image_memset32(pDstPixel, color, nWidth);
195 }
196
197 return 1;
198}
199
200static int test_image_fill_quarter(BYTE* pDstData, UINT32 nDstStep, UINT32 nWidth, UINT32 nHeight,
201 UINT32 color, UINT32 quarter)
202{
203 UINT32 x = 0;
204 UINT32 y = 0;
205 UINT32 width = 0;
206 UINT32 height = 0;
207
208 switch (quarter)
209 {
210 case 0:
211 x = 0;
212 y = 0;
213 width = nWidth / 2;
214 height = nHeight / 2;
215 break;
216
217 case 1:
218 x = nWidth / 2;
219 y = nHeight / 2;
220 width = nWidth / 2;
221 height = nHeight / 2;
222 break;
223
224 case 2:
225 x = 0;
226 y = nHeight / 2;
227 width = nWidth / 2;
228 height = nHeight / 2;
229 break;
230
231 case 3:
232 x = nWidth / 2;
233 y = 0;
234 width = nWidth / 2;
235 height = nHeight / 2;
236 break;
237 default:
238 return -1;
239 }
240
241 test_image_fill(pDstData, nDstStep, x, y, width, height, 0xFF000000);
242 return 1;
243}
244
245static int test_image_fill_unused_quarters(BYTE* pDstData, UINT32 nDstStep, UINT32 nWidth,
246 UINT32 nHeight, UINT32 color, UINT32 quarter)
247{
248 return 1;
249
250 if (quarter == 0)
251 {
252 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1);
253 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2);
254 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3);
255 }
256 else if (quarter == 1)
257 {
258 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0);
259 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2);
260 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3);
261 }
262 else if (quarter == 2)
263 {
264 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0);
265 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1);
266 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 3);
267 }
268 else if (quarter == 3)
269 {
270 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 0);
271 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 1);
272 test_image_fill_quarter(pDstData, nDstStep, nWidth, nHeight, color, 2);
273 }
274
275 return 1;
276}
277
278static BYTE* test_progressive_load_file(const char* path, const char* file, size_t* size)
279{
280 char* filename = GetCombinedPath(path, file);
281
282 if (!filename)
283 return NULL;
284
285 FILE* fp = winpr_fopen(filename, "r");
286 free(filename);
287
288 if (!fp)
289 return NULL;
290
291 (void)_fseeki64(fp, 0, SEEK_END);
292 const INT64 pos = _ftelli64(fp);
293 WINPR_ASSERT(pos >= 0);
294 WINPR_ASSERT(pos <= SIZE_MAX);
295 *size = (size_t)pos;
296 (void)_fseeki64(fp, 0, SEEK_SET);
297 BYTE* buffer = (BYTE*)malloc(*size);
298
299 if (!buffer)
300 {
301 (void)fclose(fp);
302 return NULL;
303 }
304
305 if (fread(buffer, *size, 1, fp) != 1)
306 {
307 free(buffer);
308 (void)fclose(fp);
309 return NULL;
310 }
311
312 (void)fclose(fp);
313 return buffer;
314}
315
316static int test_progressive_load_files(char* ms_sample_path, EGFX_SAMPLE_FILE files[3][4][4])
317{
318 int imageNo = 0;
319 int quarterNo = 0;
320 int passNo = 0;
321 /* image 1 */
322 files[imageNo][quarterNo][passNo].buffer =
323 test_progressive_load_file(ms_sample_path, "compress/enc_0_0_025_sampleimage1.bin",
324 &(files[imageNo][quarterNo][passNo].size));
325 passNo = (passNo + 1) % 4;
326 files[imageNo][quarterNo][passNo].buffer =
327 test_progressive_load_file(ms_sample_path, "compress/enc_0_0_050_sampleimage1.bin",
328 &(files[imageNo][quarterNo][passNo].size));
329 passNo = (passNo + 1) % 4;
330 files[imageNo][quarterNo][passNo].buffer =
331 test_progressive_load_file(ms_sample_path, "compress/enc_0_0_075_sampleimage1.bin",
332 &(files[imageNo][quarterNo][passNo].size));
333 passNo = (passNo + 1) % 4;
334 files[imageNo][quarterNo][passNo].buffer =
335 test_progressive_load_file(ms_sample_path, "compress/enc_0_0_100_sampleimage1.bin",
336 &(files[imageNo][quarterNo][passNo].size));
337 passNo = (passNo + 1) % 4;
338 quarterNo = (quarterNo + 1) % 4;
339 files[imageNo][quarterNo][passNo].buffer =
340 test_progressive_load_file(ms_sample_path, "compress/enc_0_1_025_sampleimage1.bin",
341 &(files[imageNo][quarterNo][passNo].size));
342 passNo = (passNo + 1) % 4;
343 files[imageNo][quarterNo][passNo].buffer =
344 test_progressive_load_file(ms_sample_path, "compress/enc_0_1_050_sampleimage1.bin",
345 &(files[imageNo][quarterNo][passNo].size));
346 passNo = (passNo + 1) % 4;
347 files[imageNo][quarterNo][passNo].buffer =
348 test_progressive_load_file(ms_sample_path, "compress/enc_0_1_075_sampleimage1.bin",
349 &(files[imageNo][quarterNo][passNo].size));
350 passNo = (passNo + 1) % 4;
351 files[imageNo][quarterNo][passNo].buffer =
352 test_progressive_load_file(ms_sample_path, "compress/enc_0_1_100_sampleimage1.bin",
353 &(files[imageNo][quarterNo][passNo].size));
354 passNo = (passNo + 1) % 4;
355 quarterNo = (quarterNo + 1) % 4;
356 files[imageNo][quarterNo][passNo].buffer =
357 test_progressive_load_file(ms_sample_path, "compress/enc_0_2_025_sampleimage1.bin",
358 &(files[imageNo][quarterNo][passNo].size));
359 passNo = (passNo + 1) % 4;
360 files[imageNo][quarterNo][passNo].buffer =
361 test_progressive_load_file(ms_sample_path, "compress/enc_0_2_050_sampleimage1.bin",
362 &(files[imageNo][quarterNo][passNo].size));
363 passNo = (passNo + 1) % 4;
364 files[imageNo][quarterNo][passNo].buffer =
365 test_progressive_load_file(ms_sample_path, "compress/enc_0_2_075_sampleimage1.bin",
366 &(files[imageNo][quarterNo][passNo].size));
367 passNo = (passNo + 1) % 4;
368 files[imageNo][quarterNo][passNo].buffer =
369 test_progressive_load_file(ms_sample_path, "compress/enc_0_2_100_sampleimage1.bin",
370 &(files[imageNo][quarterNo][passNo].size));
371 passNo = (passNo + 1) % 4;
372 quarterNo = (quarterNo + 1) % 4;
373 files[imageNo][quarterNo][passNo].buffer =
374 test_progressive_load_file(ms_sample_path, "compress/enc_0_3_025_sampleimage1.bin",
375 &(files[imageNo][quarterNo][passNo].size));
376 passNo = (passNo + 1) % 4;
377 files[imageNo][quarterNo][passNo].buffer =
378 test_progressive_load_file(ms_sample_path, "compress/enc_0_3_050_sampleimage1.bin",
379 &(files[imageNo][quarterNo][passNo].size));
380 passNo = (passNo + 1) % 4;
381 files[imageNo][quarterNo][passNo].buffer =
382 test_progressive_load_file(ms_sample_path, "compress/enc_0_3_075_sampleimage1.bin",
383 &(files[imageNo][quarterNo][passNo].size));
384 passNo = (passNo + 1) % 4;
385 files[imageNo][quarterNo][passNo].buffer =
386 test_progressive_load_file(ms_sample_path, "compress/enc_0_3_100_sampleimage1.bin",
387 &(files[imageNo][quarterNo][passNo].size));
388 passNo = (passNo + 1) % 4;
389 imageNo++;
390 /* image 2 */
391 files[imageNo][quarterNo][passNo].buffer =
392 test_progressive_load_file(ms_sample_path, "compress/enc_1_0_025_sampleimage2.bin",
393 &(files[imageNo][quarterNo][passNo].size));
394 passNo = (passNo + 1) % 4;
395 files[imageNo][quarterNo][passNo].buffer =
396 test_progressive_load_file(ms_sample_path, "compress/enc_1_0_050_sampleimage2.bin",
397 &(files[imageNo][quarterNo][passNo].size));
398 passNo = (passNo + 1) % 4;
399 files[imageNo][quarterNo][passNo].buffer =
400 test_progressive_load_file(ms_sample_path, "compress/enc_1_0_075_sampleimage2.bin",
401 &(files[imageNo][quarterNo][passNo].size));
402 passNo = (passNo + 1) % 4;
403 files[imageNo][quarterNo][passNo].buffer =
404 test_progressive_load_file(ms_sample_path, "compress/enc_1_0_100_sampleimage2.bin",
405 &(files[imageNo][quarterNo][passNo].size));
406 passNo = (passNo + 1) % 4;
407 quarterNo = (quarterNo + 1) % 4;
408 files[imageNo][quarterNo][passNo].buffer =
409 test_progressive_load_file(ms_sample_path, "compress/enc_1_1_025_sampleimage2.bin",
410 &(files[imageNo][quarterNo][passNo].size));
411 passNo = (passNo + 1) % 4;
412 files[imageNo][quarterNo][passNo].buffer =
413 test_progressive_load_file(ms_sample_path, "compress/enc_1_1_050_sampleimage2.bin",
414 &(files[imageNo][quarterNo][passNo].size));
415 passNo = (passNo + 1) % 4;
416 files[imageNo][quarterNo][passNo].buffer =
417 test_progressive_load_file(ms_sample_path, "compress/enc_1_1_075_sampleimage2.bin",
418 &(files[imageNo][quarterNo][passNo].size));
419 passNo = (passNo + 1) % 4;
420 files[imageNo][quarterNo][passNo].buffer =
421 test_progressive_load_file(ms_sample_path, "compress/enc_1_1_100_sampleimage2.bin",
422 &(files[imageNo][quarterNo][passNo].size));
423 passNo = (passNo + 1) % 4;
424 quarterNo = (quarterNo + 1) % 4;
425 files[imageNo][quarterNo][passNo].buffer =
426 test_progressive_load_file(ms_sample_path, "compress/enc_1_2_025_sampleimage2.bin",
427 &(files[imageNo][quarterNo][passNo].size));
428 passNo = (passNo + 1) % 4;
429 files[imageNo][quarterNo][passNo].buffer =
430 test_progressive_load_file(ms_sample_path, "compress/enc_1_2_050_sampleimage2.bin",
431 &(files[imageNo][quarterNo][passNo].size));
432 passNo = (passNo + 1) % 4;
433 files[imageNo][quarterNo][passNo].buffer =
434 test_progressive_load_file(ms_sample_path, "compress/enc_1_2_075_sampleimage2.bin",
435 &(files[imageNo][quarterNo][passNo].size));
436 passNo = (passNo + 1) % 4;
437 files[imageNo][quarterNo][passNo].buffer =
438 test_progressive_load_file(ms_sample_path, "compress/enc_1_2_100_sampleimage2.bin",
439 &(files[imageNo][quarterNo][passNo].size));
440 passNo = (passNo + 1) % 4;
441 quarterNo = (quarterNo + 1) % 4;
442 files[imageNo][quarterNo][passNo].buffer =
443 test_progressive_load_file(ms_sample_path, "compress/enc_1_3_025_sampleimage2.bin",
444 &(files[imageNo][quarterNo][passNo].size));
445 passNo = (passNo + 1) % 4;
446 files[imageNo][quarterNo][passNo].buffer =
447 test_progressive_load_file(ms_sample_path, "compress/enc_1_3_050_sampleimage2.bin",
448 &(files[imageNo][quarterNo][passNo].size));
449 passNo = (passNo + 1) % 4;
450 files[imageNo][quarterNo][passNo].buffer =
451 test_progressive_load_file(ms_sample_path, "compress/enc_1_3_075_sampleimage2.bin",
452 &(files[imageNo][quarterNo][passNo].size));
453 passNo = (passNo + 1) % 4;
454 files[imageNo][quarterNo][passNo].buffer =
455 test_progressive_load_file(ms_sample_path, "compress/enc_1_3_100_sampleimage2.bin",
456 &(files[imageNo][quarterNo][passNo].size));
457 passNo = (passNo + 1) % 4;
458 imageNo++;
459 /* image 3 */
460 files[imageNo][quarterNo][passNo].buffer =
461 test_progressive_load_file(ms_sample_path, "compress/enc_2_0_025_sampleimage3.bin",
462 &(files[imageNo][quarterNo][passNo].size));
463 passNo = (passNo + 1) % 4;
464 files[imageNo][quarterNo][passNo].buffer =
465 test_progressive_load_file(ms_sample_path, "compress/enc_2_0_050_sampleimage3.bin",
466 &(files[imageNo][quarterNo][passNo].size));
467 passNo = (passNo + 1) % 4;
468 files[imageNo][quarterNo][passNo].buffer =
469 test_progressive_load_file(ms_sample_path, "compress/enc_2_0_075_sampleimage3.bin",
470 &(files[imageNo][quarterNo][passNo].size));
471 passNo = (passNo + 1) % 4;
472 files[imageNo][quarterNo][passNo].buffer =
473 test_progressive_load_file(ms_sample_path, "compress/enc_2_0_100_sampleimage3.bin",
474 &(files[imageNo][quarterNo][passNo].size));
475 passNo = (passNo + 1) % 4;
476 quarterNo = (quarterNo + 1) % 4;
477 files[imageNo][quarterNo][passNo].buffer =
478 test_progressive_load_file(ms_sample_path, "compress/enc_2_1_025_sampleimage3.bin",
479 &(files[imageNo][quarterNo][passNo].size));
480 passNo = (passNo + 1) % 4;
481 files[imageNo][quarterNo][passNo].buffer =
482 test_progressive_load_file(ms_sample_path, "compress/enc_2_1_050_sampleimage3.bin",
483 &(files[imageNo][quarterNo][passNo].size));
484 passNo = (passNo + 1) % 4;
485 files[imageNo][quarterNo][passNo].buffer =
486 test_progressive_load_file(ms_sample_path, "compress/enc_2_1_075_sampleimage3.bin",
487 &(files[imageNo][quarterNo][passNo].size));
488 passNo = (passNo + 1) % 4;
489 files[imageNo][quarterNo][passNo].buffer =
490 test_progressive_load_file(ms_sample_path, "compress/enc_2_1_100_sampleimage3.bin",
491 &(files[imageNo][quarterNo][passNo].size));
492 passNo = (passNo + 1) % 4;
493 quarterNo = (quarterNo + 1) % 4;
494 files[imageNo][quarterNo][passNo].buffer =
495 test_progressive_load_file(ms_sample_path, "compress/enc_2_2_025_sampleimage3.bin",
496 &(files[imageNo][quarterNo][passNo].size));
497 passNo = (passNo + 1) % 4;
498 files[imageNo][quarterNo][passNo].buffer =
499 test_progressive_load_file(ms_sample_path, "compress/enc_2_2_050_sampleimage3.bin",
500 &(files[imageNo][quarterNo][passNo].size));
501 passNo = (passNo + 1) % 4;
502 files[imageNo][quarterNo][passNo].buffer =
503 test_progressive_load_file(ms_sample_path, "compress/enc_2_2_075_sampleimage3.bin",
504 &(files[imageNo][quarterNo][passNo].size));
505 passNo = (passNo + 1) % 4;
506 files[imageNo][quarterNo][passNo].buffer =
507 test_progressive_load_file(ms_sample_path, "compress/enc_2_2_100_sampleimage3.bin",
508 &(files[imageNo][quarterNo][passNo].size));
509 passNo = (passNo + 1) % 4;
510 quarterNo = (quarterNo + 1) % 4;
511 files[imageNo][quarterNo][passNo].buffer =
512 test_progressive_load_file(ms_sample_path, "compress/enc_2_3_025_sampleimage3.bin",
513 &(files[imageNo][quarterNo][passNo].size));
514 passNo = (passNo + 1) % 4;
515 files[imageNo][quarterNo][passNo].buffer =
516 test_progressive_load_file(ms_sample_path, "compress/enc_2_3_050_sampleimage3.bin",
517 &(files[imageNo][quarterNo][passNo].size));
518 passNo = (passNo + 1) % 4;
519 files[imageNo][quarterNo][passNo].buffer =
520 test_progressive_load_file(ms_sample_path, "compress/enc_2_3_075_sampleimage3.bin",
521 &(files[imageNo][quarterNo][passNo].size));
522 passNo = (passNo + 1) % 4;
523 files[imageNo][quarterNo][passNo].buffer =
524 test_progressive_load_file(ms_sample_path, "compress/enc_2_3_100_sampleimage3.bin",
525 &(files[imageNo][quarterNo][passNo].size));
526
527 /* check if all test data has been loaded */
528
529 for (imageNo = 0; imageNo < 3; imageNo++)
530 {
531 for (quarterNo = 0; quarterNo < 4; quarterNo++)
532 {
533 for (passNo = 0; passNo < 4; passNo++)
534 {
535 if (!files[imageNo][quarterNo][passNo].buffer)
536 return -1;
537 }
538 }
539 }
540
541 return 1;
542}
543
544static BYTE* test_progressive_load_bitmap(char* path, char* file, size_t* size, int quarter)
545{
546 int status = 0;
547 BYTE* buffer = NULL;
548 wImage* image = NULL;
549 char* filename = NULL;
550 filename = GetCombinedPath(path, file);
551
552 if (!filename)
553 return NULL;
554
555 image = winpr_image_new();
556
557 if (!image)
558 return NULL;
559
560 status = winpr_image_read(image, filename);
561
562 if (status < 0)
563 return NULL;
564
565 buffer = image->data;
566 *size = 1ULL * image->height * image->scanline;
567 test_fill_image_alpha_channel(image->data, image->width, image->height, 0xFF);
568 test_image_fill_unused_quarters(image->data, image->scanline, image->width, image->height,
569 quarter, 0xFF000000);
570 winpr_image_free(image, FALSE);
571 free(filename);
572 return buffer;
573}
574
575static int test_progressive_load_bitmaps(char* ms_sample_path, EGFX_SAMPLE_FILE bitmaps[3][4][4])
576{
577 int imageNo = 0;
578 int quarterNo = 0;
579 int passNo = 0;
580 /* image 1 */
581 bitmaps[imageNo][quarterNo][passNo].buffer =
582 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_0_025_sampleimage1.bmp",
583 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
584 passNo = (passNo + 1) % 4;
585 bitmaps[imageNo][quarterNo][passNo].buffer =
586 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_0_050_sampleimage1.bmp",
587 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
588 passNo = (passNo + 1) % 4;
589 bitmaps[imageNo][quarterNo][passNo].buffer =
590 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_0_075_sampleimage1.bmp",
591 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
592 passNo = (passNo + 1) % 4;
593 bitmaps[imageNo][quarterNo][passNo].buffer =
594 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_0_100_sampleimage1.bmp",
595 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
596 passNo = (passNo + 1) % 4;
597 quarterNo = (quarterNo + 1) % 4;
598 bitmaps[imageNo][quarterNo][passNo].buffer =
599 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_1_025_sampleimage1.bmp",
600 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
601 passNo = (passNo + 1) % 4;
602 bitmaps[imageNo][quarterNo][passNo].buffer =
603 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_1_050_sampleimage1.bmp",
604 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
605 passNo = (passNo + 1) % 4;
606 bitmaps[imageNo][quarterNo][passNo].buffer =
607 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_1_075_sampleimage1.bmp",
608 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
609 passNo = (passNo + 1) % 4;
610 bitmaps[imageNo][quarterNo][passNo].buffer =
611 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_1_100_sampleimage1.bmp",
612 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
613 passNo = (passNo + 1) % 4;
614 quarterNo = (quarterNo + 1) % 4;
615 bitmaps[imageNo][quarterNo][passNo].buffer =
616 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_2_025_sampleimage1.bmp",
617 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
618 passNo = (passNo + 1) % 4;
619 bitmaps[imageNo][quarterNo][passNo].buffer =
620 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_2_050_sampleimage1.bmp",
621 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
622 passNo = (passNo + 1) % 4;
623 bitmaps[imageNo][quarterNo][passNo].buffer =
624 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_2_075_sampleimage1.bmp",
625 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
626 passNo = (passNo + 1) % 4;
627 bitmaps[imageNo][quarterNo][passNo].buffer =
628 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_2_100_sampleimage1.bmp",
629 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
630 passNo = (passNo + 1) % 4;
631 quarterNo = (quarterNo + 1) % 4;
632 bitmaps[imageNo][quarterNo][passNo].buffer =
633 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_3_025_sampleimage1.bmp",
634 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
635 passNo = (passNo + 1) % 4;
636 bitmaps[imageNo][quarterNo][passNo].buffer =
637 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_3_050_sampleimage1.bmp",
638 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
639 passNo = (passNo + 1) % 4;
640 bitmaps[imageNo][quarterNo][passNo].buffer =
641 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_3_075_sampleimage1.bmp",
642 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
643 passNo = (passNo + 1) % 4;
644 bitmaps[imageNo][quarterNo][passNo].buffer =
645 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_0_3_100_sampleimage1.bmp",
646 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
647 passNo = (passNo + 1) % 4;
648 imageNo++;
649 /* image 2 */
650 bitmaps[imageNo][quarterNo][passNo].buffer =
651 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_0_025_sampleimage2.bmp",
652 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
653 passNo = (passNo + 1) % 4;
654 bitmaps[imageNo][quarterNo][passNo].buffer =
655 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_0_050_sampleimage2.bmp",
656 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
657 passNo = (passNo + 1) % 4;
658 bitmaps[imageNo][quarterNo][passNo].buffer =
659 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_0_075_sampleimage2.bmp",
660 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
661 passNo = (passNo + 1) % 4;
662 bitmaps[imageNo][quarterNo][passNo].buffer =
663 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_0_100_sampleimage2.bmp",
664 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
665 passNo = (passNo + 1) % 4;
666 quarterNo = (quarterNo + 1) % 4;
667 bitmaps[imageNo][quarterNo][passNo].buffer =
668 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_1_025_sampleimage2.bmp",
669 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
670 passNo = (passNo + 1) % 4;
671 bitmaps[imageNo][quarterNo][passNo].buffer =
672 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_1_050_sampleimage2.bmp",
673 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
674 passNo = (passNo + 1) % 4;
675 bitmaps[imageNo][quarterNo][passNo].buffer =
676 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_1_075_sampleimage2.bmp",
677 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
678 passNo = (passNo + 1) % 4;
679 bitmaps[imageNo][quarterNo][passNo].buffer =
680 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_1_100_sampleimage2.bmp",
681 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
682 passNo = (passNo + 1) % 4;
683 quarterNo = (quarterNo + 1) % 4;
684 bitmaps[imageNo][quarterNo][passNo].buffer =
685 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_2_025_sampleimage2.bmp",
686 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
687 passNo = (passNo + 1) % 4;
688 bitmaps[imageNo][quarterNo][passNo].buffer =
689 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_2_050_sampleimage2.bmp",
690 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
691 passNo = (passNo + 1) % 4;
692 bitmaps[imageNo][quarterNo][passNo].buffer =
693 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_2_075_sampleimage2.bmp",
694 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
695 passNo = (passNo + 1) % 4;
696 bitmaps[imageNo][quarterNo][passNo].buffer =
697 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_2_100_sampleimage2.bmp",
698 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
699 passNo = (passNo + 1) % 4;
700 quarterNo = (quarterNo + 1) % 4;
701 bitmaps[imageNo][quarterNo][passNo].buffer =
702 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_3_025_sampleimage2.bmp",
703 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
704 passNo = (passNo + 1) % 4;
705 bitmaps[imageNo][quarterNo][passNo].buffer =
706 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_3_050_sampleimage2.bmp",
707 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
708 passNo = (passNo + 1) % 4;
709 bitmaps[imageNo][quarterNo][passNo].buffer =
710 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_3_075_sampleimage2.bmp",
711 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
712 passNo = (passNo + 1) % 4;
713 bitmaps[imageNo][quarterNo][passNo].buffer =
714 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_1_3_100_sampleimage2.bmp",
715 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
716 passNo = (passNo + 1) % 4;
717 imageNo++;
718 /* image 3 */
719 bitmaps[imageNo][quarterNo][passNo].buffer =
720 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_0_025_sampleimage3.bmp",
721 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
722 passNo = (passNo + 1) % 4;
723 bitmaps[imageNo][quarterNo][passNo].buffer =
724 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_0_050_sampleimage3.bmp",
725 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
726 passNo = (passNo + 1) % 4;
727 bitmaps[imageNo][quarterNo][passNo].buffer =
728 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_0_075_sampleimage3.bmp",
729 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
730 passNo = (passNo + 1) % 4;
731 bitmaps[imageNo][quarterNo][passNo].buffer =
732 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_0_100_sampleimage3.bmp",
733 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
734 passNo = (passNo + 1) % 4;
735 quarterNo = (quarterNo + 1) % 4;
736 bitmaps[imageNo][quarterNo][passNo].buffer =
737 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_1_025_sampleimage3.bmp",
738 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
739 passNo = (passNo + 1) % 4;
740 bitmaps[imageNo][quarterNo][passNo].buffer =
741 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_1_050_sampleimage3.bmp",
742 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
743 passNo = (passNo + 1) % 4;
744 bitmaps[imageNo][quarterNo][passNo].buffer =
745 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_1_075_sampleimage3.bmp",
746 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
747 passNo = (passNo + 1) % 4;
748 bitmaps[imageNo][quarterNo][passNo].buffer =
749 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_1_100_sampleimage3.bmp",
750 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
751 passNo = (passNo + 1) % 4;
752 quarterNo = (quarterNo + 1) % 4;
753 bitmaps[imageNo][quarterNo][passNo].buffer =
754 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_2_025_sampleimage3.bmp",
755 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
756 passNo = (passNo + 1) % 4;
757 bitmaps[imageNo][quarterNo][passNo].buffer =
758 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_2_050_sampleimage3.bmp",
759 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
760 passNo = (passNo + 1) % 4;
761 bitmaps[imageNo][quarterNo][passNo].buffer =
762 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_2_075_sampleimage3.bmp",
763 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
764 passNo = (passNo + 1) % 4;
765 bitmaps[imageNo][quarterNo][passNo].buffer =
766 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_2_100_sampleimage3.bmp",
767 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
768 passNo = (passNo + 1) % 4;
769 quarterNo = (quarterNo + 1) % 4;
770 bitmaps[imageNo][quarterNo][passNo].buffer =
771 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_3_025_sampleimage3.bmp",
772 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
773 passNo = (passNo + 1) % 4;
774 bitmaps[imageNo][quarterNo][passNo].buffer =
775 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_3_050_sampleimage3.bmp",
776 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
777 passNo = (passNo + 1) % 4;
778 bitmaps[imageNo][quarterNo][passNo].buffer =
779 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_3_075_sampleimage3.bmp",
780 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
781 passNo = (passNo + 1) % 4;
782 bitmaps[imageNo][quarterNo][passNo].buffer =
783 test_progressive_load_bitmap(ms_sample_path, "decompress/dec_2_3_100_sampleimage3.bmp",
784 &(bitmaps[imageNo][quarterNo][passNo].size), quarterNo);
785
786 /* check if all test data has been loaded */
787
788 for (imageNo = 0; imageNo < 3; imageNo++)
789 {
790 for (quarterNo = 0; quarterNo < 4; quarterNo++)
791 {
792 for (passNo = 0; passNo < 4; passNo++)
793 {
794 if (!bitmaps[imageNo][quarterNo][passNo].buffer)
795 return -1;
796 }
797 }
798 }
799
800 return 1;
801}
802
803static size_t test_memcmp_count(const BYTE* mem1, const BYTE* mem2, size_t size, int margin)
804{
805 size_t count = 0;
806
807 for (size_t index = 0; index < size; index++)
808 {
809 if (*mem1 != *mem2)
810 {
811 const int error = (*mem1 > *mem2) ? *mem1 - *mem2 : *mem2 - *mem1;
812
813 if (error > margin)
814 count++;
815 }
816
817 mem1++;
818 mem2++;
819 }
820
821 return count;
822}
823
824static int test_progressive_decode(PROGRESSIVE_CONTEXT* progressive, EGFX_SAMPLE_FILE files[4],
825 EGFX_SAMPLE_FILE bitmaps[4], int quarter, int count)
826{
827 int nXSrc = 0;
828 int nYSrc = 0;
829
830 RECTANGLE_16 clippingRect = { 0 };
831 clippingRect.right = g_Width;
832 clippingRect.bottom = g_Height;
833
834 for (int pass = 0; pass < count; pass++)
835 {
836 const int status =
837 progressive_decompress(progressive, files[pass].buffer, files[pass].size, g_DstData,
838 PIXEL_FORMAT_XRGB32, g_DstStep, 0, 0, NULL, 0, 0);
839 printf("ProgressiveDecompress: status: %d pass: %d\n", status, pass + 1);
840 PROGRESSIVE_BLOCK_REGION* region = &(progressive->region);
841
842 switch (quarter)
843 {
844 case 0:
845 clippingRect.left = 0;
846 clippingRect.top = 0;
847 clippingRect.right = g_Width / 2;
848 clippingRect.bottom = g_Height / 2;
849 break;
850
851 case 1:
852 clippingRect.left = g_Width / 2;
853 clippingRect.top = g_Height / 2;
854 clippingRect.right = g_Width;
855 clippingRect.bottom = g_Height;
856 break;
857
858 case 2:
859 clippingRect.left = 0;
860 clippingRect.top = g_Height / 2;
861 clippingRect.right = g_Width / 2;
862 clippingRect.bottom = g_Height;
863 break;
864
865 case 3:
866 clippingRect.left = g_Width / 2;
867 clippingRect.top = 0;
868 clippingRect.right = g_Width;
869 clippingRect.bottom = g_Height / 2;
870 break;
871 default:
872 return -1;
873 }
874
875 for (UINT16 index = 0; index < region->numTiles; index++)
876 {
877 RFX_PROGRESSIVE_TILE* tile = region->tiles[index];
878
879 const RECTANGLE_16 tileRect = { tile->x, tile->y, tile->x + tile->width,
880 tile->y + tile->height };
881 RECTANGLE_16 updateRect = { 0 };
882 rectangles_intersection(&tileRect, &clippingRect, &updateRect);
883 const UINT16 nXDst = updateRect.left;
884 const UINT16 nYDst = updateRect.top;
885 const UINT16 nWidth = updateRect.right - updateRect.left;
886 const UINT16 nHeight = updateRect.bottom - updateRect.top;
887
888 if ((nWidth <= 0) || (nHeight <= 0))
889 continue;
890
891 nXSrc = nXDst - WINPR_ASSERTING_INT_CAST(int, tile->x);
892 nYSrc = nYDst - WINPR_ASSERTING_INT_CAST(int, tile->y);
893 freerdp_image_copy(g_DstData, PIXEL_FORMAT_XRGB32, g_DstStep, nXDst, nYDst, nWidth,
894 nHeight, tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL,
895 FREERDP_FLIP_NONE);
896 }
897
898 const size_t size = bitmaps[pass].size;
899 const size_t cnt = test_memcmp_count(g_DstData, bitmaps[pass].buffer, size, 1);
900
901 if (cnt)
902 {
903 const float rate = ((float)cnt) / ((float)size) * 100.0f;
904 printf("Progressive RemoteFX decompression failure\n");
905 printf("Actual, Expected (%" PRIuz "/%" PRIuz " = %.3f%%):\n", cnt, size, rate);
906 }
907
908 // WLog_Image(progressive->log, WLOG_TRACE, g_DstData, g_Width, g_Height, 32);
909 }
910
911 return 1;
912}
913
914static int test_progressive_ms_sample(char* ms_sample_path)
915{
916 int count = 0;
917 int status = 0;
918 EGFX_SAMPLE_FILE files[3][4][4] = { 0 };
919 EGFX_SAMPLE_FILE bitmaps[3][4][4] = { 0 };
920 PROGRESSIVE_CONTEXT* progressive = NULL;
921 g_Width = 1920;
922 g_Height = 1080;
923 g_DstStep = g_Width * 4;
924 status = test_progressive_load_files(ms_sample_path, files);
925
926 if (status < 0)
927 {
928 for (int i = 0; i < 3; i++)
929 {
930 for (int j = 0; j < 4; j++)
931 {
932 for (int k = 0; k < 4; k++)
933 sample_file_free(&files[i][j][k]);
934 }
935 }
936
937 return -1;
938 }
939
940 status = test_progressive_load_bitmaps(ms_sample_path, bitmaps);
941
942 if (status < 0)
943 {
944 for (int i = 0; i < 3; i++)
945 {
946 for (int j = 0; j < 4; j++)
947 {
948 for (int k = 0; k < 4; k++)
949 sample_file_free(&files[i][j][k]);
950 }
951 }
952
953 return -1;
954 }
955
956 count = 4;
957 progressive = progressive_context_new(FALSE);
958 g_DstData = winpr_aligned_malloc(1LL * g_DstStep * g_Height, 16);
959 progressive_create_surface_context(progressive, 0, g_Width, g_Height);
960
961 /* image 1 */
962
963 if (1)
964 {
965 printf("\nSample Image 1\n");
966 test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000);
967 test_progressive_decode(progressive, files[0][0], bitmaps[0][0], 0, count);
968 test_progressive_decode(progressive, files[0][1], bitmaps[0][1], 1, count);
969 test_progressive_decode(progressive, files[0][2], bitmaps[0][2], 2, count);
970 test_progressive_decode(progressive, files[0][3], bitmaps[0][3], 3, count);
971 }
972
973 /* image 2 */
974
975 if (0)
976 {
977 printf("\nSample Image 2\n"); /* sample data is in incorrect order */
978 test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000);
979 test_progressive_decode(progressive, files[1][0], bitmaps[1][0], 0, count);
980 test_progressive_decode(progressive, files[1][1], bitmaps[1][1], 1, count);
981 test_progressive_decode(progressive, files[1][2], bitmaps[1][2], 2, count);
982 test_progressive_decode(progressive, files[1][3], bitmaps[1][3], 3, count);
983 }
984
985 /* image 3 */
986
987 if (0)
988 {
989 printf("\nSample Image 3\n"); /* sample data is in incorrect order */
990 test_image_fill(g_DstData, g_DstStep, 0, 0, g_Width, g_Height, 0xFF000000);
991 test_progressive_decode(progressive, files[2][0], bitmaps[2][0], 0, count);
992 test_progressive_decode(progressive, files[2][1], bitmaps[2][1], 1, count);
993 test_progressive_decode(progressive, files[2][2], bitmaps[2][2], 2, count);
994 test_progressive_decode(progressive, files[2][3], bitmaps[2][3], 3, count);
995 }
996
997 progressive_context_free(progressive);
998
999 for (int i = 0; i < 3; i++)
1000 {
1001 for (int j = 0; j < 4; j++)
1002 {
1003 for (int k = 0; k < 4; k++)
1004 {
1005 sample_file_free(&bitmaps[i][j][k]);
1006 sample_file_free(&files[i][j][k]);
1007 }
1008 }
1009 }
1010
1011 winpr_aligned_free(g_DstData);
1012 return 0;
1013}
1014
1015static BOOL diff(BYTE a, BYTE b)
1016{
1017 BYTE big = MAX(a, b);
1018 BYTE little = MIN(a, b);
1019 if (big - little <= 0x25)
1020 return TRUE;
1021 return FALSE;
1022}
1023
1024static BOOL colordiff(UINT32 format, UINT32 a, UINT32 b)
1025{
1026 BYTE ar = 0;
1027 BYTE ag = 0;
1028 BYTE ab = 0;
1029 BYTE aa = 0;
1030 BYTE br = 0;
1031 BYTE bg = 0;
1032 BYTE bb = 0;
1033 BYTE ba = 0;
1034 FreeRDPSplitColor(a, format, &ar, &ag, &ab, &aa, NULL);
1035 FreeRDPSplitColor(b, format, &br, &bg, &bb, &ba, NULL);
1036 if (!diff(aa, ba) || !diff(ar, br) || !diff(ag, bg) || !diff(ab, bb))
1037 return FALSE;
1038 return TRUE;
1039}
1040
1041static BOOL test_encode_decode(const char* path)
1042{
1043 BOOL res = FALSE;
1044 int rc = 0;
1045 BYTE* resultData = NULL;
1046 BYTE* dstData = NULL;
1047 UINT32 dstSize = 0;
1048 UINT32 ColorFormat = PIXEL_FORMAT_BGRX32;
1049 REGION16 invalidRegion = { 0 };
1050 wImage* image = winpr_image_new();
1051 wImage* dstImage = winpr_image_new();
1052 char* name = GetCombinedPath(path, "progressive.bmp");
1053 PROGRESSIVE_CONTEXT* progressiveEnc = progressive_context_new(TRUE);
1054 PROGRESSIVE_CONTEXT* progressiveDec = progressive_context_new(FALSE);
1055
1056 region16_init(&invalidRegion);
1057 if (!image || !dstImage || !name || !progressiveEnc || !progressiveDec)
1058 goto fail;
1059
1060 rc = winpr_image_read(image, name);
1061 if (rc <= 0)
1062 goto fail;
1063
1064 resultData = calloc(image->scanline, image->height);
1065 if (!resultData)
1066 goto fail;
1067
1068 // Progressive encode
1069 rc = progressive_compress(progressiveEnc, image->data, image->scanline * image->height,
1070 ColorFormat, image->width, image->height, image->scanline, NULL,
1071 &dstData, &dstSize);
1072 if (rc < 0)
1073 goto fail;
1074
1075 // Progressive decode
1076 rc = progressive_create_surface_context(progressiveDec, 0, image->width, image->height);
1077 if (rc <= 0)
1078 goto fail;
1079
1080 rc = progressive_decompress(progressiveDec, dstData, dstSize, resultData, ColorFormat,
1081 image->scanline, 0, 0, &invalidRegion, 0, 0);
1082 if (rc < 0)
1083 goto fail;
1084
1085 // Compare result
1086 if (0) // Dump result image for manual inspection
1087 {
1088 *dstImage = *image;
1089 dstImage->data = resultData;
1090 winpr_image_write(dstImage, "/tmp/test.bmp");
1091 }
1092 for (size_t y = 0; y < image->height; y++)
1093 {
1094 const BYTE* orig = &image->data[y * image->scanline];
1095 const BYTE* dec = &resultData[y * image->scanline];
1096 for (size_t x = 0; x < image->width; x++)
1097 {
1098 const BYTE* po = &orig[x * 4];
1099 const BYTE* pd = &dec[x * 4];
1100
1101 const DWORD a = FreeRDPReadColor(po, ColorFormat);
1102 const DWORD b = FreeRDPReadColor(pd, ColorFormat);
1103 if (!colordiff(ColorFormat, a, b))
1104 {
1105 printf("xxxxxxx [%" PRIuz ":%" PRIuz "] [%s] %08X != %08X\n", x, y,
1106 FreeRDPGetColorFormatName(ColorFormat), a, b);
1107 goto fail;
1108 }
1109 }
1110 }
1111 res = TRUE;
1112fail:
1113 region16_uninit(&invalidRegion);
1114 progressive_context_free(progressiveEnc);
1115 progressive_context_free(progressiveDec);
1116 winpr_image_free(image, TRUE);
1117 winpr_image_free(dstImage, FALSE);
1118 free(resultData);
1119 free(name);
1120 return res;
1121}
1122
1123static BOOL read_cmd(FILE* fp, RDPGFX_SURFACE_COMMAND* cmd, UINT32* frameId)
1124{
1125 WINPR_ASSERT(fp);
1126 WINPR_ASSERT(cmd);
1127 WINPR_ASSERT(frameId);
1128
1129 // NOLINTBEGIN(cert-err34-c)
1130 if (1 != fscanf(fp, "frameid: %" PRIu32 "\n", frameId))
1131 return FALSE;
1132 if (1 != fscanf(fp, "surfaceId: %" PRIu32 "\n", &cmd->surfaceId))
1133 return FALSE;
1134 if (1 != fscanf(fp, "codecId: %" PRIu32 "\n", &cmd->codecId))
1135 return FALSE;
1136 if (1 != fscanf(fp, "contextId: %" PRIu32 "\n", &cmd->contextId))
1137 return FALSE;
1138 if (1 != fscanf(fp, "format: %" PRIu32 "\n", &cmd->format))
1139 return FALSE;
1140 if (1 != fscanf(fp, "left: %" PRIu32 "\n", &cmd->left))
1141 return FALSE;
1142 if (1 != fscanf(fp, "top: %" PRIu32 "\n", &cmd->top))
1143 return FALSE;
1144 if (1 != fscanf(fp, "right: %" PRIu32 "\n", &cmd->right))
1145 return FALSE;
1146 if (1 != fscanf(fp, "bottom: %" PRIu32 "\n", &cmd->bottom))
1147 return FALSE;
1148 if (1 != fscanf(fp, "width: %" PRIu32 "\n", &cmd->width))
1149 return FALSE;
1150 if (1 != fscanf(fp, "height: %" PRIu32 "\n", &cmd->height))
1151 return FALSE;
1152 if (1 != fscanf(fp, "length: %" PRIu32 "\n", &cmd->length))
1153 return FALSE;
1154 // NOLINTEND(cert-err34-c)
1155
1156 char* data = NULL;
1157
1158 size_t dlen = SIZE_MAX;
1159 SSIZE_T slen = GetLine(&data, &slen, fp);
1160 if (slen < 0)
1161 return FALSE;
1162
1163 if (slen >= 7)
1164 {
1165 const char* b64 = &data[6];
1166 slen -= 7;
1167 crypto_base64_decode(b64, slen, &cmd->data, &dlen);
1168 }
1169 free(data);
1170
1171 return cmd->length == dlen;
1172}
1173
1174static void free_cmd(RDPGFX_SURFACE_COMMAND* cmd)
1175{
1176 free(cmd->data);
1177}
1178
1179WINPR_NORETURN(static void usage(const char* name))
1180{
1181 FILE* fp = stdout;
1182 (void)fprintf(fp, "%s <directory> <width> <height>\n", name);
1183 // NOLINTNEXTLINE(concurrency-mt-unsafe)
1184 exit(-1);
1185}
1186
1187static void print_codec_stats(const char* name, UINT64 timeNS)
1188{
1189 const double dectimeMS = (double)timeNS / 1000.0 / 1000.0;
1190 (void)fprintf(stderr, "[%s] took %lf ms to decode\n", name, dectimeMS);
1191}
1192
1193static UINT64 measure_diff_and_print(const char* cname, UINT32 frameId, UINT64 start)
1194{
1195 const UINT64 end = winpr_GetTickCount64NS();
1196 const UINT64 diff = end - start;
1197 const double ddiff = (double)diff / 1000000.0;
1198 (void)fprintf(stderr, "frame [%s] %" PRIu32 " took %lf ms\n", cname, frameId, ddiff);
1199 return diff;
1200}
1201
1202static int test_dump(int argc, char* argv[])
1203{
1204 int success = -1;
1205 UINT32 count = 0;
1206
1207 UINT64 CAPROGRESSIVE_dectime = 0;
1208 UINT64 UNCOMPRESSED_dectime = 0;
1209 UINT64 CAVIDEO_dectime = 0;
1210 UINT64 CLEARCODEC_dectime = 0;
1211 UINT64 PLANAR_dectime = 0;
1212 UINT64 AVC420_dectime = 0;
1213 UINT64 ALPHA_dectime = 0;
1214 UINT64 AVC444_dectime = 0;
1215 UINT64 AVC444v2_dectime = 0;
1216 UINT64 copytime = 0;
1217
1218 if (argc < 4)
1219 usage(argv[0]);
1220
1221 const char* path = argv[1];
1222 errno = 0;
1223 const unsigned long width = strtoul(argv[2], NULL, 0);
1224 if ((errno != 0) || (width <= 0))
1225 usage(argv[0]);
1226 const unsigned long height = strtoul(argv[3], NULL, 0);
1227 if ((errno != 0) || (height <= 0))
1228 usage(argv[0]);
1229
1230 rdpCodecs* codecs = freerdp_client_codecs_new(0);
1231 if (!codecs)
1232 return -2;
1233
1234 UINT32 DstFormat = PIXEL_FORMAT_BGRA32;
1235 const UINT32 stride = (width + 16) * FreeRDPGetBytesPerPixel(DstFormat);
1236
1237 BYTE* dst = calloc(stride, height);
1238 BYTE* output = calloc(stride, height);
1239 if (!dst || !output)
1240 goto fail;
1241
1242 if (!freerdp_client_codecs_prepare(codecs, FREERDP_CODEC_ALL, width, height))
1243 goto fail;
1244
1245 success = 0;
1246 while (success >= 0)
1247 {
1248 char* fname = NULL;
1249 size_t flen = 0;
1250 winpr_asprintf(&fname, &flen, "%s/%08" PRIx32 ".raw", path, count++);
1251 FILE* fp = fopen(fname, "r");
1252 free(fname);
1253
1254 if (!fp)
1255 break;
1256
1257 UINT32 frameId = 0;
1258 RDPGFX_SURFACE_COMMAND cmd = { 0 };
1259
1260 if (read_cmd(fp, &cmd, &frameId))
1261 {
1262 REGION16 invalid = { 0 };
1263 region16_init(&invalid);
1264
1265 const char* cname = rdpgfx_get_codec_id_string(cmd.codecId);
1266 switch (cmd.codecId)
1267 {
1268 case RDPGFX_CODECID_CAPROGRESSIVE:
1269 {
1270 const UINT64 start = winpr_GetTickCount64NS();
1271 success = progressive_create_surface_context(codecs->progressive, cmd.surfaceId,
1272 width, height);
1273 if (success >= 0)
1274 success = progressive_decompress(codecs->progressive, cmd.data, cmd.length,
1275 dst, DstFormat, 0, cmd.left, cmd.top,
1276 &invalid, cmd.surfaceId, frameId);
1277 CAPROGRESSIVE_dectime += measure_diff_and_print(cname, frameId, start);
1278 }
1279 break;
1280
1281 case RDPGFX_CODECID_UNCOMPRESSED:
1282 {
1283 const UINT64 start = winpr_GetTickCount64NS();
1284 if (!freerdp_image_copy_no_overlap(dst, DstFormat, stride, cmd.left, cmd.top,
1285 cmd.width, cmd.height, cmd.data, cmd.format,
1286 0, 0, 0, NULL, FREERDP_FLIP_NONE))
1287 success = -1;
1288
1289 RECTANGLE_16 invalidRect = { .left = (UINT16)MIN(UINT16_MAX, cmd.left),
1290 .top = (UINT16)MIN(UINT16_MAX, cmd.top),
1291 .right = (UINT16)MIN(UINT16_MAX, cmd.right),
1292 .bottom = (UINT16)MIN(UINT16_MAX, cmd.bottom) };
1293 region16_union_rect(&invalid, &invalid, &invalidRect);
1294 UNCOMPRESSED_dectime += measure_diff_and_print(cname, frameId, start);
1295 }
1296 break;
1297 case RDPGFX_CODECID_CAVIDEO:
1298 {
1299 const UINT64 start = winpr_GetTickCount64NS();
1300 if (!rfx_process_message(codecs->rfx, cmd.data, cmd.length, cmd.left, cmd.top,
1301 dst, DstFormat, stride, height, &invalid))
1302 success = -1;
1303
1304 CAVIDEO_dectime += measure_diff_and_print(cname, frameId, start);
1305 }
1306 break;
1307 case RDPGFX_CODECID_CLEARCODEC:
1308 {
1309 const UINT64 start = winpr_GetTickCount64NS();
1310 success = clear_decompress(codecs->clear, cmd.data, cmd.length, cmd.width,
1311 cmd.height, dst, DstFormat, stride, cmd.left,
1312 cmd.top, width, height, NULL);
1313
1314 const RECTANGLE_16 invalidRect = { .left = (UINT16)MIN(UINT16_MAX, cmd.left),
1315 .top = (UINT16)MIN(UINT16_MAX, cmd.top),
1316 .right = (UINT16)MIN(UINT16_MAX, cmd.right),
1317 .bottom =
1318 (UINT16)MIN(UINT16_MAX, cmd.bottom) };
1319 region16_union_rect(&invalid, &invalid, &invalidRect);
1320 CLEARCODEC_dectime += measure_diff_and_print(cname, frameId, start);
1321 }
1322 break;
1323 case RDPGFX_CODECID_PLANAR:
1324 {
1325 const UINT64 start = winpr_GetTickCount64NS();
1326
1327 if (!planar_decompress(codecs->planar, cmd.data, cmd.length, cmd.width,
1328 cmd.height, dst, DstFormat, stride, cmd.left, cmd.top,
1329 cmd.width, cmd.height, FALSE))
1330 success = -1;
1331
1332 const RECTANGLE_16 invalidRect = { .left = (UINT16)MIN(UINT16_MAX, cmd.left),
1333 .top = (UINT16)MIN(UINT16_MAX, cmd.top),
1334 .right = (UINT16)MIN(UINT16_MAX, cmd.right),
1335 .bottom =
1336 (UINT16)MIN(UINT16_MAX, cmd.bottom) };
1337 region16_union_rect(&invalid, &invalid, &invalidRect);
1338
1339 PLANAR_dectime += measure_diff_and_print(cname, frameId, start);
1340 }
1341 break;
1342 case RDPGFX_CODECID_AVC420:
1343 {
1344 const UINT64 start = winpr_GetTickCount64NS();
1345
1346 AVC420_dectime += measure_diff_and_print(cname, frameId, start);
1347 success = -1;
1348 }
1349 break;
1350 case RDPGFX_CODECID_ALPHA:
1351 {
1352 const UINT64 start = winpr_GetTickCount64NS();
1353
1354 ALPHA_dectime += measure_diff_and_print(cname, frameId, start);
1355 success = -1;
1356 }
1357 break;
1358 case RDPGFX_CODECID_AVC444:
1359 {
1360 const UINT64 start = winpr_GetTickCount64NS();
1361
1362 AVC444_dectime += measure_diff_and_print(cname, frameId, start);
1363 success = -1;
1364 }
1365 break;
1366 case RDPGFX_CODECID_AVC444v2:
1367 {
1368 const UINT64 start = winpr_GetTickCount64NS();
1369
1370 AVC444v2_dectime += measure_diff_and_print(cname, frameId, start);
1371 success = -1;
1372 }
1373 break;
1374 default:
1375 (void)fprintf(stderr, "unexpected codec %s [0x%08" PRIx32 "]",
1376 rdpgfx_get_codec_id_string(cmd.codecId), cmd.codecId);
1377 success = -1;
1378 break;
1379 }
1380
1381 if (success >= 0)
1382 {
1383 UINT32 nbRects = 0;
1384 const UINT64 start = winpr_GetTickCount64NS();
1385
1386 const RECTANGLE_16* rects = region16_rects(&invalid, &nbRects);
1387 for (size_t x = 0; x < nbRects; x++)
1388 {
1389 const RECTANGLE_16* rect = &rects[x];
1390 const UINT32 w = rect->right - rect->left;
1391 const UINT32 h = rect->bottom - rect->top;
1392 if (!freerdp_image_copy_no_overlap(output, DstFormat, stride, rect->left,
1393 rect->top, w, h, dst, DstFormat, stride,
1394 rect->left, rect->top, NULL, 0))
1395 success = -42;
1396 }
1397 copytime += measure_diff_and_print(cname, frameId, start);
1398 }
1399 region16_clear(&invalid);
1400 }
1401 free_cmd(&cmd);
1402 (void)fclose(fp);
1403 }
1404
1405fail:
1406 freerdp_client_codecs_free(codecs);
1407 free(output);
1408 free(dst);
1409
1410 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_UNCOMPRESSED),
1411 UNCOMPRESSED_dectime);
1412 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_CAPROGRESSIVE),
1413 CAPROGRESSIVE_dectime);
1414 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_CAVIDEO), CAVIDEO_dectime);
1415 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_CLEARCODEC), CLEARCODEC_dectime);
1416 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_PLANAR), PLANAR_dectime);
1417 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_AVC420), AVC420_dectime);
1418 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_AVC444), AVC444_dectime);
1419 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_AVC444v2), AVC444v2_dectime);
1420 print_codec_stats(rdpgfx_get_codec_id_string(RDPGFX_CODECID_ALPHA), ALPHA_dectime);
1421
1422 const UINT64 decodetime = UNCOMPRESSED_dectime + CAPROGRESSIVE_dectime + CAVIDEO_dectime +
1423 CLEARCODEC_dectime + PLANAR_dectime + AVC420_dectime +
1424 AVC444_dectime + AVC444v2_dectime + ALPHA_dectime;
1425 print_codec_stats("surface copy", copytime);
1426 print_codec_stats("total decode", decodetime);
1427 print_codec_stats("total", decodetime + copytime);
1428
1429 return success;
1430}
1431
1432int TestFreeRDPCodecProgressive(int argc, char* argv[])
1433{
1434 if (argc > 1)
1435 return test_dump(argc, argv);
1436
1437 int rc = -1;
1438 char* ms_sample_path = NULL;
1439 char name[8192];
1440 SYSTEMTIME systemTime;
1441 WINPR_UNUSED(argc);
1442 WINPR_UNUSED(argv);
1443
1444 GetSystemTime(&systemTime);
1445 (void)sprintf_s(name, sizeof(name),
1446 "EGFX_PROGRESSIVE_MS_SAMPLE-%04" PRIu16 "%02" PRIu16 "%02" PRIu16 "%02" PRIu16
1447 "%02" PRIu16 "%02" PRIu16 "%04" PRIu16,
1448 systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour,
1449 systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
1450 ms_sample_path = _strdup(CMAKE_CURRENT_SOURCE_DIR);
1451
1452 if (!ms_sample_path)
1453 {
1454 printf("Memory allocation failed\n");
1455 goto fail;
1456 }
1457
1458 if (winpr_PathFileExists(ms_sample_path))
1459 {
1460 /*
1461 if (test_progressive_ms_sample(ms_sample_path) < 0)
1462 goto fail;
1463 */
1464 if (!test_encode_decode(ms_sample_path))
1465 goto fail;
1466 rc = 0;
1467 }
1468
1469fail:
1470 free(ms_sample_path);
1471 return rc;
1472}