Coverage Report

Created: 2023-09-25 06:56

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