Coverage Report

Created: 2024-09-08 06:18

/src/FreeRDP/libfreerdp/codec/planar.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RDP6 Planar Codec
4
 *
5
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2016 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/crt.h>
25
#include <winpr/wtypes.h>
26
#include <winpr/assert.h>
27
#include <winpr/print.h>
28
29
#include <freerdp/primitives.h>
30
#include <freerdp/log.h>
31
#include <freerdp/codec/bitmap.h>
32
#include <freerdp/codec/planar.h>
33
34
#define TAG FREERDP_TAG("codec")
35
36
#define PLANAR_ALIGN(val, align) \
37
10.8k
  ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align))
38
39
typedef struct
40
{
41
  /**
42
   * controlByte:
43
   * [0-3]: nRunLength
44
   * [4-7]: cRawBytes
45
   */
46
  BYTE controlByte;
47
  BYTE* rawValues;
48
} RDP6_RLE_SEGMENT;
49
50
typedef struct
51
{
52
  UINT32 cSegments;
53
  RDP6_RLE_SEGMENT* segments;
54
} RDP6_RLE_SEGMENTS;
55
56
typedef struct
57
{
58
  /**
59
   * formatHeader:
60
   * [0-2]: Color Loss Level (CLL)
61
   *  [3] : Chroma Subsampling (CS)
62
   *  [4] : Run Length Encoding (RLE)
63
   *  [5] : No Alpha (NA)
64
   * [6-7]: Reserved
65
   */
66
  BYTE formatHeader;
67
} RDP6_BITMAP_STREAM;
68
69
struct S_BITMAP_PLANAR_CONTEXT
70
{
71
  UINT32 maxWidth;
72
  UINT32 maxHeight;
73
  UINT32 maxPlaneSize;
74
75
  BOOL AllowSkipAlpha;
76
  BOOL AllowRunLengthEncoding;
77
  BOOL AllowColorSubsampling;
78
  BOOL AllowDynamicColorFidelity;
79
80
  UINT32 ColorLossLevel;
81
82
  BYTE* planes[4];
83
  BYTE* planesBuffer;
84
85
  BYTE* deltaPlanes[4];
86
  BYTE* deltaPlanesBuffer;
87
88
  BYTE* rlePlanes[4];
89
  BYTE* rlePlanesBuffer;
90
91
  BYTE* pTempData;
92
  UINT32 nTempStep;
93
94
  BOOL bgr;
95
  BOOL topdown;
96
};
97
98
static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL alpha,
99
                                          UINT32 DstFormat)
100
11.5k
{
101
102
11.5k
  if (planar->bgr && alpha)
103
0
  {
104
0
    switch (DstFormat)
105
0
    {
106
0
      case PIXEL_FORMAT_ARGB32:
107
0
        DstFormat = PIXEL_FORMAT_ABGR32;
108
0
        break;
109
0
      case PIXEL_FORMAT_XRGB32:
110
0
        DstFormat = PIXEL_FORMAT_XBGR32;
111
0
        break;
112
0
      case PIXEL_FORMAT_ABGR32:
113
0
        DstFormat = PIXEL_FORMAT_ARGB32;
114
0
        break;
115
0
      case PIXEL_FORMAT_XBGR32:
116
0
        DstFormat = PIXEL_FORMAT_XRGB32;
117
0
        break;
118
0
      case PIXEL_FORMAT_BGRA32:
119
0
        DstFormat = PIXEL_FORMAT_RGBA32;
120
0
        break;
121
0
      case PIXEL_FORMAT_BGRX32:
122
0
        DstFormat = PIXEL_FORMAT_RGBX32;
123
0
        break;
124
0
      case PIXEL_FORMAT_RGBA32:
125
0
        DstFormat = PIXEL_FORMAT_BGRA32;
126
0
        break;
127
0
      case PIXEL_FORMAT_RGBX32:
128
0
        DstFormat = PIXEL_FORMAT_BGRX32;
129
0
        break;
130
0
      case PIXEL_FORMAT_RGB24:
131
0
        DstFormat = PIXEL_FORMAT_BGR24;
132
0
        break;
133
0
      case PIXEL_FORMAT_BGR24:
134
0
        DstFormat = PIXEL_FORMAT_RGB24;
135
0
        break;
136
0
      case PIXEL_FORMAT_RGB16:
137
0
        DstFormat = PIXEL_FORMAT_BGR16;
138
0
        break;
139
0
      case PIXEL_FORMAT_BGR16:
140
0
        DstFormat = PIXEL_FORMAT_RGB16;
141
0
        break;
142
0
      case PIXEL_FORMAT_ARGB15:
143
0
        DstFormat = PIXEL_FORMAT_ABGR15;
144
0
        break;
145
0
      case PIXEL_FORMAT_RGB15:
146
0
        DstFormat = PIXEL_FORMAT_BGR15;
147
0
        break;
148
0
      case PIXEL_FORMAT_ABGR15:
149
0
        DstFormat = PIXEL_FORMAT_ARGB15;
150
0
        break;
151
0
      case PIXEL_FORMAT_BGR15:
152
0
        DstFormat = PIXEL_FORMAT_RGB15;
153
0
        break;
154
0
      default:
155
0
        break;
156
0
    }
157
0
  }
158
11.5k
  return DstFormat;
159
11.5k
}
160
161
static INLINE BOOL freerdp_bitmap_planar_compress_plane_rle(const BYTE* WINPR_RESTRICT plane,
162
                                                            UINT32 width, UINT32 height,
163
                                                            BYTE* outPlane,
164
                                                            UINT32* WINPR_RESTRICT dstSize);
165
static INLINE BYTE* freerdp_bitmap_planar_delta_encode_plane(const BYTE* WINPR_RESTRICT inPlane,
166
                                                             UINT32 width, UINT32 height,
167
                                                             BYTE* WINPR_RESTRICT outPlane);
168
169
static INLINE INT32 planar_skip_plane_rle(const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
170
                                          UINT32 nWidth, UINT32 nHeight)
171
3.27k
{
172
3.27k
  UINT32 used = 0;
173
3.27k
  BYTE controlByte = 0;
174
175
3.27k
  WINPR_ASSERT(pSrcData);
176
177
50.4k
  for (UINT32 y = 0; y < nHeight; y++)
178
49.3k
  {
179
13.9M
    for (UINT32 x = 0; x < nWidth;)
180
13.9M
    {
181
13.9M
      int cRawBytes = 0;
182
13.9M
      int nRunLength = 0;
183
184
13.9M
      if (used >= SrcSize)
185
428
      {
186
428
        WLog_ERR(TAG, "planar plane used %" PRIu32 " exceeds SrcSize %" PRIu32, used,
187
428
                 SrcSize);
188
428
        return -1;
189
428
      }
190
191
13.9M
      controlByte = pSrcData[used++];
192
13.9M
      nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
193
13.9M
      cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
194
195
13.9M
      if (nRunLength == 1)
196
16.9k
      {
197
16.9k
        nRunLength = cRawBytes + 16;
198
16.9k
        cRawBytes = 0;
199
16.9k
      }
200
13.9M
      else if (nRunLength == 2)
201
37.6k
      {
202
37.6k
        nRunLength = cRawBytes + 32;
203
37.6k
        cRawBytes = 0;
204
37.6k
      }
205
206
13.9M
      used += cRawBytes;
207
13.9M
      x += cRawBytes;
208
13.9M
      x += nRunLength;
209
210
13.9M
      if (x > nWidth)
211
995
      {
212
995
        WLog_ERR(TAG, "planar plane x %" PRIu32 " exceeds width %" PRIu32, x, nWidth);
213
995
        return -1;
214
995
      }
215
216
13.9M
      if (used > SrcSize)
217
718
      {
218
718
        WLog_ERR(TAG, "planar plane used %" PRIu32 " exceeds SrcSize %" PRIu32, used,
219
718
                 INT32_MAX);
220
718
        return -1;
221
718
      }
222
13.9M
    }
223
49.3k
  }
224
225
1.12k
  if (used > INT32_MAX)
226
0
  {
227
0
    WLog_ERR(TAG, "planar plane used %" PRIu32 " exceeds SrcSize %" PRIu32, used, SrcSize);
228
0
    return -1;
229
0
  }
230
1.12k
  return (INT32)used;
231
1.12k
}
232
233
static INLINE INT32 planar_decompress_plane_rle_only(const BYTE* WINPR_RESTRICT pSrcData,
234
                                                     UINT32 SrcSize, BYTE* WINPR_RESTRICT pDstData,
235
                                                     UINT32 nWidth, UINT32 nHeight)
