22#include <freerdp/config.h>
25#include <winpr/wtypes.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
28#include <winpr/print.h>
30#include <freerdp/primitives.h>
31#include <freerdp/log.h>
32#include <freerdp/codec/bitmap.h>
33#include <freerdp/codec/planar.h>
35#define TAG FREERDP_TAG("codec")
37#define PLANAR_ALIGN(val, align) \
38 ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align))
54 RDP6_RLE_SEGMENT* segments;
70struct S_BITMAP_PLANAR_CONTEXT
77 BOOL AllowRunLengthEncoding;
78 BOOL AllowColorSubsampling;
79 BOOL AllowDynamicColorFidelity;
81 UINT32 ColorLossLevel;
87 BYTE* deltaPlanesBuffer;
90 BYTE* rlePlanesBuffer;
99static inline BYTE PLANAR_CONTROL_BYTE(UINT32 nRunLength, UINT32 cRawBytes)
101 return WINPR_ASSERTING_INT_CAST(UINT8, ((nRunLength & 0x0F) | ((cRawBytes & 0x0F) << 4)));
104static inline BYTE PLANAR_CONTROL_BYTE_RUN_LENGTH(UINT32 controlByte)
106 return (controlByte & 0x0F);
108static inline BYTE PLANAR_CONTROL_BYTE_RAW_BYTES(UINT32 controlByte)
110 return ((controlByte >> 4) & 0x0F);
113static inline UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL alpha,
116 WINPR_ASSERT(planar);
117 if (planar->bgr && alpha)
121 case PIXEL_FORMAT_ARGB32:
122 DstFormat = PIXEL_FORMAT_ABGR32;
124 case PIXEL_FORMAT_XRGB32:
125 DstFormat = PIXEL_FORMAT_XBGR32;
127 case PIXEL_FORMAT_ABGR32:
128 DstFormat = PIXEL_FORMAT_ARGB32;
130 case PIXEL_FORMAT_XBGR32:
131 DstFormat = PIXEL_FORMAT_XRGB32;
133 case PIXEL_FORMAT_BGRA32:
134 DstFormat = PIXEL_FORMAT_RGBA32;
136 case PIXEL_FORMAT_BGRX32:
137 DstFormat = PIXEL_FORMAT_RGBX32;
139 case PIXEL_FORMAT_RGBA32:
140 DstFormat = PIXEL_FORMAT_BGRA32;
142 case PIXEL_FORMAT_RGBX32:
143 DstFormat = PIXEL_FORMAT_BGRX32;
145 case PIXEL_FORMAT_RGB24:
146 DstFormat = PIXEL_FORMAT_BGR24;
148 case PIXEL_FORMAT_BGR24:
149 DstFormat = PIXEL_FORMAT_RGB24;
151 case PIXEL_FORMAT_RGB16:
152 DstFormat = PIXEL_FORMAT_BGR16;
154 case PIXEL_FORMAT_BGR16:
155 DstFormat = PIXEL_FORMAT_RGB16;
157 case PIXEL_FORMAT_ARGB15:
158 DstFormat = PIXEL_FORMAT_ABGR15;
160 case PIXEL_FORMAT_RGB15:
161 DstFormat = PIXEL_FORMAT_BGR15;
163 case PIXEL_FORMAT_ABGR15:
164 DstFormat = PIXEL_FORMAT_ARGB15;
166 case PIXEL_FORMAT_BGR15:
167 DstFormat = PIXEL_FORMAT_RGB15;
176static inline BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane,
177 UINT32 width, UINT32 height,
178 BYTE* WINPR_RESTRICT outPlane,
179 UINT32* WINPR_RESTRICT dstSize);
180static inline BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane,
181 UINT32 width, UINT32 height,
182 BYTE* WINPR_RESTRICT outPlane);
184static inline INT32 planar_skip_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
185 UINT32 nWidth, UINT32 nHeight)
189 WINPR_ASSERT(pSrcData);
191 for (UINT32 y = 0; y < nHeight; y++)
193 for (UINT32 x = 0; x < nWidth;)
197 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used,
202 const uint8_t controlByte = pSrcData[used++];
203 uint32_t nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
204 uint32_t cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
208 nRunLength = cRawBytes + 16;
211 else if (nRunLength == 2)
213 nRunLength = cRawBytes + 32;
223 WLog_ERR(TAG,
"planar plane x %" PRIu32
" exceeds width %" PRIu32, x, nWidth);
229 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRId32, used,
236 if (used > INT32_MAX)
238 WLog_ERR(TAG,
"planar plane used %" PRIu32
" exceeds SrcSize %" PRIu32, used, SrcSize);
244static inline UINT8 clamp(INT16 val)
249static inline bool check_source_available(
const BYTE* buffer,
size_t length,
const BYTE* cur,
252 WINPR_ASSERT(cur >= buffer);
253 const size_t len = WINPR_ASSERTING_INT_CAST(
size_t, (cur - buffer));
255 if ((SIZE_MAX - len < required) || (len + required > length))
257 WLog_ERR(TAG,
"error reading input buffer");
263static inline INT32 planar_decompress_plane_rle_only(
const BYTE* WINPR_RESTRICT pSrcData,
264 UINT32 SrcSize, BYTE* WINPR_RESTRICT pDstData,
265 UINT32 nWidth, UINT32 nHeight)
267 BYTE* previousScanline =
nullptr;
268 const BYTE* srcp = pSrcData;
270 WINPR_ASSERT(nHeight <= INT32_MAX);
271 WINPR_ASSERT(nWidth <= INT32_MAX);
273 for (UINT32 y = 0; y < nHeight; y++)
275 BYTE* dstp = &pDstData[1ULL * (y)*nWidth];
277 BYTE* currentScanline = dstp;
279 for (UINT32 x = 0; x < nWidth;)
281 if (!check_source_available(pSrcData, SrcSize, srcp, 1))
284 const BYTE controlByte = *srcp++;
286 UINT32 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
287 UINT32 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
291 nRunLength = cRawBytes + 16;
294 else if (nRunLength == 2)
296 nRunLength = cRawBytes + 32;
300 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 1ll)
302 WLog_ERR(TAG,
"too many pixels in scanline");
306 if (!previousScanline)
308 if (!check_source_available(pSrcData, SrcSize, srcp, cRawBytes))
311 while (cRawBytes > 0)
314 *dstp = clamp(pixel);
320 while (nRunLength > 0)
322 *dstp = clamp(pixel);
330 if (!check_source_available(pSrcData, SrcSize, srcp, cRawBytes))
334 while (cRawBytes > 0)
336 UINT8 deltaValue = *srcp++;
340 deltaValue = deltaValue >> 1;
341 deltaValue = deltaValue + 1;
342 pixel = WINPR_ASSERTING_INT_CAST(int16_t, -1 * (int16_t)deltaValue);
346 deltaValue = deltaValue >> 1;
347 pixel = WINPR_ASSERTING_INT_CAST(INT16, deltaValue);
351 WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[x] + pixel);
352 *dstp = clamp(delta);
358 while (nRunLength > 0)
360 const INT16 deltaValue =
361 WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[x] + pixel);
362 *dstp = clamp(deltaValue);
370 previousScanline = currentScanline;
373 return (INT32)(srcp - pSrcData);
376static inline INT32 planar_decompress_plane_rle(
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
377 BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
378 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
379 UINT32 nHeight, UINT32 nChannel, BOOL vFlip)
384 BYTE* previousScanline =
nullptr;
385 const BYTE* srcp = pSrcData;
387 WINPR_ASSERT(nHeight <= INT32_MAX);
388 WINPR_ASSERT(nWidth <= INT32_MAX);
389 WINPR_ASSERT(nDstStep <= INT32_MAX);
393 beg = (INT32)nHeight - 1;
400 end = (INT32)nHeight;
404 for (INT32 y = beg; y != end; y += inc)
406 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (4LL * nXDst) + nChannel * 1LL;
407 BYTE* dstp = &pDstData[off];
408 BYTE* currentScanline = dstp;
411 for (INT32 x = 0; x < (INT32)nWidth;)
413 if (!check_source_available(pSrcData, SrcSize, srcp, 1))
416 const BYTE controlByte = *srcp++;
418 UINT32 nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
419 UINT32 cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
423 nRunLength = cRawBytes + 16;
426 else if (nRunLength == 2)
428 nRunLength = cRawBytes + 32;
432 if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4ll)
434 WLog_ERR(TAG,
"too many pixels in scanline");
438 if (!previousScanline)
440 if (!check_source_available(pSrcData, SrcSize, srcp, cRawBytes))
444 while (cRawBytes > 0)
448 *dstp = WINPR_ASSERTING_INT_CAST(BYTE, pixel);
454 while (nRunLength > 0)
456 *dstp = WINPR_ASSERTING_INT_CAST(BYTE, pixel);
464 if (!check_source_available(pSrcData, SrcSize, srcp, cRawBytes))
468 while (cRawBytes > 0)
470 BYTE deltaValue = *srcp++;
474 deltaValue = deltaValue >> 1;
475 deltaValue = deltaValue + 1;
476 pixel = WINPR_ASSERTING_INT_CAST(int16_t, -deltaValue);
480 deltaValue = deltaValue >> 1;
485 WINPR_ASSERTING_INT_CAST(int16_t, previousScanline[4LL * x] + pixel);
486 *dstp = clamp(delta);
492 while (nRunLength > 0)
494 const INT16 deltaValue =
495 WINPR_ASSERTING_INT_CAST(int16_t, pixel + previousScanline[4LL * x]);
496 *dstp = clamp(deltaValue);
504 previousScanline = currentScanline;
507 return (INT32)(srcp - pSrcData);
510static inline INT32 planar_set_plane(BYTE bValue, BYTE* pDstData, UINT32 nDstStep, UINT32 nXDst,
511 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 nChannel,
515 INT32 end = (INT32)nHeight;
518 WINPR_ASSERT(nHeight <= INT32_MAX);
519 WINPR_ASSERT(nWidth <= INT32_MAX);
520 WINPR_ASSERT(nDstStep <= INT32_MAX);
524 beg = (INT32)nHeight - 1;
529 for (INT32 y = beg; y != end; y += inc)
531 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (4LL * nXDst) + nChannel * 1LL;
532 BYTE* dstp = &pDstData[off];
534 for (INT32 x = 0; x < (INT32)nWidth; ++x)
544static inline BOOL writeLine(BYTE** WINPR_RESTRICT ppRgba, UINT32 DstFormat, UINT32 width,
545 const BYTE** WINPR_RESTRICT ppR,
const BYTE** WINPR_RESTRICT ppG,
546 const BYTE** WINPR_RESTRICT ppB,
const BYTE** WINPR_RESTRICT ppA)
548 WINPR_ASSERT(ppRgba);
555 case PIXEL_FORMAT_BGRA32:
556 for (UINT32 x = 0; x < width; x++)
558 *(*ppRgba)++ = *(*ppB)++;
559 *(*ppRgba)++ = *(*ppG)++;
560 *(*ppRgba)++ = *(*ppR)++;
561 *(*ppRgba)++ = *(*ppA)++;
566 case PIXEL_FORMAT_BGRX32:
567 for (UINT32 x = 0; x < width; x++)
569 *(*ppRgba)++ = *(*ppB)++;
570 *(*ppRgba)++ = *(*ppG)++;
571 *(*ppRgba)++ = *(*ppR)++;
580 for (UINT32 x = 0; x < width; x++)
582 BYTE alpha = *(*ppA)++;
584 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
585 FreeRDPWriteColor(*ppRgba, DstFormat, color);
586 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
591 const BYTE alpha = 0xFF;
593 for (UINT32 x = 0; x < width; x++)
596 FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
597 FreeRDPWriteColor(*ppRgba, DstFormat, color);
598 *ppRgba += FreeRDPGetBytesPerPixel(DstFormat);
606static inline BOOL planar_decompress_planes_raw(
const BYTE* WINPR_RESTRICT pSrcData[4],
607 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
608 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
609 UINT32 nWidth, UINT32 nHeight, BOOL vFlip,
615 const BYTE* pR = pSrcData[0];
616 const BYTE* pG = pSrcData[1];
617 const BYTE* pB = pSrcData[2];
618 const BYTE* pA = pSrcData[3];
619 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
623 beg = WINPR_ASSERTING_INT_CAST(int32_t, nHeight - 1);
630 end = WINPR_ASSERTING_INT_CAST(int32_t, nHeight);
634 if (nYDst + nHeight > totalHeight)
637 "planar plane destination Y %" PRIu32
" + height %" PRIu32
638 " exceeds totalHeight %" PRIu32,
639 nYDst, nHeight, totalHeight);
643 if ((nXDst + nWidth) * bpp > nDstStep)
646 "planar plane destination (X %" PRIu32
" + width %" PRIu32
") * bpp %" PRIu32
647 " exceeds stride %" PRIu32,
648 nXDst, nWidth, bpp, nDstStep);
652 for (INT32 y = beg; y != end; y += inc)
654 BYTE* pRGB =
nullptr;
656 if (y > WINPR_ASSERTING_INT_CAST(INT64, nHeight))
658 WLog_ERR(TAG,
"planar plane destination Y %" PRId32
" exceeds height %" PRIu32, y,
663 const intptr_t off = ((1LL * nYDst + y) * nDstStep) + (1LL * nXDst * bpp);
664 pRGB = &pDstData[off];
666 if (!writeLine(&pRGB, DstFormat, nWidth, &pR, &pG, &pB, &pA))
673static BOOL planar_subsample_expand(
const BYTE* WINPR_RESTRICT plane,
size_t planeLength,
674 UINT32 nWidth, UINT32 nHeight, UINT32 nPlaneWidth,
675 UINT32 nPlaneHeight, BYTE* WINPR_RESTRICT deltaPlane)
678 WINPR_UNUSED(planeLength);
681 WINPR_ASSERT(deltaPlane);
683 if (nWidth > nPlaneWidth * 2)
685 WLog_ERR(TAG,
"planar subsample width %" PRIu32
" > PlaneWidth %" PRIu32
" * 2", nWidth,
690 if (nHeight > nPlaneHeight * 2)
692 WLog_ERR(TAG,
"planar subsample height %" PRIu32
" > PlaneHeight %" PRIu32
" * 2", nHeight,
697 for (
size_t y = 0; y < nHeight; y++)
699 const BYTE* src = plane + y / 2 * nPlaneWidth;
701 for (UINT32 x = 0; x < nWidth; x++)
703 deltaPlane[pos++] = src[x / 2];
710#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
711BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
712 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
713 UINT32 nSrcHeight, BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
714 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
715 UINT32 nDstHeight, BOOL vFlip)
717 return freerdp_bitmap_decompress_planar(planar, pSrcData, SrcSize, nSrcWidth, nSrcHeight,
718 pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
723BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
724 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
725 UINT32 nSrcWidth, UINT32 nSrcHeight,
726 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
727 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth,
728 UINT32 nDstHeight, BOOL vFlip)
730 BOOL useAlpha = FALSE;
732 INT32 rleSizes[4] = { 0, 0, 0, 0 };
733 UINT32 rawSizes[4] = WINPR_C_ARRAY_INIT;
734 UINT32 rawWidths[4] = WINPR_C_ARRAY_INIT;
735 UINT32 rawHeights[4] = WINPR_C_ARRAY_INIT;
736 const BYTE* planes[4] = WINPR_C_ARRAY_INIT;
737 const UINT32 w = MIN(nSrcWidth, nDstWidth);
738 const UINT32 h = MIN(nSrcHeight, nDstHeight);
741 WINPR_ASSERT(planar);
744 if (planar->maxWidth < nSrcWidth)
746 if (planar->maxHeight < nSrcHeight)
749 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
751 nDstStep = nDstWidth * bpp;
753 const BYTE* srcp = pSrcData;
755 if (!pSrcData || (SrcSize < 1))
757 WLog_ERR(TAG,
"Invalid argument pSrcData=%p [size=%" PRIu32
"]",
758 WINPR_CXX_COMPAT_CAST(
const void*, pSrcData), SrcSize);
764 WLog_ERR(TAG,
"Invalid argument pDstData=nullptr");
768 const BYTE FormatHeader = *srcp++;
769 const BYTE cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
770 const BYTE cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) != 0;
771 const BYTE rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) != 0;
772 const BYTE alpha = !(FormatHeader & PLANAR_FORMAT_HEADER_NA);
774 DstFormat = planar_invert_format(planar, alpha, DstFormat);
777 useAlpha = FreeRDPColorHasAlpha(DstFormat);
784 WLog_ERR(TAG,
"Chroma subsampling requires YCoCg and does not work with RGB data");
788 const UINT32 subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
789 const UINT32 subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
790 const UINT32 planeSize = nSrcWidth * nSrcHeight;
791 const UINT32 subSize = subWidth * subHeight;
795 rawSizes[0] = planeSize;
796 rawWidths[0] = nSrcWidth;
797 rawHeights[0] = nSrcHeight;
798 rawSizes[1] = planeSize;
799 rawWidths[1] = nSrcWidth;
800 rawHeights[1] = nSrcHeight;
801 rawSizes[2] = planeSize;
802 rawWidths[2] = nSrcWidth;
803 rawHeights[2] = nSrcHeight;
804 rawSizes[3] = planeSize;
805 rawWidths[3] = nSrcWidth;
806 rawHeights[3] = nSrcHeight;
810 rawSizes[0] = planeSize;
811 rawWidths[0] = nSrcWidth;
812 rawHeights[0] = nSrcHeight;
813 rawSizes[1] = subSize;
814 rawWidths[1] = subWidth;
815 rawHeights[1] = subHeight;
816 rawSizes[2] = subSize;
817 rawWidths[2] = subWidth;
818 rawHeights[2] = subHeight;
819 rawSizes[3] = planeSize;
820 rawWidths[3] = nSrcWidth;
821 rawHeights[3] = nSrcHeight;
824 const size_t diff = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(srcp - pSrcData));
827 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
834 UINT32 base = planeSize * 3;
836 base = planeSize + planeSize / 2;
840 if ((SrcSize - diff) < (planeSize + base))
842 WLog_ERR(TAG,
"Alpha plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff,
848 planes[0] = planes[3] + rawSizes[3];
849 planes[1] = planes[0] + rawSizes[0];
850 planes[2] = planes[1] + rawSizes[1];
852 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
854 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p",
855 WINPR_CXX_COMPAT_CAST(
const void*, planes[2]), rawSizes[2],
856 WINPR_CXX_COMPAT_CAST(
const void*, &pSrcData[SrcSize]));
862 if ((SrcSize - diff) < base)
864 WLog_ERR(TAG,
"plane size mismatch %" PRIuz
" < %" PRIu32, SrcSize - diff, base);
869 planes[1] = planes[0] + rawSizes[0];
870 planes[2] = planes[1] + rawSizes[1];
872 if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
874 WLog_ERR(TAG,
"plane size mismatch %p + %" PRIu32
" > %p",
875 WINPR_CXX_COMPAT_CAST(
const void*, planes[2]), rawSizes[2],
876 WINPR_CXX_COMPAT_CAST(
const void*, &pSrcData[SrcSize]));
886 rleSizes[3] = planar_skip_plane_rle(planes[3], (UINT32)(SrcSize - diff), rawWidths[3],
892 planes[0] = planes[3] + rleSizes[3];
897 const size_t diff0 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[0] - pSrcData));
900 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff0);
903 rleSizes[0] = planar_skip_plane_rle(planes[0], (UINT32)(SrcSize - diff0), rawWidths[0],
909 planes[1] = planes[0] + rleSizes[0];
911 const size_t diff1 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[1] - pSrcData));
914 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff1);
917 rleSizes[1] = planar_skip_plane_rle(planes[1], (UINT32)(SrcSize - diff1), rawWidths[1],
923 planes[2] = planes[1] + rleSizes[1];
924 const size_t diff2 = WINPR_ASSERTING_INT_CAST(
size_t, (intptr_t)(planes[2] - pSrcData));
927 WLog_ERR(TAG,
"Size mismatch %" PRIu32
" < %" PRIuz, SrcSize, diff);
930 rleSizes[2] = planar_skip_plane_rle(planes[2], (UINT32)(SrcSize - diff2), rawWidths[2],
939 UINT32 TempFormat = 0;
940 BYTE* pTempData = pDstData;
941 UINT32 nTempStep = nDstStep;
942 UINT32 nTotalHeight = nYDst + nDstHeight;
945 TempFormat = PIXEL_FORMAT_BGRA32;
947 TempFormat = PIXEL_FORMAT_BGRX32;
949 TempFormat = planar_invert_format(planar, alpha, TempFormat);
951 if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth) || (nSrcHeight != nDstHeight))
953 pTempData = planar->pTempData;
954 nTempStep = planar->nTempStep;
955 nTotalHeight = planar->maxHeight;
960 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
961 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
965 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
967 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
969 if ((SrcSize - (srcp - pSrcData)) == 1)
974 if (nYDst + nSrcHeight > nTotalHeight)
977 "planar plane destination Y %" PRIu32
" + height %" PRIu32
978 " exceeds totalHeight %" PRIu32,
979 nYDst, nSrcHeight, nTotalHeight);
983 if ((nXDst + nSrcWidth) * bpp > nTempStep)
986 "planar plane destination (X %" PRIu32
" + width %" PRIu32
987 ") * bpp %" PRIu32
" exceeds stride %" PRIu32,
988 nXDst, nSrcWidth, bpp, nTempStep);
992 status = planar_decompress_plane_rle(
993 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), pTempData, nTempStep,
994 nXDst, nYDst, nSrcWidth, nSrcHeight, 2, vFlip);
999 status = planar_decompress_plane_rle(
1000 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), pTempData, nTempStep,
1001 nXDst, nYDst, nSrcWidth, nSrcHeight, 1, vFlip);
1006 status = planar_decompress_plane_rle(
1007 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), pTempData, nTempStep,
1008 nXDst, nYDst, nSrcWidth, nSrcHeight, 0, vFlip);
1013 srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
1017 status = planar_decompress_plane_rle(
1018 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), pTempData,
1019 nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 3, vFlip);
1022 status = planar_set_plane(0xFF, pTempData, nTempStep, nXDst, nYDst, nSrcWidth,
1023 nSrcHeight, 3, vFlip);
1029 srcp += rleSizes[3];
1032 if (pTempData != pDstData)
1034 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, w, h,
1035 pTempData, TempFormat, nTempStep, nXDst, nYDst,
1036 nullptr, FREERDP_FLIP_NONE))
1038 WLog_ERR(TAG,
"planar image copy failed");
1045 UINT32 TempFormat = 0;
1046 BYTE* pTempData = planar->pTempData;
1047 UINT32 nTempStep = planar->nTempStep;
1048 UINT32 nTotalHeight = planar->maxHeight;
1049 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
1052 TempFormat = PIXEL_FORMAT_BGRA32;
1054 TempFormat = PIXEL_FORMAT_BGRX32;
1061 BYTE* rleBuffer[4] = WINPR_C_ARRAY_INIT;
1063 if (!planar->rlePlanesBuffer)
1066 rleBuffer[3] = planar->rlePlanesBuffer;
1067 rleBuffer[0] = rleBuffer[3] + planeSize;
1068 rleBuffer[1] = rleBuffer[0] + planeSize;
1069 rleBuffer[2] = rleBuffer[1] + planeSize;
1072 status = planar_decompress_plane_rle_only(
1073 planes[3], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[3]), rleBuffer[3],
1074 rawWidths[3], rawHeights[3]);
1081 srcp += rleSizes[3];
1083 status = planar_decompress_plane_rle_only(
1084 planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), rleBuffer[0],
1085 rawWidths[0], rawHeights[0]);
1090 status = planar_decompress_plane_rle_only(
1091 planes[1], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[1]), rleBuffer[1],
1092 rawWidths[1], rawHeights[1]);
1097 status = planar_decompress_plane_rle_only(
1098 planes[2], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[2]), rleBuffer[2],
1099 rawWidths[2], rawHeights[2]);
1104 planes[0] = rleBuffer[0];
1105 planes[1] = rleBuffer[1];
1106 planes[2] = rleBuffer[2];
1107 planes[3] = rleBuffer[3];
1116 if (!planar_subsample_expand(planes[1], rawSizes[1], nSrcWidth, nSrcHeight,
1117 rawWidths[1], rawHeights[1], planar->deltaPlanes[0]))
1120 planes[1] = planar->deltaPlanes[0];
1121 rawSizes[1] = planeSize;
1122 rawWidths[1] = nSrcWidth;
1123 rawHeights[1] = nSrcHeight;
1125 if (!planar_subsample_expand(planes[2], rawSizes[2], nSrcWidth, nSrcHeight,
1126 rawWidths[2], rawHeights[2], planar->deltaPlanes[1]))
1129 planes[2] = planar->deltaPlanes[1];
1130 rawSizes[2] = planeSize;
1131 rawWidths[2] = nSrcWidth;
1132 rawHeights[2] = nSrcHeight;
1135 if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep, nXDst,
1136 nYDst, nSrcWidth, nSrcHeight, vFlip, nTotalHeight))
1140 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
1142 srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
1144 if ((SrcSize - (srcp - pSrcData)) == 1)
1148 WINPR_ASSERT(prims->YCoCgToRGB_8u_AC4R);
1149 int rc = prims->YCoCgToRGB_8u_AC4R(
1150 pTempData, WINPR_ASSERTING_INT_CAST(int32_t, nTempStep), dst, DstFormat,
1151 WINPR_ASSERTING_INT_CAST(int32_t, nDstStep), w, h, cll, useAlpha);
1152 if (rc != PRIMITIVES_SUCCESS)
1154 WLog_ERR(TAG,
"YCoCgToRGB_8u_AC4R failed with %d", rc);
1163static inline BOOL freerdp_split_color_planes(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar,
1164 const BYTE* WINPR_RESTRICT data, UINT32 format,
1165 UINT32 width, UINT32 height, UINT32 scanline,
1166 BYTE* WINPR_RESTRICT planes[4])
1168 WINPR_ASSERT(planar);
1170 if ((width > INT32_MAX) || (height > INT32_MAX) || (scanline > INT32_MAX))
1174 scanline = width * FreeRDPGetBytesPerPixel(format);
1176 if (planar->topdown)
1179 for (UINT32 i = 0; i < height; i++)
1181 const BYTE* pixel = &data[1ULL * scanline * i];
1183 for (UINT32 j = 0; j < width; j++)
1185 const UINT32 color = FreeRDPReadColor(pixel, format);
1186 pixel += FreeRDPGetBytesPerPixel(format);
1187 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1188 &planes[0][k],
nullptr);
1197 for (INT64 i = (INT64)height - 1; i >= 0; i--)
1199 const BYTE* pixel = &data[1ULL * scanline * (UINT32)i];
1201 for (UINT32 j = 0; j < width; j++)
1203 const UINT32 color = FreeRDPReadColor(pixel, format);
1204 pixel += FreeRDPGetBytesPerPixel(format);
1205 FreeRDPSplitColor(color, format, &planes[1][k], &planes[2][k], &planes[3][k],
1206 &planes[0][k],
nullptr);
1214static inline UINT32 freerdp_bitmap_planar_write_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1215 UINT32 cRawBytes, UINT32 nRunLength,
1216 BYTE* WINPR_RESTRICT pOutBuffer,
1217 UINT32 outBufferSize)
1219 const BYTE* pInput = pInBuffer;
1220 BYTE* pOutput = pOutBuffer;
1221 BYTE controlByte = 0;
1222 UINT32 nBytesToWrite = 0;
1224 if (!cRawBytes && !nRunLength)
1229 cRawBytes += nRunLength;
1237 if (nRunLength > 15)
1239 if (nRunLength < 18)
1241 controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
1247 controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
1254 controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
1261 controlByte = PLANAR_CONTROL_BYTE(0, 15);
1265 if (outBufferSize < 1)
1269 *pOutput = controlByte;
1271 nBytesToWrite = (controlByte >> 4);
1275 if (outBufferSize < nBytesToWrite)
1278 outBufferSize -= nBytesToWrite;
1279 CopyMemory(pOutput, pInput, nBytesToWrite);
1280 pOutput += nBytesToWrite;
1281 pInput += nBytesToWrite;
1287 if (nRunLength > 47)
1289 if (nRunLength < 50)
1291 controlByte = PLANAR_CONTROL_BYTE(2, 13);
1296 controlByte = PLANAR_CONTROL_BYTE(2, 15);
1300 else if (nRunLength > 31)
1302 controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
1305 else if (nRunLength > 15)
1307 controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
1312 controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
1316 if (outBufferSize < 1)
1320 *pOutput = controlByte;
1324 const intptr_t diff = (pOutput - pOutBuffer);
1325 if ((diff < 0) || (diff > UINT32_MAX))
1327 return (UINT32)diff;
1330static inline UINT32 freerdp_bitmap_planar_encode_rle_bytes(
const BYTE* WINPR_RESTRICT pInBuffer,
1331 UINT32 inBufferSize,
1332 BYTE* WINPR_RESTRICT pOutBuffer,
1333 UINT32 outBufferSize)
1336 const BYTE* pInput = pInBuffer;
1337 BYTE* pOutput = pOutBuffer;
1338 const BYTE* pBytes =
nullptr;
1339 UINT32 cRawBytes = 0;
1340 UINT32 nRunLength = 0;
1341 UINT32 nBytesWritten = 0;
1342 UINT32 nTotalBytesWritten = 0;
1352 const UINT32 bSymbolMatch = (symbol == *pInput) != 0;
1357 if (nRunLength && !bSymbolMatch)
1361 cRawBytes += nRunLength;
1366 pBytes = pInput - (cRawBytes + nRunLength + 1);
1367 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1368 pOutput, outBufferSize);
1371 if (!nBytesWritten || (nBytesWritten > outBufferSize))
1374 nTotalBytesWritten += nBytesWritten;
1375 outBufferSize -= nBytesWritten;
1376 pOutput += nBytesWritten;
1381 nRunLength += bSymbolMatch;
1382 cRawBytes += (!bSymbolMatch) != 0;
1383 }
while (outBufferSize);
1385 if (cRawBytes || nRunLength)
1387 pBytes = pInput - (cRawBytes + nRunLength);
1388 nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes, cRawBytes, nRunLength,
1389 pOutput, outBufferSize);
1394 nTotalBytesWritten += nBytesWritten;
1400 return nTotalBytesWritten;
1403BOOL freerdp_bitmap_planar_compress_plane_rle(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1404 UINT32 height, BYTE* WINPR_RESTRICT outPlane,
1405 UINT32* WINPR_RESTRICT dstSize)
1411 const BYTE* pInput = inPlane;
1412 BYTE* pOutput = outPlane;
1413 UINT32 outBufferSize = *dstSize;
1414 UINT32 nTotalBytesWritten = 0;
1416 while (outBufferSize > 0)
1418 const UINT32 nBytesWritten =
1419 freerdp_bitmap_planar_encode_rle_bytes(pInput, width, pOutput, outBufferSize);
1421 if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
1424 outBufferSize -= nBytesWritten;
1425 nTotalBytesWritten += nBytesWritten;
1426 pOutput += nBytesWritten;
1430 if (index >= height)
1434 *dstSize = nTotalBytesWritten;
1438static inline BOOL freerdp_bitmap_planar_compress_planes_rle(BYTE* WINPR_RESTRICT inPlanes[4],
1439 UINT32 width, UINT32 height,
1440 BYTE* WINPR_RESTRICT outPlanes,
1441 UINT32* WINPR_RESTRICT dstSizes,
1444 UINT32 outPlanesSize = width * height * 4;
1453 dstSizes[0] = outPlanesSize;
1455 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[0], width, height, outPlanes,
1459 outPlanes += dstSizes[0];
1460 outPlanesSize -= dstSizes[0];
1464 dstSizes[1] = outPlanesSize;
1466 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height, outPlanes,
1470 outPlanes += dstSizes[1];
1471 outPlanesSize -= dstSizes[1];
1473 dstSizes[2] = outPlanesSize;
1475 if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height, outPlanes,
1479 outPlanes += dstSizes[2];
1480 outPlanesSize -= dstSizes[2];
1482 dstSizes[3] = outPlanesSize;
1484 return (freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height, outPlanes,
1488BYTE* freerdp_bitmap_planar_delta_encode_plane(
const BYTE* WINPR_RESTRICT inPlane, UINT32 width,
1489 UINT32 height, BYTE* WINPR_RESTRICT outPlane)
1493 if (width * height == 0)
1496 outPlane = (BYTE*)calloc(height, width);
1502 CopyMemory(outPlane, inPlane, width);
1504 for (UINT32 y = 1; y < height; y++)
1506 const size_t off = 1ull * width * y;
1507 BYTE* outPtr = &outPlane[off];
1508 const BYTE* srcPtr = &inPlane[off];
1509 const BYTE* prevLinePtr = &inPlane[off - width];
1510 for (UINT32 x = 0; x < width; x++)
1512 const int delta = (int)srcPtr[x] - (
int)prevLinePtr[x];
1513 const int s2c1i = (delta >= 0) ? delta : (INT_MAX + delta) + 1;
1514 const int8_t s2c1 = WINPR_CXX_COMPAT_CAST(int8_t, s2c1i);
1515 const uint32_t s2c =
1516 (s2c1 >= 0) ? ((UINT32)s2c1 << 1) : (((UINT32)(~(s2c1) + 1) << 1) - 1);
1517 outPtr[x] = (BYTE)s2c;
1524static inline BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* WINPR_RESTRICT inPlanes[4],
1525 UINT32 width, UINT32 height,
1526 BYTE* WINPR_RESTRICT outPlanes[4])
1528 for (UINT32 i = 0; i < 4; i++)
1531 freerdp_bitmap_planar_delta_encode_plane(inPlanes[i], width, height, outPlanes[i]);
1540BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1541 const BYTE* WINPR_RESTRICT data, UINT32 format, UINT32 width,
1542 UINT32 height, UINT32 scanline, BYTE* WINPR_RESTRICT dstData,
1543 UINT32* WINPR_RESTRICT pDstSize)
1546 BYTE* dstp =
nullptr;
1547 UINT32 dstSizes[4] = WINPR_C_ARRAY_INIT;
1548 BYTE FormatHeader = 0;
1550 if (!context || !context->rlePlanesBuffer)
1553 if (context->AllowSkipAlpha)
1554 FormatHeader |= PLANAR_FORMAT_HEADER_NA;
1556 const UINT32 planeSize = width * height;
1558 if (!context->AllowSkipAlpha)
1559 format = planar_invert_format(context, TRUE, format);
1561 if (!freerdp_split_color_planes(context, data, format, width, height, scanline,
1565 if (context->AllowRunLengthEncoding)
1567 if (!freerdp_bitmap_planar_delta_encode_planes(context->planes, width, height,
1568 context->deltaPlanes))
1571 if (!freerdp_bitmap_planar_compress_planes_rle(context->deltaPlanes, width, height,
1572 context->rlePlanesBuffer, dstSizes,
1573 context->AllowSkipAlpha))
1577 uint32_t offset = 0;
1578 FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
1579 context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
1580 offset += dstSizes[0];
1581 context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
1582 offset += dstSizes[1];
1583 context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
1584 offset += dstSizes[2];
1585 context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
1587#if defined(WITH_DEBUG_CODECS)
1589 "R: [%" PRIu32
"/%" PRIu32
"] G: [%" PRIu32
"/%" PRIu32
"] B: [%" PRIu32
1591 dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
1596 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1598 if (!context->AllowRunLengthEncoding)
1601 if (context->rlePlanes[0] ==
nullptr)
1604 if (context->rlePlanes[1] ==
nullptr)
1607 if (context->rlePlanes[2] ==
nullptr)
1610 if (context->rlePlanes[3] ==
nullptr)
1618 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1620 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1621 size += dstSizes[0];
1626 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1627 size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
1629 size += (planeSize * 3);
1631 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1634 dstData = malloc(size);
1643 *dstp = FormatHeader;
1648 if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
1650 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1652 CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]);
1653 dstp += dstSizes[0];
1657 CopyMemory(dstp, context->planes[0], planeSize);
1664 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1666 CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]);
1667 dstp += dstSizes[1];
1671 CopyMemory(dstp, context->planes[1], planeSize);
1677 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1679 CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]);
1680 dstp += dstSizes[2];
1684 CopyMemory(dstp, context->planes[2], planeSize);
1690 if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
1692 CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]);
1693 dstp += dstSizes[3];
1697 CopyMemory(dstp, context->planes[3], planeSize);
1703 if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
1709 const intptr_t diff = (dstp - dstData);
1710 if ((diff < 0) || (diff > UINT32_MAX))
1715 size = (UINT32)diff;
1720BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT context,
1721 UINT32 width, UINT32 height)
1726 context->bgr = FALSE;
1727 context->maxWidth = PLANAR_ALIGN(width, 4);
1728 context->maxHeight = PLANAR_ALIGN(height, 4);
1730 const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight;
1731 if (tmp > UINT32_MAX)
1733 context->maxPlaneSize = (UINT32)tmp;
1736 if (context->maxWidth > UINT32_MAX / 4)
1738 context->nTempStep = context->maxWidth * 4;
1740 memset((
void*)context->planes, 0,
sizeof(context->planes));
1741 memset((
void*)context->rlePlanes, 0,
sizeof(context->rlePlanes));
1742 memset((
void*)context->deltaPlanes, 0,
sizeof(context->deltaPlanes));
1744 if (context->maxPlaneSize > 0)
1746 void* tmp = winpr_aligned_recalloc(context->planesBuffer, context->maxPlaneSize, 4, 32);
1749 context->planesBuffer = tmp;
1751 tmp = winpr_aligned_recalloc(context->pTempData, context->maxPlaneSize, 6, 32);
1754 context->pTempData = tmp;
1756 tmp = winpr_aligned_recalloc(context->deltaPlanesBuffer, context->maxPlaneSize, 4, 32);
1759 context->deltaPlanesBuffer = tmp;
1761 tmp = winpr_aligned_recalloc(context->rlePlanesBuffer, context->maxPlaneSize, 4, 32);
1764 context->rlePlanesBuffer = tmp;
1766 context->planes[0] = &context->planesBuffer[0ULL * context->maxPlaneSize];
1767 context->planes[1] = &context->planesBuffer[1ULL * context->maxPlaneSize];
1768 context->planes[2] = &context->planesBuffer[2ULL * context->maxPlaneSize];
1769 context->planes[3] = &context->planesBuffer[3ULL * context->maxPlaneSize];
1770 context->deltaPlanes[0] = &context->deltaPlanesBuffer[0ULL * context->maxPlaneSize];
1771 context->deltaPlanes[1] = &context->deltaPlanesBuffer[1ULL * context->maxPlaneSize];
1772 context->deltaPlanes[2] = &context->deltaPlanesBuffer[2ULL * context->maxPlaneSize];
1773 context->deltaPlanes[3] = &context->deltaPlanesBuffer[3ULL * context->maxPlaneSize];
1778BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, UINT32 maxWidth,
1781 BITMAP_PLANAR_CONTEXT* context =
1782 (BITMAP_PLANAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(BITMAP_PLANAR_CONTEXT), 32);
1787 if (flags & PLANAR_FORMAT_HEADER_NA)
1788 context->AllowSkipAlpha = TRUE;
1790 if (flags & PLANAR_FORMAT_HEADER_RLE)
1791 context->AllowRunLengthEncoding = TRUE;
1793 if (flags & PLANAR_FORMAT_HEADER_CS)
1794 context->AllowColorSubsampling = TRUE;
1796 context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
1798 if (context->ColorLossLevel)
1799 context->AllowDynamicColorFidelity = TRUE;
1801 if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
1803 WINPR_PRAGMA_DIAG_PUSH
1804 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1805 freerdp_bitmap_planar_context_free(context);
1806 WINPR_PRAGMA_DIAG_POP
1813void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
1818 winpr_aligned_free(context->pTempData);
1819 winpr_aligned_free(context->planesBuffer);
1820 winpr_aligned_free(context->deltaPlanesBuffer);
1821 winpr_aligned_free(context->rlePlanesBuffer);
1822 winpr_aligned_free(context);
1825void freerdp_planar_switch_bgr(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL bgr)
1827 WINPR_ASSERT(planar);
1831void freerdp_planar_topdown_image(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, BOOL topdown)
1833 WINPR_ASSERT(planar);
1834 planar->topdown = topdown;