Coverage Report

Created: 2025-07-01 06:46

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