236
540
{
237
540
  UINT32 pixel = 0;
238
540
  UINT32 cRawBytes = 0;
239
540
  UINT32 nRunLength = 0;
240
540
  INT32 deltaValue = 0;
241
540
  BYTE controlByte = 0;
242
540
  BYTE* currentScanline = NULL;
243
540
  BYTE* previousScanline = NULL;
244
540
  const BYTE* srcp = pSrcData;
245
246
540
  WINPR_ASSERT(nHeight <= INT32_MAX);
247
540
  WINPR_ASSERT(nWidth <= INT32_MAX);
248
249
540
  previousScanline = NULL;
250
251
14.0k
  for (INT32 y = 0; y < (INT32)nHeight; y++)
252
13.5k
  {
253
13.5k
    BYTE* dstp = &pDstData[(1ULL * (y) * (INT32)nWidth)];
254
13.5k
    pixel = 0;
255
13.5k
    currentScanline = dstp;
256
257
67.4k
    for (INT32 x = 0; x < (INT32)nWidth;)
258
53.9k
    {
259
53.9k
      controlByte = *srcp;
260
53.9k
      srcp++;
261
262
53.9k
      if ((srcp - pSrcData) > SrcSize * 1ll)
263
0
      {
264
0
        WLog_ERR(TAG, "error reading input buffer");
265
0
        return -1;
266
0
      }
267
268
53.9k
      nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
269
53.9k
      cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
270
271
53.9k
      if (nRunLength == 1)
272
5.76k
      {
273
5.76k
        nRunLength = cRawBytes + 16;
274
5.76k
        cRawBytes = 0;
275
5.76k
      }
276
48.2k
      else if (nRunLength == 2)
277
6.93k
      {
278
6.93k
        nRunLength = cRawBytes + 32;
279
6.93k
        cRawBytes = 0;
280
6.93k
      }
281
282
53.9k
      if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 1ll)
283
0
      {
284
0
        WLog_ERR(TAG, "too many pixels in scanline");
285
0
        return -1;
286
0
      }
287
288
53.9k
      if (!previousScanline)
289
1.99k
      {
290
        /* first scanline, absolute values */
291
3.41k
        while (cRawBytes > 0)
292
1.41k
        {
293
1.41k
          pixel = *srcp;
294
1.41k
          srcp++;
295
1.41k
          *dstp = pixel;
296
1.41k
          dstp++;
297
1.41k
          x++;
298
1.41k
          cRawBytes--;
299
1.41k
        }
300
301
14.0k
        while (nRunLength > 0)
302
12.0k
        {
303
12.0k
          *dstp = pixel;
304
12.0k
          dstp++;
305
12.0k
          x++;
306
12.0k
          nRunLength--;
307
12.0k
        }
308
1.99k
      }
309
51.9k
      else
310
51.9k
      {
311
        /* delta values relative to previous scanline */
312
94.4k
        while (cRawBytes > 0)
313
42.4k
        {
314
42.4k
          deltaValue = *srcp;
315
42.4k
          srcp++;
316
317
42.4k
          if (deltaValue & 1)
318
1.60k
          {
319
1.60k
            deltaValue = deltaValue >> 1;
320
1.60k
            deltaValue = deltaValue + 1;
321
1.60k
            pixel = -deltaValue;
322
1.60k
          }
323
40.8k
          else
324
40.8k
          {
325
40.8k
            deltaValue = deltaValue >> 1;
326
40.8k
            pixel = deltaValue;
327
40.8k
          }
328
329
42.4k
          deltaValue = previousScanline[x] + pixel;
330
42.4k
          *dstp = deltaValue;
331
42.4k
          dstp++;
332
42.4k
          x++;
333
42.4k
          cRawBytes--;
334
42.4k
        }
335
336
392k
        while (nRunLength > 0)
337
340k
        {
338
340k
          deltaValue = previousScanline[x] + pixel;
339
340k
          *dstp = deltaValue;
340
340k
          dstp++;
341
340k
          x++;
342
340k
          nRunLength--;
343
340k
        }
344
51.9k
      }
345
53.9k
    }
346
347
13.5k
    previousScanline = currentScanline;
348
13.5k
  }
349
350
540
  return (INT32)(srcp - pSrcData);
351
540
}
352
353
static INLINE INT32 planar_decompress_plane_rle(const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
354
                                                BYTE* WINPR_RESTRICT pDstData, INT32 nDstStep,
355
                                                UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
356
                                                UINT32 nHeight, UINT32 nChannel, BOOL vFlip)
357
477
{
358
477
  UINT32 pixel = 0;
359
477
  UINT32 cRawBytes = 0;
360
477
  UINT32 nRunLength = 0;
361
477
  INT32 deltaValue = 0;
362
477
  INT32 beg = 0;
363
477
  INT32 end = 0;
364
477
  INT32 inc = 0;
365
477
  BYTE controlByte = 0;
366
477
  BYTE* currentScanline = NULL;
367
477
  BYTE* previousScanline = NULL;
368
477
  const BYTE* srcp = pSrcData;
369
370
477
  WINPR_ASSERT(nHeight <= INT32_MAX);
371
477
  WINPR_ASSERT(nWidth <= INT32_MAX);
372
477
  WINPR_ASSERT(nDstStep <= INT32_MAX);
373
374
477
  previousScanline = NULL;
375
376
477
  if (vFlip)
377
0
  {
378
0
    beg = (INT32)nHeight - 1;
379
0
    end = -1;
380
0
    inc = -1;
381
0
  }
382
477
  else
383
477
  {
384
477
    beg = 0;
385
477
    end = (INT32)nHeight;
386
477
    inc = 1;
387
477
  }
388
389
17.4k
  for (INT32 y = beg; y != end; y += inc)
390
16.9k
  {
391
16.9k
    BYTE* dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel];
392
16.9k
    pixel = 0;
393
16.9k
    currentScanline = dstp;
394
395
5.79M
    for (INT32 x = 0; x < (INT32)nWidth;)
396
5.78M
    {
397
5.78M
      controlByte = *srcp;
398
5.78M
      srcp++;
399
400
5.78M
      if ((srcp - pSrcData) > SrcSize * 1ll)
401
0
      {
402
0
        WLog_ERR(TAG, "error reading input buffer");
403
0
        return -1;
404
0
      }
405
406
5.78M
      nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
407
5.78M
      cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
408
409
5.78M
      if (nRunLength == 1)
410
2.03k
      {
411
2.03k
        nRunLength = cRawBytes + 16;
412
2.03k
        cRawBytes = 0;
413
2.03k
      }
414
5.78M
      else if (nRunLength == 2)
415
12.9k
      {
416
12.9k
        nRunLength = cRawBytes + 32;
417
12.9k
        cRawBytes = 0;
418
12.9k
      }
419
420
5.78M
      if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4ll)
421
0
      {
422
0
        WLog_ERR(TAG, "too many pixels in scanline");
423
0
        return -1;
424
0
      }
425
426
5.78M
      if (!previousScanline)
427
102k
      {
428
        /* first scanline, absolute values */
429
106k
        while (cRawBytes > 0)
430
4.40k
        {
431
4.40k
          pixel = *srcp;
432
4.40k
          srcp++;
433
4.40k
          *dstp = pixel;
434
4.40k
          dstp += 4;
435
4.40k
          x++;
436
4.40k
          cRawBytes--;
437
4.40k
        }
438
439
114k
        while (nRunLength > 0)
440
12.5k
        {
441
12.5k
          *dstp = pixel;
442
12.5k
          dstp += 4;
443
12.5k
          x++;
444
12.5k
          nRunLength--;
445
12.5k
        }
446
102k
      }
447
5.68M
      else
448
5.68M
      {
449
        /* delta values relative to previous scanline */
450
5.84M
        while (cRawBytes > 0)
451
168k
        {
452
168k
          deltaValue = *srcp;
453
168k
          srcp++;
454
455
168k
          if (deltaValue & 1)
456
1.31k
          {
457
1.31k
            deltaValue = deltaValue >> 1;
458
1.31k
            deltaValue = deltaValue + 1;
459
1.31k
            pixel = -deltaValue;
460
1.31k
          }
461
166k
          else
462
166k
          {
463
166k
            deltaValue = deltaValue >> 1;
464
166k
            pixel = deltaValue;
465
166k
          }
466
467
168k
          deltaValue = previousScanline[4LL * x] + pixel;
468
168k
          *dstp = deltaValue;
469
168k
          dstp += 4;
470
168k
          x++;
471
168k
          cRawBytes--;
472
168k
        }
473
474
6.14M
        while (nRunLength > 0)
475
469k
        {
476
469k
          deltaValue = previousScanline[4LL * x] + pixel;
477
469k
          *dstp = deltaValue;
478
469k
          dstp += 4;
479
469k
          x++;
480
469k
          nRunLength--;
481
469k
        }
482
5.68M
      }
483
5.78M
    }
