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