Coverage Report

Created: 2023-09-25 06:56

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