484
485
16.9k
    previousScanline = currentScanline;
486
16.9k
  }
487
488
477
  return (INT32)(srcp - pSrcData);
489
477
}
490
491
static INLINE INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, INT32 nDstStep, UINT32 nXDst,
492
                                     UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 nChannel,
493
                                     BOOL vFlip)
494
159
{
495
159
  INT32 beg = 0;
496
159
  INT32 end = 0;
497
159
  INT32 inc = 0;
498
499
159
  WINPR_ASSERT(nHeight <= INT32_MAX);
500
159
  WINPR_ASSERT(nWidth <= INT32_MAX);
501
159
  WINPR_ASSERT(nDstStep <= INT32_MAX);
502
503
159
  if (vFlip)
504
0
  {
505
0
    beg = (INT32)nHeight - 1;
506
0
    end = -1;
507
0
    inc = -1;
508
0
  }
509
159
  else
510
159
  {
511
159
    beg = 0;
512
159
    end = (INT32)nHeight;
513
159
    inc = 1;
514
159
  }
515
516
5.82k
  for (INT32 y = beg; y != end; y += inc)
517
5.66k
  {
518
5.66k
    BYTE* dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel];
519
520
223k
    for (INT32 x = 0; x < (INT32)nWidth; ++x)
521
218k
    {
522
218k
      *dstp = bValue;
523
218k
      dstp += 4;
524
218k
    }
525
5.66k
  }
526
527
159
  return 0;
528
159
}
529
530
static INLINE BOOL writeLine(BYTE** WINPR_RESTRICT ppRgba, UINT32 DstFormat, UINT32 width,
531
                             const BYTE** WINPR_RESTRICT ppR, const BYTE** WINPR_RESTRICT ppG,
532
                             const BYTE** WINPR_RESTRICT ppB, const BYTE** WINPR_RESTRICT ppA)
533
51.8k
{
534
51.8k
  WINPR_ASSERT(ppRgba);
535
51.8k
  WINPR_ASSERT(ppR);
536
51.8k
  WINPR_ASSERT(ppG);
537
51.8k
  WINPR_ASSERT(ppB);
538
539
51.8k
  switch (DstFormat)
540
51.8k
  {
541
0
    case PIXEL_FORMAT_BGRA32:
542
0
      for (UINT32 x = 0; x < width; x++)
543
0
      {
544
0
        *(*ppRgba)++ = *(*ppB)++;
545
0
        *(*ppRgba)++ = *(*ppG)++;
546
0
        *(*ppRgba)++ = *(*ppR)++;
547
0
        *(*ppRgba)++ = *(*ppA)++;
548
0
      }
549
550
0
      return TRUE;
551
552
51.8k
    case PIXEL_FORMAT_BGRX32:
553
2.61M
      for (UINT32 x = 0; x < width; x++)
554
2.56M
      {
555
2.56M
        *(*ppRgba)++ = *(*ppB)++;
556
2.56M
        *(*ppRgba)++ = *(*ppG)++;
557
2.56M
        *(*ppRgba)++ = *(*ppR)++;
558
2.56M
        *(*ppRgba)++ = 0xFF;
559
2.56M
      }
560
561
51.8k
      return TRUE;
562
563
0
    default:
564
0
      if (ppA)
565
0
      {
566
0
        for (UINT32 x = 0; x < width; x++)
567
0
        {
568
0
          BYTE alpha = *(*ppA)++;
569
0
          UINT32 color =
570
0
              FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
571
0
          FreeRDPWriteColor(*ppRgba, DstFormat, color);
572
0
          *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
573
0
        }
574
0
      }
575
0
      else
576
0
      {
577
0
        const BYTE alpha = 0xFF;
578
579
0
        for (UINT32 x = 0; x < width; x++)
580
0
        {
581
0
          UINT32 color =
582
0
              FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
583
0
          FreeRDPWriteColor(*ppRgba, DstFormat, color);
584
0
          *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
585
0
        }
586
0
      }
587
588
0
      return TRUE;
589
51.8k
  }
590
51.8k
}
591
592
static INLINE BOOL planar_decompress_planes_raw(const BYTE* WINPR_RESTRICT pSrcData[4],
593
                                                BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
594
                                                UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
595
                                                UINT32 nWidth, UINT32 nHeight, BOOL vFlip,
596
                                                UINT32 totalHeight)
597
1.17k
{
598
1.17k
  INT32 beg = 0;
599
1.17k
  INT32 end = 0;
600
1.17k
  INT32 inc = 0;
601
1.17k
  const BYTE* pR = pSrcData[0];
602
1.17k
  const BYTE* pG = pSrcData[1];
603
1.17k
  const BYTE* pB = pSrcData[2];
604
1.17k
  const BYTE* pA = pSrcData[3];
605
1.17k
  const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
606
607
1.17k
  if (vFlip)
608
0
  {
609
0
    beg = nHeight - 1;
610
0
    end = -1;
611
0
    inc = -1;
612
0
  }
613
1.17k
  else
614
1.17k
  {
615
1.17k
    beg = 0;
616
1.17k
    end = nHeight;
617
1.17k
    inc = 1;
618
1.17k
  }
619
620
1.17k
  if (nYDst + nHeight > totalHeight)
621
0
  {
622
0
    WLog_ERR(TAG,
623
0
             "planar plane destination Y %" PRIu32 " + height %" PRIu32
624
0
             " exceeds totalHeight %" PRIu32,
625
0
             nYDst, nHeight, totalHeight);
626
0
    return FALSE;
627
0
  }
628
629
1.17k
  if ((nXDst + nWidth) * bpp > nDstStep)
630
0
  {
631
0
    WLog_ERR(TAG,
632
0
             "planar plane destination (X %" PRIu32 " + width %" PRIu32 ") * bpp %" PRIu32
633
0
             " exceeds stride %" PRIu32,
634
0
             nXDst, nWidth, bpp, nDstStep);
635
0
    return FALSE;
636
0
  }
637
638
53.0k
  for (INT32 y = beg; y != end; y += inc)
639
51.8k
  {
640
51.8k
    BYTE* pRGB = NULL;
641
642
51.8k
    if (y > (INT64)nHeight)
643
0
    {
644
0
      WLog_ERR(TAG, "planar plane destination Y %" PRId32 " exceeds height %" PRIu32, y,
645
0
               nHeight);
646
0
      return FALSE;
647
0
    }
648
649
51.8k
    pRGB = &pDstData[((nYDst + y) * nDstStep) + (nXDst * bpp)];
650
651
51.8k
    if (!writeLine(&pRGB, DstFormat, nWidth, &pR, &pG, &pB, &pA))
652
0
      return FALSE;
653
51.8k
  }
654
655
1.17k
  return TRUE;
656
1.17k
}
657
658
static BOOL planar_subsample_expand(const BYTE* WINPR_RESTRICT plane, size_t planeLength,
659
                                    UINT32 nWidth, UINT32 nHeight, UINT32 nPlaneWidth,
660
                                    UINT32 nPlaneHeight, BYTE* WINPR_RESTRICT deltaPlane)
661
402
{
662
402
  size_t pos = 0;
663
402
  WINPR_UNUSED(planeLength);
664
665
402
  WINPR_ASSERT(plane);
666
402
  WINPR_ASSERT(deltaPlane);
667
668
402
  if (nWidth > nPlaneWidth * 2)
669
0
  {
670
0
    WLog_ERR(TAG, "planar subsample width %" PRIu32 " > PlaneWidth %" PRIu32 " * 2", nWidth,
671
0
             nPlaneWidth);
672
0
    return FALSE;
673
0
  }
674
675
402
  if (nHeight > nPlaneHeight * 2)
676
0
  {
677
0
    WLog_ERR(TAG, "planar subsample height %" PRIu32 " > PlaneHeight %" PRIu32 " * 2", nHeight,
678
0
             nPlaneHeight);
679
0
    return FALSE;
680
0
  }
681
682
15.2k
  for (size_t y = 0; y < nHeight; y++)
683
14.8k
  {
684
14.8k
    const BYTE* src = plane + y / 2 * nPlaneWidth;
685
686
616k
    for (UINT32 x = 0; x < nWidth; x++)
687
602k
    {
688
602k
      deltaPlane[pos++] = src[x / 2];
689
602k
    }
690
14.8k
  }
691
692
402
  return TRUE;
693
402
}
694
695
BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
696
                       const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
697
                       UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
698
                       UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
699
                       UINT32 nDstHeight, BOOL vFlip)
