Coverage Report

Created: 2024-05-20 06:11

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