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