700
10.8k
{
701
10.8k
  BOOL cs = 0;
702
10.8k
  BOOL rle = 0;
703
10.8k
  UINT32 cll = 0;
704
10.8k
  BOOL alpha = 0;
705
10.8k
  BOOL useAlpha = FALSE;
706
10.8k
  INT32 status = 0;
707
10.8k
  const BYTE* srcp = NULL;
708
10.8k
  UINT32 subSize = 0;
709
10.8k
  UINT32 subWidth = 0;
710
10.8k
  UINT32 subHeight = 0;
711
10.8k
  UINT32 planeSize = 0;
712
10.8k
  INT32 rleSizes[4] = { 0, 0, 0, 0 };
713
10.8k
  UINT32 rawSizes[4];
714
10.8k
  UINT32 rawWidths[4];
715
10.8k
  UINT32 rawHeights[4];
716
10.8k
  BYTE FormatHeader = 0;
717
10.8k
  const BYTE* planes[4] = { 0 };
718
10.8k
  const UINT32 w = MIN(nSrcWidth, nDstWidth);
719
10.8k
  const UINT32 h = MIN(nSrcHeight, nDstHeight);
720
10.8k
  const primitives_t* prims = primitives_get();
721
722
10.8k
  WINPR_ASSERT(planar);
723
10.8k
  WINPR_ASSERT(prims);
724
725
10.8k
  if (nDstStep <= 0)
726
10.8k
    nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat);
727
728
10.8k
  srcp = pSrcData;
729
730
10.8k
  if (!pSrcData)
731
0
  {
732
0
    WLog_ERR(TAG, "Invalid argument pSrcData=NULL");
733
0
    return FALSE;
734
0
  }
735
736
10.8k
  if (!pDstData)
737
0
  {
738
0
    WLog_ERR(TAG, "Invalid argument pDstData=NULL");
739
0
    return FALSE;
740
0
  }
741
742
10.8k
  FormatHeader = *srcp++;
743
10.8k
  cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
744
10.8k
  cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) ? TRUE : FALSE;
745
10.8k
  rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) ? TRUE : FALSE;
746
10.8k
  alpha = (FormatHeader & PLANAR_FORMAT_HEADER_NA) ? FALSE : TRUE;
747
748
10.8k
  DstFormat = planar_invert_format(planar, alpha, DstFormat);
749
750
10.8k
  if (alpha)
751
5.57k
    useAlpha = FreeRDPColorHasAlpha(DstFormat);
752
753
  // WLog_INFO(TAG, "CLL: %"PRIu32" CS: %"PRIu8" RLE: %"PRIu8" ALPHA: %"PRIu8"", cll, cs, rle,
754
  // alpha);
755
756
10.8k
  if (!cll && cs)
757
290
  {
758
290
    WLog_ERR(TAG, "Chroma subsampling requires YCoCg and does not work with RGB data");
759
290
    return FALSE; /* Chroma subsampling requires YCoCg */
760
290
  }
761
762
10.5k
  subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
763
10.5k
  subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
764
10.5k
  planeSize = nSrcWidth * nSrcHeight;
765
10.5k
  subSize = subWidth * subHeight;
766
767
10.5k
  if (!cs)
768
9.21k
  {
769
9.21k
    rawSizes[0] = planeSize; /* LumaOrRedPlane */
770
9.21k
    rawWidths[0] = nSrcWidth;
771
9.21k
    rawHeights[0] = nSrcHeight;
772
9.21k
    rawSizes[1] = planeSize; /* OrangeChromaOrGreenPlane */
773
9.21k
    rawWidths[1] = nSrcWidth;
774
9.21k
    rawHeights[1] = nSrcHeight;
775
9.21k
    rawSizes[2] = planeSize; /* GreenChromaOrBluePlane */
776
9.21k
    rawWidths[2] = nSrcWidth;
777
9.21k
    rawHeights[2] = nSrcHeight;
778
9.21k
    rawSizes[3] = planeSize; /* AlphaPlane */
779
9.21k
    rawWidths[3] = nSrcWidth;
780
9.21k
    rawHeights[3] = nSrcHeight;
781
9.21k
  }
782
1.30k
  else /* Chroma Subsampling */
783
1.30k
  {
784
1.30k
    rawSizes[0] = planeSize; /* LumaOrRedPlane */
785
1.30k
    rawWidths[0] = nSrcWidth;
786
1.30k
    rawHeights[0] = nSrcHeight;
787
1.30k
    rawSizes[1] = subSize; /* OrangeChromaOrGreenPlane */
788
1.30k
    rawWidths[1] = subWidth;
789
1.30k
    rawHeights[1] = subHeight;
790
1.30k
    rawSizes[2] = subSize; /* GreenChromaOrBluePlane */
791
1.30k
    rawWidths[2] = subWidth;
792
1.30k
    rawHeights[2] = subHeight;
793
1.30k
    rawSizes[3] = planeSize; /* AlphaPlane */
794
1.30k
    rawWidths[3] = nSrcWidth;
795
1.30k
    rawHeights[3] = nSrcHeight;
796
1.30k
  }
797
798
10.5k
  const size_t diff = srcp - pSrcData;
799
10.5k
  if (SrcSize < diff)
800
0
  {
801
0
    WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff);
802
0
    return FALSE;
803
0
  }
804
805
10.5k
  if (!rle) /* RAW */
806
8.04k
  {
807
808
8.04k
    UINT32 base = planeSize * 3;
809
8.04k
    if (cs)
810
500
      base = planeSize + planeSize / 2;
811
812
8.04k
    if (alpha)
813
5.03k
    {
814
5.03k
      if ((SrcSize - diff) < (planeSize + base))
815
4.43k
      {
816
4.43k
        WLog_ERR(TAG, "Alpha plane size mismatch %" PRIuz " < %" PRIu32, SrcSize - diff,
817
4.43k
                 (planeSize + base));
818
4.43k
        return FALSE;
819
4.43k
      }
820
821
602
      planes[3] = srcp;                    /* AlphaPlane */
822
602
      planes[0] = planes[3] + rawSizes[3]; /* LumaOrRedPlane */
823
602
      planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */
824
602
      planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */
825
826
602
      if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
827
0
      {
828
0
        WLog_ERR(TAG, "plane size mismatch %p + %" PRIu32 " > %p", planes[2], rawSizes[2],
829
0
                 &pSrcData[SrcSize]);
830
0
        return FALSE;
831
0
      }
832
602
    }
833
3.00k
    else
834
3.00k
    {
835
3.00k
      if ((SrcSize - diff) < base)
836
2.60k
      {
837
2.60k
        WLog_ERR(TAG, "plane size mismatch %" PRIu32 " < %" PRIu32, SrcSize - diff, base);
838
2.60k
        return FALSE;
839
2.60k
      }
840
841
395
      planes[0] = srcp;                    /* LumaOrRedPlane */
842
395
      planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */
843
395
      planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */
844
845
395
      if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
846
0
      {
847
0
        WLog_ERR(TAG, "plane size mismatch %p + %" PRIu32 " > %p", planes[2], rawSizes[2],
848
0
                 &pSrcData[SrcSize]);
849
0
        return FALSE;
850
0
      }
851
395
    }
852
8.04k
  }
853
2.48k
  else /* RLE */
854
2.48k
  {
855
2.48k
    if (alpha)
856
450
    {
857
450
      planes[3] = srcp;
858
450
      rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - diff, rawWidths[3],
859
450
                                          rawHeights[3]); /* AlphaPlane */
860
861
450
      if (rleSizes[3] < 0)
862
407
        return FALSE;
863
864
43
      planes[0] = planes[3] + rleSizes[3];
865
43
    }
866
2.03k
    else
867
2.03k
      planes[0] = srcp;
868
869
2.07k
    const size_t diff0 = (planes[0] - pSrcData);
870
2.07k
    if (SrcSize < diff0)
871
0
    {
872
0
      WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff0);
873
0
      return FALSE;
874
0
    }
875
2.07k
    rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - diff0, rawWidths[0],
876
2.07k
                                        rawHeights[0]); /* RedPlane */
877
878
2.07k
    if (rleSizes[0] < 0)
879
1.69k
      return FALSE;
880
881
381
    planes[1] = planes[0] + rleSizes[0];
882
883
381
    const size_t diff1 = (planes[1] - pSrcData);
884
381
    if (SrcSize < diff1)
885
0
    {
886
0
      WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff1);
887
0
      return FALSE;
888
0
    }
889
381
    rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - diff1, rawWidths[1],
890
381
                                        rawHeights[1]); /* GreenPlane */
891
892
381
    if (rleSizes[1] < 1)
893
15
      return FALSE;
894
895
366
    planes[2] = planes[1] + rleSizes[1];
896
366
    const size_t diff2 = (planes[2] - pSrcData);
897
366
    if (SrcSize < diff2)
898
0
    {
899
0
      WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff);
900
0
      return FALSE;
901
0
    }
902
366
    rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - diff2, rawWidths[2],
