FreeRDP
Loading...
Searching...
No Matches
progressive.c
1
22#include <freerdp/config.h>
23
24#include <winpr/assert.h>
25#include <winpr/cast.h>
26#include <winpr/crt.h>
27#include <winpr/print.h>
28#include <winpr/bitstream.h>
29
30#include <freerdp/primitives.h>
31#include <freerdp/codec/color.h>
32#include <freerdp/codec/progressive.h>
33#include <freerdp/codec/region.h>
34#include <freerdp/log.h>
35
36#include "rfx_differential.h"
37#include "rfx_quantization.h"
38#include "rfx_dwt.h"
39#include "rfx_rlgr.h"
40#include "rfx_constants.h"
41#include "rfx_types.h"
42#include "progressive.h"
43
44#define TAG FREERDP_TAG("codec.progressive")
45
46typedef struct
47{
48 BOOL nonLL;
49 wBitStream* srl;
50 wBitStream* raw;
51
52 /* SRL state */
53
54 UINT32 kp;
55 int nz;
56 BOOL mode;
57} RFX_PROGRESSIVE_UPGRADE_STATE;
58
59static inline void
60progressive_component_codec_quant_read(wStream* WINPR_RESTRICT s,
61 RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT quantVal)
62{
63 BYTE b = 0;
64 Stream_Read_UINT8(s, b);
65 quantVal->LL3 = b & 0x0F;
66 quantVal->HL3 = b >> 4;
67 Stream_Read_UINT8(s, b);
68 quantVal->LH3 = b & 0x0F;
69 quantVal->HH3 = b >> 4;
70 Stream_Read_UINT8(s, b);
71 quantVal->HL2 = b & 0x0F;
72 quantVal->LH2 = b >> 4;
73 Stream_Read_UINT8(s, b);
74 quantVal->HH2 = b & 0x0F;
75 quantVal->HL1 = b >> 4;
76 Stream_Read_UINT8(s, b);
77 quantVal->LH1 = b & 0x0F;
78 quantVal->HH1 = b >> 4;
79}
80
81static inline void progressive_rfx_quant_add(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
82 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2,
84{
85 dst->HL1 = q1->HL1 + q2->HL1; /* HL1 */
86 dst->LH1 = q1->LH1 + q2->LH1; /* LH1 */
87 dst->HH1 = q1->HH1 + q2->HH1; /* HH1 */
88 dst->HL2 = q1->HL2 + q2->HL2; /* HL2 */
89 dst->LH2 = q1->LH2 + q2->LH2; /* LH2 */
90 dst->HH2 = q1->HH2 + q2->HH2; /* HH2 */
91 dst->HL3 = q1->HL3 + q2->HL3; /* HL3 */
92 dst->LH3 = q1->LH3 + q2->LH3; /* LH3 */
93 dst->HH3 = q1->HH3 + q2->HH3; /* HH3 */
94 dst->LL3 = q1->LL3 + q2->LL3; /* LL3 */
95}
96
97WINPR_ATTR_NODISCARD
98static inline BOOL progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
99{
100 if (q->HL1 < val)
101 return FALSE;
102 q->HL1 -= val; /* HL1 */
103
104 if (q->LH1 < val)
105 return FALSE;
106 q->LH1 -= val; /* LH1 */
107
108 if (q->HH1 < val)
109 return FALSE;
110 q->HH1 -= val; /* HH1 */
111
112 if (q->HL2 < val)
113 return FALSE;
114 q->HL2 -= val; /* HL2 */
115
116 if (q->LH2 < val)
117 return FALSE;
118 q->LH2 -= val; /* LH2 */
119
120 if (q->HH2 < val)
121 return FALSE;
122 q->HH2 -= val; /* HH2 */
123
124 if (q->HL3 < val)
125 return FALSE;
126 q->HL3 -= val; /* HL3 */
127
128 if (q->LH3 < val)
129 return FALSE;
130 q->LH3 -= val; /* LH3 */
131
132 if (q->HH3 < val)
133 return FALSE;
134 q->HH3 -= val; /* HH3 */
135
136 if (q->LL3 < val)
137 return FALSE;
138 q->LL3 -= val; /* LL3 */
139 return TRUE;
140}
141
142WINPR_ATTR_NODISCARD
143static inline BOOL progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
144 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2,
146{
147 if (q1->HL1 < q2->HL1)
148 return FALSE;
149 dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */
150
151 if (q1->LH1 < q2->LH1)
152 return FALSE;
153 dst->LH1 = q1->LH1 - q2->LH1; /* LH1 */
154
155 if (q1->HH1 < q2->HH1)
156 return FALSE;
157 dst->HH1 = q1->HH1 - q2->HH1; /* HH1 */
158
159 if (q1->HL2 < q2->HL2)
160 return FALSE;
161 dst->HL2 = q1->HL2 - q2->HL2; /* HL2 */
162
163 if (q1->LH2 < q2->LH2)
164 return FALSE;
165 dst->LH2 = q1->LH2 - q2->LH2; /* LH2 */
166
167 if (q1->HH2 < q2->HH2)
168 return FALSE;
169 dst->HH2 = q1->HH2 - q2->HH2; /* HH2 */
170
171 if (q1->HL3 < q2->HL3)
172 return FALSE;
173 dst->HL3 = q1->HL3 - q2->HL3; /* HL3 */
174
175 if (q1->LH3 < q2->LH3)
176 return FALSE;
177 dst->LH3 = q1->LH3 - q2->LH3; /* LH3 */
178
179 if (q1->HH3 < q2->HH3)
180 return FALSE;
181 dst->HH3 = q1->HH3 - q2->HH3; /* HH3 */
182
183 if (q1->LL3 < q2->LL3)
184 return FALSE;
185 dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */
186
187 return TRUE;
188}
189
190static inline BOOL
191progressive_rfx_quant_lcmp_less_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
192{
193 if (q->HL1 > val)
194 return FALSE; /* HL1 */
195
196 if (q->LH1 > val)
197 return FALSE; /* LH1 */
198
199 if (q->HH1 > val)
200 return FALSE; /* HH1 */
201
202 if (q->HL2 > val)
203 return FALSE; /* HL2 */
204
205 if (q->LH2 > val)
206 return FALSE; /* LH2 */
207
208 if (q->HH2 > val)
209 return FALSE; /* HH2 */
210
211 if (q->HL3 > val)
212 return FALSE; /* HL3 */
213
214 if (q->LH3 > val)
215 return FALSE; /* LH3 */
216
217 if (q->HH3 > val)
218 return FALSE; /* HH3 */
219
220 if (q->LL3 > val)
221 return FALSE; /* LL3 */
222
223 return TRUE;
224}
225
226static inline BOOL
227progressive_rfx_quant_lcmp_greater_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
228{
229 if (q->HL1 < val)
230 return FALSE; /* HL1 */
231
232 if (q->LH1 < val)
233 return FALSE; /* LH1 */
234
235 if (q->HH1 < val)
236 return FALSE; /* HH1 */
237
238 if (q->HL2 < val)
239 return FALSE; /* HL2 */
240
241 if (q->LH2 < val)
242 return FALSE; /* LH2 */
243
244 if (q->HH2 < val)
245 return FALSE; /* HH2 */
246
247 if (q->HL3 < val)
248 return FALSE; /* HL3 */
249
250 if (q->LH3 < val)
251 return FALSE; /* LH3 */
252
253 if (q->HH3 < val)
254 return FALSE; /* HH3 */
255
256 if (q->LL3 < val)
257 return FALSE; /* LL3 */
258
259 return TRUE;
260}
261
262static inline BOOL
263progressive_rfx_quant_cmp_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
264 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2)
265{
266 if (q1->HL1 != q2->HL1)
267 return FALSE; /* HL1 */
268
269 if (q1->LH1 != q2->LH1)
270 return FALSE; /* LH1 */
271
272 if (q1->HH1 != q2->HH1)
273 return FALSE; /* HH1 */
274
275 if (q1->HL2 != q2->HL2)
276 return FALSE; /* HL2 */
277
278 if (q1->LH2 != q2->LH2)
279 return FALSE; /* LH2 */
280
281 if (q1->HH2 != q2->HH2)
282 return FALSE; /* HH2 */
283
284 if (q1->HL3 != q2->HL3)
285 return FALSE; /* HL3 */
286
287 if (q1->LH3 != q2->LH3)
288 return FALSE; /* LH3 */
289
290 if (q1->HH3 != q2->HH3)
291 return FALSE; /* HH3 */
292
293 if (q1->LL3 != q2->LL3)
294 return FALSE; /* LL3 */
295
296 return TRUE;
297}
298
299static inline BOOL progressive_set_surface_data(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
300 UINT16 surfaceId,
301 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT pData)
302{
303 ULONG_PTR key = 0;
304 key = ((ULONG_PTR)surfaceId) + 1;
305
306 if (pData)
307 return HashTable_Insert(progressive->SurfaceContexts, (void*)key, pData);
308
309 HashTable_Remove(progressive->SurfaceContexts, (void*)key);
310 return TRUE;
311}
312
313static inline PROGRESSIVE_SURFACE_CONTEXT*
314progressive_get_surface_data(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, UINT16 surfaceId)
315{
316 void* key = (void*)(((ULONG_PTR)surfaceId) + 1);
317
318 if (!progressive)
319 return nullptr;
320
321 return HashTable_GetItemValue(progressive->SurfaceContexts, key);
322}
323
324static void progressive_tile_free(RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile)
325{
326 if (tile)
327 {
328 winpr_aligned_free(tile->sign);
329 winpr_aligned_free(tile->current);
330 winpr_aligned_free(tile->data);
331 winpr_aligned_free(tile);
332 }
333}
334
335static void progressive_surface_context_free(void* ptr)
336{
337 PROGRESSIVE_SURFACE_CONTEXT* surface = ptr;
338
339 if (!surface)
340 return;
341
342 if (surface->tiles)
343 {
344 for (size_t index = 0; index < surface->tilesSize; index++)
345 {
346 RFX_PROGRESSIVE_TILE* tile = surface->tiles[index];
347 progressive_tile_free(tile);
348 }
349 }
350
351 winpr_aligned_free((void*)surface->tiles);
352 winpr_aligned_free(surface->updatedTileIndices);
353 winpr_aligned_free(surface);
354}
355
356static inline RFX_PROGRESSIVE_TILE* progressive_tile_new(void)
357{
358 RFX_PROGRESSIVE_TILE* tile = winpr_aligned_calloc(1, sizeof(RFX_PROGRESSIVE_TILE), 32);
359 if (!tile)
360 goto fail;
361
362 tile->width = 64;
363 tile->height = 64;
364 tile->stride = 4 * tile->width;
365
366 {
367 const size_t dataLen = 1ull * tile->stride * tile->height;
368 tile->data = (BYTE*)winpr_aligned_calloc(tile->stride, tile->height, 16);
369 if (!tile->data)
370 goto fail;
371 memset(tile->data, 0xFF, dataLen);
372 }
373
374 {
375 const size_t signLen = (8192ULL + 32ULL);
376 tile->sign = (BYTE*)winpr_aligned_calloc(3, signLen, 16);
377 }
378
379 if (!tile->sign)
380 goto fail;
381
382 {
383 const size_t currentLen = (8192ULL + 32ULL);
384 tile->current = (BYTE*)winpr_aligned_calloc(3, currentLen, 16);
385 }
386 if (!tile->current)
387 goto fail;
388
389 return tile;
390
391fail:
392 progressive_tile_free(tile);
393 return nullptr;
394}
395
396static inline BOOL
397progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface, size_t min)
398{
399 size_t oldIndex = 0;
400
401 WINPR_ASSERT(surface);
402 WINPR_ASSERT(surface->gridSize > 0);
403
404 UINT32 gridSize = surface->gridSize;
405 if (surface->tiles)
406 {
407 oldIndex = gridSize;
408 while (gridSize < min)
409 {
410 if (gridSize > UINT32_MAX - 1024)
411 return FALSE;
412 gridSize += 1024;
413 }
414 }
415
416 void* tmp =
417 winpr_aligned_recalloc((void*)surface->tiles, gridSize, sizeof(RFX_PROGRESSIVE_TILE*), 32);
418 if (!tmp)
419 return FALSE;
420 surface->tilesSize = gridSize;
421 surface->tiles = (RFX_PROGRESSIVE_TILE**)tmp;
422
423 for (size_t x = oldIndex; x < surface->tilesSize; x++)
424 {
425 surface->tiles[x] = progressive_tile_new();
426 if (!surface->tiles[x])
427 return FALSE;
428 }
429
430 tmp = winpr_aligned_recalloc(surface->updatedTileIndices, gridSize, sizeof(UINT32), 32);
431 if (!tmp)
432 return FALSE;
433
434 surface->gridSize = gridSize;
435 surface->updatedTileIndices = tmp;
436
437 return TRUE;
438}
439
440static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width,
441 UINT32 height)
442{
443 PROGRESSIVE_SURFACE_CONTEXT* surface = (PROGRESSIVE_SURFACE_CONTEXT*)winpr_aligned_calloc(
444 1, sizeof(PROGRESSIVE_SURFACE_CONTEXT), 32);
445
446 if (!surface)
447 return nullptr;
448
449 surface->id = surfaceId;
450 surface->width = width;
451 surface->height = height;
452 surface->gridWidth = (width + (64 - width % 64)) / 64;
453 surface->gridHeight = (height + (64 - height % 64)) / 64;
454 surface->gridSize = surface->gridWidth * surface->gridHeight;
455
456 if (!progressive_allocate_tile_cache(surface, surface->gridSize))
457 {
458 progressive_surface_context_free(surface);
459 return nullptr;
460 }
461
462 return surface;
463}
464
465static inline BOOL
466progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
467 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
468 const RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile, BOOL upgrade)
469{
470 RFX_PROGRESSIVE_TILE* t = nullptr;
471
472 size_t zIdx = 0;
473 if (!surface || !tile)
474 return FALSE;
475
476 zIdx = (tile->yIdx * surface->gridWidth) + tile->xIdx;
477
478 if (zIdx >= surface->tilesSize)
479 {
480 WLog_ERR(TAG, "Invalid zIndex %" PRIuz, zIdx);
481 return FALSE;
482 }
483
484 t = surface->tiles[zIdx];
485
486 t->blockType = tile->blockType;
487 t->blockLen = tile->blockLen;
488 t->quantIdxY = tile->quantIdxY;
489 t->quantIdxCb = tile->quantIdxCb;
490 t->quantIdxCr = tile->quantIdxCr;
491 t->xIdx = tile->xIdx;
492 t->yIdx = tile->yIdx;
493 t->flags = tile->flags;
494 t->quality = tile->quality;
495 t->x = tile->xIdx * t->width;
496 t->y = tile->yIdx * t->height;
497
498 if (upgrade)
499 {
500 t->ySrlLen = tile->ySrlLen;
501 t->yRawLen = tile->yRawLen;
502 t->cbSrlLen = tile->cbSrlLen;
503 t->cbRawLen = tile->cbRawLen;
504 t->crSrlLen = tile->crSrlLen;
505 t->crRawLen = tile->crRawLen;
506 t->ySrlData = tile->ySrlData;
507 t->yRawData = tile->yRawData;
508 t->cbSrlData = tile->cbSrlData;
509 t->cbRawData = tile->cbRawData;
510 t->crSrlData = tile->crSrlData;
511 t->crRawData = tile->crRawData;
512 }
513 else
514 {
515 t->yLen = tile->yLen;
516 t->cbLen = tile->cbLen;
517 t->crLen = tile->crLen;
518 t->tailLen = tile->tailLen;
519 t->yData = tile->yData;
520 t->cbData = tile->cbData;
521 t->crData = tile->crData;
522 t->tailData = tile->tailData;
523 }
524
525 if (region->usedTiles >= region->numTiles)
526 {
527 WLog_ERR(TAG, "Invalid tile count, only expected %" PRIu16 ", got %" PRIu16,
528 region->numTiles, region->usedTiles);
529 return FALSE;
530 }
531
532 region->tiles[region->usedTiles++] = t;
533 if (!t->dirty)
534 {
535 if (surface->numUpdatedTiles >= surface->gridSize)
536 {
537 if (!progressive_allocate_tile_cache(surface, surface->numUpdatedTiles + 1))
538 return FALSE;
539 }
540
541 surface->updatedTileIndices[surface->numUpdatedTiles++] = (UINT32)zIdx;
542 }
543
544 t->dirty = TRUE;
545 return TRUE;
546}
547
548INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
549 UINT16 surfaceId, UINT32 width, UINT32 height)
550{
551 PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
552
553 if (!surface)
554 {
555 surface = progressive_surface_context_new(surfaceId, width, height);
556
557 if (!surface)
558 return -1;
559
560 if (!progressive_set_surface_data(progressive, surfaceId, (void*)surface))
561 {
562 progressive_surface_context_free(surface);
563 return -1;
564 }
565 }
566
567 return 1;
568}
569
570int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
571 UINT16 surfaceId)
572{
573 progressive_set_surface_data(progressive, surfaceId, nullptr);
574
575 return 1;
576}
577
578/*
579 * Band Offset Dimensions Size
580 *
581 * HL1 0 31x33 1023
582 * LH1 1023 33x31 1023
583 * HH1 2046 31x31 961
584 *
585 * HL2 3007 16x17 272
586 * LH2 3279 17x16 272
587 * HH2 3551 16x16 256
588 *
589 * HL3 3807 8x9 72
590 * LH3 3879 9x8 72
591 * HH3 3951 8x8 64
592 *
593 * LL3 4015 9x9 81
594 */
595
596static int16_t clampi16(int val)
597{
598 if (val < INT16_MIN)
599 return INT16_MIN;
600 if (val > INT16_MAX)
601 return INT16_MAX;
602 return (int16_t)val;
603}
604
605static inline void progressive_rfx_idwt_x(const INT16* WINPR_RESTRICT pLowBand, size_t nLowStep,
606 const INT16* WINPR_RESTRICT pHighBand, size_t nHighStep,
607 INT16* WINPR_RESTRICT pDstBand, size_t nDstStep,
608 size_t nLowCount, size_t nHighCount, size_t nDstCount)
609{
610 INT16 H1 = 0;
611 INT16 X1 = 0;
612
613 for (size_t i = 0; i < nDstCount; i++)
614 {
615 const INT16* pL = pLowBand;
616 const INT16* pH = pHighBand;
617 INT16* pX = pDstBand;
618 INT16 H0 = *pH++;
619 INT16 L0 = *pL++;
620 INT16 X0 = clampi16((int32_t)L0 - H0);
621 INT16 X2 = clampi16((int32_t)L0 - H0);
622
623 for (size_t j = 0; j < (nHighCount - 1); j++)
624 {
625 H1 = *pH;
626 pH++;
627 L0 = *pL;
628 pL++;
629 X2 = clampi16((int32_t)L0 - ((H0 + H1) / 2));
630 X1 = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
631 pX[0] = X0;
632 pX[1] = X1;
633 pX += 2;
634 X0 = X2;
635 H0 = H1;
636 }
637
638 if (nLowCount <= (nHighCount + 1))
639 {
640 if (nLowCount <= nHighCount)
641 {
642 pX[0] = X2;
643 pX[1] = clampi16((int32_t)X2 + (2 * H0));
644 }
645 else
646 {
647 L0 = *pL;
648 pL++;
649 X0 = clampi16((int32_t)L0 - H0);
650 pX[0] = X2;
651 pX[1] = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
652 pX[2] = X0;
653 }
654 }
655 else
656 {
657 L0 = *pL;
658 pL++;
659 X0 = clampi16((int32_t)L0 - (H0 / 2));
660 pX[0] = X2;
661 pX[1] = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
662 pX[2] = X0;
663 L0 = *pL;
664 pL++;
665 pX[3] = clampi16((int32_t)(X0 + L0) / 2);
666 }
667
668 pLowBand += nLowStep;
669 pHighBand += nHighStep;
670 pDstBand += nDstStep;
671 }
672}
673
674static inline void progressive_rfx_idwt_y(const INT16* WINPR_RESTRICT pLowBand, size_t nLowStep,
675 const INT16* WINPR_RESTRICT pHighBand, size_t nHighStep,
676 INT16* WINPR_RESTRICT pDstBand, size_t nDstStep,
677 size_t nLowCount, size_t nHighCount, size_t nDstCount)
678{
679 for (size_t i = 0; i < nDstCount; i++)
680 {
681 INT16 H1 = 0;
682 INT16 X1 = 0;
683 const INT16* pL = pLowBand;
684 const INT16* pH = pHighBand;
685 INT16* pX = pDstBand;
686 INT16 H0 = *pH;
687 pH += nHighStep;
688 INT16 L0 = *pL;
689 pL += nLowStep;
690 int16_t X0 = clampi16((int32_t)L0 - H0);
691 int16_t X2 = clampi16((int32_t)L0 - H0);
692
693 for (size_t j = 0; j < (nHighCount - 1); j++)
694 {
695 H1 = *pH;
696 pH += nHighStep;
697 L0 = *pL;
698 pL += nLowStep;
699 X2 = clampi16((int32_t)L0 - ((H0 + H1) / 2));
700 X1 = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
701 *pX = X0;
702 pX += nDstStep;
703 *pX = X1;
704 pX += nDstStep;
705 X0 = X2;
706 H0 = H1;
707 }
708
709 if (nLowCount <= (nHighCount + 1))
710 {
711 if (nLowCount <= nHighCount)
712 {
713 *pX = X2;
714 pX += nDstStep;
715 *pX = clampi16((int32_t)X2 + (2 * H0));
716 }
717 else
718 {
719 L0 = *pL;
720 X0 = clampi16((int32_t)L0 - H0);
721 *pX = X2;
722 pX += nDstStep;
723 *pX = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
724 pX += nDstStep;
725 *pX = X0;
726 }
727 }
728 else
729 {
730 L0 = *pL;
731 pL += nLowStep;
732 X0 = clampi16((int32_t)L0 - (H0 / 2));
733 *pX = X2;
734 pX += nDstStep;
735 *pX = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
736 pX += nDstStep;
737 *pX = X0;
738 pX += nDstStep;
739 L0 = *pL;
740 *pX = clampi16((int32_t)(X0 + L0) / 2);
741 }
742
743 pLowBand++;
744 pHighBand++;
745 pDstBand++;
746 }
747}
748
749static inline size_t progressive_rfx_get_band_l_count(size_t level)
750{
751 return (64 >> level) + 1;
752}
753
754static inline size_t progressive_rfx_get_band_h_count(size_t level)
755{
756 if (level == 1)
757 return (64 >> 1) - 1;
758 else
759 return (64 + (1u << (level - 1))) >> level;
760}
761
762static inline void progressive_rfx_dwt_2d_decode_block(INT16* WINPR_RESTRICT buffer,
763 INT16* WINPR_RESTRICT temp, size_t level)
764{
765 size_t nDstStepX = 0;
766 size_t nDstStepY = 0;
767 const INT16* WINPR_RESTRICT HL = nullptr;
768 const INT16* WINPR_RESTRICT LH = nullptr;
769 const INT16* WINPR_RESTRICT HH = nullptr;
770 INT16* WINPR_RESTRICT LL = nullptr;
771 INT16* WINPR_RESTRICT L = nullptr;
772 INT16* WINPR_RESTRICT H = nullptr;
773 INT16* WINPR_RESTRICT LLx = nullptr;
774
775 const size_t nBandL = progressive_rfx_get_band_l_count(level);
776 const size_t nBandH = progressive_rfx_get_band_h_count(level);
777 size_t offset = 0;
778
779 HL = &buffer[offset];
780 offset += (nBandH * nBandL);
781 LH = &buffer[offset];
782 offset += (nBandL * nBandH);
783 HH = &buffer[offset];
784 offset += (nBandH * nBandH);
785 LL = &buffer[offset];
786 nDstStepX = (nBandL + nBandH);
787 nDstStepY = (nBandL + nBandH);
788 offset = 0;
789 L = &temp[offset];
790 offset += (nBandL * nDstStepX);
791 H = &temp[offset];
792 LLx = &buffer[0];
793
794 /* horizontal (LL + HL -> L) */
795 progressive_rfx_idwt_x(LL, nBandL, HL, nBandH, L, nDstStepX, nBandL, nBandH, nBandL);
796
797 /* horizontal (LH + HH -> H) */
798 progressive_rfx_idwt_x(LH, nBandL, HH, nBandH, H, nDstStepX, nBandL, nBandH, nBandH);
799
800 /* vertical (L + H -> LL) */
801 progressive_rfx_idwt_y(L, nDstStepX, H, nDstStepX, LLx, nDstStepY, nBandL, nBandH,
802 nBandL + nBandH);
803}
804
805void rfx_dwt_2d_extrapolate_decode(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
806{
807 WINPR_ASSERT(buffer);
808 WINPR_ASSERT(dwt_buffer);
809 progressive_rfx_dwt_2d_decode_block(&buffer[3807], dwt_buffer, 3);
810 progressive_rfx_dwt_2d_decode_block(&buffer[3007], dwt_buffer, 2);
811 progressive_rfx_dwt_2d_decode_block(&buffer[0], dwt_buffer, 1);
812}
813
814static inline int progressive_rfx_dwt_2d_decode(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
815 INT16* WINPR_RESTRICT buffer,
816 INT16* WINPR_RESTRICT current, BOOL coeffDiff,
817 BOOL extrapolate, BOOL reverse)
818{
819 const primitives_t* prims = primitives_get();
820
821 if (!progressive || !buffer || !current)
822 return -1;
823
824 const uint32_t belements = 4096;
825 const uint32_t bsize = belements * sizeof(INT16);
826 if (reverse)
827 memcpy(buffer, current, bsize);
828 else if (!coeffDiff)
829 memcpy(current, buffer, bsize);
830 else
831 {
832 const pstatus_t rc = prims->add_16s_inplace(buffer, current, belements);
833 if (rc != PRIMITIVES_SUCCESS)
834 return -1;
835 }
836
837 INT16* temp = (INT16*)BufferPool_Take(progressive->bufferPool, -1); /* DWT buffer */
838
839 if (!temp)
840 return -2;
841
842 if (!extrapolate)
843 {
844 progressive->rfx_context->dwt_2d_decode(buffer, temp);
845 }
846 else
847 {
848 WINPR_ASSERT(progressive->rfx_context->dwt_2d_extrapolate_decode);
849 progressive->rfx_context->dwt_2d_extrapolate_decode(buffer, temp);
850 }
851 BufferPool_Return(progressive->bufferPool, temp);
852 return 1;
853}
854
855static inline BOOL progressive_rfx_decode_block(const primitives_t* prims,
856 INT16* WINPR_RESTRICT buffer, UINT32 length,
857 UINT32 shift)
858{
859 if (shift == 0)
860 return TRUE;
861
862 return prims->lShiftC_16s_inplace(buffer, shift, length) == PRIMITIVES_SUCCESS;
863}
864
865static inline int
866progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
867 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT shift,
868 const BYTE* WINPR_RESTRICT data, UINT32 length,
869 INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT current,
870 INT16* WINPR_RESTRICT sign, BOOL coeffDiff,
871 WINPR_ATTR_UNUSED BOOL subbandDiff, BOOL extrapolate)
872{
873 int status = 0;
874 const primitives_t* prims = primitives_get();
875
876 status = progressive->rfx_context->rlgr_decode(RLGR1, data, length, buffer, 4096);
877
878 if (status < 0)
879 return status;
880
881 CopyMemory(sign, buffer, 4096ULL * 2ULL);
882 if (!extrapolate)
883 {
884 if (!rfx_differential_decode(buffer + 4032, 64))
885 return -1;
886 if (!progressive_rfx_decode_block(prims, &buffer[0], 1024, shift->HL1)) /* HL1 */
887 return -1;
888 if (!progressive_rfx_decode_block(prims, &buffer[1024], 1024, shift->LH1)) /* LH1 */
889 return -1;
890 if (!progressive_rfx_decode_block(prims, &buffer[2048], 1024, shift->HH1)) /* HH1 */
891 return -1;
892 if (!progressive_rfx_decode_block(prims, &buffer[3072], 256, shift->HL2)) /* HL2 */
893 return -1;
894 if (!progressive_rfx_decode_block(prims, &buffer[3328], 256, shift->LH2)) /* LH2 */
895 return -1;
896 if (!progressive_rfx_decode_block(prims, &buffer[3584], 256, shift->HH2)) /* HH2 */
897 return -1;
898 if (!progressive_rfx_decode_block(prims, &buffer[3840], 64, shift->HL3)) /* HL3 */
899 return -1;
900 if (!progressive_rfx_decode_block(prims, &buffer[3904], 64, shift->LH3)) /* LH3 */
901 return -1;
902 if (!progressive_rfx_decode_block(prims, &buffer[3968], 64, shift->HH3)) /* HH3 */
903 return -1;
904 if (!progressive_rfx_decode_block(prims, &buffer[4032], 64, shift->LL3)) /* LL3 */
905 return -1;
906 }
907 else
908 {
909 if (!progressive_rfx_decode_block(prims, &buffer[0], 1023, shift->HL1)) /* HL1 */
910 return -1;
911 if (!progressive_rfx_decode_block(prims, &buffer[1023], 1023, shift->LH1)) /* LH1 */
912 return -1;
913 if (!progressive_rfx_decode_block(prims, &buffer[2046], 961, shift->HH1)) /* HH1 */
914 return -1;
915 if (!progressive_rfx_decode_block(prims, &buffer[3007], 272, shift->HL2)) /* HL2 */
916 return -1;
917 if (!progressive_rfx_decode_block(prims, &buffer[3279], 272, shift->LH2)) /* LH2 */
918 return -1;
919 if (!progressive_rfx_decode_block(prims, &buffer[3551], 256, shift->HH2)) /* HH2 */
920 return -1;
921 if (!progressive_rfx_decode_block(prims, &buffer[3807], 72, shift->HL3)) /* HL3 */
922 return -1;
923 if (!progressive_rfx_decode_block(prims, &buffer[3879], 72, shift->LH3)) /* LH3 */
924 return -1;
925 if (!progressive_rfx_decode_block(prims, &buffer[3951], 64, shift->HH3)) /* HH3 */
926 return -1;
927 if (!rfx_differential_decode(&buffer[4015], 81)) /* LL3 */
928 return -1;
929 if (!progressive_rfx_decode_block(prims, &buffer[4015], 81, shift->LL3)) /* LL3 */
930 return -1;
931 }
932 return progressive_rfx_dwt_2d_decode(progressive, buffer, current, coeffDiff, extrapolate,
933 FALSE);
934}
935
936static inline int
937progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
938 RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile,
939 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
940 const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
941{
942 int rc = 0;
943 BOOL diff = 0;
944 BOOL sub = 0;
945 BOOL extrapolate = 0;
946 BYTE* pBuffer = nullptr;
947 INT16* pSign[3];
948 INT16* pSrcDst[3];
949 INT16* pCurrent[3];
950 RFX_COMPONENT_CODEC_QUANT shiftY = WINPR_C_ARRAY_INIT;
951 RFX_COMPONENT_CODEC_QUANT shiftCb = WINPR_C_ARRAY_INIT;
952 RFX_COMPONENT_CODEC_QUANT shiftCr = WINPR_C_ARRAY_INIT;
953 RFX_COMPONENT_CODEC_QUANT* quantY = nullptr;
954 RFX_COMPONENT_CODEC_QUANT* quantCb = nullptr;
955 RFX_COMPONENT_CODEC_QUANT* quantCr = nullptr;
956 RFX_COMPONENT_CODEC_QUANT* quantProgY = nullptr;
957 RFX_COMPONENT_CODEC_QUANT* quantProgCb = nullptr;
958 RFX_COMPONENT_CODEC_QUANT* quantProgCr = nullptr;
959 RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal = nullptr;
960 static const prim_size_t roi_64x64 = { 64, 64 };
961 const primitives_t* prims = primitives_get();
962
963 tile->pass = 1;
964 diff = tile->flags & RFX_TILE_DIFFERENCE;
965 sub = context->flags & RFX_SUBBAND_DIFFING;
966 extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
967
968#if defined(WITH_DEBUG_CODECS)
969 WLog_Print(progressive->log, WLOG_DEBUG,
970 "ProgressiveTile%s: quantIdx Y: %" PRIu8 " Cb: %" PRIu8 " Cr: %" PRIu8
971 " xIdx: %" PRIu16 " yIdx: %" PRIu16 " flags: 0x%02" PRIX8 " quality: %" PRIu8
972 " yLen: %" PRIu16 " cbLen: %" PRIu16 " crLen: %" PRIu16 " tailLen: %" PRIu16 "",
973 (tile->blockType == PROGRESSIVE_WBT_TILE_FIRST) ? "First" : "Simple",
974 tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx,
975 tile->flags, tile->quality, tile->yLen, tile->cbLen, tile->crLen, tile->tailLen);
976#endif
977
978 if (tile->quantIdxY >= region->numQuant)
979 {
980 WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
981 return -1;
982 }
983
984 quantY = &(region->quantVals[tile->quantIdxY]);
985
986 if (tile->quantIdxCb >= region->numQuant)
987 {
988 WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
989 region->numQuant);
990 return -1;
991 }
992
993 quantCb = &(region->quantVals[tile->quantIdxCb]);
994
995 if (tile->quantIdxCr >= region->numQuant)
996 {
997 WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
998 region->numQuant);
999 return -1;
1000 }
1001
1002 quantCr = &(region->quantVals[tile->quantIdxCr]);
1003
1004 if (tile->quality == 0xFF)
1005 {
1006 quantProgVal = &(progressive->quantProgValFull);
1007 }
1008 else
1009 {
1010 if (tile->quality >= region->numProgQuant)
1011 {
1012 WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
1013 region->numProgQuant);
1014 return -1;
1015 }
1016
1017 quantProgVal = &(region->quantProgVals[tile->quality]);
1018 }
1019
1020 quantProgY = &(quantProgVal->yQuantValues);
1021 quantProgCb = &(quantProgVal->cbQuantValues);
1022 quantProgCr = &(quantProgVal->crQuantValues);
1023
1024 tile->yQuant = *quantY;
1025 tile->cbQuant = *quantCb;
1026 tile->crQuant = *quantCr;
1027 tile->yProgQuant = *quantProgY;
1028 tile->cbProgQuant = *quantProgCb;
1029 tile->crProgQuant = *quantProgCr;
1030
1031 progressive_rfx_quant_add(quantY, quantProgY, &(tile->yBitPos));
1032 progressive_rfx_quant_add(quantCb, quantProgCb, &(tile->cbBitPos));
1033 progressive_rfx_quant_add(quantCr, quantProgCr, &(tile->crBitPos));
1034 progressive_rfx_quant_add(quantY, quantProgY, &shiftY);
1035 if (!progressive_rfx_quant_lsub(&shiftY, 1)) /* -6 + 5 = -1 */
1036 goto fail;
1037 progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb);
1038 if (!progressive_rfx_quant_lsub(&shiftCb, 1)) /* -6 + 5 = -1 */
1039 goto fail;
1040 progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
1041 if (!progressive_rfx_quant_lsub(&shiftCr, 1)) /* -6 + 5 = -1 */
1042 goto fail;
1043
1044 pSign[0] =
1045 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1046 pSign[1] =
1047 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1048 pSign[2] =
1049 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1050
1051 pCurrent[0] =
1052 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1053 pCurrent[1] =
1054 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1055 pCurrent[2] =
1056 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1057
1058 pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
1059 pSrcDst[0] =
1060 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1061 pSrcDst[1] =
1062 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1063 pSrcDst[2] =
1064 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1065
1066 rc = progressive_rfx_decode_component(progressive, &shiftY, tile->yData, tile->yLen, pSrcDst[0],
1067 pCurrent[0], pSign[0], diff, sub, extrapolate); /* Y */
1068 if (rc < 0)
1069 goto fail;
1070 rc = progressive_rfx_decode_component(progressive, &shiftCb, tile->cbData, tile->cbLen,
1071 pSrcDst[1], pCurrent[1], pSign[1], diff, sub,
1072 extrapolate); /* Cb */
1073 if (rc < 0)
1074 goto fail;
1075 rc = progressive_rfx_decode_component(progressive, &shiftCr, tile->crData, tile->crLen,
1076 pSrcDst[2], pCurrent[2], pSign[2], diff, sub,
1077 extrapolate); /* Cr */
1078 if (rc < 0)
1079 goto fail;
1080
1081 {
1082 const INT16** ptr = WINPR_REINTERPRET_CAST(pSrcDst, INT16**, const INT16**);
1083 rc = prims->yCbCrToRGB_16s8u_P3AC4R(ptr, 64 * 2, tile->data, tile->stride,
1084 progressive->format, &roi_64x64);
1085 }
1086fail:
1087 BufferPool_Return(progressive->bufferPool, pBuffer);
1088 return rc;
1089}
1090
1091static inline INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state,
1092 UINT32 numBits)
1093{
1094 WINPR_ASSERT(state);
1095
1096 wBitStream* bs = state->srl;
1097 WINPR_ASSERT(bs);
1098
1099 if (state->nz)
1100 {
1101 state->nz--;
1102 return 0;
1103 }
1104
1105 const UINT32 k = state->kp / 8;
1106
1107 if (!state->mode)
1108 {
1109 /* zero encoding */
1110 const UINT32 bit = (bs->accumulator & 0x80000000) ? 1 : 0;
1111 BitStream_Shift(bs, 1);
1112
1113 if (!bit)
1114 {
1115 /* '0' bit, nz >= (1 << k), nz = (1 << k) */
1116 state->nz = (1 << k);
1117 state->kp += 4;
1118
1119 if (state->kp > 80)
1120 state->kp = 80;
1121
1122 state->nz--;
1123 return 0;
1124 }
1125 else
1126 {
1127 /* '1' bit, nz < (1 << k), nz = next k bits */
1128 state->nz = 0;
1129 state->mode = 1; /* unary encoding is next */
1130
1131 if (k)
1132 {
1133 bs->mask = ((1u << k) - 1);
1134 state->nz =
1135 WINPR_ASSERTING_INT_CAST(int16_t, ((bs->accumulator >> (32u - k)) & bs->mask));
1136 BitStream_Shift(bs, k);
1137 }
1138
1139 if (state->nz)
1140 {
1141 state->nz--;
1142 return 0;
1143 }
1144 }
1145 }
1146
1147 state->mode = 0; /* zero encoding is next */
1148 /* unary encoding */
1149 /* read sign bit */
1150 const UINT32 sign = (bs->accumulator & 0x80000000) ? 1 : 0;
1151 BitStream_Shift(bs, 1);
1152
1153 if (state->kp < 6)
1154 state->kp = 0;
1155 else
1156 state->kp -= 6;
1157
1158 if (numBits == 1)
1159 return sign ? -1 : 1;
1160
1161 UINT32 mag = 1;
1162 const UINT32 max = (1u << numBits) - 1;
1163
1164 while (mag < max)
1165 {
1166 /* Past its end the stream only yields '0' bits, the unary code would never terminate.
1167 * Compare position and length directly, earlier unchecked reads may already have moved
1168 * position past length and BitStream_GetRemainingLength would wrap. */
1169 if (bs->position >= bs->length)
1170 {
1171 mag = max;
1172 break;
1173 }
1174
1175 const UINT32 bit = (bs->accumulator & 0x80000000) ? 1 : 0;
1176 BitStream_Shift(bs, 1);
1177
1178 if (bit)
1179 break;
1180
1181 mag++;
1182 }
1183
1184 if (mag > INT16_MAX)
1185 mag = INT16_MAX;
1186 return (INT16)(sign ? -1 * (int)mag : (INT16)mag);
1187}
1188
1189static inline int
1190progressive_rfx_upgrade_state_finish(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state)
1191{
1192 UINT32 pad = 0;
1193 wBitStream* srl = nullptr;
1194 wBitStream* raw = nullptr;
1195 if (!state)
1196 return -1;
1197
1198 srl = state->srl;
1199 raw = state->raw;
1200 /* Read trailing bits from RAW/SRL bit streams */
1201 pad = (raw->position % 8) ? (8 - (raw->position % 8)) : 0;
1202
1203 if (pad)
1204 BitStream_Shift(raw, pad);
1205
1206 pad = (srl->position % 8) ? (8 - (srl->position % 8)) : 0;
1207
1208 if (pad)
1209 BitStream_Shift(srl, pad);
1210
1211 if (BitStream_GetRemainingLength(srl) == 8)
1212 BitStream_Shift(srl, 8);
1213
1214 return 1;
1215}
1216
1217static inline int16_t rawShift(wBitStream* raw, UINT32 numBits)
1218{
1219 WINPR_ASSERT(raw);
1220 WINPR_ASSERT(numBits > 0);
1221
1222 raw->mask = ((1u << numBits) - 1);
1223 const int16_t input = (int16_t)((raw->accumulator >> (32 - numBits)) & raw->mask);
1224 BitStream_Shift(raw, numBits);
1225 return input;
1226}
1227
1228static inline int progressive_rfx_upgrade_block(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state,
1229 INT16* WINPR_RESTRICT buffer,
1230 INT16* WINPR_RESTRICT sign, UINT32 length,
1231 UINT32 shift, WINPR_ATTR_UNUSED UINT32 bitPos,
1232 UINT32 numBits)
1233{
1234 if (numBits < 1)
1235 return 1;
1236
1237 wBitStream* raw = state->raw;
1238 int32_t input = 0;
1239
1240 if (!state->nonLL)
1241 {
1242 for (UINT32 index = 0; index < length; index++)
1243 {
1244 input = rawShift(raw, numBits);
1245
1246 const int32_t shifted = input << shift;
1247 const int32_t val = buffer[index] + shifted;
1248 const int16_t ival = WINPR_ASSERTING_INT_CAST(int16_t, val);
1249 buffer[index] = ival;
1250 }
1251
1252 return 1;
1253 }
1254
1255 for (UINT32 index = 0; index < length; index++)
1256 {
1257 if (sign[index] > 0)
1258 {
1259 /* sign > 0, read from raw */
1260 input = rawShift(raw, numBits);
1261 }
1262 else if (sign[index] < 0)
1263 {
1264 /* sign < 0, read from raw */
1265 input = rawShift(raw, numBits);
1266 input *= -1;
1267 }
1268 else
1269 {
1270 /* sign == 0, read from srl */
1271 input = progressive_rfx_srl_read(state, numBits);
1272 sign[index] = WINPR_ASSERTING_INT_CAST(int16_t, input);
1273 }
1274
1275 const int32_t val = input << shift;
1276 const int32_t ival = buffer[index] + val;
1277 buffer[index] = WINPR_ASSERTING_INT_CAST(INT16, ival);
1278 }
1279
1280 return 1;
1281}
1282
1283static inline int progressive_rfx_upgrade_component(
1284 PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1285 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT shift,
1286 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT bitPos,
1287 const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT numBits, INT16* WINPR_RESTRICT buffer,
1288 INT16* WINPR_RESTRICT current, INT16* WINPR_RESTRICT sign, const BYTE* WINPR_RESTRICT srlData,
1289 UINT32 srlLen, const BYTE* WINPR_RESTRICT rawData, UINT32 rawLen, BOOL coeffDiff,
1290 WINPR_ATTR_UNUSED BOOL subbandDiff, BOOL extrapolate)
1291{
1292 int rc = 0;
1293 wBitStream s_srl = WINPR_C_ARRAY_INIT;
1294 wBitStream s_raw = WINPR_C_ARRAY_INIT;
1295 RFX_PROGRESSIVE_UPGRADE_STATE state = WINPR_C_ARRAY_INIT;
1296
1297 state.kp = 8;
1298 state.mode = 0;
1299 state.srl = &s_srl;
1300 state.raw = &s_raw;
1301 BitStream_Attach(state.srl, srlData, srlLen);
1302 BitStream_Fetch(state.srl);
1303 BitStream_Attach(state.raw, rawData, rawLen);
1304 BitStream_Fetch(state.raw);
1305
1306 state.nonLL = TRUE;
1307 rc = progressive_rfx_upgrade_block(&state, &current[0], &sign[0], 1023, shift->HL1, bitPos->HL1,
1308 numBits->HL1); /* HL1 */
1309 if (rc < 0)
1310 return rc;
1311 rc = progressive_rfx_upgrade_block(&state, &current[1023], &sign[1023], 1023, shift->LH1,
1312 bitPos->LH1, numBits->LH1); /* LH1 */
1313 if (rc < 0)
1314 return rc;
1315 rc = progressive_rfx_upgrade_block(&state, &current[2046], &sign[2046], 961, shift->HH1,
1316 bitPos->HH1, numBits->HH1); /* HH1 */
1317 if (rc < 0)
1318 return rc;
1319 rc = progressive_rfx_upgrade_block(&state, &current[3007], &sign[3007], 272, shift->HL2,
1320 bitPos->HL2, numBits->HL2); /* HL2 */
1321 if (rc < 0)
1322 return rc;
1323 rc = progressive_rfx_upgrade_block(&state, &current[3279], &sign[3279], 272, shift->LH2,
1324 bitPos->LH2, numBits->LH2); /* LH2 */
1325 if (rc < 0)
1326 return rc;
1327 rc = progressive_rfx_upgrade_block(&state, &current[3551], &sign[3551], 256, shift->HH2,
1328 bitPos->HH2, numBits->HH2); /* HH2 */
1329 if (rc < 0)
1330 return rc;
1331 rc = progressive_rfx_upgrade_block(&state, &current[3807], &sign[3807], 72, shift->HL3,
1332 bitPos->HL3, numBits->HL3); /* HL3 */
1333 if (rc < 0)
1334 return rc;
1335 rc = progressive_rfx_upgrade_block(&state, &current[3879], &sign[3879], 72, shift->LH3,
1336 bitPos->LH3, numBits->LH3); /* LH3 */
1337 if (rc < 0)
1338 return rc;
1339 rc = progressive_rfx_upgrade_block(&state, &current[3951], &sign[3951], 64, shift->HH3,
1340 bitPos->HH3, numBits->HH3); /* HH3 */
1341 if (rc < 0)
1342 return rc;
1343
1344 state.nonLL = FALSE;
1345 rc = progressive_rfx_upgrade_block(&state, &current[4015], &sign[4015], 81, shift->LL3,
1346 bitPos->LL3, numBits->LL3); /* LL3 */
1347 if (rc < 0)
1348 return rc;
1349 rc = progressive_rfx_upgrade_state_finish(&state);
1350 if (rc < 0)
1351 return rc;
1352 return progressive_rfx_dwt_2d_decode(progressive, buffer, current, coeffDiff, extrapolate,
1353 TRUE);
1354}
1355
1356static inline int
1357progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1358 RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile,
1359 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
1360 const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
1361{
1362 int status = 0;
1363 BOOL coeffDiff = 0;
1364 BOOL sub = 0;
1365 BOOL extrapolate = 0;
1366 BYTE* pBuffer = nullptr;
1367 INT16* pSign[3] = WINPR_C_ARRAY_INIT;
1368 INT16* pSrcDst[3] = WINPR_C_ARRAY_INIT;
1369 INT16* pCurrent[3] = WINPR_C_ARRAY_INIT;
1370 RFX_COMPONENT_CODEC_QUANT shiftY = WINPR_C_ARRAY_INIT;
1371 RFX_COMPONENT_CODEC_QUANT shiftCb = WINPR_C_ARRAY_INIT;
1372 RFX_COMPONENT_CODEC_QUANT shiftCr = WINPR_C_ARRAY_INIT;
1373 RFX_COMPONENT_CODEC_QUANT yBitPos = WINPR_C_ARRAY_INIT;
1374 RFX_COMPONENT_CODEC_QUANT cbBitPos = WINPR_C_ARRAY_INIT;
1375 RFX_COMPONENT_CODEC_QUANT crBitPos = WINPR_C_ARRAY_INIT;
1376 RFX_COMPONENT_CODEC_QUANT yNumBits = WINPR_C_ARRAY_INIT;
1377 RFX_COMPONENT_CODEC_QUANT cbNumBits = WINPR_C_ARRAY_INIT;
1378 RFX_COMPONENT_CODEC_QUANT crNumBits = WINPR_C_ARRAY_INIT;
1379 RFX_COMPONENT_CODEC_QUANT* quantY = nullptr;
1380 RFX_COMPONENT_CODEC_QUANT* quantCb = nullptr;
1381 RFX_COMPONENT_CODEC_QUANT* quantCr = nullptr;
1382 RFX_COMPONENT_CODEC_QUANT* quantProgY = nullptr;
1383 RFX_COMPONENT_CODEC_QUANT* quantProgCb = nullptr;
1384 RFX_COMPONENT_CODEC_QUANT* quantProgCr = nullptr;
1385 RFX_PROGRESSIVE_CODEC_QUANT* quantProg = nullptr;
1386 static const prim_size_t roi_64x64 = { 64, 64 };
1387 const primitives_t* prims = primitives_get();
1388
1389 coeffDiff = tile->flags & RFX_TILE_DIFFERENCE;
1390 sub = context->flags & RFX_SUBBAND_DIFFING;
1391 extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
1392
1393 tile->pass++;
1394
1395#if defined(WITH_DEBUG_CODECS)
1396 WLog_Print(progressive->log, WLOG_DEBUG,
1397 "ProgressiveTileUpgrade: pass: %" PRIu16 " quantIdx Y: %" PRIu8 " Cb: %" PRIu8
1398 " Cr: %" PRIu8 " xIdx: %" PRIu16 " yIdx: %" PRIu16 " quality: %" PRIu8
1399 " ySrlLen: %" PRIu16 " yRawLen: %" PRIu16 " cbSrlLen: %" PRIu16 " cbRawLen: %" PRIu16
1400 " crSrlLen: %" PRIu16 " crRawLen: %" PRIu16 "",
1401 tile->pass, tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx,
1402 tile->yIdx, tile->quality, tile->ySrlLen, tile->yRawLen, tile->cbSrlLen,
1403 tile->cbRawLen, tile->crSrlLen, tile->crRawLen);
1404#endif
1405
1406 if (tile->quantIdxY >= region->numQuant)
1407 {
1408 WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
1409 return -1;
1410 }
1411
1412 quantY = &(region->quantVals[tile->quantIdxY]);
1413
1414 if (tile->quantIdxCb >= region->numQuant)
1415 {
1416 WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
1417 region->numQuant);
1418 return -1;
1419 }
1420
1421 quantCb = &(region->quantVals[tile->quantIdxCb]);
1422
1423 if (tile->quantIdxCr >= region->numQuant)
1424 {
1425 WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
1426 region->numQuant);
1427 return -1;
1428 }
1429
1430 quantCr = &(region->quantVals[tile->quantIdxCr]);
1431
1432 if (tile->quality == 0xFF)
1433 {
1434 quantProg = &(progressive->quantProgValFull);
1435 }
1436 else
1437 {
1438 if (tile->quality >= region->numProgQuant)
1439 {
1440 WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
1441 region->numProgQuant);
1442 return -1;
1443 }
1444
1445 quantProg = &(region->quantProgVals[tile->quality]);
1446 }
1447
1448 quantProgY = &(quantProg->yQuantValues);
1449 quantProgCb = &(quantProg->cbQuantValues);
1450 quantProgCr = &(quantProg->crQuantValues);
1451
1452 if (!progressive_rfx_quant_cmp_equal(quantY, &(tile->yQuant)))
1453 WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantY has changed!");
1454
1455 if (!progressive_rfx_quant_cmp_equal(quantCb, &(tile->cbQuant)))
1456 WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantCb has changed!");
1457
1458 if (!progressive_rfx_quant_cmp_equal(quantCr, &(tile->crQuant)))
1459 WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantCr has changed!");
1460
1461 if (!(context->flags & RFX_SUBBAND_DIFFING))
1462 WLog_WARN(TAG, "PROGRESSIVE_BLOCK_CONTEXT::flags & RFX_SUBBAND_DIFFING not set");
1463
1464 progressive_rfx_quant_add(quantY, quantProgY, &yBitPos);
1465 progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos);
1466 progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos);
1467 if (!progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits))
1468 goto fail;
1469 if (!progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits))
1470 goto fail;
1471 if (!progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits))
1472 goto fail;
1473 progressive_rfx_quant_add(quantY, quantProgY, &shiftY);
1474 if (!progressive_rfx_quant_lsub(&shiftY, 1)) /* -6 + 5 = -1 */
1475 goto fail;
1476 progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb);
1477 if (!progressive_rfx_quant_lsub(&shiftCb, 1)) /* -6 + 5 = -1 */
1478 goto fail;
1479 progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
1480 if (!progressive_rfx_quant_lsub(&shiftCr, 1)) /* -6 + 5 = -1 */
1481 goto fail;
1482
1483 tile->yBitPos = yBitPos;
1484 tile->cbBitPos = cbBitPos;
1485 tile->crBitPos = crBitPos;
1486 tile->yQuant = *quantY;
1487 tile->cbQuant = *quantCb;
1488 tile->crQuant = *quantCr;
1489 tile->yProgQuant = *quantProgY;
1490 tile->cbProgQuant = *quantProgCb;
1491 tile->crProgQuant = *quantProgCr;
1492
1493 pSign[0] =
1494 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1495 pSign[1] =
1496 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1497 pSign[2] =
1498 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1499
1500 pCurrent[0] =
1501 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1502 pCurrent[1] =
1503 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1504 pCurrent[2] =
1505 WINPR_PACKED_ALIGN_CAST(INT16*, (&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1506
1507 pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
1508 pSrcDst[0] =
1509 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
1510 pSrcDst[1] =
1511 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
1512 pSrcDst[2] =
1513 WINPR_PACKED_ALIGN_CAST(INT16*, (&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
1514
1515 status = progressive_rfx_upgrade_component(progressive, &shiftY, quantProgY, &yNumBits,
1516 pSrcDst[0], pCurrent[0], pSign[0], tile->ySrlData,
1517 tile->ySrlLen, tile->yRawData, tile->yRawLen,
1518 coeffDiff, sub, extrapolate); /* Y */
1519
1520 if (status < 0)
1521 goto fail;
1522
1523 status = progressive_rfx_upgrade_component(progressive, &shiftCb, quantProgCb, &cbNumBits,
1524 pSrcDst[1], pCurrent[1], pSign[1], tile->cbSrlData,
1525 tile->cbSrlLen, tile->cbRawData, tile->cbRawLen,
1526 coeffDiff, sub, extrapolate); /* Cb */
1527
1528 if (status < 0)
1529 goto fail;
1530
1531 status = progressive_rfx_upgrade_component(progressive, &shiftCr, quantProgCr, &crNumBits,
1532 pSrcDst[2], pCurrent[2], pSign[2], tile->crSrlData,
1533 tile->crSrlLen, tile->crRawData, tile->crRawLen,
1534 coeffDiff, sub, extrapolate); /* Cr */
1535
1536 if (status < 0)
1537 goto fail;
1538
1539 {
1540 const INT16** ptr = WINPR_REINTERPRET_CAST(pSrcDst, INT16**, const INT16**);
1541 status = prims->yCbCrToRGB_16s8u_P3AC4R(ptr, 64 * 2, tile->data, tile->stride,
1542 progressive->format, &roi_64x64);
1543 }
1544fail:
1545 BufferPool_Return(progressive->bufferPool, pBuffer);
1546 return status;
1547}
1548
1549static inline BOOL progressive_tile_read_upgrade(
1550 PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, wStream* WINPR_RESTRICT s, UINT16 blockType,
1551 UINT32 blockLen, PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
1552 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
1553 WINPR_ATTR_UNUSED const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
1554{
1555 RFX_PROGRESSIVE_TILE tile = WINPR_C_ARRAY_INIT;
1556 const size_t expect = 20;
1557
1558 if (!Stream_CheckAndLogRequiredLength(TAG, s, expect))
1559 return FALSE;
1560
1561 tile.blockType = blockType;
1562 tile.blockLen = blockLen;
1563 tile.flags = 0;
1564
1565 Stream_Read_UINT8(s, tile.quantIdxY);
1566 Stream_Read_UINT8(s, tile.quantIdxCb);
1567 Stream_Read_UINT8(s, tile.quantIdxCr);
1568 Stream_Read_UINT16(s, tile.xIdx);
1569 Stream_Read_UINT16(s, tile.yIdx);
1570 Stream_Read_UINT8(s, tile.quality);
1571 Stream_Read_UINT16(s, tile.ySrlLen);
1572 Stream_Read_UINT16(s, tile.yRawLen);
1573 Stream_Read_UINT16(s, tile.cbSrlLen);
1574 Stream_Read_UINT16(s, tile.cbRawLen);
1575 Stream_Read_UINT16(s, tile.crSrlLen);
1576 Stream_Read_UINT16(s, tile.crRawLen);
1577
1578 tile.ySrlData = Stream_Pointer(s);
1579 if (!Stream_SafeSeek(s, tile.ySrlLen))
1580 {
1581 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.ySrlLen);
1582 return FALSE;
1583 }
1584
1585 tile.yRawData = Stream_Pointer(s);
1586 if (!Stream_SafeSeek(s, tile.yRawLen))
1587 {
1588 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yRawLen);
1589 return FALSE;
1590 }
1591
1592 tile.cbSrlData = Stream_Pointer(s);
1593 if (!Stream_SafeSeek(s, tile.cbSrlLen))
1594 {
1595 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
1596 tile.cbSrlLen);
1597 return FALSE;
1598 }
1599
1600 tile.cbRawData = Stream_Pointer(s);
1601 if (!Stream_SafeSeek(s, tile.cbRawLen))
1602 {
1603 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
1604 tile.cbRawLen);
1605 return FALSE;
1606 }
1607
1608 tile.crSrlData = Stream_Pointer(s);
1609 if (!Stream_SafeSeek(s, tile.crSrlLen))
1610 {
1611 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
1612 tile.crSrlLen);
1613 return FALSE;
1614 }
1615
1616 tile.crRawData = Stream_Pointer(s);
1617 if (!Stream_SafeSeek(s, tile.crRawLen))
1618 {
1619 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
1620 tile.crRawLen);
1621 return FALSE;
1622 }
1623
1624 return progressive_surface_tile_replace(surface, region, &tile, TRUE);
1625}
1626
1627static inline BOOL
1628progressive_tile_read(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, BOOL simple,
1629 wStream* WINPR_RESTRICT s, UINT16 blockType, UINT32 blockLen,
1630 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
1631 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
1632 WINPR_ATTR_UNUSED const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
1633{
1634 RFX_PROGRESSIVE_TILE tile = WINPR_C_ARRAY_INIT;
1635 size_t expect = simple ? 16 : 17;
1636
1637 if (!Stream_CheckAndLogRequiredLength(TAG, s, expect))
1638 return FALSE;
1639
1640 tile.blockType = blockType;
1641 tile.blockLen = blockLen;
1642
1643 Stream_Read_UINT8(s, tile.quantIdxY);
1644 Stream_Read_UINT8(s, tile.quantIdxCb);
1645 Stream_Read_UINT8(s, tile.quantIdxCr);
1646 Stream_Read_UINT16(s, tile.xIdx);
1647 Stream_Read_UINT16(s, tile.yIdx);
1648 Stream_Read_UINT8(s, tile.flags);
1649
1650 if (!simple)
1651 Stream_Read_UINT8(s, tile.quality);
1652 else
1653 tile.quality = 0xFF;
1654 Stream_Read_UINT16(s, tile.yLen);
1655 Stream_Read_UINT16(s, tile.cbLen);
1656 Stream_Read_UINT16(s, tile.crLen);
1657 Stream_Read_UINT16(s, tile.tailLen);
1658
1659 tile.yData = Stream_Pointer(s);
1660 if (!Stream_SafeSeek(s, tile.yLen))
1661 {
1662 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yLen);
1663 return FALSE;
1664 }
1665
1666 tile.cbData = Stream_Pointer(s);
1667 if (!Stream_SafeSeek(s, tile.cbLen))
1668 {
1669 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.cbLen);
1670 return FALSE;
1671 }
1672
1673 tile.crData = Stream_Pointer(s);
1674 if (!Stream_SafeSeek(s, tile.crLen))
1675 {
1676 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.crLen);
1677 return FALSE;
1678 }
1679
1680 tile.tailData = Stream_Pointer(s);
1681 if (!Stream_SafeSeek(s, tile.tailLen))
1682 {
1683 WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.tailLen);
1684 return FALSE;
1685 }
1686
1687 return progressive_surface_tile_replace(surface, region, &tile, FALSE);
1688}
1689
1690static void CALLBACK progressive_process_tiles_tile_work_callback(PTP_CALLBACK_INSTANCE instance,
1691 void* context, PTP_WORK work)
1692{
1694
1695 WINPR_UNUSED(instance);
1696 WINPR_UNUSED(work);
1697
1698 switch (param->tile->blockType)
1699 {
1700 case PROGRESSIVE_WBT_TILE_SIMPLE:
1701 case PROGRESSIVE_WBT_TILE_FIRST:
1702 progressive_decompress_tile_first(param->progressive, param->tile, param->region,
1703 param->context);
1704 break;
1705
1706 case PROGRESSIVE_WBT_TILE_UPGRADE:
1707 progressive_decompress_tile_upgrade(param->progressive, param->tile, param->region,
1708 param->context);
1709 break;
1710 default:
1711 WLog_Print(param->progressive->log, WLOG_ERROR, "Invalid block type %04" PRIx16 " (%s)",
1712 param->tile->blockType,
1713 rfx_get_progressive_block_type_string(param->tile->blockType));
1714 break;
1715 }
1716}
1717
1718static inline SSIZE_T
1719progressive_process_tiles(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1720 wStream* WINPR_RESTRICT s,
1721 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
1722 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
1723 const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
1724{
1725 int status = 0;
1726 size_t end = 0;
1727 const size_t start = Stream_GetPosition(s);
1728 UINT16 blockType = 0;
1729 UINT32 blockLen = 0;
1730 UINT32 count = 0;
1731 UINT16 close_cnt = 0;
1732
1733 WINPR_ASSERT(progressive);
1734 WINPR_ASSERT(region);
1735
1736 if (!Stream_CheckAndLogRequiredLength(TAG, s, region->tileDataSize))
1737 return -1;
1738
1739 while ((Stream_GetRemainingLength(s) >= 6) &&
1740 (region->tileDataSize > (Stream_GetPosition(s) - start)))
1741 {
1742 const size_t pos = Stream_GetPosition(s);
1743
1744 Stream_Read_UINT16(s, blockType);
1745 Stream_Read_UINT32(s, blockLen);
1746
1747#if defined(WITH_DEBUG_CODECS)
1748 WLog_Print(progressive->log, WLOG_DEBUG, "%s",
1749 rfx_get_progressive_block_type_string(blockType));
1750#endif
1751
1752 if (blockLen < 6)
1753 {
1754 WLog_Print(progressive->log, WLOG_ERROR, "Expected >= %" PRIu32 " remaining %" PRIu32,
1755 6u, blockLen);
1756 return -1003;
1757 }
1758 if (!Stream_CheckAndLogRequiredLength(TAG, s, blockLen - 6))
1759 return -1003;
1760
1761 switch (blockType)
1762 {
1763 case PROGRESSIVE_WBT_TILE_SIMPLE:
1764 if (!progressive_tile_read(progressive, TRUE, s, blockType, blockLen, surface,
1765 region, context))
1766 return -1022;
1767 break;
1768
1769 case PROGRESSIVE_WBT_TILE_FIRST:
1770 if (!progressive_tile_read(progressive, FALSE, s, blockType, blockLen, surface,
1771 region, context))
1772 return -1027;
1773 break;
1774
1775 case PROGRESSIVE_WBT_TILE_UPGRADE:
1776 if (!progressive_tile_read_upgrade(progressive, s, blockType, blockLen, surface,
1777 region, context))
1778 return -1032;
1779 break;
1780 default:
1781 WLog_ERR(TAG, "Invalid block type %04" PRIx16 " (%s)", blockType,
1782 rfx_get_progressive_block_type_string(blockType));
1783 return -1039;
1784 }
1785
1786 size_t rem = Stream_GetPosition(s);
1787 if ((rem - pos) != blockLen)
1788 {
1789 WLog_Print(progressive->log, WLOG_ERROR,
1790 "Actual block read %" PRIuz " but expected %" PRIu32, rem - pos, blockLen);
1791 return -1040;
1792 }
1793 count++;
1794 }
1795
1796 end = Stream_GetPosition(s);
1797 if ((end - start) != region->tileDataSize)
1798 {
1799 WLog_Print(progressive->log, WLOG_ERROR,
1800 "Actual total blocks read %" PRIuz " but expected %" PRIu32, end - start,
1801 region->tileDataSize);
1802 return -1041;
1803 }
1804
1805 if (count != region->numTiles)
1806 {
1807 WLog_Print(progressive->log, WLOG_WARN,
1808 "numTiles inconsistency: actual: %" PRIu32 ", expected: %" PRIu16 "\n", count,
1809 region->numTiles);
1810 return -1044;
1811 }
1812
1813 for (UINT32 idx = 0; idx < region->numTiles; idx++)
1814 {
1815 RFX_PROGRESSIVE_TILE* tile = region->tiles[idx];
1816 PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = &progressive->params[idx];
1817 param->progressive = progressive;
1818 param->region = region;
1819 param->context = context;
1820 param->tile = tile;
1821
1822 if (progressive->rfx_context->priv->UseThreads)
1823 {
1824 progressive->work_objects[idx] = CreateThreadpoolWork(
1825 progressive_process_tiles_tile_work_callback, (void*)param, nullptr);
1826 if (!progressive->work_objects[idx])
1827 {
1828 WLog_Print(progressive->log, WLOG_ERROR,
1829 "Failed to create ThreadpoolWork for tile %" PRIu32, idx);
1830 status = -1;
1831 break;
1832 }
1833
1834 SubmitThreadpoolWork(progressive->work_objects[idx]);
1835
1836 close_cnt = WINPR_ASSERTING_INT_CAST(UINT16, idx + 1);
1837 }
1838 else
1839 {
1840 progressive_process_tiles_tile_work_callback(nullptr, param, nullptr);
1841 }
1842
1843 if (status < 0)
1844 {
1845 WLog_Print(progressive->log, WLOG_ERROR, "Failed to decompress %s at %" PRIu16,
1846 rfx_get_progressive_block_type_string(tile->blockType), idx);
1847 goto fail;
1848 }
1849 }
1850
1851 if (progressive->rfx_context->priv->UseThreads)
1852 {
1853 for (UINT32 idx = 0; idx < close_cnt; idx++)
1854 {
1855 WaitForThreadpoolWorkCallbacks(progressive->work_objects[idx], FALSE);
1856 CloseThreadpoolWork(progressive->work_objects[idx]);
1857 }
1858 }
1859
1860fail:
1861
1862 if (status < 0)
1863 return -1;
1864
1865 return (SSIZE_T)(end - start);
1866}
1867
1868static inline SSIZE_T progressive_wb_sync(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1869 wStream* WINPR_RESTRICT s, UINT16 blockType,
1870 UINT32 blockLen)
1871{
1872 const UINT32 magic = 0xCACCACCA;
1873 const UINT16 version = 0x0100;
1874 PROGRESSIVE_BLOCK_SYNC sync = WINPR_C_ARRAY_INIT;
1875
1876 sync.blockType = blockType;
1877 sync.blockLen = blockLen;
1878
1879 if (sync.blockLen != 12)
1880 {
1881 WLog_Print(progressive->log, WLOG_ERROR,
1882 "PROGRESSIVE_BLOCK_SYNC::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
1883 sync.blockLen, 12u);
1884 return -1005;
1885 }
1886
1887 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1888 return -1004;
1889
1890#if defined(WITH_DEBUG_CODECS)
1891 WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveSync");
1892#endif
1893
1894 Stream_Read_UINT32(s, sync.magic);
1895 Stream_Read_UINT16(s, sync.version);
1896
1897 if (sync.magic != magic)
1898 {
1899 WLog_Print(progressive->log, WLOG_ERROR,
1900 "PROGRESSIVE_BLOCK_SYNC::magic = 0x%08" PRIx32 " != 0x%08" PRIx32, sync.magic,
1901 magic);
1902 return -1005;
1903 }
1904
1905 if (sync.version != 0x0100)
1906 {
1907 WLog_Print(progressive->log, WLOG_ERROR,
1908 "PROGRESSIVE_BLOCK_SYNC::version = 0x%04" PRIx16 " != 0x%04" PRIu16,
1909 sync.version, version);
1910 return -1006;
1911 }
1912
1913 if ((progressive->state & FLAG_WBT_SYNC) != 0)
1914 WLog_WARN(TAG, "Duplicate PROGRESSIVE_BLOCK_SYNC, ignoring");
1915
1916 progressive->state |= FLAG_WBT_SYNC;
1917 return 0;
1918}
1919
1920static inline SSIZE_T progressive_wb_frame_begin(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1921 wStream* WINPR_RESTRICT s, UINT16 blockType,
1922 UINT32 blockLen)
1923{
1924 PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin = WINPR_C_ARRAY_INIT;
1925
1926 frameBegin.blockType = blockType;
1927 frameBegin.blockLen = blockLen;
1928
1929 if (frameBegin.blockLen != 12)
1930 {
1931 WLog_Print(progressive->log, WLOG_ERROR,
1932 " RFX_PROGRESSIVE_FRAME_BEGIN::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
1933 frameBegin.blockLen, 12u);
1934 return -1005;
1935 }
1936
1937 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1938 return -1007;
1939
1940 Stream_Read_UINT32(s, frameBegin.frameIndex);
1941 Stream_Read_UINT16(s, frameBegin.regionCount);
1942
1943#if defined(WITH_DEBUG_CODECS)
1944 WLog_Print(progressive->log, WLOG_DEBUG,
1945 "ProgressiveFrameBegin: frameIndex: %" PRIu32 " regionCount: %" PRIu16 "",
1946 frameBegin.frameIndex, frameBegin.regionCount);
1947#endif
1948
1955 if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
1956 {
1957 WLog_ERR(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_BEGIN in stream, this is not allowed!");
1958 return -1008;
1959 }
1960
1961 if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
1962 {
1963 WLog_ERR(TAG, "RFX_PROGRESSIVE_FRAME_BEGIN after RFX_PROGRESSIVE_FRAME_END in stream, this "
1964 "is not allowed!");
1965 return -1008;
1966 }
1967
1968 progressive->state |= FLAG_WBT_FRAME_BEGIN;
1969 return 0;
1970}
1971
1972static inline SSIZE_T progressive_wb_frame_end(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
1973 wStream* WINPR_RESTRICT s, UINT16 blockType,
1974 UINT32 blockLen)
1975{
1976 PROGRESSIVE_BLOCK_FRAME_END frameEnd = WINPR_C_ARRAY_INIT;
1977
1978 frameEnd.blockType = blockType;
1979 frameEnd.blockLen = blockLen;
1980
1981 if (frameEnd.blockLen != 6)
1982 {
1983 WLog_Print(progressive->log, WLOG_ERROR,
1984 " RFX_PROGRESSIVE_FRAME_END::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
1985 frameEnd.blockLen, 6u);
1986 return -1005;
1987 }
1988
1989 if (Stream_GetRemainingLength(s) != 0)
1990 {
1991 WLog_Print(progressive->log, WLOG_ERROR,
1992 "ProgressiveFrameEnd short %" PRIuz ", expected %u",
1993 Stream_GetRemainingLength(s), 0U);
1994 return -1008;
1995 }
1996
1997#if defined(WITH_DEBUG_CODECS)
1998 WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveFrameEnd");
1999#endif
2000
2001 if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
2002 WLog_WARN(TAG, "RFX_PROGRESSIVE_FRAME_END before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
2003 if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
2004 WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_END, ignoring");
2005
2006 progressive->state |= FLAG_WBT_FRAME_END;
2007 return 0;
2008}
2009
2010static inline SSIZE_T progressive_wb_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2011 wStream* WINPR_RESTRICT s, UINT16 blockType,
2012 UINT32 blockLen)
2013{
2014 PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
2015 context->blockType = blockType;
2016 context->blockLen = blockLen;
2017
2018 if (context->blockLen != 10)
2019 {
2020 WLog_Print(progressive->log, WLOG_ERROR,
2021 "RFX_PROGRESSIVE_CONTEXT::blockLen = 0x%08" PRIx32 " != 0x%08x",
2022 context->blockLen, 10u);
2023 return -1005;
2024 }
2025
2026 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2027 return -1009;
2028
2029 Stream_Read_UINT8(s, context->ctxId);
2030 Stream_Read_UINT16(s, context->tileSize);
2031 Stream_Read_UINT8(s, context->flags);
2032
2033 if (context->ctxId != 0x00)
2034 WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT::ctxId != 0x00: %" PRIu8, context->ctxId);
2035
2036 if (context->tileSize != 64)
2037 {
2038 WLog_ERR(TAG, "RFX_PROGRESSIVE_CONTEXT::tileSize != 0x40: %" PRIu16, context->tileSize);
2039 return -1010;
2040 }
2041
2042 if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
2043 WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_BEGIN");
2044 if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
2045 WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_END");
2046 if ((progressive->state & FLAG_WBT_CONTEXT) != 0)
2047 WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_CONTEXT received, ignoring.");
2048
2049#if defined(WITH_DEBUG_CODECS)
2050 WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveContext: flags: 0x%02" PRIX8 "",
2051 context->flags);
2052#endif
2053
2054 progressive->state |= FLAG_WBT_CONTEXT;
2055 return 0;
2056}
2057
2058static inline SSIZE_T
2059progressive_wb_read_region_header(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2060 wStream* WINPR_RESTRICT s, UINT16 blockType, UINT32 blockLen,
2061 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
2062{
2063 region->usedTiles = 0;
2064
2065 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
2066 return -1011;
2067
2068 region->blockType = blockType;
2069 region->blockLen = blockLen;
2070 Stream_Read_UINT8(s, region->tileSize);
2071 Stream_Read_UINT16(s, region->numRects);
2072 Stream_Read_UINT8(s, region->numQuant);
2073 Stream_Read_UINT8(s, region->numProgQuant);
2074 Stream_Read_UINT8(s, region->flags);
2075 Stream_Read_UINT16(s, region->numTiles);
2076 Stream_Read_UINT32(s, region->tileDataSize);
2077
2078 if (region->tileSize != 64)
2079 {
2080 WLog_Print(progressive->log, WLOG_ERROR,
2081 "ProgressiveRegion tile size %" PRIu8 ", expected %u", region->tileSize, 64U);
2082 return -1012;
2083 }
2084
2085 if (region->numRects < 1)
2086 {
2087 WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion missing rect count %" PRIu16,
2088 region->numRects);
2089 return -1013;
2090 }
2091
2092 if (region->numQuant > 7)
2093 {
2094 WLog_Print(progressive->log, WLOG_ERROR,
2095 "ProgressiveRegion quant count too high %" PRIu8 ", expected < %u",
2096 region->numQuant, 7U);
2097 return -1014;
2098 }
2099
2100 const SSIZE_T rc = WINPR_ASSERTING_INT_CAST(SSIZE_T, Stream_GetRemainingLength(s));
2101 const SSIZE_T expect = region->numRects * 8ll + region->numQuant * 5ll +
2102 region->numProgQuant * 16ll + region->tileDataSize;
2103 SSIZE_T len = rc;
2104 if (expect != rc)
2105 {
2106 if (len / 8LL < region->numRects)
2107 {
2108 WLog_Print(progressive->log, WLOG_ERROR,
2109 "ProgressiveRegion data short for region->rects");
2110 return -1015;
2111 }
2112 len -= region->numRects * 8LL;
2113
2114 if (len / 5LL < region->numQuant)
2115 {
2116 WLog_Print(progressive->log, WLOG_ERROR,
2117 "ProgressiveRegion data short for region->cQuant");
2118 return -1018;
2119 }
2120 len -= region->numQuant * 5LL;
2121
2122 if (len / 16LL < region->numProgQuant)
2123 {
2124 WLog_Print(progressive->log, WLOG_ERROR,
2125 "ProgressiveRegion data short for region->cProgQuant");
2126 return -1021;
2127 }
2128 len -= region->numProgQuant * 16LL;
2129
2130 if (len < region->tileDataSize * 1ll)
2131 {
2132 WLog_Print(progressive->log, WLOG_ERROR,
2133 "ProgressiveRegion data short for region->tiles");
2134 return -1024;
2135 }
2136 len -= region->tileDataSize;
2137
2138 if (len > 0)
2139 WLog_Print(progressive->log, WLOG_WARN,
2140 "Unused bytes detected, %" PRIdz " bytes not processed", len);
2141 }
2142
2143 return rc;
2144}
2145
2146static inline SSIZE_T progressive_wb_skip_region(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2147 wStream* WINPR_RESTRICT s, UINT16 blockType,
2148 UINT32 blockLen)
2149{
2150 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region = &progressive->region;
2151
2152 const SSIZE_T rc =
2153 progressive_wb_read_region_header(progressive, s, blockType, blockLen, region);
2154 if (rc < 0)
2155 return rc;
2156
2157 if (!Stream_SafeSeek(s, WINPR_ASSERTING_INT_CAST(size_t, rc)))
2158 return -1111;
2159
2160 return rc;
2161}
2162
2163static inline SSIZE_T progressive_wb_region(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2164 wStream* WINPR_RESTRICT s, UINT16 blockType,
2165 UINT32 blockLen,
2166 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
2167 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
2168{
2169 SSIZE_T rc = -1;
2170 UINT16 boxLeft = 0;
2171 UINT16 boxTop = 0;
2172 UINT16 boxRight = 0;
2173 UINT16 boxBottom = 0;
2174 UINT16 idxLeft = 0;
2175 UINT16 idxTop = 0;
2176 UINT16 idxRight = 0;
2177 UINT16 idxBottom = 0;
2178 const PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
2179
2180 if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
2181 {
2182 WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
2183 return progressive_wb_skip_region(progressive, s, blockType, blockLen);
2184 }
2185 if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
2186 {
2187 WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION after RFX_PROGRESSIVE_FRAME_END, ignoring");
2188 return progressive_wb_skip_region(progressive, s, blockType, blockLen);
2189 }
2190
2191 progressive->state |= FLAG_WBT_REGION;
2192
2193 rc = progressive_wb_read_region_header(progressive, s, blockType, blockLen, region);
2194 if (rc < 0)
2195 return rc;
2196
2197 for (UINT16 index = 0; index < region->numRects; index++)
2198 {
2199 RFX_RECT* rect = &(region->rects[index]);
2200 Stream_Read_UINT16(s, rect->x);
2201 Stream_Read_UINT16(s, rect->y);
2202 Stream_Read_UINT16(s, rect->width);
2203 Stream_Read_UINT16(s, rect->height);
2204 }
2205
2206 for (BYTE index = 0; index < region->numQuant; index++)
2207 {
2208 RFX_COMPONENT_CODEC_QUANT* quantVal = &(region->quantVals[index]);
2209 progressive_component_codec_quant_read(s, quantVal);
2210
2211 if (!progressive_rfx_quant_lcmp_greater_equal(quantVal, 6))
2212 {
2213 WLog_Print(progressive->log, WLOG_ERROR,
2214 "ProgressiveRegion region->cQuant[%" PRIu32 "] < 6", index);
2215 return -1;
2216 }
2217
2218 if (!progressive_rfx_quant_lcmp_less_equal(quantVal, 15))
2219 {
2220 WLog_Print(progressive->log, WLOG_ERROR,
2221 "ProgressiveRegion region->cQuant[%" PRIu32 "] > 15", index);
2222 return -1;
2223 }
2224 }
2225
2226 for (BYTE index = 0; index < region->numProgQuant; index++)
2227 {
2228 RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal = &(region->quantProgVals[index]);
2229
2230 Stream_Read_UINT8(s, quantProgVal->quality);
2231
2232 progressive_component_codec_quant_read(s, &(quantProgVal->yQuantValues));
2233 progressive_component_codec_quant_read(s, &(quantProgVal->cbQuantValues));
2234 progressive_component_codec_quant_read(s, &(quantProgVal->crQuantValues));
2235 }
2236
2237#if defined(WITH_DEBUG_CODECS)
2238 WLog_Print(progressive->log, WLOG_DEBUG,
2239 "ProgressiveRegion: numRects: %" PRIu16 " numTiles: %" PRIu16
2240 " tileDataSize: %" PRIu32 " flags: 0x%02" PRIX8 " numQuant: %" PRIu8
2241 " numProgQuant: %" PRIu8 "",
2242 region->numRects, region->numTiles, region->tileDataSize, region->flags,
2243 region->numQuant, region->numProgQuant);
2244#endif
2245
2246 boxLeft = WINPR_ASSERTING_INT_CAST(UINT16, surface->gridWidth);
2247 boxTop = WINPR_ASSERTING_INT_CAST(UINT16, surface->gridHeight);
2248 boxRight = 0;
2249 boxBottom = 0;
2250
2251 for (UINT16 index = 0; index < region->numRects; index++)
2252 {
2253 RFX_RECT* rect = &(region->rects[index]);
2254 idxLeft = rect->x / 64;
2255 idxTop = rect->y / 64;
2256 idxRight = (rect->x + rect->width + 63) / 64;
2257 idxBottom = (rect->y + rect->height + 63) / 64;
2258
2259 if (idxLeft < boxLeft)
2260 boxLeft = idxLeft;
2261
2262 if (idxTop < boxTop)
2263 boxTop = idxTop;
2264
2265 if (idxRight > boxRight)
2266 boxRight = idxRight;
2267
2268 if (idxBottom > boxBottom)
2269 boxBottom = idxBottom;
2270
2271#if defined(WITH_DEBUG_CODECS)
2272 WLog_Print(progressive->log, WLOG_DEBUG,
2273 "rect[%" PRIu16 "]: x: %" PRIu16 " y: %" PRIu16 " w: %" PRIu16 " h: %" PRIu16 "",
2274 index, rect->x, rect->y, rect->width, rect->height);
2275#endif
2276 }
2277
2278 const SSIZE_T res = progressive_process_tiles(progressive, s, region, surface, context);
2279 if (res < 0)
2280 return -1;
2281 return rc;
2282}
2283
2284static inline SSIZE_T progressive_parse_block(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2285 wStream* WINPR_RESTRICT s,
2286 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
2287 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
2288{
2289 UINT16 blockType = 0;
2290 UINT32 blockLen = 0;
2291 SSIZE_T rc = -1;
2292 wStream sub = WINPR_C_ARRAY_INIT;
2293
2294 WINPR_ASSERT(progressive);
2295
2296 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
2297 return -1;
2298
2299 Stream_Read_UINT16(s, blockType);
2300 Stream_Read_UINT32(s, blockLen);
2301
2302 if (blockLen < 6)
2303 {
2304 WLog_WARN(TAG, "Invalid blockLen %" PRIu32 ", expected >= 6", blockLen);
2305 return -1;
2306 }
2307 if (!Stream_CheckAndLogRequiredLength(TAG, s, blockLen - 6))
2308 return -1;
2309 Stream_StaticConstInit(&sub, Stream_Pointer(s), blockLen - 6);
2310 Stream_Seek(s, blockLen - 6);
2311
2312 switch (blockType)
2313 {
2314 case PROGRESSIVE_WBT_SYNC:
2315 rc = progressive_wb_sync(progressive, &sub, blockType, blockLen);
2316 break;
2317
2318 case PROGRESSIVE_WBT_FRAME_BEGIN:
2319 rc = progressive_wb_frame_begin(progressive, &sub, blockType, blockLen);
2320 break;
2321
2322 case PROGRESSIVE_WBT_FRAME_END:
2323 rc = progressive_wb_frame_end(progressive, &sub, blockType, blockLen);
2324 break;
2325
2326 case PROGRESSIVE_WBT_CONTEXT:
2327 rc = progressive_wb_context(progressive, &sub, blockType, blockLen);
2328 break;
2329
2330 case PROGRESSIVE_WBT_REGION:
2331 rc = progressive_wb_region(progressive, &sub, blockType, blockLen, surface, region);
2332 break;
2333
2334 default:
2335 WLog_Print(progressive->log, WLOG_ERROR, "Invalid block type %04" PRIx16, blockType);
2336 return -1;
2337 }
2338
2339 if (rc < 0)
2340 return -1;
2341
2342 if (Stream_GetRemainingLength(&sub) > 0)
2343 {
2344 WLog_Print(progressive->log, WLOG_ERROR,
2345 "block len %" PRIu32 " does not match read data %" PRIuz, blockLen,
2346 blockLen - Stream_GetRemainingLength(&sub));
2347 return -1;
2348 }
2349
2350 return rc;
2351}
2352
2353WINPR_ATTR_NODISCARD
2354static inline BOOL update_tiles(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2355 PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
2356 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep,
2357 UINT32 nXDst, UINT32 nYDst,
2358 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
2359 REGION16* WINPR_RESTRICT invalidRegion)
2360{
2361 BOOL rc = FALSE;
2362
2363 if ((nXDst > UINT16_MAX) || (nYDst > UINT16_MAX))
2364 return FALSE;
2365
2366 REGION16 clippingRects = WINPR_C_ARRAY_INIT;
2367 region16_init(&clippingRects);
2368 for (UINT32 i = 0; i < region->numRects; i++)
2369 {
2370 RECTANGLE_16 clippingRect = WINPR_C_ARRAY_INIT;
2371 const RFX_RECT* rect = &(region->rects[i]);
2372
2373 const UINT32 cx = nXDst + rect->x;
2374 const UINT32 cy = nYDst + rect->y;
2375 if ((cx > UINT16_MAX) || (cy > UINT16_MAX))
2376 goto fail;
2377
2378 clippingRect.left = (UINT16)cx;
2379 clippingRect.top = (UINT16)cy;
2380
2381 const UINT32 cr = 1u * clippingRect.left + rect->width;
2382 const UINT32 cb = 1u * clippingRect.top + rect->height;
2383 if ((cr > UINT16_MAX) || (cb > UINT16_MAX))
2384 goto fail;
2385
2386 clippingRect.right = (UINT16)cr;
2387 clippingRect.bottom = (UINT16)cb;
2388 if (!region16_union_rect(&clippingRects, &clippingRects, &clippingRect))
2389 goto fail;
2390 }
2391
2392 for (UINT32 i = 0; i < surface->numUpdatedTiles; i++)
2393 {
2394 UINT32 nbUpdateRects = 0;
2395 const RECTANGLE_16* updateRects = nullptr;
2396 RECTANGLE_16 updateRect = WINPR_C_ARRAY_INIT;
2397
2398 WINPR_ASSERT(surface->updatedTileIndices);
2399 const UINT32 index = surface->updatedTileIndices[i];
2400
2401 WINPR_ASSERT(index < surface->tilesSize);
2402 RFX_PROGRESSIVE_TILE* tile = surface->tiles[index];
2403 WINPR_ASSERT(tile);
2404
2405 const UINT32 dl = nXDst + tile->x;
2406 if (dl > UINT16_MAX - 64)
2407 goto fail;
2408 updateRect.left = WINPR_ASSERTING_INT_CAST(UINT16, dl);
2409
2410 const UINT32 dt = nYDst + tile->y;
2411 if (dt > UINT16_MAX - 64)
2412 goto fail;
2413 updateRect.top = WINPR_ASSERTING_INT_CAST(UINT16, dt);
2414 updateRect.right = updateRect.left + 64;
2415 updateRect.bottom = updateRect.top + 64;
2416
2417 REGION16 updateRegion = WINPR_C_ARRAY_INIT;
2418 region16_init(&updateRegion);
2419 BOOL success = FALSE;
2420 if (!region16_intersect_rect(&updateRegion, &clippingRects, &updateRect))
2421 goto loop_end;
2422
2423 updateRects = region16_rects(&updateRegion, &nbUpdateRects);
2424
2425 for (UINT32 j = 0; j < nbUpdateRects; j++)
2426 {
2427 const RECTANGLE_16* rect = &updateRects[j];
2428 if (rect->left < updateRect.left)
2429 goto loop_end;
2430 const UINT32 nXSrc = rect->left - updateRect.left;
2431 const UINT32 nYSrc = rect->top - updateRect.top;
2432 const UINT32 width = rect->right - rect->left;
2433 const UINT32 height = rect->bottom - rect->top;
2434
2435 if (rect->left + width > surface->width)
2436 goto loop_end;
2437 if (rect->top + height > surface->height)
2438 goto loop_end;
2439 const BOOL res = freerdp_image_copy_no_overlap(
2440 pDstData, DstFormat, nDstStep, rect->left, rect->top, width, height, tile->data,
2441 progressive->format, tile->stride, nXSrc, nYSrc, nullptr, FREERDP_KEEP_DST_ALPHA);
2442 if (!res)
2443 goto loop_end;
2444
2445 if (invalidRegion)
2446 {
2447 if (!region16_union_rect(invalidRegion, invalidRegion, rect))
2448 goto loop_end;
2449 }
2450 }
2451
2452 tile->dirty = FALSE;
2453 success = TRUE;
2454
2455 loop_end:
2456 region16_uninit(&updateRegion);
2457 if (!success)
2458 goto fail;
2459 }
2460
2461 rc = TRUE;
2462
2463fail:
2464 region16_uninit(&clippingRects);
2465 return rc;
2466}
2467
2468INT32 progressive_decompress(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2469 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
2470 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep,
2471 UINT32 nXDst, UINT32 nYDst, REGION16* WINPR_RESTRICT invalidRegion,
2472 UINT16 surfaceId, UINT32 frameId)
2473{
2474 INT32 rc = -1;
2475
2476 WINPR_ASSERT(progressive);
2477 PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
2478
2479 if (!surface)
2480 {
2481 WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion no surface for %" PRIu16,
2482 surfaceId);
2483 return -1001;
2484 }
2485
2486 PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region = &progressive->region;
2487 WINPR_ASSERT(region);
2488
2489 if (surface->frameId != frameId)
2490 {
2491 surface->frameId = frameId;
2492 surface->numUpdatedTiles = 0;
2493 }
2494
2495 wStream ss = WINPR_C_ARRAY_INIT;
2496 wStream* s = Stream_StaticConstInit(&ss, pSrcData, SrcSize);
2497 WINPR_ASSERT(s);
2498
2499 switch (DstFormat)
2500 {
2501 case PIXEL_FORMAT_RGBA32:
2502 case PIXEL_FORMAT_RGBX32:
2503 case PIXEL_FORMAT_BGRA32:
2504 case PIXEL_FORMAT_BGRX32:
2505 progressive->format = DstFormat;
2506 break;
2507 default:
2508 progressive->format = PIXEL_FORMAT_XRGB32;
2509 break;
2510 }
2511
2512 const size_t start = Stream_GetPosition(s);
2513 progressive->state = 0; /* Set state to not initialized */
2514 while (Stream_GetRemainingLength(s) > 0)
2515 {
2516 if (progressive_parse_block(progressive, s, surface, region) < 0)
2517 goto fail;
2518 }
2519
2520 {
2521 const size_t end = Stream_GetPosition(s);
2522 if ((end - start) != SrcSize)
2523 {
2524 WLog_Print(progressive->log, WLOG_ERROR,
2525 "total block len %" PRIuz " does not match read data %" PRIu32, end - start,
2526 SrcSize);
2527 rc = -1041;
2528 goto fail;
2529 }
2530 }
2531
2532 if (!update_tiles(progressive, surface, pDstData, DstFormat, nDstStep, nXDst, nYDst, region,
2533 invalidRegion))
2534 return -2002;
2535
2536 rc = 1;
2537fail:
2538 return rc;
2539}
2540
2541BOOL progressive_rfx_write_message_progressive_simple(
2542 PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, wStream* WINPR_RESTRICT s,
2543 const RFX_MESSAGE* WINPR_RESTRICT msg)
2544{
2545 RFX_CONTEXT* context = nullptr;
2546
2547 WINPR_ASSERT(progressive);
2548 WINPR_ASSERT(s);
2549 WINPR_ASSERT(msg);
2550 context = progressive->rfx_context;
2551 return rfx_write_message_progressive_simple(context, s, msg);
2552}
2553
2554int progressive_compress(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
2555 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 SrcFormat,
2556 UINT32 Width, UINT32 Height, UINT32 ScanLine,
2557 const REGION16* WINPR_RESTRICT invalidRegion,
2558 BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
2559{
2560 BOOL rc = FALSE;
2561 int res = -6;
2562 wStream* s = nullptr;
2563 UINT32 numRects = 0;
2564 RFX_RECT* rects = nullptr;
2565 RFX_MESSAGE* message = nullptr;
2566
2567 if (!progressive || !pSrcData || !ppDstData || !pDstSize)
2568 {
2569 return -1;
2570 }
2571
2572 if (ScanLine == 0)
2573 {
2574 switch (SrcFormat)
2575 {
2576 case PIXEL_FORMAT_ABGR32:
2577 case PIXEL_FORMAT_ARGB32:
2578 case PIXEL_FORMAT_XBGR32:
2579 case PIXEL_FORMAT_XRGB32:
2580 case PIXEL_FORMAT_BGRA32:
2581 case PIXEL_FORMAT_BGRX32:
2582 case PIXEL_FORMAT_RGBA32:
2583 case PIXEL_FORMAT_RGBX32:
2584 ScanLine = Width * 4;
2585 break;
2586 default:
2587 return -2;
2588 }
2589 }
2590
2591 if (SrcSize < Height * ScanLine)
2592 return -4;
2593
2594 if (!invalidRegion)
2595 {
2596 numRects = (Width + 63) / 64;
2597 numRects *= (Height + 63) / 64;
2598 }
2599 else
2600 {
2601 const int nr = region16_n_rects(invalidRegion);
2602 numRects = WINPR_ASSERTING_INT_CAST(uint32_t, nr);
2603 }
2604
2605 if (numRects == 0)
2606 return 0;
2607
2608 if (!Stream_EnsureRemainingCapacity(progressive->rects, numRects * sizeof(RFX_RECT)))
2609 return -5;
2610 rects = Stream_BufferAs(progressive->rects, RFX_RECT);
2611 if (invalidRegion)
2612 {
2613 const RECTANGLE_16* region_rects = region16_rects(invalidRegion, nullptr);
2614 for (UINT32 idx = 0; idx < numRects; idx++)
2615 {
2616 const RECTANGLE_16* r = &region_rects[idx];
2617 RFX_RECT* rect = &rects[idx];
2618
2619 rect->x = r->left;
2620 rect->y = r->top;
2621 rect->width = r->right - r->left;
2622 rect->height = r->bottom - r->top;
2623 }
2624 }
2625 else
2626 {
2627 UINT16 x = 0;
2628 UINT16 y = 0;
2629
2630 for (UINT32 i = 0; i < numRects; i++)
2631 {
2632 RFX_RECT* r = &rects[i];
2633 r->x = x;
2634 r->y = y;
2635
2636 WINPR_ASSERT(Width >= x);
2637 WINPR_ASSERT(Height >= y);
2638 r->width = MIN(64, WINPR_ASSERTING_INT_CAST(UINT16, Width - x));
2639 r->height = MIN(64, WINPR_ASSERTING_INT_CAST(UINT16, Height - y));
2640
2641 if (x + 64UL >= Width)
2642 {
2643 y += 64;
2644 x = 0;
2645 }
2646 else
2647 x += 64;
2648
2649 WINPR_ASSERT(r->x % 64 == 0);
2650 WINPR_ASSERT(r->y % 64 == 0);
2651 WINPR_ASSERT(r->width <= 64);
2652 WINPR_ASSERT(r->height <= 64);
2653 }
2654 }
2655 s = progressive->buffer;
2656 Stream_ResetPosition(s);
2657
2658 progressive->rfx_context->mode = RLGR1;
2659
2660 progressive->rfx_context->width = WINPR_ASSERTING_INT_CAST(UINT16, Width);
2661 progressive->rfx_context->height = WINPR_ASSERTING_INT_CAST(UINT16, Height);
2662 rfx_context_set_pixel_format(progressive->rfx_context, SrcFormat);
2663 message = rfx_encode_message(progressive->rfx_context, rects, numRects, pSrcData, Width, Height,
2664 ScanLine);
2665 if (!message)
2666 {
2667 WLog_ERR(TAG, "failed to encode rfx message");
2668 goto fail;
2669 }
2670
2671 rc = progressive_rfx_write_message_progressive_simple(progressive, s, message);
2672 rfx_message_free(progressive->rfx_context, message);
2673 if (!rc)
2674 goto fail;
2675
2676 {
2677 const size_t pos = Stream_GetPosition(s);
2678 WINPR_ASSERT(pos <= UINT32_MAX);
2679 *pDstSize = (UINT32)pos;
2680 }
2681 *ppDstData = Stream_Buffer(s);
2682 res = 1;
2683fail:
2684 return res;
2685}
2686
2687BOOL progressive_context_reset(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive)
2688{
2689 return (progressive != nullptr);
2690}
2691
2692PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor)
2693{
2694 return progressive_context_new_ex(Compressor, 0);
2695}
2696
2697PROGRESSIVE_CONTEXT* progressive_context_new_ex(BOOL Compressor, UINT32 ThreadingFlags)
2698{
2699 PROGRESSIVE_CONTEXT* progressive =
2700 (PROGRESSIVE_CONTEXT*)winpr_aligned_calloc(1, sizeof(PROGRESSIVE_CONTEXT), 32);
2701
2702 if (!progressive)
2703 return nullptr;
2704
2705 progressive->Compressor = Compressor;
2706 progressive->quantProgValFull.quality = 100;
2707 progressive->log = WLog_Get(TAG);
2708 if (!progressive->log)
2709 goto fail;
2710 progressive->rfx_context = rfx_context_new_ex(Compressor, ThreadingFlags);
2711 if (!progressive->rfx_context)
2712 goto fail;
2713 progressive->buffer = Stream_New(nullptr, 1024);
2714 if (!progressive->buffer)
2715 goto fail;
2716 progressive->rects = Stream_New(nullptr, 1024);
2717 if (!progressive->rects)
2718 goto fail;
2719 progressive->bufferPool = BufferPool_New(TRUE, (8192LL + 32LL) * 3LL, 16);
2720 if (!progressive->bufferPool)
2721 goto fail;
2722 progressive->SurfaceContexts = HashTable_New(TRUE);
2723 if (!progressive->SurfaceContexts)
2724 goto fail;
2725
2726 {
2727 wObject* obj = HashTable_ValueObject(progressive->SurfaceContexts);
2728 WINPR_ASSERT(obj);
2729 obj->fnObjectFree = progressive_surface_context_free;
2730 }
2731 return progressive;
2732fail:
2733 WINPR_PRAGMA_DIAG_PUSH
2734 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2735 progressive_context_free(progressive);
2736 WINPR_PRAGMA_DIAG_POP
2737 return nullptr;
2738}
2739
2740void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
2741{
2742 if (!progressive)
2743 return;
2744
2745 Stream_Free(progressive->buffer, TRUE);
2746 Stream_Free(progressive->rects, TRUE);
2747 rfx_context_free(progressive->rfx_context);
2748
2749 BufferPool_Free(progressive->bufferPool);
2750 HashTable_Free(progressive->SurfaceContexts);
2751
2752 winpr_aligned_free(progressive);
2753}
Definition rfx.h:44
WINPR_ATTR_NODISCARD fn_lShiftC_16s_inplace_t lShiftC_16s_inplace
Definition primitives.h:303
WINPR_ATTR_NODISCARD fn_add_16s_inplace_t add_16s_inplace
Do vecotor addition, store result in both input buffers pSrcDst1 = pSrcDst2 = pSrcDst1 + pSrcDst2.
Definition primitives.h:302
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:59