903
366
                                        rawHeights[2]); /* BluePlane */
904
905
366
    if (rleSizes[2] < 1)
906
27
      return FALSE;
907
366
  }
908
909
1.33k
  if (!cll) /* RGB */
910
745
  {
911
745
    UINT32 TempFormat = 0;
912
745
    BYTE* pTempData = pDstData;
913
745
    UINT32 nTempStep = nDstStep;
914
745
    UINT32 nTotalHeight = nYDst + nDstHeight;
915
916
745
    if (useAlpha)
917
0
      TempFormat = PIXEL_FORMAT_BGRA32;
918
745
    else
919
745
      TempFormat = PIXEL_FORMAT_BGRX32;
920
921
745
    TempFormat = planar_invert_format(planar, alpha, TempFormat);
922
923
745
    if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth) || (nSrcHeight != nDstHeight))
924
745
    {
925
745
      pTempData = planar->pTempData;
926
745
      nTempStep = planar->nTempStep;
927
745
      nTotalHeight = planar->maxHeight;
928
745
    }
929
930
745
    if (!rle) /* RAW */
931
586
    {
932
586
      if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
933
586
                                        nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
934
0
        return FALSE;
935
936
586
      if (alpha)
937
364
        srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
938
222
      else /* NoAlpha */
939
222
        srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
940
941
586
      if ((SrcSize - (srcp - pSrcData)) == 1)
942
0
        srcp++; /* pad */
943
586
    }
944
159
    else /* RLE */
945
159
    {
946
159
      status =
947
159
          planar_decompress_plane_rle(planes[0], rleSizes[0], pTempData, nTempStep, nXDst,
948
159
                                      nYDst, nSrcWidth, nSrcHeight, 2, vFlip); /* RedPlane */
949
950
159
      if (status < 0)
951
0
        return FALSE;
952
953
159
      status = planar_decompress_plane_rle(planes[1], rleSizes[1], pTempData, nTempStep,
954
159
                                           nXDst, nYDst, nSrcWidth, nSrcHeight, 1,
955
159
                                           vFlip); /* GreenPlane */
956
957
159
      if (status < 0)
958
0
        return FALSE;
959
960
159
      status =
961
159
          planar_decompress_plane_rle(planes[2], rleSizes[2], pTempData, nTempStep, nXDst,
962
159
                                      nYDst, nSrcWidth, nSrcHeight, 0, vFlip); /* BluePlane */
963
964
159
      if (status < 0)
965
0
        return FALSE;
966
967
159
      srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
968
969
159
      if (useAlpha)
970
0
      {
971
0
        status = planar_decompress_plane_rle(planes[3], rleSizes[3], pTempData, nTempStep,
972
0
                                             nXDst, nYDst, nSrcWidth, nSrcHeight, 3,
973
0
                                             vFlip); /* AlphaPlane */
974
0
      }
975
159
      else
976
159
        status = planar_set_plane(0xFF, pTempData, nTempStep, nXDst, nYDst, nSrcWidth,
977
159
                                  nSrcHeight, 3, vFlip);
978
979
159
      if (status < 0)
980
0
        return FALSE;
981
982
159
      if (alpha)
983
17
        srcp += rleSizes[3];
984
159
    }
985
986
745
    if (pTempData != pDstData)
987
745
    {
988
745
      if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, w, h,
989
745
                                         pTempData, TempFormat, nTempStep, nXDst, nYDst, NULL,
990
745
                                         FREERDP_FLIP_NONE))
991
0
      {
992
0
        WLog_ERR(TAG, "planar image copy failed");
993
0
        return FALSE;
994
0
      }
995
745
    }
996
745
  }
997
591
  else /* YCoCg */
998
591
  {
999
591
    UINT32 TempFormat = 0;
1000
591
    BYTE* pTempData = planar->pTempData;
1001
591
    UINT32 nTempStep = planar->nTempStep;
1002
591
    UINT32 nTotalHeight = planar->maxHeight;
1003
591
    BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
1004
1005
591
    if (useAlpha)
1006
0
      TempFormat = PIXEL_FORMAT_BGRA32;
1007
591
    else
1008
591
      TempFormat = PIXEL_FORMAT_BGRX32;
1009
1010
591
    if (!pTempData)
1011
0
      return FALSE;
1012
1013
591
    if (rle) /* RLE encoded data. Decode and handle it like raw data. */
1014
180
    {
1015
180
      BYTE* rleBuffer[4] = { 0 };
1016
1017
180
      if (!planar->rlePlanesBuffer)
1018
0
        return FALSE;
1019
1020
180
      rleBuffer[3] = planar->rlePlanesBuffer;  /* AlphaPlane */
1021
180
      rleBuffer[0] = rleBuffer[3] + planeSize; /* LumaOrRedPlane */
1022
180
      rleBuffer[1] = rleBuffer[0] + planeSize; /* OrangeChromaOrGreenPlane */
1023
180
      rleBuffer[2] = rleBuffer[1] + planeSize; /* GreenChromaOrBluePlane */
1024
180
      if (useAlpha)
1025
0
      {
1026
0
        status =
1027
0
            planar_decompress_plane_rle_only(planes[3], rleSizes[3], rleBuffer[3],
1028
0
                                             rawWidths[3], rawHeights[3]); /* AlphaPlane */
1029
1030
0
        if (status < 0)
1031
0
          return FALSE;
1032
0
      }
1033
1034
180
      if (alpha)
1035
4
        srcp += rleSizes[3];
1036
1037
180
      status = planar_decompress_plane_rle_only(planes[0], rleSizes[0], rleBuffer[0],
1038
180
                                                rawWidths[0], rawHeights[0]); /* LumaPlane */
1039
1040
180
      if (status < 0)
1041
0
        return FALSE;
1042
1043
180
      status =
1044
180
          planar_decompress_plane_rle_only(planes[1], rleSizes[1], rleBuffer[1], rawWidths[1],
1045
180
                                           rawHeights[1]); /* OrangeChromaPlane */
1046
1047
180
      if (status < 0)
1048
0
        return FALSE;
1049
1050
180
      status =
1051
180
          planar_decompress_plane_rle_only(planes[2], rleSizes[2], rleBuffer[2], rawWidths[2],
1052
180
                                           rawHeights[2]); /* GreenChromaPlane */
1053
1054
180
      if (status < 0)
1055
0
        return FALSE;
1056
1057
180
      planes[0] = rleBuffer[0];
1058
180
      planes[1] = rleBuffer[1];
1059
180
      planes[2] = rleBuffer[2];
1060
180
      planes[3] = rleBuffer[3];
1061
180
    }
1062
1063
    /* RAW */
1064
591
    {
1065
591
      if (cs)
1066
201
      { /* Chroma subsampling for Co and Cg:
1067
         * Each pixel contains the value that should be expanded to
1068
         * [2x,2y;2x+1,2y;2x+1,2y+1;2x;2y+1] */
1069
201
        if (!planar_subsample_expand(planes[1], rawSizes[1], nSrcWidth, nSrcHeight,
1070
201
                                     rawWidths[1], rawHeights[1], planar->deltaPlanes[0]))
1071
0
          return FALSE;
1072
1073
201
        planes[1] = planar->deltaPlanes[0];
1074
201
        rawSizes[1] = planeSize; /* OrangeChromaOrGreenPlane */
1075
201
        rawWidths[1] = nSrcWidth;
1076
201
        rawHeights[1] = nSrcHeight;
1077
1078
201
        if (!planar_subsample_expand(planes[2], rawSizes[2], nSrcWidth, nSrcHeight,
1079
201
                                     rawWidths[2], rawHeights[2], planar->deltaPlanes[1]))
1080
0
          return FALSE;
1081
1082
201
        planes[2] = planar->deltaPlanes[1];
1083
201
        rawSizes[2] = planeSize; /* GreenChromaOrBluePlane */
1084
201
        rawWidths[2] = nSrcWidth;
1085
201
        rawHeights[2] = nSrcHeight;
1086
201
      }
1087
1088
591
      if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
1089
591
                                        nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
1090
0
        return FALSE;
1091
1092
591
      if (alpha)
1093
242
        srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
1094
349
      else /* NoAlpha */
1095
349
        srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
1096
1097
591
      if ((SrcSize - (srcp - pSrcData)) == 1)
1098
0
        srcp++; /* pad */
1099
591
    }
1100
1101
591
    WINPR_ASSERT(prims->YCoCgToRGB_8u_AC4R);
1102
591
    int rc = prims->YCoCgToRGB_8u_AC4R(pTempData, nTempStep, dst, DstFormat, nDstStep, w, h,
1103
591
                                       cll, useAlpha);
1104
591
    if (rc != PRIMITIVES_SUCCESS)
1105
0
    {
1106
0
      WLog_ERR(TAG, "YCoCgToRGB_8u_AC4R failed with %d", rc);
1107
0
      return FALSE;
1108
0
    }
1109
591
  }
1110
1111
1.33k
  WINPR_UNUSED(srcp);
1112
1.33k
  return TRUE;
1113
1.33k
}
1114
1115
static INLINE BOOL freerdp_split_color_planes(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
1116
                                              const BYTE* WINPR_RESTRICT data, UINT32 format,
1117
                                              UINT32 width, UINT32 height, UINT32 scanline,
1118
                                              BYTE* WINPR_RESTRICT planes[4])
1119
0
{
1120
0
  WINPR_ASSERT(planar);
1121
1122
0
  if ((width > INT32_MAX) || (height > INT32_MAX) || (scanline > INT32_MAX))
1123
0
    return FALSE;
1124
1125
0
  if (scanline == 0)
1126
0
    scanline = width * FreeRDPGetBytesPerPixel(format);
1127
1128
0
  if (planar->topdown)
1129
0
  {
1130
0
    UINT32 k = 0;
1131
0
    for (UINT32 i = 0; i < height; i++)
1132
0
    {
1133
0
      const BYTE* pixel = &data[1ULL * scanline * i];
1134
1135
0
      for (UINT32 j = 0; j < width; j++)
1136
0
      {
1137
0
        const UINT32 color = FreeRDPReadColor(pixel, format);
1138
0
        pixel += FreeRDPGetBytesPerPixel(format);
1139
0
        FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1140
0
                          &planes[0][k], NULL);
1141
0
        k++;
1142
0
      }
1143
0
    }
1144
0
  }
1145
0
  else
1146
0
  {
1147
0
    UINT32 k = 0;
1148
1149
0
    for (INT64 i = (INT64)height - 1; i >= 0; i--)
1150
0
    {
1151
0
      const BYTE* pixel = &data[1ULL * scanline * (UINT32)i];
1152
1153
0
      for (UINT32 j = 0; j < width; j++)
1154
0
      {
1155
0
        const UINT32 color = FreeRDPReadColor(pixel, format);
1156
0
        pixel += FreeRDPGetBytesPerPixel(format);
1157
0
        FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1158
0
                          &planes[0][k], NULL);
1159
0
        k++;
1160
0
      }
1161
0
    }
1162
0
  }
1163
0
  return TRUE;
1164
0
}
1165
1166
static INLINE UINT32 freerdp_bitmap_planar_write_rle_bytes(const BYTE* WINPR_RESTRICT pInBuffer,
1167
                                                           UINT32 cRawBytes, UINT32 nRunLength,
1168
                                                           BYTE* WINPR_RESTRICT pOutBuffer,
1169
                                                           UINT32 outBufferSize)
1170
0
{
1171
0
  const BYTE* pInput = NULL;
1172
0
  BYTE* pOutput = NULL;
1173
0
  BYTE controlByte = 0;
1174
0
  UINT32 nBytesToWrite = 0;
1175
0
  pInput = pInBuffer;
1176
0
  pOutput = pOutBuffer;
1177
1178
0
  if (!cRawBytes && !nRunLength)
1179
0
    return 0;
1180
1181
0
  if (nRunLength < 3)
1182
0
  {
1183
0
    cRawBytes += nRunLength;
1184
0
    nRunLength = 0;
1185
0
  }
1186
1187
0
  while (cRawBytes)
1188
0
  {
1189
0
    if (cRawBytes < 16)
1190
0
    {
1191
0
      if (nRunLength > 15)
1192
0
      {
1193
0
        if (nRunLength < 18)
1194
0
        {
1195
0
          controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
1196
0
          nRunLength -= 13;
1197
0
          cRawBytes = 0;
1198
0
        }
1199
0
        else
1200
0
        {
1201
0
          controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
1202
0
          nRunLength -= 15;
1203
0
          cRawBytes = 0;
1204
0
        }
1205
0
      }
1206
0
      else
1207
0
      {
1208
0
        controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
1209
0
        nRunLength = 0;
1210
0
        cRawBytes = 0;
1211
0
      }
1212
0
    }
1213
0
    else
1214
0
    {
1215
0
      controlByte = PLANAR_CONTROL_BYTE(0, 15);
1216
0
      cRawBytes -= 15;
1217
0
    }
1218
1219
0
    if (outBufferSize < 1)
1220
0
      return 0;
1221
1222
0
    outBufferSize--;
1223
0
    *pOutput = controlByte;
1224
0
    pOutput++;
1225
0
    nBytesToWrite = (controlByte >> 4);
1226
1227
0
    if (nBytesToWrite)
1228
0
    {
1229
0
      if (outBufferSize < nBytesToWrite)
1230
0
        return 0;
1231
1232
0
      outBufferSize -= nBytesToWrite;
1233
0
      CopyMemory(pOutput, pInput, nBytesToWrite);
1234
0
      pOutput += nBytesToWrite;
1235
0
      pInput += nBytesToWrite;
1236
0
    }
1237
0
  }
1238
1239
0
  while (nRunLength)
1240
0
  {
1241
0
    if (nRunLength > 47)
1242
0
    {
1243
0
      if (nRunLength < 50)
1244
0
      {
1245
0
        controlByte = PLANAR_CONTROL_BYTE(2, 13);
1246
0
        nRunLength -= 45;
1247
0
      }
1248
0
      else
1249
0
      {
1250
0
        controlByte = PLANAR_CONTROL_BYTE(2, 15);
1251
0
        nRunLength -= 47;
1252
0
      }
1253
0
    }
1254
0
    else if (nRunLength > 31)
1255
0
    {
1256
0
      controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
1257
0
      nRunLength = 0;
1258
0
    }
1259
0
    else if (nRunLength > 15)
1260
0
    {
1261
0
      controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
1262
0
      nRunLength = 0;
1263
0
    }
1264
0
    else
1265
0
    {
1266
0
      controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
1267
0
      nRunLength = 0;
1268
0
    }
1269
1270
0
    if (outBufferSize < 1)
1271
0
      return 0;
1272
1273
0
    --outBufferSize;
1274
0
    *pOutput = controlByte;
1275
0
    pOutput++;
1276
0
  }
1277
1278
0
  return (pOutput - pOutBuffer);
1279
0
}
1280
1281
static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(const BYTE* WINPR_RESTRICT pInBuffer,
1282
                                                            UINT32 inBufferSize,
1283
                                                            BYTE* WINPR_RESTRICT pOutBuffer,
1284
                                                            UINT32 outBufferSize)
1285
0
{
1286
0
  BYTE symbol = 0;
1287
0
  const BYTE* pInput = NULL;
1288
0
  BYTE* pOutput = NULL;
1289
0
  const BYTE* pBytes = NULL;
1290
0
  UINT32 cRawBytes = 0;
1291
0
  UINT32 nRunLength = 0;
1292
0
  UINT32 bSymbolMatch = 0;
1293
0
  UINT32 nBytesWritten = 0;
1294
0
  UINT32 nTotalBytesWritten = 0;
1295
0
  symbol = 0;
1296
0
  cRawBytes = 0;
1297
0
  nRunLength = 0;
1298
0
  pInput = pInBuffer;
1299
0
  pOutput = pOutBuffer;
1300
0
  nTotalBytesWritten = 0;
1301
1302
0
  if (!outBufferSize)
1303
0
    return 0;
1304
1305
0
  do
1306
0
  {
1307
0
    if (!inBufferSize)
1308
0
      break;
1309
1310
0
    bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
1311
0
    symbol = *pInput;
1312
0
    pInput++;
1313
0
    inBufferSize--;
1314
1315
0
    if (nRunLength && !bSymbolMatch)
1316
0
    {
1317
0
      if (nRunLength < 3)
1318
0
      {
1319
0
        cRawBytes += nRunLength;
1320
0
        nRunLength = 0;
1321
0
      }
1322
0
      else
1323
0
      {
1324
0
        pBytes = pInput - (cRawBytes + nRunLength + 1);
1325
0
        nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1326
0
                                                              pOutput, outBufferSize);
1327
0
        nRunLength = 0;
1328
1329
0
        if (!nBytesWritten || (nBytesWritten > outBufferSize))
1330
0
          return nRunLength;
1331
1332
0
        nTotalBytesWritten += nBytesWritten;
1333
0
        outBufferSize -= nBytesWritten;
1334
0
        pOutput += nBytesWritten;
1335
0
        cRawBytes = 0;
1336
0
      }
1337
0
    }
1338
1339
0
    nRunLength += bSymbolMatch;
1340
0
    cRawBytes += (!bSymbolMatch) ? TRUE : FALSE;
1341
0
  } while (outBufferSize);
1342
1343
0
  if (cRawBytes || nRunLength)
1344
0
  {
1345
0
    pBytes = pInput - (cRawBytes + nRunLength);
1346
0
    nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1347
0
                                                          pOutput, outBufferSize);
1348
1349
0
    if (!nBytesWritten)
1350
0
      return 0;
1351
1352
0
    nTotalBytesWritten += nBytesWritten;
1353
0
  }
1354
1355
0
  if (inBufferSize)
1356
0
    return 0;
1357
1358
0
  return nTotalBytesWritten;
1359
0
}
1360
1361
BOOL freerdp_bitmap_planar_compress_plane_rle(const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1362
                                              UINT32 height, BYTE* WINPR_RESTRICT outPlane,
1363
                                              UINT32* WINPR_RESTRICT dstSize)
1364
0
{
1365
0
  UINT32 index = 0;
1366
0
  const BYTE* pInput = NULL;
1367
0
  BYTE* pOutput = NULL;
1368
0
  UINT32 outBufferSize = 0;
1369
0
  UINT32 nBytesWritten = 0;
1370
0
  UINT32 nTotalBytesWritten = 0;
1371
1372
0
  if (!outPlane)
1373
0
    return FALSE;
1374
1375
0
  index = 0;
1376
0
  pInput = inPlane;
1377
0
  pOutput = outPlane;
1378
0
  outBufferSize = *dstSize;
1379
0
  nTotalBytesWritten = 0;
1380
1381
0
  while (outBufferSize)
1382
0
  {
1383
0
    nBytesWritten =
1384
0
        freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
1385
1386
0
    if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
1387
0
      return FALSE;
1388
1389
0
    outBufferSize -= nBytesWritten;
1390
0
    nTotalBytesWritten += nBytesWritten;
1391
0
    pOutput += nBytesWritten;
1392
0
    pInput += width;
1393
0
    index++;
1394
1395
0
    if (index >= height)
1396
0
      break;
1397
0
  }
1398
1399
0
  *dstSize = nTotalBytesWritten;
1400
0
  return TRUE;
1401
0
}
1402
1403
static INLINE BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRICT inPlanes[4],
1404
                                                             UINT32 width, UINT32 height,
1405
                                                             BYTE* WINPR_RESTRICT outPlanes,
1406
                                                             UINT32* WINPR_RESTRICT dstSizes,
1407
                                                             BOOL skipAlpha)
1408
0
{
1409
0
  UINT32 outPlanesSize = width * height * 4;
1410
1411
  /* AlphaPlane */
1412
0
  if (skipAlpha)
1413
0
  {
1414
0
    dstSizes[0] = 0;
1415
0
  }
1416
0
  else
1417
0
  {
1418
0
    dstSizes[0] = outPlanesSize;
1419
1420
0
    if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes,
1421
0
                                                  &dstSizes[0]))
1422
0
      return FALSE;
1423
1424
0
    outPlanes += dstSizes[0];
1425
0
    outPlanesSize -= dstSizes[0];
1426
0
  }
1427
1428
  /* LumaOrRedPlane */
1429
0
  dstSizes[1] = outPlanesSize;
1430
1431
0
  if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes,
1432
0
                                                &dstSizes[1]))
1433
0
    return FALSE;
1434
1435
0
  outPlanes += dstSizes[1];
1436
0
  outPlanesSize -= dstSizes[1];
1437
  /* OrangeChromaOrGreenPlane */
1438
0
  dstSizes[2] = outPlanesSize;
1439
1440
0
  if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes,
1441
0
                                                &dstSizes[2]))
1442
0
    return FALSE;
1443
1444
0
  outPlanes += dstSizes[2];
1445
0
  outPlanesSize -= dstSizes[2];
1446
  /* GreenChromeOrBluePlane */
1447
0
  dstSizes[3] = outPlanesSize;
1448
1449
0
  if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes,
1450
0
                                                &dstSizes[3]))
1451
0
    return FALSE;
1452
1453
0
  return TRUE;
1454
0
}
1455
1456
BYTE* freerdp_bitmap_planar_delta_encode_plane(const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1457
                                               UINT32 height, BYTE* WINPR_RESTRICT outPlane)
1458
0
{
1459
0
  char s2c = 0;
1460
0
  BYTE* outPtr = NULL;
1461
0
  const BYTE* srcPtr = NULL;
1462
0
  const BYTE* prevLinePtr = NULL;
1463
1464
0
  if (!outPlane)
1465
0
  {
1466
0
    if (width * height == 0)
1467
0
      return NULL;
1468
1469
0
    if (!(outPlane = (BYTE*)calloc(height, width)))
1470
0
      return NULL;
1471
0
  }
1472
1473
  // first line is copied as is
1474
0
  CopyMemory(outPlane, inPlane, width);
1475
0
  outPtr = outPlane + width;
1476
0
  srcPtr = inPlane + width;
1477
0
  prevLinePtr = inPlane;
1478
1479
0
  for (UINT32 y = 1; y < height; y++)
1480
0
  {
1481
0
    for (UINT32 x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
1482
0
    {
1483
0
      INT32 delta = *srcPtr - *prevLinePtr;
1484
0
      s2c = (delta >= 0) ? (char)delta : (char)(~((BYTE)(-delta)) + 1);
1485
0
      s2c = (s2c >= 0) ? (char)((UINT32)s2c << 1)
1486
0
                       : (char)(((UINT32)(~((BYTE)s2c) + 1) << 1) - 1);
1487
0
      *outPtr = (BYTE)s2c;
1488
0
    }
1489
0
  }
1490
1491
0
  return outPlane;
1492
0
}
1493
1494
static INLINE BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* WINPR_RESTRICT inPlanes[4],
1495
                                                             UINT32 width, UINT32 height,
1496
                                                             BYTE* WINPR_RESTRICT outPlanes[4])
1497
0
{
1498
0
  for (UINT32 i = 0; i < 4; i++)
1499
0
  {
1500
0
    outPlanes[i] =
1501
0
        freerdp_bitmap_planar_delta_encode_plane(inPlanes[i], width, height, outPlanes[i]);
1502
1503
0
    if (!outPlanes[i])
1504
0
      return FALSE;
1505
0
  }
1506
1507
0
  return TRUE;
1508
0
}
1509
1510
BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1511
                                     const BYTE* WINPR_RESTRICT data, UINT32 format, UINT32 width,
1512
                                     UINT32 height, UINT32 scanline, BYTE* WINPR_RESTRICT dstData,
1513
                                     UINT32* WINPR_RESTRICT pDstSize)
1514
0
{
1515
0
  UINT32 size = 0;
1516
0
  BYTE* dstp = NULL;
1517
0
  UINT32 planeSize = 0;
1518
0
  UINT32 dstSizes[4] = { 0 };
1519
0
  BYTE FormatHeader = 0;
1520
1521
0
  if (!context || !context->rlePlanesBuffer)
1522
0
    return NULL;
1523
1524
0
  if (context->AllowSkipAlpha)
1525
0
    FormatHeader |= PLANAR_FORMAT_HEADER_NA;
1526
1527
0
  planeSize = width * height;
1528
1529
0
  if (!context->AllowSkipAlpha)
1530
0
    format = planar_invert_format(context, TRUE, format);
1531
1532
0
  if (!freerdp_split_color_planes(context, data, format, width, height, scanline,
1533
0
                                  context->planes))
1534
0
    return NULL;
1535
1536
0
  if (context->AllowRunLengthEncoding)
1537
0
  {
1538
0
    if (!freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height,
1539
0
                                                   context->deltaPlanes))
1540
0
      return NULL;
1541
1542
0
    if (!freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
1543
0
                                                   context->rlePlanesBuffer, dstSizes,
1544
0
                                                   context->AllowSkipAlpha))
1545
0
      return NULL;
1546
1547
0
    {
1548
0
      int offset = 0;
1549
0
      FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
1550
0
      context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
1551
0
      offset += dstSizes[0];
1552
0
      context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
1553
0
      offset += dstSizes[1];
1554
0
      context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
1555
0
      offset += dstSizes[2];
1556
0
      context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
1557
1558
#if defined(WITH_DEBUG_CODECS)
1559
      WLog_DBG(TAG,
1560
               "R: [%" PRIu32 "/%" PRIu32 "] G: [%" PRIu32 "/%" PRIu32 "] B: [%" PRIu32
1561
               " / %" PRIu32 "] ",
1562
               dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
1563
#endif
1564
0
    }
1565
0
  }
1566
1567
0
  if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1568
0
  {
1569
0
    if (!context->AllowRunLengthEncoding)
1570
0
      return NULL;
1571
1572
0
    if (context->rlePlanes[0] == NULL)
1573
0
      return NULL;
1574
1575
0
    if (context->rlePlanes[1] == NULL)
1576
0
      return NULL;
1577
1578
0
    if (context->rlePlanes[2] == NULL)
1579
0
      return NULL;
1580
1581
0
    if (context->rlePlanes[3] == NULL)
1582
0
      return NULL;
1583
0
  }
1584
1585
0
  if (!dstData)
1586
0
  {
1587
0
    size = 1;
1588
1589
0
    if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1590
0
    {
1591
0
      if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1592
0
        size += dstSizes[0];
1593
0
      else
1594
0
        size += planeSize;
1595
0
    }
1596
1597
0
    if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1598
0
      size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
1599
0
    else
1600
0
      size += (planeSize * 3);
1601
1602
0
    if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1603
0
      size++;
1604
1605
0
    dstData = malloc(size);
1606
1607
0
    if (!dstData)
1608
0
      return NULL;
1609
1610
0
    *pDstSize = size;
1611
0
  }
1612
1613
0
  dstp = dstData;
1614
0
  *dstp = FormatHeader; /* FormatHeader */
1615
0
  dstp++;
1616
1617
  /* AlphaPlane */
1618
1619
0
  if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1620
0
  {
1621
0
    if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1622
0
    {
1623
0
      CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]); /* Alpha */
1624
0
      dstp += dstSizes[0];
1625
0
    }
1626
0
    else
1627
0
    {
1628
0
      CopyMemory(dstp, context->planes[0], planeSize); /* Alpha */
1629
0
      dstp += planeSize;
1630
0
    }
1631
0
  }
1632
1633
  /* LumaOrRedPlane */
1634
1635
0
  if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1636
0
  {
1637
0
    CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]); /* Red */
1638
0
    dstp += dstSizes[1];
1639
0
  }
1640
0
  else
1641
0
  {
1642
0
    CopyMemory(dstp, context->planes[1], planeSize); /* Red */
1643
0
    dstp += planeSize;
1644
0
  }
1645
1646
  /* OrangeChromaOrGreenPlane */
1647
1648
0
  if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1649
0
  {
1650
0
    CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]); /* Green */
1651
0
    dstp += dstSizes[2];
1652
0
  }
1653
0
  else
1654
0
  {
1655
0
    CopyMemory(dstp, context->planes[2], planeSize); /* Green */
1656
0
    dstp += planeSize;
1657
0
  }
1658
1659
  /* GreenChromeOrBluePlane */
1660
1661
0
  if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1662
0
  {
1663
0
    CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]); /* Blue */
1664
0
    dstp += dstSizes[3];
1665
0
  }
1666
0
  else
1667
0
  {
1668
0
    CopyMemory(dstp, context->planes[3], planeSize); /* Blue */
1669
0
    dstp += planeSize;
1670
0
  }
1671
1672
  /* Pad1 (1 byte) */
1673
1674
0
  if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1675
0
  {
1676
0
    *dstp = 0;
1677
0
    dstp++;
1678
0
  }
1679
1680
0
  size = (dstp - dstData);
1681
0
  *pDstSize = size;
1682
0
  return dstData;
1683
0
}
1684
1685
BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1686
                                         UINT32 width, UINT32 height)
1687
5.40k
{
1688
5.40k
  if (!context)
1689
0
    return FALSE;
1690
1691
5.40k
  context->bgr = FALSE;
1692
5.40k
  context->maxWidth = PLANAR_ALIGN(width, 4);
1693
5.40k
  context->maxHeight = PLANAR_ALIGN(height, 4);
1694
5.40k
  {
1695
5.40k
    const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
1696
5.40k
    if (tmp > UINT32_MAX)
1697
0
      return FALSE;
1698
5.40k
    context->maxPlaneSize = tmp;
1699
5.40k
  }
1700
1701
5.40k
  if (context->maxWidth > UINT32_MAX / 4)
1702
0
    return FALSE;
1703
5.40k
  context->nTempStep = context->maxWidth * 4;
1704
1705
5.40k
  memset(context->planes, 0, sizeof(context->planes));
1706
5.40k
  memset(context->rlePlanes, 0, sizeof(context->rlePlanes));
1707
5.40k
  memset(context->deltaPlanes, 0, sizeof(context->deltaPlanes));
1708
1709
5.40k
  if (context->maxPlaneSize > 0)
1710
5.40k
  {
1711
5.40k
    void* tmp = winpr_aligned_recalloc(context->planesBuffer, context->maxPlaneSize, 4, 32);
1712
5.40k
    if (!tmp)
1713
0
      return FALSE;
1714
5.40k
    context->planesBuffer = tmp;
1715
1716
5.40k
    tmp = winpr_aligned_recalloc(context->pTempData, context->maxPlaneSize, 6, 32);
1717
5.40k
    if (!tmp)
1718
0
      return FALSE;
1719
5.40k
    context->pTempData = tmp;
1720
1721
5.40k
    tmp = winpr_aligned_recalloc(context->deltaPlanesBuffer, context->maxPlaneSize, 4, 32);
1722
5.40k
    if (!tmp)
1723
0
      return FALSE;
1724
5.40k
    context->deltaPlanesBuffer = tmp;
1725
1726
5.40k
    tmp = winpr_aligned_recalloc(context->rlePlanesBuffer, context->maxPlaneSize, 4, 32);
1727
5.40k
    if (!tmp)
1728
0
      return FALSE;
1729
5.40k
    context->rlePlanesBuffer = tmp;
1730
1731
5.40k
    context->planes[0] = &context->planesBuffer[0ULL * context->maxPlaneSize];
1732
5.40k
    context->planes[1] = &context->planesBuffer[1ULL * context->maxPlaneSize];
1733
5.40k
    context->planes[2] = &context->planesBuffer[2ULL * context->maxPlaneSize];
1734
5.40k
    context->planes[3] = &context->planesBuffer[3ULL * context->maxPlaneSize];
1735
5.40k
    context->deltaPlanes[0] = &context->deltaPlanesBuffer[0ULL * context->maxPlaneSize];
1736
5.40k
    context->deltaPlanes[1] = &context->deltaPlanesBuffer[1ULL * context->maxPlaneSize];
1737
5.40k
    context->deltaPlanes[2] = &context->deltaPlanesBuffer[2ULL * context->maxPlaneSize];
1738
5.40k
    context->deltaPlanes[3] = &context->deltaPlanesBuffer[3ULL * context->maxPlaneSize];
1739
5.40k
  }
1740
5.40k
  return TRUE;
1741
5.40k
}
1742
1743
BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, UINT32 maxWidth,
1744
                                                         UINT32 maxHeight)
1745
5.40k
{
1746
5.40k
  BITMAP_PLANAR_CONTEXT* context =
1747
5.40k
      (BITMAP_PLANAR_CONTEXT*)winpr_aligned_calloc(1, sizeof(BITMAP_PLANAR_CONTEXT), 32);
1748
1749
5.40k
  if (!context)
1750
0
    return NULL;
1751
1752
5.40k
  if (flags & PLANAR_FORMAT_HEADER_NA)
1753
5.40k
    context->AllowSkipAlpha = TRUE;
1754
1755
5.40k
  if (flags & PLANAR_FORMAT_HEADER_RLE)
1756
5.40k
    context->AllowRunLengthEncoding = TRUE;
1757
1758
5.40k
  if (flags & PLANAR_FORMAT_HEADER_CS)
1759
0
    context->AllowColorSubsampling = TRUE;
1760
1761
5.40k
  context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
1762
1763
5.40k
  if (context->ColorLossLevel)
1764
0
    context->AllowDynamicColorFidelity = TRUE;
1765
1766
5.40k
  if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
1767
0
  {
1768
0
    WINPR_PRAGMA_DIAG_PUSH
1769
0
    WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1770
0
    freerdp_bitmap_planar_context_free(context);
1771
0
    WINPR_PRAGMA_DIAG_POP
1772
0
    return NULL;
1773
0
  }
1774
1775
5.40k
  return context;
1776
5.40k
}
1777
1778
void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
1779
5.40k
{
1780
5.40k
  if (!context)
1781
0
    return;
1782
1783
5.40k
  winpr_aligned_free(context->pTempData);
1784
5.40k
  winpr_aligned_free(context->planesBuffer);
1785
5.40k
  winpr_aligned_free(context->deltaPlanesBuffer);
1786
5.40k
  winpr_aligned_free(context->rlePlanesBuffer);
1787
5.40k
  winpr_aligned_free(context);
1788
5.40k
}
1789
1790
void freerdp_planar_switch_bgr(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL bgr)
1791
0
{
1792
0
  WINPR_ASSERT(planar);
1793
0
  planar->bgr = bgr;
1794
0
}
1795
1796
void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL topdown)
1797
0
{
1798
0
  WINPR_ASSERT(planar);
1799
0
  planar->topdown = topdown;
1800
0
}